1. 程式人生 > >跟蹤分析Linux內核5.0系統調用處理過程

跟蹤分析Linux內核5.0系統調用處理過程

bubuko 內存空間 轉換 ase 運行 ubuntu fig 1.0 bss

學號尾號:155

基於ubuntu kylin 18.10虛擬機

原創作品轉載請註明出處https://github.com/mengning/linuxkernel/


實驗準備

下載和編譯內核

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz # 下載內核

# 解壓文件
xz -d linux-5.0.1.tar.xz
tar -xvf linux-5.0.tar.xz
cd linux-5.0

# 編譯內核
make i386_defconfig

此處出現報錯:
技術分享圖片

執行以下命令

apt-get install flex

再次執行

make i386_defconfig

出現報錯
技術分享圖片

執行以下命令

apt-get install bison

再次執行

make i386_defconfig
make

出現報錯
技術分享圖片
執行以下命令

apt-get install libssl-dev

再次執行

make

等待一段時間後,控制臺會輸出如下信息,表示編譯完成
技術分享圖片

制作根文件系統

cd ..
mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
gcc -pthread -o init linktable.c menu.c test.c -m32 -static

此處出現問題:
技術分享圖片

apt install gcc-multilib
gcc -pthread -o init linktable.c menu.c test.c -m32 -static

再次出現問題
技術分享圖片

apt-get install gcc-4.8 gcc-4.8-multilib g++-4.8 g++-4.8-multilib
gcc -pthread -o init linktable.c menu.c test.c -m32 -static

成功了
技術分享圖片

cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

制作成功!
技術分享圖片

啟動MenuOS

cd ..
qemu -kernel linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img

啟動成功!

技術分享圖片
---

跟蹤系統調用

我的學號尾號是155,在查閱系統調用表後,發現155號系統調用是

#define __NR_sched_getparam 155

函數的原型是

#include <sched.h> 

//該函數用於根據進程號獲取進程的調度參數,pid用於指定要獲取調度參數的進程號,為0時表示獲取當前進程的調度參數
//param用於存儲獲得的進程調度參數
//返回0時表示成功獲得進程的調度參數,返回-1時表示出錯,並設置errno
//errno有兩種,EPERM:調用進程沒有足夠的權限來獲取調度參數。ESRCH:進程pid不存在。
int sched_getparam(pid_t pid,struct sched_param * param);

struct sched_param
{
    int32_t  sched_priority;//獲取調度參數時,此成員將反映分配給線程或進程的優先級
    int32_t  sched_curpriority;//獲取調度參數時,此成員將設置為線程或進程當前運行的優先級。這是內核在進行調度決策時使用的值。
    union
    {
        int32_t  reserved[8];
        struct
        {
            int32_t  __ss_low_priority;
            int32_t  __ss_max_repl;
            struct timespec     __ss_repl_period;
            struct timespec     __ss_init_budget;
        }           __ss;
    }           __ss_un;
}

#define sched_ss_low_priority   __ss_un.__ss.__ss_low_priority
#define sched_ss_max_repl       __ss_un.__ss.__ss_max_repl
#define sched_ss_repl_period    __ss_un.__ss.__ss_repl_period
#define sched_ss_init_budget    __ss_un.__ss.__ss_init_budget

對於該系統調用,我們可以寫出如下代碼對其進行測試

//在menu文件夾中的test.c文件中加入如下代碼
#include <sched.h> 
int test_get_param()
{
    struct sched_param param;
    sched_getparam(0,&param);
    
    printf("The original priority of the process is %d\n",param.sched_priority);
}

int main()
{
    PrintMenuOS();
    SetPrompt("MenuOS>>");
    MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
    MenuConfig("quit","Quit from MenuOS",Quit);
    MenuConfig("time","Show System Time",Time);
    MenuConfig("time-asm","Show System Time(asm)",TimeAsm);
    MenuConfig("get_param","根據進程號獲取進程的優先級",test_get_param);
    ExecuteMenu();
}

重新制作根文件系統

gcc -pthread -o init linktable.c menu.c test.c -m32 -static
cd ../rootfs
cp ../menu/init ./
find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img

使用gdb跟蹤調試內核

cd ..
qemu -kernel linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr

此時啟動的qemu窗口是stopped的狀態
技術分享圖片

另開一個shell窗口

gdb
file vmlinux # target remote之前加載符號表
target remote:1234 # 建立gdb和gdbserver之間的連接,按c讓qemu上的Linux系統繼續運行
b sys_sched_getparam # 打上斷點

技術分享圖片

在gdb窗口中輸入

c

技術分享圖片

在qemu窗口中輸入

get_param

技術分享圖片

在gdb窗口中輸入

c

技術分享圖片


系統調用分析

可以看到,sched_getparam系統調用的流程如下:

  1. 用戶調用sched_getparam接口
  2. 將系統調用號155放入eax寄存器
  3. 執行int $0x80指令產生一個向量為128的編程異常,進入內核態
  4. 保護現場
  5. 根據系統調用號,查找系統調用表,找到中斷處理程序的地址並執行中斷處理程序
  6. 恢復現場,進入用戶態

由此可以看出,用戶態進程是無法訪問內核的內存空間的,只有內核態進程才能訪問內核。因此當執行系統調用時,必須要先將進程轉換成內核態才能執行系統調用,執行完畢後再恢復到用戶態。

跟蹤分析Linux內核5.0系統調用處理過程