Post

(kernel) addr\_limit - kernel space arg

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

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct {
unsigned long    seg;
} mm\_segment\_t;

  

struct thread\_struct {
...
mm\_segment\_t     addr\_limit;
...
};

* 기본값은 addr\_limit==PAGE\_OFFSET이다.

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

1
2
3
4
#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))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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 발생.

1
2
3
4
5
6
7
8
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가 들어가는 경우 : ]

1
2
3
4
5
6
7
8
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);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.

dmesg가 제대로 찍히는 것을 보면 LKM은 제대로 동작했는데, orig\_sys\_write()에서 제대로 출력되지 않은 것 같다. * 사실 이런 종류의 문자열 수정은 그냥 buf[0]으로 접근하면 addr_limit 설정이 필요 없기는 하다.

[ addr_limit를 해제한 경우 : ]

1
2
3
4
root@kali32:~/lkm/addr\_limit/write\_hook# insmod sys\_hook.ko
root@kali32:~/lkm/addr\_limit/write\_hook# ../../write\_test
BUM

This post is licensed under CC BY 4.0 by the author.