리눅스 커널 인자로 문자열을 넘길때 공백을 넣는 방법.
Posted by 미스란디르
어떤 리눅스 커널 모듈을 만들었다고 치고.
insmod xxx.ko test=hello world
저러면 원하는대로 test에 hello world라는 값을 넣을 수 없다.
요건 어찌하면 좋을까?
쉘에서 분리하지 않게 test=”hello world” 해도 안된다.
insmod.c를 살펴보면,
for (i = 2; i < argc; i++) {
options = realloc(options,
strlen(options) + 1 + strlen(argv[i]) + 1);
strcat(options, argv[i]);
strcat(options, " ");
}
.
.
.
ret = init_module(file, len, options);
요게 전부다.
따로 strtok를 하지도 않고 그냥 붙여서 init_module 해버린다.
그런데 저 init_module을 사실은 시스템콜이다. 본체를 찾아보니 kernel/module.c 에 @sys_init_module@이 있다.
요녀석은 다시
mod = load_module(umod, len, uargs);
로 넘긴다.
이녀석을 찾아보면,
args = strndup_user(uargs, ~0UL >> 1);
.
.
.
mod->args = args;
if (obsparmindex)
printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
mod->name);
/* Size of section 0 is 0, so this works well if no params */
err = parse_args(mod->name, mod->args,
(struct kernel_param *)
sechdrs[setupindex].sh_addr,
sechdrs[setupindex].sh_size
/ sizeof(struct kernel_param),
NULL);
뭐 이런걸 찾을 수 있다.
parse_args를 찾아 kernel/params.c로 뛰어보면,
args = next_arg(args, ¶m, &val);
irq_was_disabled = irqs_disabled();
ret = parse_one(param, val, params, num, unknown);
슬슬 목표에 가까워지는 기분이다.
우선 next_arg
static char *next_arg(char *args, char **param, char **val)
{
unsigned int i, equals = 0;
int in_quote = 0, quoted = 0;
char *next;
if (*args == '"') {
args++;
in_quote = 1;
quoted = 1;
}
“로 시작하면 인용문자열이라고 인식하는거다.
for (i = 0; args[i]; i++) {
if (args[i] == ' ' && !in_quote)
break;
if (equals == 0) {
if (args[i] == '=')
equals = i;
}
if (args[i] == '"')
in_quote = !in_quote;
}
이제 공백이 나왔는데 인용문자열이 아니면 끝내는거다. 바로 요거다. 공백을 넣으려면 “로 싸야한다. 그 다음은 = 이 나왔을때 등호의 위치를 기억해두는거다. 그리고 그 다음은 quote상태를 토글하는거고.
그 밑에는 등호의 위치를 이용해서 param과 val를 나누고, val에서 “를 빼는 따위의 짓을 한다.
이제 대충 결론이 났다. test에 Hello world를 넣으려면,
insmod xxx.ko 'test="Hello world"'
라고 해주면 되겠다.
