Merge branch 'kill-child-feature' of https://github.com/nh2/util-linux

* 'kill-child-feature' of https://github.com/nh2/util-linux:
  unshare: Allow passing <signame> to --kill-child
  unshare: Add --kill-child option.
  signames: Make input char buffers const
  kill: Extract signal names into signames.h/signames.c
This commit is contained in:
Karel Zak 2017-10-23 12:58:21 +02:00
commit c5910c7f27
8 changed files with 270 additions and 129 deletions

View File

@ -27,6 +27,7 @@ _unshare_module()
--user
--cgroup
--fork
--kill-child
--mount-proc
--map-root-user
--propagation

View File

@ -47,6 +47,7 @@ dist_noinst_HEADERS += \
include/randutils.h \
include/rpmatch.h \
include/sha1.h \
include/signames.h \
include/setproctitle.h \
include/statfs_magic.h \
include/strutils.h \

132
include/signames.h Normal file
View File

@ -0,0 +1,132 @@
#ifndef SIGNAMES_H
#define SIGNAMES_H
/*
* Copyright (c) 1988, 1993, 1994, 2017
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
/*
* 2017-10-14 Niklas Hambüchen <mail@nh2.me>
* - Extracted signal names mapping from kill.c
*
* Copyright (C) 2014 Sami Kerola <kerolasa@iki.fi>
* Copyright (C) 2014 Karel Zak <kzak@redhat.com>
* Copyright (C) 2017 Niklas Hambüchen <mail@nh2.me>
*/
#include <signal.h>
static const struct signv {
const char *name;
int val;
} sys_signame[] = {
/* POSIX signals */
{ "HUP", SIGHUP }, /* 1 */
{ "INT", SIGINT }, /* 2 */
{ "QUIT", SIGQUIT }, /* 3 */
{ "ILL", SIGILL }, /* 4 */
#ifdef SIGTRAP
{ "TRAP", SIGTRAP }, /* 5 */
#endif
{ "ABRT", SIGABRT }, /* 6 */
#ifdef SIGIOT
{ "IOT", SIGIOT }, /* 6, same as SIGABRT */
#endif
#ifdef SIGEMT
{ "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */
#endif
#ifdef SIGBUS
{ "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
#endif
{ "FPE", SIGFPE }, /* 8 */
{ "KILL", SIGKILL }, /* 9 */
{ "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
{ "SEGV", SIGSEGV }, /* 11 */
{ "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
{ "PIPE", SIGPIPE }, /* 13 */
{ "ALRM", SIGALRM }, /* 14 */
{ "TERM", SIGTERM }, /* 15 */
#ifdef SIGSTKFLT
{ "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */
#endif
{ "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
#ifdef SIGCLD
{ "CLD", SIGCLD }, /* same as SIGCHLD (mips) */
#endif
{ "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
{ "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
{ "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
{ "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
{ "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
#ifdef SIGURG
{ "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
#endif
#ifdef SIGXCPU
{ "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
#endif
#ifdef SIGXFSZ
{ "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
#endif
#ifdef SIGVTALRM
{ "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
#endif
#ifdef SIGPROF
{ "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
#endif
#ifdef SIGWINCH
{ "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
#endif
#ifdef SIGIO
{ "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
#endif
#ifdef SIGPOLL
{ "POLL", SIGPOLL }, /* same as SIGIO */
#endif
#ifdef SIGINFO
{ "INFO", SIGINFO }, /* 29 (alpha) */
#endif
#ifdef SIGLOST
{ "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */
#endif
#ifdef SIGPWR
{ "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
#endif
#ifdef SIGUNUSED
{ "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */
#endif
#ifdef SIGSYS
{ "SYS", SIGSYS }, /* 31 (mips,alpha,sparc*) */
#endif
};
int signame_to_signum(const char *sig);
#endif /* SIGNAMES_H */

View File

@ -26,7 +26,8 @@ libcommon_la_SOURCES = \
lib/ttyutils.c \
lib/exec_shell.c \
lib/strv.c \
lib/sha1.c
lib/sha1.c \
lib/signames.c
if LINUX
libcommon_la_SOURCES += \

95
lib/signames.c Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 1988, 1993, 1994, 2017
* The Regents of the University of California. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
/*
* 2017-10-14 Niklas Hambüchen <mail@nh2.me>
* - Extracted signal names mapping from kill.c
*
* Copyright (C) 2014 Sami Kerola <kerolasa@iki.fi>
* Copyright (C) 2014 Karel Zak <kzak@redhat.com>
* Copyright (C) 2017 Niklas Hambüchen <mail@nh2.me>
*/
#include <ctype.h> /* for isdigit() */
#include <signames.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "c.h"
#include "strutils.h"
#ifdef SIGRTMIN
static int rtsig_to_signum(const char *sig)
{
int num, maxi = 0;
char *ep = NULL;
if (strncasecmp(sig, "min+", 4) == 0)
sig += 4;
else if (strncasecmp(sig, "max-", 4) == 0) {
sig += 4;
maxi = 1;
}
if (!isdigit(*sig))
return -1;
errno = 0;
num = strtol(sig, &ep, 10);
if (!ep || sig == ep || errno || num < 0)
return -1;
num = maxi ? SIGRTMAX - num : SIGRTMIN + num;
if (num < SIGRTMIN || SIGRTMAX < num)
return -1;
return num;
}
#endif
int signame_to_signum(const char *sig)
{
size_t n;
if (!strncasecmp(sig, "sig", 3))
sig += 3;
#ifdef SIGRTMIN
/* RT signals */
if (!strncasecmp(sig, "rt", 2))
return rtsig_to_signum(sig + 2);
#endif
/* Normal signals */
for (n = 0; n < ARRAY_SIZE(sys_signame); n++) {
if (!strcasecmp(sys_signame[n].name, sig))
return sys_signame[n].val;
}
return -1;
}

View File

@ -55,6 +55,7 @@
#include "closestream.h"
#include "nls.h"
#include "procutils.h"
#include "signames.h"
#include "strutils.h"
#include "ttyutils.h"
#include "xalloc.h"
@ -82,89 +83,6 @@ struct kill_control {
verbose:1;
};
static const struct signv {
const char *name;
int val;
} sys_signame[] = {
/* POSIX signals */
{ "HUP", SIGHUP }, /* 1 */
{ "INT", SIGINT }, /* 2 */
{ "QUIT", SIGQUIT }, /* 3 */
{ "ILL", SIGILL }, /* 4 */
#ifdef SIGTRAP
{ "TRAP", SIGTRAP }, /* 5 */
#endif
{ "ABRT", SIGABRT }, /* 6 */
#ifdef SIGIOT
{ "IOT", SIGIOT }, /* 6, same as SIGABRT */
#endif
#ifdef SIGEMT
{ "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */
#endif
#ifdef SIGBUS
{ "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */
#endif
{ "FPE", SIGFPE }, /* 8 */
{ "KILL", SIGKILL }, /* 9 */
{ "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */
{ "SEGV", SIGSEGV }, /* 11 */
{ "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */
{ "PIPE", SIGPIPE }, /* 13 */
{ "ALRM", SIGALRM }, /* 14 */
{ "TERM", SIGTERM }, /* 15 */
#ifdef SIGSTKFLT
{ "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */
#endif
{ "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */
#ifdef SIGCLD
{ "CLD", SIGCLD }, /* same as SIGCHLD (mips) */
#endif
{ "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */
{ "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */
{ "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */
{ "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */
{ "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */
#ifdef SIGURG
{ "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */
#endif
#ifdef SIGXCPU
{ "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */
#endif
#ifdef SIGXFSZ
{ "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */
#endif
#ifdef SIGVTALRM
{ "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */
#endif
#ifdef SIGPROF
{ "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */
#endif
#ifdef SIGWINCH
{ "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */
#endif
#ifdef SIGIO
{ "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */
#endif
#ifdef SIGPOLL
{ "POLL", SIGPOLL }, /* same as SIGIO */
#endif
#ifdef SIGINFO
{ "INFO", SIGINFO }, /* 29 (alpha) */
#endif
#ifdef SIGLOST
{ "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */
#endif
#ifdef SIGPWR
{ "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */
#endif
#ifdef SIGUNUSED
{ "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */
#endif
#ifdef SIGSYS
{ "SYS", SIGSYS }, /* 31 (mips,alpha,sparc*) */
#endif
};
static void print_signal_name(int signum)
{
size_t n;
@ -236,50 +154,6 @@ static void err_nosig(char *name)
exit(EXIT_FAILURE);
}
#ifdef SIGRTMIN
static int rtsig_to_signum(char *sig)
{
int num, maxi = 0;
char *ep = NULL;
if (strncasecmp(sig, "min+", 4) == 0)
sig += 4;
else if (strncasecmp(sig, "max-", 4) == 0) {
sig += 4;
maxi = 1;
}
if (!isdigit(*sig))
return -1;
errno = 0;
num = strtol(sig, &ep, 10);
if (!ep || sig == ep || errno || num < 0)
return -1;
num = maxi ? SIGRTMAX - num : SIGRTMIN + num;
if (num < SIGRTMIN || SIGRTMAX < num)
return -1;
return num;
}
#endif
static int signame_to_signum(char *sig)
{
size_t n;
if (!strncasecmp(sig, "sig", 3))
sig += 3;
#ifdef SIGRTMIN
/* RT signals */
if (!strncasecmp(sig, "rt", 2))
return rtsig_to_signum(sig + 2);
#endif
/* Normal signals */
for (n = 0; n < ARRAY_SIZE(sys_signame); n++) {
if (!strcasecmp(sys_signame[n].name, sig))
return sys_signame[n].val;
}
return -1;
}
static int arg_to_signum(char *arg, int maskbit)
{
int numsig;

View File

@ -138,6 +138,13 @@ by bind mount.
Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than
running it directly. This is useful when creating a new PID namespace.
.TP
.BR \-\-kill\-child [ =\fIsigname ]
When \fBunshare\fR terminates, have \fIsigname\fP be sent to the forked child process.
Combined with \fB--pid\fR this allows for an easy and realiable killing of the entire
process tree below \fBunshare\fR.
If not given, \fIsigname\fP defaults to \fBSIGKILL\fR.
This option implies \fB--fork\fR.
.TP
.BR \-\-mount\-proc [ =\fImountpoint ]
Just before running the program, mount the proc filesystem at \fImountpoint\fP
(default is /proc). This is useful when creating a new PID namespace. It also
@ -229,6 +236,17 @@ the bind reference.
Establish a persistent mount namespace referenced by the bind mount
/root/namespaces/mnt. This example shows a portable solution, because it
makes sure that the bind mount is created on a shared filesystem.
.TP
.B # unshare -pf --kill-child -- bash -c "(sleep 999 &) && sleep 1000" &
.TQ
.B # pid=$!
.TQ
.B # kill $pid
.br
Reliable killing of subprocesses of the \fIprogram\fR.
When \fBunshare\fR gets killed, everything below it gets killed as well.
Without it, the children of \fIprogram\fR would have orphaned and
been re-parented to PID 1.
.SH SEE ALSO
.BR clone (2),

View File

@ -28,6 +28,7 @@
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/prctl.h>
/* we only need some defines missing in sys/mount.h, no libmount linkage */
#include <libmount.h>
@ -40,6 +41,7 @@
#include "xalloc.h"
#include "pathnames.h"
#include "all-io.h"
#include "signames.h"
/* synchronize parent and child by pipe */
#define PIPE_SYNC_BYTE 0x06
@ -258,6 +260,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -U, --user[=<file>] unshare user namespace\n"), out);
fputs(_(" -C, --cgroup[=<file>] unshare cgroup namespace\n"), out);
fputs(_(" -f, --fork fork before launching <program>\n"), out);
fputs(_(" --kill-child[=<signame>] when dying, kill the forked child (implies --fork); defaults to SIGKILL\n"), out);
fputs(_(" --mount-proc[=<dir>] mount proc filesystem first (implies --mount)\n"), out);
fputs(_(" -r, --map-root-user map current user to root (implies --user)\n"), out);
fputs(_(" --propagation slave|shared|private|unchanged\n"
@ -276,7 +279,8 @@ int main(int argc, char *argv[])
enum {
OPT_MOUNTPROC = CHAR_MAX + 1,
OPT_PROPAGATION,
OPT_SETGROUPS
OPT_SETGROUPS,
OPT_KILLCHILD
};
static const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
@ -291,6 +295,7 @@ int main(int argc, char *argv[])
{ "cgroup", optional_argument, NULL, 'C' },
{ "fork", no_argument, NULL, 'f' },
{ "kill-child", optional_argument, NULL, OPT_KILLCHILD },
{ "mount-proc", optional_argument, NULL, OPT_MOUNTPROC },
{ "map-root-user", no_argument, NULL, 'r' },
{ "propagation", required_argument, NULL, OPT_PROPAGATION },
@ -301,6 +306,7 @@ int main(int argc, char *argv[])
int setgrpcmd = SETGROUPS_NONE;
int unshare_flags = 0;
int c, forkit = 0, maproot = 0;
int kill_child_signo = 0; /* 0 means --kill-child was not used */
const char *procmnt = NULL;
pid_t pid = 0;
int fds[2];
@ -373,6 +379,16 @@ int main(int argc, char *argv[])
case OPT_PROPAGATION:
propagation = parse_propagation(optarg);
break;
case OPT_KILLCHILD:
forkit = 1;
if (optarg) {
if ((kill_child_signo = signame_to_signum(optarg)) < 0)
errx(EXIT_FAILURE, _("unknown signal: %s"),
optarg);
} else {
kill_child_signo = SIGKILL;
}
break;
default:
errtryhelp(EXIT_FAILURE);
}
@ -430,6 +446,9 @@ int main(int argc, char *argv[])
}
}
if (kill_child_signo != 0)
if (prctl(PR_SET_PDEATHSIG, kill_child_signo) < 0)
err(EXIT_FAILURE, "prctl failed");
if (maproot) {
if (setgrpcmd == SETGROUPS_ALLOW)