Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Null out after free

...

Code Block
bgColor#ccccff
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

extern char **environ;

/* These arrays are both null-terminated. */
static char *spc_restricted_environ[  ] = {
  "IFS= \t\n",
  0, /* leave room for PATH=... */
  0
};

static char *spc_preserve_environ[  ] = {
  "TZ",
  0
};

void spc_sanitize_environment(int preservec, const char **preservev) {
  int    i;
  char   **new_environ, *path, *ptr;
  const char *value, *var;
  size_t path_size, arr_size = 1, arr_ptr = 0, len, new_size = 0;

  if ((path_size = confstr(_CS_PATH, NULL, 0)) > 0) {
    path = (char *)malloc(path_size + sizeof("PATH=") - 1);
    if (path == NULL) {
      /* handle error */
    }
    strcpy(path, "PATH=");
    if (confstr(_CS_PATH, path + sizeof("PATH=") - 1, path_size) > 0) {
      spc_restricted_environ[1] = path;
    }
    else {
      free(path);
      path = NULL;
    }
  }
  for (i = 0;  (var = spc_restricted_environ[i]) != 0;  i++) {
    new_size += strlen(var) + 1;
    arr_size++;
  }
  for (i = 0;  (var = spc_preserve_environ[i]) != 0;  i++) {
    if ((value = getenv(var)) == NULL) continue;
    new_size += strlen(var) + strlen(value) + 2; /* include the '=' */
    arr_size++;
  }
  if (preservec && preservev) {
    for (i = 0;  i < preservec && (var = preservev[i]) != 0;  i++) {
      if ((value = getenv(var)) == NULL) continue;
      new_size += strlen(var) + strlen(value) + 2; /* include the '=' */
      arr_size++;
    }
  }

  new_size += (arr_size * sizeof(char *));
  if ((new_environ = (char **)malloc(new_size)) == NULL) abort(  );
  new_environ[arr_size - 1] = 0;

  ptr = (char *)new_environ + (arr_size * sizeof(char *));
  for (i = 0;  (var = spc_restricted_environ[i]) != 0;  i++) {
    new_environ[arr_ptr++] = ptr;
    len = strlen(var);
    memcpy(ptr, var, len + 1);
    ptr += len + 1;
  }
  for (i = 0;  (var = spc_preserve_environ[i]) != 0;  i++) {
    if ((value = getenv(var)) == NULL) continue;
    new_environ[arr_ptr++] = ptr;
    len = strlen(var);
    memcpy(ptr, var, len);
    *(ptr + len + 1) = '=';
    memcpy(ptr + len + 2, value, strlen(value) + 1);
    ptr += len + strlen(value) + 2; /* include the '=' */
  }
  if (preservec && preservev) {
    for (i = 0;  i < preservec && (var = preservev[i]) != 0;  i++) {
      if ((value = getenv(var)) == NULL) continue;
      new_environ[arr_ptr++] = ptr;
      len = strlen(var);
      memcpy(ptr, var, len);
      *(ptr + len + 1) = '=';
      memcpy(ptr + len + 2, value, strlen(value) + 1);
      ptr += len + strlen(value) + 2; /* include the '=' */
    }
  }

  /* new_environ can now be used as the envp argument to execle or execve */
}

...

Code Block
bgColor#ccccff
#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* ... */

uid_t uid;
struct passwd *pwd;

/* Sanitize environment, from previous compliant example  */
spc_sanitize_environment(0, NULL);

/* Get /etc/passwd entry for current user */
uid = getuid();
if ((pwd = getpwuid(uid)) == NULL) {
  /* handle error */
  endpwent();
  return 1;
}

/* Ensure home dir has no ', so we can quote it */
if (strchr( pwd->pw_dir, '\'') != NULL) {
  /* handle ' in home dir */
}

/* build system cmd using home dir from pw entry */
const char* cmd_format = "rm '%s'/foo";
const size_t len = strlen(pwd->pw_dir) + strlen(cmd_format);
char* cmd = (char*) malloc(len+1);
snprintf( cmd, len, cmd_format, pwd->pw_dir);
if (system(cmd) != 0) {
  /* handle error in rm command */
}

endpwent();
free(cmd);
cmd = NULL; 

...

Code Block
bgColor#ccccff
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* ... */

uid_t uid;
struct passwd *pwd;

/* Get /etc/passwd entry for current user */
uid = getuid();
if ((pwd = getpwuid(uid)) == NULL) {
  /* handle error */
  endpwent();
  return 1;
}

/* build full pathname home dir from pw entry */
const char* file_format = "%s/foo";
const size_t len = strlen(pwd->pw_dir) + strlen(file_format);
char* file = (char*) malloc(len+1);
snprintf( file, len, file_format, pwd->pw_dir);
if (unlink(file) != 0) {
  /* handle error in unlink */
}

endpwent();
free(cmd);
cmd = NULL; 

Risk Assessment

Invoking an external program in an attacker-controlled environment is dangerous.

...