linux, darwin: don't touch environ in uv_setup_args

Don't overwrite the environment. On OS X, the entries in the environ
table are not necessarily adjacent. It's arguably also safer for setuid
binaries.

Fixes joyent/node#4847.
This commit is contained in:
Ben Noordhuis 2013-02-26 19:14:40 +01:00
parent c5101ae9b5
commit a0c1d84c14

View File

@ -30,68 +30,45 @@ static void* args_mem;
static struct { static struct {
char* str; char* str;
int len; size_t len;
} process_title; } process_title;
char** uv_setup_args(int argc, char** argv) { char** uv_setup_args(int argc, char** argv) {
char** new_argv; char** new_argv;
char** new_env;
size_t size; size_t size;
int envc;
char* s; char* s;
int i; int i;
#if defined(__APPLE__) if (argc <= 0)
char*** _NSGetArgv(void); return argv;
char*** _NSGetEnviron(void);
char** environ = *_NSGetEnviron();
#else
extern char** environ;
#endif
for (envc = 0; environ[envc]; envc++); /* Calculate how much memory we need for the argv strings. */
size = 0;
if (envc == 0) for (i = 0; i < argc; i++)
s = argv[argc - 1]; size += strlen(argv[i]) + 1;
else
s = environ[envc - 1];
process_title.str = argv[0]; process_title.str = argv[0];
process_title.len = s + strlen(s) + 1 - argv[0]; process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
size = process_title.len; /* Add space for the argv pointers. */
size += (argc + 1) * sizeof(char**); size += (argc + 1) * sizeof(char*);
size += (envc + 1) * sizeof(char**);
s = args_mem = malloc(size);
if (s == NULL) { new_argv = malloc(size);
process_title.str = NULL; if (new_argv == NULL)
process_title.len = 0;
return argv; return argv;
args_mem = new_argv;
/* Copy over the strings and set up the pointer table. */
s = (char*) &new_argv[argc + 1];
for (i = 0; i < argc; i++) {
size = strlen(argv[i]) + 1;
memcpy(s, argv[i], size);
new_argv[i] = s;
s += size;
} }
new_argv[i] = NULL;
new_argv = (char**) s;
new_env = new_argv + argc + 1;
s = (char*) (new_env + envc + 1);
memcpy(s, process_title.str, process_title.len);
for (i = 0; i < argc; i++)
new_argv[i] = s + (argv[i] - argv[0]);
new_argv[argc] = NULL;
s += environ[0] - argv[0];
for (i = 0; i < envc; i++)
new_env[i] = s + (environ[i] - environ[0]);
new_env[envc] = NULL;
#if defined(__APPLE__)
*_NSGetArgv() = new_argv;
*_NSGetEnviron() = new_env;
#else
environ = new_env;
#endif
return new_argv; return new_argv;
} }
@ -101,8 +78,8 @@ uv_err_t uv_set_process_title(const char* title) {
if (process_title.len == 0) if (process_title.len == 0)
return uv_ok_; return uv_ok_;
/* No need to terminate, last char is always '\0'. */ /* No need to terminate, byte after is always '\0'. */
strncpy(process_title.str, title, process_title.len - 1); strncpy(process_title.str, title, process_title.len);
uv__set_process_title(title); uv__set_process_title(title);
return uv_ok_; return uv_ok_;