addr_limit

system call은 원래 user mode에서 호출하도록 되어 있기 때문에, system call의 인자로 넘어오는 데이터는 user space의 데이터여야 한다. 인자로 kernel space의 데이터가 넘어오면 제대로 동작하지 않는다.

kernel은 `` addr_limit``를 기준으로 인자로 넘어온 데이터가 user space data인지 kernel space data를 구분한다. 
따라서 이 경계를 조정해주면 user space data를 넘겨도 정상 동작하도록 만들 수 있다.

/source/arch/x86/include/asm/processor.h#L421

```c

typedef struct {

    unsigned long    seg;

} mm_segment_t;


struct thread_struct {

    ...

    mm_segment_t     addr_limit;

    ...

};

```

* 기본값은 ``c addr_limit==PAGE_OFFSET``이다.


/source/arch/x86/include/asm/uaccess.h#L27

```c

#define get_ds()     (KERNEL_DS)   // == MAKE_MM_SEG(-1UL)

#define get_fs()     (current->thread.addr_limit)

#define set_fs(x)    (current->thread.addr_limit = (x))

```

```c

#include <asm/uaccess.h>


mm_segment_t orig_fs;

orig_fs = get_fs();

set_fs(get_ds());


/* do something */


set_fs(orig_fs);

```

Note ) 현재 thread에 대해서 `` addr_limit``를 수정하는 것이기 때문에, 시스템 전역적으로 적용되는 것이 아니다.


Note ) `` addr_limit``를 해제한다고 해도, user mode에서 kernel space에 접근할 수 있는 것이 아니다.
따라서 kernel code에 접근하거나, kernel data에 접근하는 것은 불가능하다.
user mode의 test 프로세스가 c95d32bc 에 접근하려 하면 segfault 발생.
```bash
root@kali32:~/lkm/addr_limit# dmesg | tail -6
[91770.266480] b_hook LKM is loaded
[91770.266482] sct[__NR_swapon]  c95d32bc : c91b0fe0 : 26748d3e
[91770.266484] sct[__NR_swapon]  c95d32bc : f96c9000 : 26748d3e
[91771.717924] orig_addr_limit : c0000000
[91771.717925] new_addr_limit  : ffffffff
[91771.717929] test[10583]: segfault at c95d32bc ip 00400581 sp bffff630 error 5 in test[400000+1000]

```


e.g.

[ user space data가 들어가야 할 자리에 kernel space data가 들어가는 경우 : ]

```c

asmlinkage long hook_sys_write(unsigned int fd, char __user *buf, size_t count){

    if (!strcmp(buf, "bum")){

        printk("hook");

        return orig_sys_write(fd, "BUM", count);

    }   

    return orig_sys_write(fd, buf, count);

}

```

```bash

root@kali32:~/lkm/addr_limit/write_hook# ../../write_test 

bum

root@kali32:~/lkm/addr_limit/write_hook# insmod sys_hook.ko

root@kali32:~/lkm/addr_limit/write_hook# ../../write_test 

root@kali32:~/lkm/addr_limit/write_hook# rmmod sys_hook 

root@kali32:~/lkm/addr_limit/write_hook# ../../write_test

bum

root@kali32:~/lkm/addr_limit/write_hook# dmesg | tail -5

[112700.607849] b_hook LKM is loaded

[112700.607851] sct[__NR_write(4)]  c95d3170 : c91dc6e0 : 26748d3e

[112700.607852] sct[__NR_write(4)]  c95d3170 : f970c000 : 26748d3e

[112702.850690] hook

[112706.057887] b_hook LKM is removed.

```

``bash dmesg``가 제대로 찍히는 것을 보면 LKM은 제대로 동작했는데, ``c orig_sys_write()``에서 제대로 출력되지 않은 것 같다.

* 사실 이런 종류의 문자열 수정은 그냥 ``c buf[0]``으로 접근하면 addr_limit 설정이 필요 없기는 하다.


[ addr_limit를 해제한 경우 : ]

```bash

root@kali32:~/lkm/addr_limit/write_hook# insmod sys_hook.ko

root@kali32:~/lkm/addr_limit/write_hook# ../../write_test 

BUM

```

'OS > Kernel' 카테고리의 다른 글

[kernel] get sys_call_table  (0) 2017.10.16
[kernel] Page Protection  (0) 2017.10.16
[kernel] LKM, Loadable Kernel Module / Kernel Compile  (0) 2017.10.14
[kernel] virt_to_phys  (0) 2017.10.13
[kernel] exploit  (0) 2017.10.06