From 8e1b983ef52eea03b51528ceb9e54971d6fecd48 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 26 Jan 2017 07:15:03 -0500 Subject: [PATCH] Import nginx code to set process title, use it for "cinit" When debugging things, it's really useful to be able to see from the process output which thing is which. Here, we're using the term "cinit" for the in-container init. I looked around on the internets for this - I thought systemd would have a good implementation, but they don't do the requsite trick with malloc to ensure we have enough space. nginx does. Now, I also found https://tycho.ws/blog/2015/02/setproctitle.html but their implementation sounded way more complex. So, going from the nginx code, I heavily edited it to drop Solaris/FreeBSD etc. Also, to use `xmalloc` instead of their allocator, etc. This just makes things easier to debug; there's a risk though that it's new parsing code that is reachable in the suid case by an attacker outside; I'll do some extra review on this if we agree to take it. --- Makefile-bwrap.am | 2 + bubblewrap.c | 5 ++ ngx_setproctitle.c | 135 +++++++++++++++++++++++++++++++++++++++++++++ ngx_setproctitle.h | 37 +++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 ngx_setproctitle.c create mode 100644 ngx_setproctitle.h diff --git a/Makefile-bwrap.am b/Makefile-bwrap.am index 4e967ee5..7953184f 100644 --- a/Makefile-bwrap.am +++ b/Makefile-bwrap.am @@ -7,6 +7,8 @@ bwrap_SOURCES = \ $(bwrap_srcpath)/network.c \ $(bwrap_srcpath)/utils.h \ $(bwrap_srcpath)/utils.c \ + $(bwrap_srcpath)/ngx_setproctitle.h \ + $(bwrap_srcpath)/ngx_setproctitle.c \ $(NULL) bwrap_CFLAGS = $(AM_CFLAGS) diff --git a/bubblewrap.c b/bubblewrap.c index a1848ffa..2d507256 100644 --- a/bubblewrap.c +++ b/bubblewrap.c @@ -37,6 +37,7 @@ #include "utils.h" #include "network.h" #include "bind-mount.h" +#include "ngx_setproctitle.h" #ifndef CLONE_NEWCGROUP #define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ @@ -399,6 +400,8 @@ do_init (int event_fd, pid_t initial_pid, struct sock_fprog *seccomp_prog) /* Keep fd open to hang on to lock */ } + ngx_setproctitle ("cinit"); + if (seccomp_prog != NULL && prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, seccomp_prog) != 0) die_with_error ("prctl(PR_SET_SECCOMP)"); @@ -1700,6 +1703,8 @@ main (int argc, read_overflowids (); + ngx_init_setproctitle(argc, argv); + argv0 = argv[0]; if (isatty (1)) diff --git a/ngx_setproctitle.c b/ngx_setproctitle.c new file mode 100644 index 00000000..fc51f14e --- /dev/null +++ b/ngx_setproctitle.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2002-2017 Igor Sysoev + * Copyright (C) 2011-2017 Nginx, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* walters: replaced nginx util C headers and functions with ours */ +#include "ngx_setproctitle.h" +#include "utils.h" + + +/* + * To change the process title in Linux and Solaris we have to set argv[1] + * to NULL and to copy the title to the same place where the argv[0] points to. + * However, argv[0] may be too small to hold a new title. Fortunately, Linux + * and Solaris store argv[] and environ[] one after another. So we should + * ensure that is the continuous memory and then we allocate the new memory + * for environ[] and copy it. After this we could use the memory starting + * from argv[0] for our process title. + * + * The Solaris's standard /bin/ps does not show the changed process title. + * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps does not + * show a new title if its length less than the origin command line length. + * To avoid it we append to a new title the origin command line in the + * parenthesis. + */ + +/* The original */ +static char **ngx_os_argv; +static char **ngx_os_environ; +/* A copy we make */ +static int ngx_argc; +static char **ngx_argv; +extern char **environ; + +static char *ngx_os_argv_last; + +/* In upstream nginx, this is called early in main. However, + * I don't see a reason not to merge it with ngx_init_setproctitle() + */ +static void +ngx_save_argv(int argc, char *const *argv) +{ + int i; + + ngx_os_argv = (char **) argv; + ngx_argc = argc; + + ngx_argv = xmalloc((argc + 1) * sizeof(char *)); + + for (i = 0; i < argc; i++) { + ngx_argv[i] = xstrdup(argv[i]); + } + + ngx_argv[i] = NULL; + ngx_os_environ = environ; +} + +void +ngx_init_setproctitle(int argc, char *const *argv) +{ + char *p; + size_t size; + unsigned i; + + ngx_save_argv(argc, argv); + + size = 0; + + for (i = 0; environ[i]; i++) { + size += strlen(environ[i]) + 1; + } + + p = xmalloc(size); + + ngx_os_argv_last = ngx_os_argv[0]; + + for (i = 0; ngx_os_argv[i]; i++) { + if (ngx_os_argv_last == ngx_os_argv[i]) { + ngx_os_argv_last = ngx_os_argv[i] + strlen(ngx_os_argv[i]) + 1; + } + } + + for (i = 0; environ[i]; i++) { + if (ngx_os_argv_last == environ[i]) { + + size = strlen(environ[i]) + 1; + ngx_os_argv_last = environ[i] + size; + + strncpy(p, environ[i], size); + environ[i] = (char *) p; + p += size; + } + } + + ngx_os_argv_last--; +} + +void +ngx_setproctitle(char *title) +{ + char *p; + + ngx_os_argv[1] = NULL; + + p = stpncpy(ngx_os_argv[0], "bwrap: ", + ngx_os_argv_last - ngx_os_argv[0]); + + p = stpncpy(p, title, ngx_os_argv_last - p); + + if (ngx_os_argv_last - p) { + memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - p); + } +} diff --git a/ngx_setproctitle.h b/ngx_setproctitle.h new file mode 100644 index 00000000..da64d95a --- /dev/null +++ b/ngx_setproctitle.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2002-2017 Igor Sysoev + * Copyright (C) 2011-2017 Nginx, Inc. + * All rights reserved. + * Copyright 2017 Colin Walters + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* walters: stripped out all non-linux stuff */ + +#pragma once + +#define NGX_SETPROCTITLE_USES_ENV 1 +#define NGX_SETPROCTITLE_PAD '\0' + +void ngx_init_setproctitle(int argc, char *const*argv); +void ngx_setproctitle(char *title);