유저레벨에서 커널에 있는 API 를 동작시키는 인터페이스는 시스템 콜로써 항상 사용되는 것이다.
하지만 커널 레벨에서 사용자 공간의 어플리케이션을 실행하는 것은 그다지 알려져 있지 않다.
하지만 가만히 생각해 보면 핫플러그인과 같이 USB 가 꼽히면 자동으로 마운트되는 것을 우리는 알고 있다.
과연 어플리케이션에서 주기적으로 USB 꼽힌 것을 체크해서 마운트 하는 것일까?
그렇지 않다.
커널 레벨에서 USB가 인식되면 종류에 따라 마운트를 시켜주는 함수가 실행되게 된다.
혹은 모듈이 필요하면 모듈까지도 로딩을 시켜준다.
이런 인터페이스가 가능한 커널 함수를 소개한다.
그 인터페이시의 이름은 usermodehelper API 이다.
그 API를 한번 살펴보면
usermod 헬퍼 API 핵심함수
call_usermodehelper_setup 사용자 지역 호출을 위한 핸들러 준비
call_usermodehelper_setkeys 헬퍼의 세션 키 설정
call_usermodehelper_setcleanup 헬퍼의 정리 함수 설정
call_usermodehelper_stdinpipe 헬퍼의 stdin 파이프 작성
call_usermodehelper_exec 사용자 지역 호출 호출
이정도로 구성되어 있다.
자료구조를 살펴보면
kernel/kmod.c#L117
117struct subprocess_info {
118 struct work_struct work;
119 struct completion *complete;
120 char *path;
121 char **argv;
122 char **envp;
123 struct key *ring;
124 enum umh_wait wait;
125 int retval;
126 struct file *stdin;
127 void (*cleanup)(char **argv, char **envp);
128};
의외로 아주 간단한 구조를 갖고 있다.
이제 사용자 모드 헬퍼 API 의 내부구조를 살펴보자.
kernel_execve 를 사용하여 커널 공간 커널모듈 로더로 사용하는 구현을 한다.
kernel_execve 는 부팅시 init 프로세스를 시작하는데 사용되는 함수이며 사용자 모드 헬퍼 API는 사용하지 않는다.
#include <linux/kmod.h> 추가 --> call_usermodehelper() 함수 사용가능!!
< call_usermodehelper : 커널에서 유저레벨 응용프로그램 실행하게 해줌!! >
static int umh_test( void )
{
char *argv[] = { "/usr/bin/logger", "help!", NULL };
static char *envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };ㅓㅓ
return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
}
마치 사용자 프로그램에서 main 프로그램의 변형을 보는 것 같다.
위의 에제를 실행함에 있어 빠진 것들이 있다.
일반적으로 사용자 환경에서 실행될때 shell 에서 해주는 역할들이 없기 때문에
signal 처리, 세션 키 링 설정, stdio 파이프 설치등 모든 설정을 envp 에 일일이 해주어야 한다는 것이다.
위의 예제가 logger 가 아니라 printf("hello world\n"); 를 실행하는 예제라면
"hello world" 라는 문구를 볼수 없다. 왜냐하면 stdio pipe 를 연결하지 않았기 때문이다.
logger 는 /var/log/messages 안에서 내용을 살펴보면 실행 여부를 확인할수 있다.
tried with full path?
Like execve() in user space do_execve() may want the absolute path of the file to execute (execlp is not a syscall..). In your case "/bin/sh" instead of "sh". In fact, what the error "no a file or directory" says is exactly "you passed the wrong file name"...