Skip to content

Commit

Permalink
Use seccomp instead of setsid() to workaround CVE-2017-5226
Browse files Browse the repository at this point in the history
The setsid() workaround of
containers#143 is problematic,
because it e.g. breaks shell job control for bubblewrap instances.
So, instead we use a seccomp approach based on:
 util-linux/util-linux@8e49250
However, since we don't want to pull in any more dependencies into
the setuid binary we pre-compile the seccomp code during the build.

If libseccomp is not available on your architecture, we still support
the old fix with --disable-seccomp-tty-fix.
  • Loading branch information
alexlarsson committed Jan 16, 2017
1 parent b35f84a commit 9fde059
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 0 deletions.
20 changes: 20 additions & 0 deletions Makefile-bwrap.am
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
noinst_PROGRAMS += generate-seccomp

generate_seccomp_SOURCES=\
$(bwrap_srcpath)/generate-seccomp.c \
$(bwrap_srcpath)/utils.h \
$(bwrap_srcpath)/utils.c \
$(NULL)
generate_seccomp_CFLAGS = $(AM_CFLAGS)
generate_seccomp_LDADD = $(LIBSECCOMP_LIBS) $(SELINUX_LIBS)

seccomp-filter.h: generate-seccomp$(EXEEXT)
./generate-seccomp$(EXEEXT) > seccomp-filter.h

bwrap_SOURCES = \
$(bwrap_srcpath)/bubblewrap.c \
Expand All @@ -8,6 +20,14 @@ bwrap_SOURCES = \
$(bwrap_srcpath)/utils.h \
$(bwrap_srcpath)/utils.c \
$(NULL)
nodist_bwrap_SOURCES = \
seccomp-filter.h \
$(NULL)

CLEANFILES += seccomp-filter.h

bwrap_CFLAGS = $(AM_CFLAGS)
bwrap_LDADD = $(SELINUX_LIBS)

MAINTAINERCLEANFILES += seccomp-filter.h
BUILT_SOURCES += seccomp-filter.h
3 changes: 3 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
AM_CFLAGS = $(WARN_CFLAGS)
CLEANFILES =
MAINTAINERCLEANFILES =
EXTRA_DIST =
BUILT_SOURCES =
noinst_PROGRAMS =

GITIGNOREFILES = build-aux/ gtk-doc.make config.h.in aclocal.m4

Expand Down
19 changes: 19 additions & 0 deletions bubblewrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#include "utils.h"
#include "network.h"
#include "seccomp-filter.h"
#include "bind-mount.h"

#ifndef CLONE_NEWCGROUP
Expand Down Expand Up @@ -2027,6 +2028,18 @@ main (int argc,
close (opt_block_fd);
}

#ifdef HAVE_BWRAP_SECCOMP_FILTER
{
struct sock_fprog prog;

prog.len = N_ELEMENTS (bwrap_seccomp_filter) / 8;
prog.filter = (struct sock_filter *) bwrap_seccomp_filter;

if (prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0)
die_with_error ("prctl(PR_SET_SECCOMP)");
}
#endif

if (opt_seccomp_fd != -1)
{
cleanup_free char *seccomp_data = NULL;
Expand Down Expand Up @@ -2121,8 +2134,14 @@ main (int argc,
/* We want sigchild in the child */
unblock_sigchild ();

#ifndef HAVE_BWRAP_SECCOMP_FILTER
/* If we don'y have seccomp, then we need to setsid to protect against CVE-2017-5226
* See e.g. https://github.com/projectatomic/bubblewrap/pull/143
* This workaround is pretty bad though, as it breaks shell job control.
*/
if (setsid () == (pid_t) -1)
die_with_error ("setsid");
#endif

if (label_exec (opt_exec_label) == -1)
die_with_error ("label_exec %s", argv[0]);
Expand Down
14 changes: 14 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ else
BASH_COMPLETION_DIR="$with_bash_completion_dir"
fi

AC_ARG_ENABLE([seccomp-tty-fix],
AC_HELP_STRING([--disable-seccomp-tty-fix],
[Disable libseccomp-based TIOCSTI ioctl workaround (not recommended)]),
[enable_seccomp_tty_fix=no],
[enable_seccomp_tty_fix=yes])

if test "x$enable_seccomp_tty_fix" = "xno"; then
AC_DEFINE([DISABLE_SECCOMP], [1],
[Define if using seccomp])
else
PKG_CHECK_MODULES(LIBSECCOMP, [libseccomp])
fi

AC_SUBST([BASH_COMPLETION_DIR])
AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "x$with_bash_completion_dir" != "xno"])
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -111,6 +124,7 @@ echo "

man pages (xsltproc): $enable_man
SELinux: $have_selinux
Seccomp tty fix: $enable_seccomp_tty_fix
setuid mode on make install: $with_priv_mode
mysteriously satisfying to pop: yes"
echo ""
126 changes: 126 additions & 0 deletions generate-seccomp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <config.h>
#include "utils.h"

#ifndef DISABLE_SECCOMP
#include <seccomp.h>
#endif


int
main (int argc, char *argv[])
{
#ifndef DISABLE_SECCOMP
scmp_filter_ctx ctx = NULL;
int filter1_fd;
int filter2_fd;
int res;
uint32_t extra_arches[][2] = {
{SCMP_ARCH_X86_64, SCMP_ARCH_X86},
#ifdef SCMP_ARCH_AARCH64
{SCMP_ARCH_AARCH64, SCMP_ARCH_ARM},
#endif
{0}
};
int i;
unsigned char *filter1;
unsigned char *filter2;
size_t filter1_size;
size_t filter2_size;
char tmpname1[] = "/tmp/bwrap-filterXXXXXX";
char tmpname2[] = "/tmp/bwrap-filterXXXXXX";

ctx = seccomp_init (SCMP_ACT_ALLOW);
if (!ctx)
{
printf ("Initialize seccomp failed\n");
return 1;
}

for (i = 0; extra_arches[i][0] != 0; i++)
{
if (seccomp_arch_native () == extra_arches[i][0])
{
res = seccomp_arch_add (ctx, extra_arches[i][1]);
if (res < 0)
{
printf ("Error adding extra arch\n");
return 1;
}
}
}

if (seccomp_rule_add (ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(ioctl), 1,
SCMP_A1(SCMP_CMP_EQ, (int)TIOCSTI)) < 0)
{
printf ("Failed to add TIOCSTI rule\n");
return 1;
}

filter1_fd = mkstemp (tmpname1);
if (filter1_fd == -1)
{
perror ("Can't write filter");
return 1;
}

unlink (tmpname1);

res = seccomp_export_bpf (ctx, filter1_fd);
if (res < 0)
{
printf ("Error exporting bpf\n");
return 1;
}


filter2_fd = mkstemp (tmpname2);
if (filter2_fd == -1)
{
perror ("Can't write filter");
return 1;
}

unlink (tmpname2);

res = seccomp_export_pfc (ctx, filter2_fd);
if (res < 0)
{
printf ("Error exporting bpf\n");
return 1;
}

seccomp_release (ctx);

lseek (filter1_fd, 0, SEEK_SET);
filter1 = (unsigned char *)load_file_data (filter1_fd, &filter1_size);

lseek (filter2_fd, 0, SEEK_SET);
filter2 = (unsigned char *)load_file_data (filter2_fd, &filter2_size);

printf ("#define HAVE_BWRAP_SECCOMP_FILTER 1\n");
printf ("/*\n"
"%s\n"
"*/\n",
filter2);
printf ("unsigned char bwrap_seccomp_filter[] = { ");
for (i = 0; i < filter1_size; i++)
{
if (i != 0)
printf (", ");
printf ("%d", filter1[i]);
}
printf (" };\n");
#endif

return 0;
}

0 comments on commit 9fde059

Please sign in to comment.