Files
nixpkgs/pkgs/test/make-binary-wrapper/prefix/prefix.c
Archit Gupta d75cae80fa 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.
2026-08-04 17:46:56 -07:00

65 lines
1.9 KiB
C

#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) {
set_env_prefix("PATH", ":", "/usr/bin/");
set_env_prefix("PATH", ":", "/usr/local/bin/");
argv[0] = "/send/me/flags";
return execv("/send/me/flags", argv);
}