过滤execve环境的正确方法
correct way to filter execve environment
我正在尝试编写一个 LD_PRELOAD
able 库来防止进程从该变量中删除自身(以确保子进程继承它)。
到目前为止,我已成功包装 putenv
、setenv
和 clearenv
,但 execve
给我带来了问题。
到目前为止我的代码:
int (*real_execve)(const char *filename, char *const argv[], char *const envp[]);
int execve(const char *filename, char *const argv[], char *const envp[]){
real_execve = dlsym(RTLD_NEXT,"execve");
char *path = getenv("LD_PRELOAD");
fprintf(stderr, "INTERCEPTED execve, env:\n");
int i;
for(i=0;envp[i]!=NULL;i++);
char *nenvp[i+1];
nenvp[i]=NULL;
for(i=0;envp[i]!=NULL;i++){
char *string = envp[i];
char *buf = malloc((strlen(string)+1)*sizeof(char));
strcpy(buf,string);
char *name = strtok(buf,"=");
char *value = strtok(NULL,"=");
if(0==strcmp(name,"LD_PRELOAD")){
fprintf(stderr," FIXING '%s'\n",string);
char * nstring = malloc((strlen(name)+strlen(path)+strlen(value)+3)*sizeof(char));
strcpy(nstring,name);
strcat(nstring,"=");
strcat(nstring,path);
strcat(nstring,":");
strcat(nstring,value);
nenvp[i]=nstring;
fprintf(stderr," TO '%s'\n",nenvp[i]);
free(string);
}else{
nenvp[i]=envp[i];
fprintf(stderr," LEFT '%s'\n",nenvp[i]);
}
free(buf);
}
fprintf(stderr, " CALLING %s\n", filename);
return real_execve(filename,argv,nenvp);
}
我遇到了 2 个问题:
它记录如下内容:
FIXING 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1'
TO 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1:/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1'
而不是预期的自我路径前置,所以我想我不知何故弄乱了 strtok。
我遇到了很多这样的错误:
Error in 'sh': munmap_chunk(): invalid pointer: 0x00007fff3888af4a
这对我来说听起来可能是我释放得太多了,但我找不到罪魁祸首。
我希望这听起来不像 "hey fix this for me" post 但我有点碰壁了,我们将不胜感激。
您不能假设 envp
中的单个字符串是用 malloc
分配的,因此 free(string)
可能是未定义的行为。用完全空的堆调用 exec*
几乎是不可能的,而且整个图像都会被替换,因此不值得担心。
您的第二个 strtok
调用应提供 NULL
作为其第一个参数。有关解释和示例,请参阅 man strtok
。
直接这样做:
- 创建一个 new 指针数组,其大小必须容纳新的 env/ var/s
strdup()
从旧数组到新数组所需的所有元素。
- 根据需要添加新内容。
- 确保数组中的最后一个指针是
NULL
。
- 将新的指针数组传递给原来的
execve()
。
不要修改甚至(尝试)旧环境的free()
条目。
我正在尝试编写一个 LD_PRELOAD
able 库来防止进程从该变量中删除自身(以确保子进程继承它)。
到目前为止,我已成功包装 putenv
、setenv
和 clearenv
,但 execve
给我带来了问题。
到目前为止我的代码:
int (*real_execve)(const char *filename, char *const argv[], char *const envp[]);
int execve(const char *filename, char *const argv[], char *const envp[]){
real_execve = dlsym(RTLD_NEXT,"execve");
char *path = getenv("LD_PRELOAD");
fprintf(stderr, "INTERCEPTED execve, env:\n");
int i;
for(i=0;envp[i]!=NULL;i++);
char *nenvp[i+1];
nenvp[i]=NULL;
for(i=0;envp[i]!=NULL;i++){
char *string = envp[i];
char *buf = malloc((strlen(string)+1)*sizeof(char));
strcpy(buf,string);
char *name = strtok(buf,"=");
char *value = strtok(NULL,"=");
if(0==strcmp(name,"LD_PRELOAD")){
fprintf(stderr," FIXING '%s'\n",string);
char * nstring = malloc((strlen(name)+strlen(path)+strlen(value)+3)*sizeof(char));
strcpy(nstring,name);
strcat(nstring,"=");
strcat(nstring,path);
strcat(nstring,":");
strcat(nstring,value);
nenvp[i]=nstring;
fprintf(stderr," TO '%s'\n",nenvp[i]);
free(string);
}else{
nenvp[i]=envp[i];
fprintf(stderr," LEFT '%s'\n",nenvp[i]);
}
free(buf);
}
fprintf(stderr, " CALLING %s\n", filename);
return real_execve(filename,argv,nenvp);
}
我遇到了 2 个问题:
它记录如下内容:
FIXING 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1' TO 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1:/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1'
而不是预期的自我路径前置,所以我想我不知何故弄乱了 strtok。
我遇到了很多这样的错误:
Error in 'sh': munmap_chunk(): invalid pointer: 0x00007fff3888af4a
这对我来说听起来可能是我释放得太多了,但我找不到罪魁祸首。
我希望这听起来不像 "hey fix this for me" post 但我有点碰壁了,我们将不胜感激。
您不能假设 envp
中的单个字符串是用 malloc
分配的,因此 free(string)
可能是未定义的行为。用完全空的堆调用 exec*
几乎是不可能的,而且整个图像都会被替换,因此不值得担心。
您的第二个 strtok
调用应提供 NULL
作为其第一个参数。有关解释和示例,请参阅 man strtok
。
直接这样做:
- 创建一个 new 指针数组,其大小必须容纳新的 env/ var/s
strdup()
从旧数组到新数组所需的所有元素。- 根据需要添加新内容。
- 确保数组中的最后一个指针是
NULL
。 - 将新的指针数组传递给原来的
execve()
。
不要修改甚至(尝试)旧环境的free()
条目。