summaryrefslogtreecommitdiff
blob: f513ee8cca67cafc955d26902e78c2cdc2fa0e6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
From 10027a400d6a05f463f3981e1191a2f35d0cc02b Mon Sep 17 00:00:00 2001
From: Colin Watson <cjwatson@debian.org>
Date: Wed, 7 Feb 2018 13:44:30 +0000
Subject: [PATCH] Fix manconv under seccomp when man is setuid

We must drop privileges before loading the sandbox.

Reported by Lars Wendler.

* src/manconv_client.c (manconv_pre_exec): New function.
(manconv_stdin): Move setuid hack to ...
(add_manconv): ... here, now implemented using a custom pre-exec hook.
We no longer have a fall-through if dropping privileges fails, since
that's now harder to do and wasn't really necessary in the first place.
---
 src/manconv_client.c | 80 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 45 insertions(+), 35 deletions(-)

diff --git a/src/manconv_client.c b/src/manconv_client.c
index d6e010b0..41ce4790 100644
--- a/src/manconv_client.c
+++ b/src/manconv_client.c
@@ -56,41 +56,6 @@ static void manconv_stdin (void *data)
 	struct manconv_codes *codes = data;
 	pipeline *p;
 
-#ifdef MAN_OWNER
-	/* iconv_open may not work correctly in setuid processes; in GNU
-	 * libc, gconv modules may be linked against other gconv modules and
-	 * rely on RPATH $ORIGIN to load those modules from the correct
-	 * path, but $ORIGIN is disabled in setuid processes.  It is
-	 * impossible to reset libc's idea of setuidness without creating a
-	 * whole new process image.  Therefore, if the calling process is
-	 * setuid, we must drop privileges and execute manconv.
-	 *
-	 * If dropping privileges fails, fall through to the in-process
-	 * code, as in some situations it may actually manage to work.
-	 */
-	if (running_setuid () && !idpriv_drop ()) {
-		char **from_code;
-		char *sources = NULL;
-		pipecmd *cmd;
-
-		for (from_code = codes->from; *from_code; ++from_code) {
-			sources = appendstr (sources, *from_code, NULL);
-			if (*(from_code + 1))
-				sources = appendstr (sources, ":", NULL);
-		}
-
-		cmd = pipecmd_new_args (MANCONV, "-f", sources,
-					"-t", codes->to, NULL);
-		free (sources);
-
-		if (quiet >= 2)
-			pipecmd_arg (cmd, "-q");
-
-		pipecmd_exec (cmd);
-		/* never returns */
-	}
-#endif /* MAN_OWNER */
-
 	p = decompress_fdopen (dup (STDIN_FILENO));
 	pipeline_start (p);
 	manconv (p, codes->from, codes->to);
@@ -98,6 +63,17 @@ static void manconv_stdin (void *data)
 	pipeline_free (p);
 }
 
+#ifdef MAN_OWNER
+static void manconv_pre_exec (void *data)
+{
+	/* We must drop privileges before loading the sandbox, since our
+	 * seccomp filter doesn't allow setresuid and friends.
+	 */
+	drop_privs (NULL);
+	sandbox_load (data);
+}
+#endif /* MAN_OWNER */
+
 static void free_manconv_codes (void *data)
 {
 	struct manconv_codes *codes = data;
@@ -139,6 +115,40 @@ void add_manconv (pipeline *p, const char *source, const char *target)
 	name = appendstr (name, " -t ", codes->to, NULL);
 	if (quiet >= 2)
 		name = appendstr (name, " -q", NULL);
+
+#ifdef MAN_OWNER
+	/* iconv_open may not work correctly in setuid processes; in GNU
+	 * libc, gconv modules may be linked against other gconv modules and
+	 * rely on RPATH $ORIGIN to load those modules from the correct
+	 * path, but $ORIGIN is disabled in setuid processes.  It is
+	 * impossible to reset libc's idea of setuidness without creating a
+	 * whole new process image.  Therefore, if the calling process is
+	 * setuid, we must drop privileges and execute manconv.
+	 */
+	if (running_setuid ()) {
+		char **from_code;
+		char *sources = NULL;
+
+		cmd = pipecmd_new_args (MANCONV, "-f", NULL);
+		for (from_code = codes->from; *from_code; ++from_code) {
+			sources = appendstr (sources, *from_code, NULL);
+			if (*(from_code + 1))
+				sources = appendstr (sources, ":", NULL);
+		}
+		pipecmd_arg (cmd, sources);
+		free (sources);
+		pipecmd_args (cmd, "-t", codes->to, NULL);
+		if (quiet >= 2)
+			pipecmd_arg (cmd, "-q");
+		pipecmd_pre_exec (cmd, manconv_pre_exec, sandbox_free,
+				  sandbox);
+		free (name);
+		free_manconv_codes (codes);
+		pipeline_command (p, cmd);
+		return;
+	}
+#endif /* MAN_OWNER */
+
 	cmd = pipecmd_new_function (name, &manconv_stdin, &free_manconv_codes,
 				    codes);
 	free (name);
-- 
2.16.1