이 문서를 읽기 전에 우선 숙지해야 할 사항은 kernel 영역에서 user 영역의 file에 대해 read/write를 사용하는 것은 절대 좋지 않은 정책이라는 것이다. 첫번째 이유는 커널의 보호문제이다. File의 data를 interrupt해가는 과정에서 유발되는 error는 buffer overflow 공격을 받을 가능성이 있다. 두번째 이유는 정책의 문제이다. 특정 fle system으로부터 특정 위치에서 특정 file을 읽어야 하는 kernel module은 user 영역에 의존성을 가지게 된다. 이것은 kernel developer들이 가장 피하는 정책이기도 하다.
이럼에도 불구하고 kernel 영역에서 user 영역의 file을 handling하여야 하는 경우는 종종 발생하는데, 이런 경우에서의 handling 하는 방법을 정리하는 것이 이 문서의 목표이다.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
static void read_file (char *filename)
{
int fd;
char buf[1];
loff_t pos = 0;
struct file *file;
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
fd = sys_open (filename, O_RDONLY, 0);
if (fd >= 0)
{
file = fget (fd);
if (file)
{
vfs_read (file, buf, sizeof (buf), &pos);
printk (“buf is %c\n”, buf[0]);
}
sys_close (fd);
}
set_fs (old_fs);
}
static void write_file (char *filename, char *data)
{
int fd;
loff_t pos = 0;
struct file *file;
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
fd = sys_open (filename, ORWONLY | O_CREAT, 0644);
if (fd >= 0)
{
file = fget (fd);
if (file)
{
vfs_write (file, data, strlen (data), &pos);
fput (file);
}
}
set_fs (old_fs);
}
static int __init init (void)
{
printk (“<0> file handling start\n”);
read_file (“/etc/shadow”);
write_file (“/etc/temp”, “foo”);
printk (“<0> file handing end\n”);
return 0;
}
static void __exit exit (void)
{
printk (“<0> bye\n”);
}
MODULE_LICENSE (“GPL”);
module_init (init);
module_exit (exit);
Kernel 은 sys_open에서 전달된 pointer가 user 영역에서 온 것이라고 판단한다. 따라서 이를 kernel 영역에 맞도록 전환하려고 하는데 이 예제에서는 kernel 영역에서 pointer를 넘긴 것이므로 여기서 발생하는 mistmach를 제거하기 위해 사용된다. set_fs ()에서 사용하는 parameter는 KERNEL_DS (kernel segment), USER_DS (user segment) 뿐이며, get_fs ()는 parameter 없이 현재의 segment 정보를 가져온다.
System call인 open / close가 kernel 내부에서 불리워지는 형태이며 parameter도 동일하다.
sys_open을 통해 생성된 fd를 vfs_ 계열의 함수에서 사용할 수 있는 struct file *의 형태로 변환시켜주고, fput ()으로 쓰여진 buffer를 sync한다.
ssize_t vfs_read (struct file *, char *, size_t, loff_t)
System call인 write / read가 kernel 내부에서 불리워지는 형태이며 parameter도 동일하다.
'Linux > Kernel Analysis' 카테고리의 다른 글
프로세스 정보 얻기 (Task Struct 이용) (0) | 2013.07.10 |
---|---|
커널영역에서 파일 입출력 (0) | 2013.07.10 |
커널 유저영역 데이터 전달 (0) | 2013.06.11 |
프로세스의 전체 실행시간 확인하기. (0) | 2013.05.15 |
부팅시 쉘 스크립트등 강제 실행하기. (0) | 2013.05.11 |