diff options
| author | Colin Watson <cjwatson@debian.org> | 2018-02-07 13:44:30 +0000 |
|---|---|---|
| committer | Colin Watson <cjwatson@debian.org> | 2018-02-07 13:44:30 +0000 |
| commit | 10027a400d6a05f463f3981e1191a2f35d0cc02b (patch) | |
| tree | 628e874ef57b76b8f20a048da7dd11ade8c57582 | |
| parent | 24624eaf853158856b8fd0a6f78c873475a16686 (diff) | |
| download | man-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.c | 80 |
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); |
