操作系統實驗三:Linux進程管理及其擴展


一、實驗內容

1.閱讀並分析Linux內核源代碼,了解進程控制塊、進程隊列等數據結構;
2.實現一個系統調用,使得可以根據指定的參數隱藏進程,使用戶無法使用ps或top觀察到進程狀態。具體要求如下:
  (1)實現系統調用int hide(pid_t pid, int on),在進程pid有效的前提下,如果on置1,進程被隱藏,用戶無法通過ps或top觀察到進程狀態;如果on置0且此前為隱藏狀態,則恢復正常狀態。
  (2)考慮權限問題,只有根用戶才能隱藏進程。
  (3)設計一個新的系統調用int hide_user_processes(uid_t uid, char *binname),參數uid為用戶ID號,當binname參數為NULL時,隱藏該用戶的所有進程;否則,隱藏二進制映像名為binname的用戶進程。該系統調用應與hide系統調用共存。
  (4)在/proc目錄下創建一個文件/proc/hidden,該文件可讀可寫,對應一個全局變量hidden_flag,當hidden_flag為0時,所有進程都無法隱藏,即便此前進程被hide系統調用要求隱藏。只有當hidden_flag為1時,此前通過hide調用要求被屏蔽的進程才隱藏起來。
  (5)在/proc目錄下創建一個文件/proc/hidden_process,該文件的內容包含所有被隱藏進程的pid,各pid之間用空格分開。

 

二、實驗目的

1.加深理解進程控制塊、進程隊列等概念

2.了解進程管理的具體實施方法

 自<a>dfx</a>己獨立<span>adsf</span>完成別<b>fdas</b>總是<xxx>fdas</xxx>有事沒事<zzz>fdas</zzz>抄<qq>435fff</qq>別人的哦

三、新增系統調用hide

1、設計思路和流程圖

(1)設置標識

通過設置一個標記位來控制進程是否隱藏。

在include/linux/sched.h中修改結構體 task_struct ,添加一個成員 cloak ,0表示顯示,1表示隱藏。

 

(2)初始化

進程剛創建時是處於顯示的狀態,所以需要將標記cloak初始化為0。

fork系統調用的實現位於kernel/fork.c中,具體實現的主要函數為do_fork,do_fork中調用copy_process函數創建子進程,在該函數中初始化cloak。

 

(3)添加hide系統調用

具體流程參考實驗二,具體解釋見代碼部分。

 

(4)過濾隱藏的進程

修改fs/proc/base.c中的proc_pid_readdir函數以及proc_pid_lookup函數,過濾掉被隱藏的進程。

 

2、主要數據結構及說明

使用了結構體task_struct,通過對結構體里的cloak等變量進行賦值,改變進程的狀態。

 

3、源程序並附上注釋

(1)hide.c

使用內核函數find_task_by_pid,通過pid獲取進程task_struct。在隱藏后調用函數proc_flush_task來清空VFS層的緩沖,解除已有的dentry項。

其中包括對用戶權限的判斷,必須是root用戶,即uid=0才能進行相關操作。

#include<linux/linkage.h>
#include<linux/types.h>
#include<linux/sched.h>
#include<linux/pid.h>
#include<linux/proc_fs.h>

asmlinkage int sys_hide(pid_t pid, int on)
{
    struct task_struct *p=NULL;
    if(pid>0 && (current->uid)==0)//only the root user can hide the process
    {
        p=find_task_by_pid(pid);
        p->cloak=on;//set the state of the process
        if(on==1)
        {
            printk("Process %d is hidden by root.\n",pid);
        }
        if(on==0)
        {
            printk("Process %d is displayed by root.\n",pid);
        }
        proc_flush_task(p);
    }
    else
        printk("Sorry, you are not root user.Permission denied.\n");
    
    return 0;
}

 

(2)測試程序

比如隱藏進程號為1的進程,代碼如下

#include<stdio.h>
#include<sys/syscall.h>
#include<unistd.h>
int main()
{
    int syscallNum=321;
    pid_t pid=1;
    int on=1;
    syscall(syscallNum,pid,on);
    return 0;
}

  

4、程序運行結果及分析

(1)初始狀態

目前進程都是處於顯示的狀態,我們的目的是隱藏1號進程

 

(2)在非root用戶下執行測試程序

進程未被隱藏,用 dmesg 命令查看輸出

 

(3)切換到root用戶

再次執行程序,結果如下,1號進程被隱藏了

 

(4)更改參數on=0

被隱藏的進程將再次出現

 

 

四、新增系統調用hide_user_processes

1、設計思路和流程圖

基於實驗二以及新增系統調用hidden這兩個實驗,這個實驗很容易完成。

遍歷系統中所有的進程,隱藏滿足要求的進程。使用函數for_each_process遍歷所有進程,每個進程的task_struct中有成員變量uid和comm,uid為該進程的用戶id,comm為進程名,根據要求隱藏對應進程。具體解釋見代碼部分。

 

2、主要數據結構及說明

使用了結構體task_struct,通過其中的cloak等變量,控制進程的狀態。 

 

3、源程序並附上注釋

(1)hide_user_processes.c

包括三個參數,前兩個參數是根據實驗要求設置的,第三個參數recover用於恢復被隱藏的進程。如果recover=0那么隱藏相應的進程,如果不為0,則恢復所有進程為顯示狀態。

#include<linux/linkage.h>
#include<linux/types.h>
#include<linux/sched.h>
#include<linux/pid.h>
#include<linux/proc_fs.h>
#include<linux/string.h>

asmlinkage int sys_hide_user_processes(uid_t uid,char *binname,int recover){
    struct task_struct *p=NULL;
    if(recover==0)
    {
        if(current->uid==0)//1.Paragram recover=0;2.root => you can hide the process
        {
            if(binname==NULL)//when null, hide all the processes of the corresponding user
            {
                for_each_process(p)
                {
                    if((p->uid)==uid)
                    {
                        p->cloak=1;
                        proc_flush_task(p);
                    }
                }
                printk("All of the processes of uid %d are hidden.\n",uid);
            }
            else//otherwise, hide the process of the corresponding name
            {
                for_each_process(p)
                {
                    char *s=p->comm;
                    if(strcmp(s,binname)==0 && p->uid==uid)
                    {
                        p->cloak=1;
                        printk("Process %s of uid %d is hidden.\n",binname,uid);
                        proc_flush_task(p);
                    }
                }
            }
        }
        else
            printk("Sorry, you are not root user. Permission denied.\n");
    }
    else if(recover != 0 && (current->uid)==0)//display all of the processes, including which are hidden
    {
        for_each_process(p)
        {
            p->cloak=0;
        }
    }
    
    return 0;
}

  

(2)測試程序(可以修改參數,從而實現不同的要求)

#include<stdio.h>
#include<sys/syscall.h>
#include<unistd.h>
int main()
{
    int syscallNum=322;
    uid_t uid=500;
    char *binname=NULL;//Author:Kong
    int recover=0;
    syscall(syscallNum,uid,binname,recover);
    return 0;
}

  

4、程序運行結果及分析

(1)與上個實驗一樣,如果非root用戶,則沒有隱藏進程的權限

初始狀態如下

 

(2)隱藏uid為0,進程名為init的進程

修改參數uid_t uid=0; char *binname="init";

結果如下,對應的進程被隱藏了

 

(3)隱藏uid=500(對應用戶名為seu)的所有進程

修改參數uid_t uid=500; char *binname=NULL;

結果如下,seu用戶的所有進程被隱藏了

 

(4)更改參數recover=1,所有進程將恢復為顯示狀態

結果如下

 

 

五、在/proc目錄下創建一個文件/proc/hidden

1、設計思路和流程圖

(1)全局變量hidden_flag

因為這個實驗又涉及到隱藏進程的問題,所以需要再設置一個標識作為判斷,hidden文件的讀寫對它進行操作即可。

在/fs/proc目錄下新建一個頭文件,里面包含一個全局變量,其它文件中需要用到這個全局變量的時候,需使用include包含這個頭文件。

1 extern int hidden_flag;

 

(2)hidden文件的創建及讀寫

 proc文件系統在初始化函數proc_root_init中會調用proc_misc_init函數,此函數用於創建/proc根目錄下的文件,那么將創建hidden文件的代碼插入到此函數中就可以在proc初始化時得到執行。在/fs/proc/proc_misc.c中添加回調函數,在/fs/proc/proc_misc.c中proc_misc_init函數的最后添加創建hidden文件的代碼,並指定其回調函數,具體說明見代碼部分。

 

 

 

(3)根據hidden_flag顯示/隱藏進程

結合上面根據cloak判斷進程,這個實驗與之類似,只需在fs/proc/base.c文件中,修改proc_pid_readdir函數以及proc_pid_lookup函數,在cloak判斷之前,增加hidden_flag對進程的約束。

 

 

(4)重新編譯安裝內核,重啟之后進行測試。

 

2、主要數據結構及說明

使用到了結構體、進程控制塊等數據結構。 

 

3、源程序並附上注釋

主要是hidden文件的創建及讀寫。

在/fs/proc/proc_misc.c中添加回調函數,首先初始化全局變量hidden_flag為1;讀操作中sprintf將hidden_flag的值傳給page,然后顯示出來;寫操作中使用copy_from_user先將用戶輸入的值傳給temp,然后從temp中得到值傳給hidden_flag。

int hidden_flag=1;

static int proc_read_hidden(char *page,char **start,off_t off,int count,int *eof,void *data)
{
    int len=0;
    len=sprintf(page,"%d",hidden_flag);
    return len;
}

static int proc_write_hidden(struct file *file,const char *buffer,unsigned long count,void *data)
{
    int len=0;
    char temp[BUF_LEN];
    if(count > BUF_LEN)
            len = BUF_LEN;
        else
            len = count;
    
    copy_from_user(temp, buffer, len);//convert user's input to temp
    temp[len]='\0';
    hidden_flag=temp[0]-'0';//set the value of hidden_flag
    return len;
}

  

下面是創建hidden文件的代碼,使用的是create_proc_entry函數,然后指定其回調函數

struct proc_dir_entry *ptr=create_proc_entry("hidden",0644,NULL);
ptr->read_proc=proc_read_hidden;
ptr->write_proc=proc_write_hidden;

  

4、程序運行結果及分析

(1)首先默認設置hidden_flag=1,使用hide_user_processes隱藏uid=500,即seu用戶的所有進程。

 

(2)將hidden_flag的值改為0,這時再查看進程,所有被隱藏的進程又出現了。

 

 

(3)將hidden_flag改回為1,查看進程,seu用戶的進程又處於隱藏狀態了。

 

 

 

六、在/proc目錄下創建一個文件/proc/hidden_process

1、設計思路和流程圖

 該文件用於存儲所有被隱藏進程的pid,因為這個文件暫時不涉及用戶寫入,所以只需設置其讀回調函數。具體說明見代碼部分。

 

 

 

 

然后重新編譯安裝內核,重啟后測試。

 

2、主要數據結構及說明

使用了結構體、進程控制塊、進程隊列等數據結構。 

 

3、源程序並附上注釋

通過for_each_process函數,將被隱藏的進程的pid傳給buf,最后將buf傳給page顯示在終端上。

static int proc_read_hidden_processes(char *page,char **start,off_t off,int count,int *eof,void *data)
{    
    static char buf[1024*8]="";
        char tmp[128]; 
        struct task_struct *p;
    if(off>0)
        return 0;
    sprintf(buf,"%s","");
        for_each_process(p)
       { //自<a>dfx</a>己獨立<span>adsf</span>完成別<b>fdas</b>總是<xxx>fdas</xxx>有事沒事<zzz>fdas</zzz>抄<qq>435fff</qq>別人的哦
        if(p->cloak==1)
        {
                sprintf(tmp,"%d ",p->pid); //a important step
                strcat(buf,tmp); 
        }
        } 
    sprintf(page,"%s",buf);//convert buf to page to display on the terminal
        return strlen(buf);//Author:Kong
}

  

 4、程序運行結果及分析

(1)首先隱藏uid=500,即seu用戶的所有進程

查看hidden_process文件里的內容,發現所有被隱藏進程的pid都存在這里。

 

(2)恢復所有進程為顯示狀態

這時沒有被隱藏的進程,hidden_process文件里的內容也為空。

 

(3)經過多次不同的測試,實現了效果,沒有bug發生

 

七、實驗體會

這次實驗的前兩個,增加系統函數的使用很容易就完成了。我主要在后面的文件系統部分遇到了一些問題,使用指針的時候總是遇到很大的問題,要么是重啟之后不能進入內核,要么是測試的時候虛擬機卡住一動不動,然后必須進入原來的內核當中修改新內核,耗費了很多的時間。其實該做好備份的,這樣也許可以節省很多時間。

最令我不解的是,使用char *a的形式總是出問題,改為char a[]的形式問題便消失了,具體原因還有待我繼續尋找。

這次實驗之后,我對linux的進程控制、命令、系統調用、文件系統等方面都有了更深的認識,使用起來比以前熟練多了,但問題依然有很多,需要我繼續想方設法解決。以前看的資料大多是籠統地講解linux,雖然對整體了解有幫助,但是內部實現我涉獵不廣,這次實驗幫助我對內部實現有了更多的認識。


免責聲明!

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



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