要求:
高级操作系统与分布式系统作业
ps和top命令列出了unix中当前所有进程的相关信息,作业要求在linux中增加两个系统调用,功能如下:
hide():执行此系统调用后,隐藏当前进程,即当前进程不能够被ps和top命令查看到。
unhide():执行此系统调用后,取消隐藏当前进程,即当前进程恢复正常,能够被ps和top命令查看到。
解题思路:
Ps命令和top命令从/proc文件系统中读取进程信息并显示出来。因此,如果一个进程的进程号没有在/proc文件系统中反映出来,则这个进程被“隐藏”了,“隐藏”进程在ps或top命令的输出不出现。
2。修改linux的进程控制块task_struts,在进程控制块中增加一个字段:
int hide;
hide的值为1时,表示该进程被隐藏;为0时,表示该进程不被隐藏。
3。修改创建进程的相关代码,在进程创建时,置hide为0;即进程在初始创建时(默认)不被隐藏。
4。在系统中增加系统调用hide(),其功能为:
1)将进程控制块中的hide置1;
2)删除/proc文件系统中该进程的相关目录项;
5。在系统中增加系统调用unhide(),其功能为:
1)将进程控制块中的hide清0;
2)增加/proc文件系统中该进程的相关目录项
具体做法:(实验内核版本2.6.28,)
跟踪内核可知,proc目录下进程号目录是动态生成的,是在每次readdir,getdents时动态生成,所以从某种意义上说增加或删除/proc文件系统中该进程的相关目录项这种说法是不正确的。proc目录内容的填充函数是proc_pid_readdir(fs/proc/base.c)
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) //内核源码,修改前
{
unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode);
struct tgid_iter iter;
struct pid_namespace *ns;
if (!reaper)
goto out_no_task;
for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { //这个for,填充self目录
const struct pid_entry *p = &proc_base_stuff[nr];
if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
goto out;
}
ns = filp->f_dentry->d_sb->s_fs_info;
iter.task = NULL;
iter.tgid = filp->f_pos - TGID_OFFSET;
for (iter = next_tgid(ns, iter);
iter.task;
iter.tgid += 1, iter = next_tgid(ns, iter)) { //这个for,根据系统内进程动态添加子进程号目录,也正是我们需要修改的函数
filp->f_pos = iter.tgid + TGID_OFFSET;
if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) {
put_task_struct(iter.task);
goto out;
}
}
filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
out:
put_task_struct(reaper);
out_no_task:
return 0;
}
将proc_pid_readdir函数中的for循环修改为
for (iter = next_tgid(ns, iter);
iter.task;
iter.tgid += 1, iter = next_tgid(ns, iter)) { //这个for,根据系统内进程动态添加子进程号目录,也正是我们需要修改的函数
if(!iter.task->hide){
filp->f_pos = iter.tgid + TGID_OFFSET;
if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) {
put_task_struct(iter.task);
goto out;
}
}
}
修改task_struct 添加hide字段(include/linux/sched.h)
struct task_struct{
...//现有字段
int hide;//添加hide字段,切忌不要在最开始添加,因为开始的字段的偏移量已固定,内核中其他部分已直接引用,如果在最开始添加,将导致现有代码不能正常工作
}
修改进程创建代码,初始化时置hide字段为0,修改copy_process函数(kernel/fork.c)
p = dup_task_struct(current);
if (!p)
goto fork_out;
p->hide=0;//添加
rt_mutex_init_task(p);
最后一步就是添加系统调用了,
修改kernel/sys.c
添加
asmlinkage long sys_hide()
{
current->hide=1;
return 0;
}
asmlinkage long sys_unhide()
{
current->hide=0;
return 0;
}
修改arch/x86/asm/include/unistd_32.h
#define __NR_inotify_init1 332
#define __NR_hide 333
#define __NR_unhide 334
#ifdef __KERNEL__
修改arch/x86/kernel/syscall_table_32.s
.long sys_dup3 /* 330 */
.long sys_pipe2
.long sys_inotify_init1
.long sys_hide
.long sys_unhide
重新编译内核...OK....
实验验证:
1 test_hide.c
#include <stdio.h>
int main(){
int pid=getpid();
char command[80];
sprintf(command,"ps aux|grep %d\n",pid);
printf("-------------------------------\n");
system(command);
printf("-------------------------------\n");
asm volatile(\
"int $0x80"\
::"a"(333)); // 执行333号系统调用即sys_hide
system(command);
asm volatile(\
"int $0x80"\
::"a"(334));
printf("-------------------------------\n");
system(command);
printf("-------------------------------\n");
return 0;
}
2 运行,查看实验结果