[lxc-devel] [PATCH] use PR_SET_MM_MAP instead of PR_SET_MM

Tycho Andersen tycho.andersen at canonical.com
Fri Nov 6 19:10:26 UTC 2015


PR_SET_MM_MAP can be called as non-root, which we are in the unprivileged
(or nested) case.

Also, let's not do the strcpy() for the new cmdline until after we're sure
the prctl succeeded. This means that even if it does fail, we won't
mutilate the command line like we did before, it just won't be as pretty.

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 src/lxc/utils.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 57 insertions(+), 12 deletions(-)

diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 01774c0..fc6bb41 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1347,7 +1347,15 @@ int setproctitle(char *title)
 	char buf[2048], *tmp;
 	FILE *f;
 	int i, len, ret = 0;
-	unsigned long arg_start, arg_end, env_start, env_end;
+
+	/* We don't really need to know all of this stuff, but unfortunately
+	 * PR_SET_MM_MAP requires us to set it all at once, so we have to
+	 * figure it out anyway.
+	 */
+	unsigned long start_data, end_data, start_brk, start_code, end_code,
+			start_stack, arg_start, arg_end, env_start, env_end,
+			brk_val;
+	struct prctl_mm_map prctl_map;
 
 	f = fopen_cloexec("/proc/self/stat", "r");
 	if (!f) {
@@ -1360,23 +1368,42 @@ int setproctitle(char *title)
 		return -1;
 	}
 
-	/* Skip the first 47 fields, column 48-51 are ARG_START and
-	 * ARG_END. */
+	/* Skip the first 25 fields, column 26-28 are start_code, end_code,
+	 * and start_stack */
 	tmp = strchr(buf, ' ');
-	for (i = 0; i < 46; i++) {
+	for (i = 0; i < 24; i++) {
 		if (!tmp)
 			return -1;
 		tmp = strchr(tmp+1, ' ');
 	}
-
 	if (!tmp)
 		return -1;
 
-	i = sscanf(tmp, "%lu %lu %lu %lu", &arg_start, &arg_end, &env_start, &env_end);
-	if (i != 4) {
+	i = sscanf(tmp, "%lu %lu %lu", &start_code, &end_code, &start_stack);
+	if (i != 3)
 		return -1;
+
+	/* Skip the next 19 fields, column 45-51 are start_data to arg_end */
+	for (i = 0; i < 19; i++) {
+		if (!tmp)
+			return -1;
+		tmp = strchr(tmp+1, ' ');
 	}
 
+	if (!tmp)
+		return -1;
+
+	i = sscanf(tmp, "%lu %lu %lu %lu %lu %lu %lu",
+		&start_data,
+		&end_data,
+		&start_brk,
+		&arg_start,
+		&arg_end,
+		&env_start,
+		&env_end);
+	if (i != 7)
+		return -1;
+
 	/* Include the null byte here, because in the calculations below we
 	 * want to have room for it. */
 	len = strlen(title) + 1;
@@ -1402,12 +1429,30 @@ int setproctitle(char *title)
 
 	}
 
-	strcpy((char*)arg_start, title);
+	brk_val = syscall(__NR_brk, 0);
 
-	ret |= prctl(PR_SET_MM, PR_SET_MM_ARG_START,   arg_start, 0, 0);
-	ret |= prctl(PR_SET_MM, PR_SET_MM_ARG_END,     arg_end, 0, 0);
-	ret |= prctl(PR_SET_MM, PR_SET_MM_ENV_START,   env_start, 0, 0);
-	ret |= prctl(PR_SET_MM, PR_SET_MM_ENV_END,     env_end, 0, 0);
+	prctl_map = (struct prctl_mm_map) {
+		.start_code = start_code,
+		.end_code = end_code,
+		.start_stack = start_stack,
+		.start_data = start_data,
+		.end_data = end_data,
+		.start_brk = start_brk,
+		.brk = brk_val,
+		.arg_start = arg_start,
+		.arg_end = arg_end,
+		.env_start = env_start,
+		.env_end = env_end,
+		.auxv = NULL,
+		.auxv_size = 0,
+		.exe_fd = -1,
+	};
+
+	ret = prctl(PR_SET_MM, PR_SET_MM_MAP, (long) &prctl_map, sizeof(prctl_map), 0);
+	if (ret == 0)
+		strcpy((char*)arg_start, title);
+	else
+		SYSERROR("setting cmdline failed");
 
 	return ret;
 }
-- 
2.5.0



More information about the lxc-devel mailing list