mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-08-25 17:55:21 +00:00
makeBinaryWrapper: fix read past NUL
When setting a prefix for a path-like environment variable, the deduplication code in set_env_prefix reads past the NUL byte at the end of the env val and into the next entry. This corrupts the resultant env value with data from the next env var, or other data sitting after it.
This commit is contained in:
@@ -366,10 +366,10 @@ void set_env_prefix(char *env, char *sep, char *prefix) {
|
||||
return;
|
||||
}
|
||||
unsigned long sep_len = strlen(sep);
|
||||
int n_before = existing_prefix - existing_env;
|
||||
int n_before = existing_prefix - existing_env - sep_len;
|
||||
assert_success(asprintf(&val, \"%s%s%.*s%s\", prefix, sep,
|
||||
n_before, existing_env,
|
||||
existing_prefix + prefix_len + sep_len));
|
||||
existing_prefix + prefix_len));
|
||||
} else {
|
||||
assert_success(asprintf(&val, \"%s%s%s\", prefix, sep, existing_env));
|
||||
}
|
||||
|
||||
@@ -42,10 +42,10 @@ void set_env_prefix(char *env, char *sep, char *prefix) {
|
||||
return;
|
||||
}
|
||||
unsigned long sep_len = strlen(sep);
|
||||
int n_before = existing_prefix - existing_env;
|
||||
int n_before = existing_prefix - existing_env - sep_len;
|
||||
assert_success(asprintf(&val, "%s%s%.*s%s", prefix, sep,
|
||||
n_before, existing_env,
|
||||
existing_prefix + prefix_len + sep_len));
|
||||
existing_prefix + prefix_len));
|
||||
} else {
|
||||
assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing_env));
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ let
|
||||
"overlength-strings"
|
||||
"prefix"
|
||||
"suffix"
|
||||
"prefix-dedup-last"
|
||||
] makeGoldenTest
|
||||
// lib.optionalAttrs (!stdenv.hostPlatform.isDarwin) {
|
||||
cross =
|
||||
|
||||
@@ -42,10 +42,10 @@ void set_env_prefix(char *env, char *sep, char *prefix) {
|
||||
return;
|
||||
}
|
||||
unsigned long sep_len = strlen(sep);
|
||||
int n_before = existing_prefix - existing_env;
|
||||
int n_before = existing_prefix - existing_env - sep_len;
|
||||
assert_success(asprintf(&val, "%s%s%.*s%s", prefix, sep,
|
||||
n_before, existing_env,
|
||||
existing_prefix + prefix_len + sep_len));
|
||||
existing_prefix + prefix_len));
|
||||
} else {
|
||||
assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing_env));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)
|
||||
|
||||
int is_surrounded_by_sep(char *env, char *ptr, unsigned long len, char *sep) {
|
||||
unsigned long sep_len = strlen(sep);
|
||||
|
||||
// Check left side (if not at start)
|
||||
if (env != ptr) {
|
||||
if (ptr - env < sep_len)
|
||||
return 0;
|
||||
if (strncmp(sep, ptr - sep_len, sep_len) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Check right side (if not at end)
|
||||
char *end_ptr = ptr + len;
|
||||
if (*end_ptr != '\0') {
|
||||
if (strncmp(sep, ptr + len, sep_len) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_env_prefix(char *env, char *sep, char *prefix) {
|
||||
char *existing_env = getenv(env);
|
||||
if (existing_env) {
|
||||
char *val;
|
||||
|
||||
char *existing_prefix = strstr(existing_env, prefix);
|
||||
unsigned long prefix_len = strlen(prefix);
|
||||
// If the prefix already exists, remove the original
|
||||
if (existing_prefix && is_surrounded_by_sep(existing_env, existing_prefix, prefix_len, sep)) {
|
||||
if (existing_env == existing_prefix) {
|
||||
return;
|
||||
}
|
||||
unsigned long sep_len = strlen(sep);
|
||||
int n_before = existing_prefix - existing_env - sep_len;
|
||||
assert_success(asprintf(&val, "%s%s%.*s%s", prefix, sep,
|
||||
n_before, existing_env,
|
||||
existing_prefix + prefix_len));
|
||||
} else {
|
||||
assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing_env));
|
||||
}
|
||||
assert_success(setenv(env, val, 1));
|
||||
free(val);
|
||||
} else {
|
||||
assert_success(setenv(env, prefix, 1));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
putenv("PATH=/usr/bin:/usr/local/bin");
|
||||
set_env_prefix("PATH", ":", "/usr/local/bin");
|
||||
argv[0] = "/send/me/flags";
|
||||
return execv("/send/me/flags", argv);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
--set PATH /usr/bin:/usr/local/bin \
|
||||
--prefix PATH : /usr/local/bin
|
||||
@@ -0,0 +1,3 @@
|
||||
PATH=/usr/local/bin:/usr/bin
|
||||
CWD=SUBST_CWD
|
||||
SUBST_ARGV0
|
||||
@@ -42,10 +42,10 @@ void set_env_prefix(char *env, char *sep, char *prefix) {
|
||||
return;
|
||||
}
|
||||
unsigned long sep_len = strlen(sep);
|
||||
int n_before = existing_prefix - existing_env;
|
||||
int n_before = existing_prefix - existing_env - sep_len;
|
||||
assert_success(asprintf(&val, "%s%s%.*s%s", prefix, sep,
|
||||
n_before, existing_env,
|
||||
existing_prefix + prefix_len + sep_len));
|
||||
existing_prefix + prefix_len));
|
||||
} else {
|
||||
assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing_env));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user