linux源碼分析(三)-start_kernel


前置:這里使用的linux版本是4.8,x86體系。

start_kernel是過了引導階段,進入到了內核啟動階段的入口。函數在init/main.c中。

set_task_stack_end_magic(&init_task);

這個函數是設置操作系統的第一個進程init。
這個init_task變量是怎么來的呢?從init/init_task.c中初始化的。

struct task_struct init_task = INIT_TASK(init_task);
EXPORT_SYMBOL(init_task);

而這個INIT_TASK的初始化在init/init_task.h:

#define INIT_TASK(tsk)    \
{                                    \
    .state        = 0,                        \
    .stack        = init_stack,                    \
    .usage        = ATOMIC_INIT(2),                \
    .flags        = PF_KTHREAD,                    \
    .prio        = MAX_PRIO-20,                    \
    .static_prio    = MAX_PRIO-20,                    \
    .normal_prio    = MAX_PRIO-20,                    \
     ...

這里使用的是gcc的結構體初始化方式。http://blog.csdn.net/justlinux2010/article/details/7494754 。這個結構體是根據task_struct結構進行初始化的。

再回到set_task_stack_end_magic

void set_task_stack_end_magic(struct task_struct *tsk)
{
    unsigned long *stackend;

    stackend = end_of_stack(tsk);
    *stackend = STACK_END_MAGIC;    /* for overflow detection */
}

這個end_of_stack 在include/linux/sched.h中。它的意思是獲取棧邊界地址。然后把棧底地址設置為STACK_END_MAGIC。這個作為棧溢出的標記。

每個進程創建的時候,系統會為這個進程創建2個頁大小的內核棧。這個內核棧底下是thread_info結構。高位是棧。

http://blog.chinaunix.net/uid-20543672-id-2996319.html

這里的STACK_END_MAGIC就是設置在thread_info結構的上面。比如如果你寫了一個無限循環,導致棧使用不斷增長了,那么,一旦把這個標記未修改了,就導致了棧溢出的錯誤。

smp_setup_processor_id();

下面是這個

    smp_setup_processor_id();   // 設置smp模型的處理器id

smp模型指的是對稱多處理模型(Symmetric Multi-Processor),與它對應的是NUMA非一致存儲訪問結構(Non-Uniform Memory Access)和MPP 海量並行處理結構(Massive Parallel Processing)。它們的區別分別在於,SMP指的是多個CPU之間是平等關系,共享全部總線,內存和I/O等。但是這個結構擴展性不好,往往CPU數量多了之后,很容易遇到搶占資源的問題。NUMA結構則是把CPU分模塊,每個模塊具有獨立的內存,I/O插槽等。各個模塊之間通過互聯模塊進行數據交互。但是這樣,就表示了有的內存數據在這個CPU模塊中,那么處理這個數據當然最好是選擇當前的CPU模塊,這樣每個CPU實際上地位就不一致了。所以叫做非一致的存儲訪問結構。而MPP呢,則是由多個SMP服務器通過互聯網方式連接起來。

支持SMP模型的CPU有AMD/AMD64。而支持NUMA的有X86等。而這里的代碼,smp_setup_process_id在普通情況下是空實現,在不同的體系,比如arch/arm/kernel/setup.c, line 586
就有對應的邏輯了。

debug_objects_early_init();

這個函數的實際代碼在lib/debugobject.c

void __init debug_objects_early_init(void)
{
    int i;

    for (i = 0; i < ODEBUG_HASH_SIZE; i++)
        raw_spin_lock_init(&obj_hash[i].lock);

    for (i = 0; i < ODEBUG_POOL_SIZE; i++)
        hlist_add_head(&obj_static_pool[i].node, &obj_pool);
}

可以看到,它主要是用來對obj_hash,obj_static_pool這兩個全局變量進行初始化設置。這兩個全局變量在進行調試的時候會使用到。

http://m.blog.chinaunix.net/uid-27717694-id-4425488.html

boot_init_stack_canary();

這個函數是做什么的呢?我們要說堆棧溢出漏洞,它的意思就是動態分配的堆中,不按照本來分配的大小進行設置,而是使用某種方法,設置變量分配大小之外的數據。甚至設置到了函數棧的數據了,那么,這個時候就可能會被調用到注入的某個函數中了。具體攻擊示例看:http://www.ibm.com/developerworks/cn/linux/l-overflow/

那么,和前面的end_magic邏輯一樣,我們在堆和棧的中介處設置一個標記位(叫做canary word)。當這個位被修改的時候,我們就知道了,這個時候存在堆棧溢出,就進行錯誤處理。

那么這個標記位的值是怎么樣子的,就是使用這個函數。這個也和CPU架構有關系了,比如在x86的系統中,是隨機產生的。https://www.ibm.com/developerworks/cn/linux/l-cn-gccstack/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM