summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2018-02-07 13:44:30 +0000
committerColin Watson <cjwatson@debian.org>2018-02-07 13:44:30 +0000
commit10027a400d6a05f463f3981e1191a2f35d0cc02b (patch)
tree628e874ef57b76b8f20a048da7dd11ade8c57582
parent24624eaf853158856b8fd0a6f78c873475a16686 (diff)
downloadman-db-10027a400d6a05f463f3981e1191a2f35d0cc02b.tar.gz
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.
-rw-r--r--src/manconv_client.c80
1 files changed, 45 insertions, 35 deletions
diff --git a/src/manconv_client.c b/src/manconv_client.c
index d6e010b..41ce479 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);