Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 669702
Collapse All | Expand All

(-)a/libsandbox/libsandbox.c (-47 / +45 lines)
Lines 1122-1131 typedef struct { Link Here
1122
 *
1122
 *
1123
 * XXX: Might be much nicer if we could serialize these vars behind the back of
1123
 * XXX: Might be much nicer if we could serialize these vars behind the back of
1124
 *      the program.  Might be hard to handle LD_PRELOAD though ...
1124
 *      the program.  Might be hard to handle LD_PRELOAD though ...
1125
 *
1126
 * execv*() must never modify environment inplace with
1127
 * setenv/putenv/unsetenv as it can relocate 'environ' and break
1128
 * vfork()/execv() users: https://bugs.gentoo.org/669702
1125
 */
1129
 */
1126
char **sb_check_envp(char **envp, size_t *mod_cnt, bool insert)
1130
struct sb_envp_ctx sb_new_envp(char **envp, bool insert)
1127
{
1131
{
1128
	char **my_env;
1132
	struct sb_envp_ctx r = {
1133
		.sb_envp   = envp,
1134
		.orig_envp = envp,
1135
		.__mod_cnt = 0,
1136
	};
1129
	char *entry;
1137
	char *entry;
1130
	size_t count, i;
1138
	size_t count, i;
1131
	env_pair vars[] = {
1139
	env_pair vars[] = {
Lines 1152-1158 char **sb_check_envp(char **envp, size_t *mod_cnt, bool insert) Link Here
1152
	/* If sandbox is explicitly disabled, do not propagate the vars
1160
	/* If sandbox is explicitly disabled, do not propagate the vars
1153
	 * and just return user's envp */
1161
	 * and just return user's envp */
1154
	if (!sbcontext.on)
1162
	if (!sbcontext.on)
1155
		return envp;
1163
		return r;
1156
1164
1157
	/* First figure out how many vars are already in the env */
1165
	/* First figure out how many vars are already in the env */
1158
	found_var_cnt = 0;
1166
	found_var_cnt = 0;
Lines 1188-1194 char **sb_check_envp(char **envp, size_t *mod_cnt, bool insert) Link Here
1188
	if ((insert && num_vars == found_var_cnt) ||
1196
	if ((insert && num_vars == found_var_cnt) ||
1189
	    (!insert && found_var_cnt == 0))
1197
	    (!insert && found_var_cnt == 0))
1190
		/* Use the user's envp */
1198
		/* Use the user's envp */
1191
		return envp;
1199
		return r;
1192
1200
1193
	/* Ok, we need to create our own envp, as we need to restore stuff
1201
	/* Ok, we need to create our own envp, as we need to restore stuff
1194
	 * and we should not touch the user's envp.  First we add our vars,
1202
	 * and we should not touch the user's envp.  First we add our vars,
Lines 1208-1268 char **sb_check_envp(char **envp, size_t *mod_cnt, bool insert) Link Here
1208
		vars[13].value = "1";
1216
		vars[13].value = "1";
1209
	}
1217
	}
1210
1218
1211
	my_env = NULL;
1219
	char ** my_env = NULL;
1212
	if (!insert) {
1220
	if (!insert) {
1213
		if (mod_cnt) {
1221
		str_list_for_each_item(envp, entry, count) {
1214
			str_list_for_each_item(envp, entry, count) {
1215
				for (i = 0; i < num_vars; ++i)
1216
					if (i != 12 && is_env_var(entry, vars[i].name, vars[i].len)) {
1217
						(*mod_cnt)++;
1218
						goto skip;
1219
					}
1220
				str_list_add_item(my_env, entry, error);
1221
 skip: ;
1222
			}
1223
		} else {
1224
			for (i = 0; i < num_vars; ++i)
1222
			for (i = 0; i < num_vars; ++i)
1225
				if (i != 12) unsetenv(vars[i].name);
1223
				if (i != 12 /* LD_LIBRARY_PATH index */
1224
				    && is_env_var(entry, vars[i].name, vars[i].len)) {
1225
					r.__mod_cnt++;
1226
					goto skip;
1227
				}
1228
			str_list_add_item(my_env, entry, error);
1229
 skip: ;
1226
		}
1230
		}
1227
	} else {
1231
	} else {
1228
		if (mod_cnt) {
1232
		/* Count directly due to variability with LD_PRELOAD and the value
1229
			/* Count directly due to variability with LD_PRELOAD and the value
1233
		 * logic below.  Getting out of sync can mean memory corruption. */
1230
			 * logic below.  Getting out of sync can mean memory corruption. */
1234
		r.__mod_cnt = 0;
1231
			*mod_cnt = 0;
1235
		if (unlikely(merge_ld_preload)) {
1232
			if (unlikely(merge_ld_preload)) {
1236
			str_list_add_item(my_env, ld_preload, error);
1233
				str_list_add_item(my_env, ld_preload, error);
1237
			r.__mod_cnt++;
1234
				(*mod_cnt)++;
1238
		}
1235
			}
1239
		for (i = 0; i < num_vars; ++i) {
1236
			for (i = 0; i < num_vars; ++i) {
1240
			if (found_vars[i] || !vars[i].value)
1237
				if (found_vars[i] || !vars[i].value)
1241
				continue;
1238
					continue;
1242
			str_list_add_item_env(my_env, vars[i].name, vars[i].value, error);
1239
				str_list_add_item_env(my_env, vars[i].name, vars[i].value, error);
1243
			r.__mod_cnt++;
1240
				(*mod_cnt)++;
1244
		}
1241
			}
1242
1245
1243
			str_list_for_each_item(envp, entry, count) {
1246
		str_list_for_each_item(envp, entry, count) {
1244
				if (unlikely(merge_ld_preload && is_env_var(entry, vars[0].name, vars[0].len)))
1247
			if (unlikely(merge_ld_preload && is_env_var(entry, vars[0].name, vars[0].len)))
1245
					continue;
1248
				continue;
1246
				str_list_add_item(my_env, entry, error);
1249
			str_list_add_item(my_env, entry, error);
1247
			}
1248
		} else {
1249
			if (unlikely(merge_ld_preload))
1250
				putenv(ld_preload);
1251
			for (i = 0; i < num_vars; ++i) {
1252
				if (found_vars[i] || !vars[i].value)
1253
					continue;
1254
				setenv(vars[i].name, vars[i].value, 1);
1255
			}
1256
		}
1250
		}
1257
	}
1251
	}
1258
1252
1259
 error:
1253
 error:
1260
	return my_env;
1254
	r.sb_envp = my_env;
1255
	return r;
1261
}
1256
}
1262
1257
1263
void sb_cleanup_envp(char **envp, size_t mod_cnt)
1258
void sb_free_envp(struct sb_envp_ctx * envp_ctx)
1264
{
1259
{
1265
	/* We assume all the stuffed vars are at the start */
1260
	/* We assume all the stuffed vars are at the start */
1261
	size_t mod_cnt = envp_ctx->__mod_cnt;
1262
	char ** envp = envp_ctx->sb_envp;
1266
	size_t i;
1263
	size_t i;
1267
	for (i = 0; i < mod_cnt; ++i)
1264
	for (i = 0; i < mod_cnt; ++i)
1268
		free(envp[i]);
1265
		free(envp[i]);
Lines 1271-1275 void sb_cleanup_envp(char **envp, size_t mod_cnt) Link Here
1271
	 * entries except for LD_PRELOAD.  All the other entries are
1268
	 * entries except for LD_PRELOAD.  All the other entries are
1272
	 * pointers to existing envp memory.
1269
	 * pointers to existing envp memory.
1273
	 */
1270
	 */
1274
	free(envp);
1271
	if (envp != envp_ctx->orig_envp)
1272
		free(envp);
1275
}
1273
}
(-)a/libsandbox/libsandbox.h (-2 / +15 lines)
Lines 56-63 void *get_dlsym(const char *symname, const char *symver); Link Here
56
56
57
extern char sandbox_lib[SB_PATH_MAX];
57
extern char sandbox_lib[SB_PATH_MAX];
58
extern bool sandbox_on;
58
extern bool sandbox_on;
59
char **sb_check_envp(char **envp, size_t *mod_cnt, bool insert);
59
60
void sb_cleanup_envp(char **envp, size_t mod_cnt);
60
struct sb_envp_ctx {
61
	/* Sandboxified environment with sandbox variables injected.
62
	 * Allocated by 'sb_new_envp', freed by 'sb_free_envp'. */
63
	char ** sb_envp;
64
	/* Original environment. Passed from outside. */
65
	char ** orig_envp;
66
67
	/* Internal counter to free.
68
	 * Not to be used outside sb_{new,free}_envp. */
69
	size_t __mod_cnt;
70
};
71
struct sb_envp_ctx sb_new_envp(char **envp, bool insert);
72
void sb_free_envp(struct sb_envp_ctx * envp_ctx);
73
61
extern pid_t trace_pid;
74
extern pid_t trace_pid;
62
75
63
extern void sb_lock(void);
76
extern void sb_lock(void);
(-)a/libsandbox/wrapper-funcs/__wrapper_exec.c (-6 / +9 lines)
Lines 275-284 WRAPPER_RET_TYPE WRAPPER_NAME(WRAPPER_ARGS_PROTO) Link Here
275
#endif
275
#endif
276
276
277
#ifdef EXEC_MY_ENV
277
#ifdef EXEC_MY_ENV
278
	size_t mod_cnt;
278
	struct sb_envp_ctx ec = sb_new_envp((char**)envp, run_in_process);
279
	char **my_env = sb_check_envp((char **)envp, &mod_cnt, run_in_process);
279
	char **my_env = ec.sb_envp;
280
#else
280
#else
281
	sb_check_envp(environ, NULL, run_in_process);
281
	struct sb_envp_ctx ec = sb_new_envp(environ, run_in_process);
282
	environ = ec.sb_envp;
282
#endif
283
#endif
283
284
284
	restore_errno();
285
	restore_errno();
Lines 287-296 WRAPPER_RET_TYPE WRAPPER_NAME(WRAPPER_ARGS_PROTO) Link Here
287
#endif
288
#endif
288
	result = SB_HIDDEN_FUNC(WRAPPER_NAME)(EXEC_ARGS);
289
	result = SB_HIDDEN_FUNC(WRAPPER_NAME)(EXEC_ARGS);
289
290
290
#ifdef EXEC_MY_ENV
291
#ifndef EXEC_MY_ENV
291
	if (my_env != envp)
292
	/* https://bugs.gentoo.org/669702: maintain illusion
292
		sb_cleanup_envp(my_env, mod_cnt);
293
	 or unmodified 'environ'. */
294
	environ = ec.orig_envp;
293
#endif
295
#endif
296
	sb_free_envp(&ec);
294
297
295
#ifdef EXEC_RECUR_CHECK
298
#ifdef EXEC_RECUR_CHECK
296
	--recursive;
299
	--recursive;
(-)a/tests/Makefile.am (+1 lines)
Lines 18-23 check_PROGRAMS = \ Link Here
18
	chown-0 \
18
	chown-0 \
19
	creat-0 \
19
	creat-0 \
20
	creat64-0 \
20
	creat64-0 \
21
	execv-0 \
21
	execvp-0 \
22
	execvp-0 \
22
	faccessat-0 \
23
	faccessat-0 \
23
	fchmodat-0 \
24
	fchmodat-0 \
(-)a/tests/execv-0.c (+21 lines)
Line 0 Link Here
1
/*
2
 * A simple wrapper for execv that validates environment
3
 * is not corrupted by wrapper: https://bugs.gentoo.org/669702
4
 */
5
6
#define _GNU_SOURCE /* for environ */
7
#include <stdio.h>
8
#include "tests.h"
9
10
int main(int argc, char *argv[])
11
{
12
	char* execv_argv[] = {"nope", (char*)NULL,};
13
	char* execv_environ[] = {"FOO=1", (char*)NULL,};
14
	environ = execv_environ;
15
	execv("./does/not/exist", execv_argv);
16
	if (environ != execv_environ) {
17
		fprintf(stderr, "environ was changed unexpectedly by execv wrapper\n");
18
		return 1;
19
	}
20
	return 0;
21
}
(-)a/tests/execv-1.sh (+4 lines)
Line 0 Link Here
1
#!/bin/sh
2
# Make sure execv run does not corrup 'environ' of caller process:
3
# https://bugs.gentoo.org/669702
4
timeout -s KILL 10 execv-0
(-)a/tests/execv.at (-1 / +1 lines)
Line 0 Link Here
0
- 
1
SB_CHECK(1)

Return to bug 669702