task_structのeuidを書き換えてrootになる
Rev.1を表示中。最新版はこちら。
プロセスは固有のtask_struct構造体で管理されるコンテキストを有しています。はそこからいろいろなstructが紐づいているのですが、こいつがプロセスその物と言っても過言でありません。従ってtask_structを操作することはプロセスそのものを操作することになります。で、まずはtask_structのeuidを書き換えて、一般プロセスがroot権限で動作できることを確認します。
動作確認カーネルモジュール
#include <linux/kernel.h> #include <linux/sched.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <asm/uaccess.h> #define PROC_NAME "hogehoge" static size_t proc_write( struct file *filp, const char __user *buff, unsigned long len, void *data ); static struct proc_dir_entry *dirp; static void do_test(struct task_struct *process); static int proc_init_module(void) { dirp = (struct proc_dir_entry *) create_proc_entry(PROC_NAME, 0666, (struct proc_dir_entry *) 0); if (dirp == 0) return(-EINVAL); dirp->write_proc = (write_proc_t *) proc_write; return 0; } static void proc_cleanup_module(void) { remove_proc_entry(PROC_NAME, (struct proc_dir_entry *) 0); } static size_t proc_write( struct file *filp, const char __user *buff, unsigned long len, void *data ) { char _buff[64]; if (copy_from_user(_buff, buff, len )) { return -EFAULT; } int mypid = (int)simple_strtol(_buff, NULL, 0); struct task_struct *process; process = find_task_by_vpid(mypid); if (process) { do_test(process); } else { printk("pid error:%d\n", mypid); return -EFAULT; } return len; } static void do_test(struct task_struct *process) { process->euid = 0; } module_init(proc_init_module); module_exit(proc_cleanup_module);
Makefile
KERNELSRCDIR = ~/rpmbuild/BUILD/kernel-2.6.27/linux-2.6.27.i686/ BUILD_DIR := $(shell pwd) VERBOSE = 0 # モジュール名 obj-m := test.o all: make -C $(KERNELSRCDIR) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules clean: rm -f *.o rm -f *.ko rm -f *.mod.c rm -f *~
モジュールをカーネルに組み込む
[root@localhost test]# insmod test.ko
/proc下にhogehogeが作成されているの確認
[root@localhost test]# ls /proc/hogehoge /proc/hogehoge
一般ユーザになる。
[root@localhost test]# su kitamura [kitamura@localhost test]$ cat /etc/shadow cat: /etc/shadow: 許可がありません
自bashのプロセスIDを確認
[kitamura@localhost test]$ ps PID TTY TIME CMD 11786 pts/0 00:00:00 bash 11806 pts/0 00:00:00 ps
そのプロセスIDを/proc/hogehogeに書き込む
[kitamura@localhost test]$ echo 11786 > /proc/hogehoge
root権限で動作できることを確認
[kitamura@localhost test]$ cat /etc/shadow root:$$8l4a.5Bm$tuixsbkdSwvmtMq6BV40:14522:0:99999:7::: bin:*:14498:0:99999:7::: daemon:*:14498:0:99999:7:::
説明
下記設定はカーネルモジュールお決まりのまじない。モジュールがロードされたときに呼び出す処理をproc_init_module、アンロードされるときの処理をproc_cleanup_moduleに記述する。module_init(proc_init_module); module_exit(proc_cleanup_module);
proc_init_moduleではアクセスモード666で/procファイルシステム下にPROC_NAME "hogehoge"を作成。その書き込みコールバック処理をproc_writeに設定している。これで、/proc/hogehogeに何か書き込まれたらproc_writeが呼ばれる。
proc_writでcopy_from_userで書き込まれたデータ(プロセスID)を取得し、find_task_by_vpidで該当するtask_structを取得し、rootのIDである0をprocess->euidにセットしている。