过滤execve环境的正确方法

correct way to filter execve environment

我正在尝试编写一个 LD_PRELOADable 库来防止进程从该变量中删除自身(以确保子进程继承它)。 到目前为止,我已成功包装 putenvsetenvclearenv,但 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 个问题:

我希望这听起来不像 "hey fix this for me" post 但我有点碰壁了,我们将不胜感激。

您不能假设 envp 中的单个字符串是用 malloc 分配的,因此 free(string) 可能是未定义的行为。用完全空的堆调用 exec* 几乎是不可能的,而且整个图像都会被替换,因此不值得担心。

您的第二个 strtok 调用应提供 NULL 作为其第一个参数。有关解释和示例,请参阅 man strtok

直接这样做:

  • 创建一个 new 指针数组,其大小必须容纳新的 env/ var/s
  • strdup() 从旧数组到新数组所需的所有元素。
  • 根据需要添加新内容。
  • 确保数组中的最后一个指针是NULL
  • 将新的指针数组传递给原来的execve()

不要修改甚至(尝试)旧环境的free()条目。