cmd: add helpers for mounting / unmounting #2827

Merged
merged 9 commits into from Mar 1, 2017
View
@@ -70,6 +70,8 @@ libsnap_confine_private_a_SOURCES = \
libsnap-confine-private/cleanup-funcs.h \
libsnap-confine-private/error.c \
libsnap-confine-private/error.h \
+ libsnap-confine-private/fault-injection.c \
+ libsnap-confine-private/fault-injection.h \
libsnap-confine-private/mount-opt.c \
libsnap-confine-private/mount-opt.h \
libsnap-confine-private/mountinfo.c \
@@ -104,8 +106,18 @@ libsnap_confine_private_unit_tests_SOURCES = \
libsnap-confine-private/utils-test.c
libsnap_confine_private_unit_tests_CFLAGS = $(GLIB_CFLAGS)
libsnap_confine_private_unit_tests_LDADD = $(GLIB_LIBS)
-libsnap_confine_private_unit_tests_LDADD += -lcap
libsnap_confine_private_unit_tests_CFLAGS += -D_ENABLE_FAULT_INJECTION
+
+# XXX: This injects a dependency on libcap in a way that makes automake happy
+# and allows us to link libcap statically. We need to link in libcap statically
+# as at this time adding runtime dependencies to snap-confine is tricky.
+
+libsnap-confine-private/unit-tests$(EXEEXT): $(libsnap_confine_private_unit_tests_OBJECTS) $(libsnap_confine_private_unit_tests_DEPENDENCIES) $(EXTRA_libsnap_confine_private_unit_tests_DEPENDENCIES) libsnap-confine-private/$(am__dirstamp)
+ @rm -f libsnap-confine-private/unit-tests$(EXEEXT)
+ $(AM_V_CCLD)$(libsnap_confine_private_unit_tests_LINK) $(libsnap_confine_private_unit_tests_OBJECTS) $(libsnap_confine_private_unit_tests_LDADD) $(LIBS)
+
+libsnap-confine-private/unit-tests$(EXEEXT): LIBS += -Wl,-Bstatic -lcap -Wl,-Bdynamic
+
endif
##
@@ -117,6 +129,14 @@ noinst_PROGRAMS += decode-mount-opts/decode-mount-opts
decode_mount_opts_decode_mount_opts_SOURCES = \
decode-mount-opts/decode-mount-opts.c
decode_mount_opts_decode_mount_opts_LDADD = libsnap-confine-private.a
+# XXX: this makes automake generate decode_mount_opts_decode_mount_opts_LINK
+decode_mount_opts_decode_mount_opts_CFLAGS = -D_fake
+
+decode-mount-opts/decode-mount-opts$(EXEEXT): $(decode_mount_opts_decode_mount_opts_OBJECTS) $(decode_mount_opts_decode_mount_opts_DEPENDENCIES) $(EXTRA_decode_mount_opts_decode_mount_opts_DEPENDENCIES) libsnap-confine-private/$(am__dirstamp)
+ @rm -f decode-mount-opts/decode-mount-opts$(EXEEXT)
+ $(AM_V_CCLD)$(decode_mount_opts_decode_mount_opts_LINK) $(decode_mount_opts_decode_mount_opts_OBJECTS) $(decode_mount_opts_decode_mount_opts_LDADD) $(LIBS)
+
+decode-mount-opts/decode-mount-opts$(EXEEXT): LIBS += -Wl,-Bstatic -lcap -Wl,-Bdynamic
##
## snap-confine
@@ -186,6 +206,12 @@ snap_confine_snap_confine_LDADD = libsnap-confine-private.a
snap_confine_snap_confine_CFLAGS += $(LIBUDEV_CFLAGS)
snap_confine_snap_confine_LDADD += $(LIBUDEV_LIBS)
+snap-confine/snap-confine$(EXEEXT): $(snap_confine_snap_confine_OBJECTS) $(snap_confine_snap_confine_DEPENDENCIES) $(EXTRA_snap_confine_snap_confine_DEPENDENCIES) libsnap-confine-private/$(am__dirstamp)
+ @rm -f snap-confine/snap-confine$(EXEEXT)
+ $(AM_V_CCLD)$(snap_confine_snap_confine_LINK) $(snap_confine_snap_confine_OBJECTS) $(snap_confine_snap_confine_LDADD) $(LIBS)
+
+snap-confine/snap-confine$(EXEEXT): LIBS += -Wl,-Bstatic -lcap -Wl,-Bdynamic
+
# This is here to help fix rpmlint hardening issue.
# https://en.opensuse.org/openSUSE:Packaging_checks#non-position-independent-executable
snap_confine_snap_confine_CFLAGS += $(SUID_CFLAGS)
@@ -204,6 +230,21 @@ snap_confine_snap_confine_CFLAGS += $(APPARMOR_CFLAGS)
snap_confine_snap_confine_LDADD += $(APPARMOR_LIBS)
endif
+# an extra build that has additional debugging enabled at compile time
+
+noinst_PROGRAMS += snap-confine/snap-confine-debug
+snap_confine_snap_confine_debug_SOURCES = $(snap_confine_snap_confine_SOURCES)
+snap_confine_snap_confine_debug_CFLAGS = $(snap_confine_snap_confine_CFLAGS)
+snap_confine_snap_confine_debug_LDFLAGS = $(snap_confine_snap_confine_LDFLAGS)
+snap_confine_snap_confine_debug_LDADD = $(snap_confine_snap_confine_LDADD)
+snap_confine_snap_confine_debug_CFLAGS += -DSNAP_CONFINE_DEBUG_BUILD=1
+
+snap-confine/snap-confine-debug$(EXEEXT): $(snap_confine_snap_confine_debug_OBJECTS) $(snap_confine_snap_confine_debug_DEPENDENCIES) $(EXTRA_snap_confine_snap_confine_debug_DEPENDENCIES) libsnap-confine-private/$(am__dirstamp)
+ @rm -f snap-confine/snap-confine-debug$(EXEEXT)
+ $(AM_V_CCLD)$(snap_confine_snap_confine_debug_LINK) $(snap_confine_snap_confine_debug_OBJECTS) $(snap_confine_snap_confine_debug_LDADD) $(LIBS)
+
+snap-confine/snap-confine-debug$(EXEEXT): LIBS += -Wl,-Bstatic -lcap -Wl,-Bdynamic
+
if WITH_UNIT_TESTS
noinst_PROGRAMS += snap-confine/snap-confine-unit-tests
snap_confine_snap_confine_unit_tests_SOURCES = \
@@ -220,6 +261,14 @@ snap_confine_snap_confine_unit_tests_SOURCES = \
snap_confine_snap_confine_unit_tests_CFLAGS = $(snap_confine_snap_confine_CFLAGS) $(GLIB_CFLAGS)
snap_confine_snap_confine_unit_tests_LDADD = $(snap_confine_snap_confine_LDADD) $(GLIB_LIBS)
snap_confine_snap_confine_unit_tests_LDFLAGS = $(snap_confine_snap_confine_LDFLAGS)
+
+
+snap-confine/snap-confine-unit-tests$(EXEEXT): $(snap_confine_snap_confine_unit_tests_OBJECTS) $(snap_confine_snap_confine_unit_tests_DEPENDENCIES) $(EXTRA_snap_confine_snap_confine_unit_tests_DEPENDENCIES) libsnap-confine-private/$(am__dirstamp)
+ @rm -f snap-confine/snap-confine-unit-tests$(EXEEXT)
+ $(AM_V_CCLD)$(snap_confine_snap_confine_unit_tests_LINK) $(snap_confine_snap_confine_unit_tests_OBJECTS) $(snap_confine_snap_confine_unit_tests_LDADD) $(LIBS)
+
+snap-confine/snap-confine-unit-tests$(EXEEXT): LIBS += -Wl,-Bstatic -lcap -Wl,-Bdynamic
+
endif
snap-confine/%.5: snap-confine/%.rst
@@ -18,7 +18,9 @@
#include "mount-opt.h"
#include "mount-opt.c"
+#include <errno.h>
#include <sys/mount.h>
+
#include <glib.h>
static void test_sc_mount_opt2str()
@@ -203,9 +205,53 @@ static void test_sc_umount_cmd()
"umount --force --lazy --expire --no-follow /mnt/foo");
}
+static void test_sc_do_mount()
+{
+ if (g_test_subprocess()) {
+ bool broken_mount(struct sc_fault_state *state, void *ptr) {
+ errno = EACCES;
+ return true;
+ }
+ sc_break("mount", broken_mount);
+ sc_do_mount("/foo", "/bar", "ext4", MS_RDONLY, NULL);
+
+ g_test_message("expected sc_do_mount not to return");
+ sc_reset_faults();
+ g_test_fail();
+ return;
+ }
+ g_test_trap_subprocess(NULL, 0, 0);
+ g_test_trap_assert_failed();
+ g_test_trap_assert_stderr
+ ("cannot perform operation: mount -t ext4 -o ro /foo /bar: Permission denied\n");
+}
+
+static void test_sc_do_umount()
+{
+ if (g_test_subprocess()) {
+ bool broken_umount(struct sc_fault_state *state, void *ptr) {
+ errno = EACCES;
+ return true;
+ }
+ sc_break("umount", broken_umount);
+ sc_do_umount("/foo", MNT_DETACH);
+
+ g_test_message("expected sc_do_umount not to return");
+ sc_reset_faults();
+ g_test_fail();
+ return;
+ }
+ g_test_trap_subprocess(NULL, 0, 0);
+ g_test_trap_assert_failed();
+ g_test_trap_assert_stderr
+ ("cannot perform operation: umount --lazy /foo: Permission denied\n");
+}
+
static void __attribute__ ((constructor)) init()
{
g_test_add_func("/mount/sc_mount_opt2str", test_sc_mount_opt2str);
g_test_add_func("/mount/sc_mount_cmd", test_sc_mount_cmd);
g_test_add_func("/mount/sc_umount_cmd", test_sc_umount_cmd);
+ g_test_add_func("/mount/sc_do_mount", test_sc_do_mount);
+ g_test_add_func("/mount/sc_do_umount", test_sc_do_umount);
}
@@ -17,14 +17,17 @@
#include "mount-opt.h"
+#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
-#include "utils.h"
+#include "fault-injection.h"
+#include "privs.h"
#include "string-utils.h"
+#include "utils.h"
const char *sc_mount_opt2str(char *buf, size_t buf_size, unsigned long flags)
{
@@ -241,3 +244,81 @@ const char *sc_umount_cmd(char *buf, size_t buf_size, const char *target,
return buf;
}
+
+void sc_do_mount(const char *source, const char *target,
+ const char *fs_type, unsigned long mountflags,
+ const void *data)
+{
+ char buf[10000];
+ const char *mount_cmd = NULL;
+
+ void ensure_mount_cmd() {
+ if (mount_cmd != NULL) {
+ return;
+ }
+ mount_cmd = sc_mount_cmd(buf, sizeof buf, source,
+ target, fs_type, mountflags, data);
+ }
+
+ if (sc_is_debug_enabled()) {
+#ifdef SNAP_CONFINE_DEBUG_BUILD
+ ensure_mount_cmd();
+#else
+ mount_cmd = "(disabled) use debug build to see details";
+#endif
+ debug("performing operation: %s", mount_cmd);
+ }
+ if (sc_faulty("mount", NULL)
+ || mount(source, target, fs_type, mountflags, data) < 0) {
+ // Save errno as ensure can clobber it.
+ int saved_errno = errno;
+
+ // Drop privileges so that we can compute our nice error message
+ // without risking an attack on one of the string functions there.
+ sc_privs_drop();
+
+ // Compute the equivalent mount command.
+ ensure_mount_cmd();
+
+ // Restore errno and die.
+ errno = saved_errno;
+ die("cannot perform operation: %s", mount_cmd);
+ }
+}
+
+void sc_do_umount(const char *target, int flags)
+{
+ char buf[10000];
+ const char *umount_cmd = NULL;
+
+ void ensure_umount_cmd() {
+ if (umount_cmd != NULL) {
+ return;
+ }
+ umount_cmd = sc_umount_cmd(buf, sizeof buf, target, flags);
+ }
+
+ if (sc_is_debug_enabled()) {
+#ifdef SNAP_CONFINE_DEBUG_BUILD
+ ensure_umount_cmd();
+#else
+ umount_cmd = "(disabled) use debug build to see details";
+#endif
+ debug("performing operation: %s", umount_cmd);
+ }
+ if (sc_faulty("umount", NULL) || umount2(target, flags) < 0) {
+ // Save errno as ensure can clobber it.
+ int saved_errno = errno;
+
+ // Drop privileges so that we can compute our nice error message
+ // without risking an attack on one of the string functions there.
+ sc_privs_drop();
+
+ // Compute the equivalent umount command.
+ ensure_umount_cmd();
+
+ // Restore errno and die.
+ errno = saved_errno;
+ die("cannot perform operation: %s", umount_cmd);
+ }
+}
@@ -60,4 +60,16 @@ const char *sc_mount_cmd(char *buf, size_t buf_size, const char *source, const c
const char *sc_umount_cmd(char *buf, size_t buf_size, const char *target,
int flags);
+/**
+ * A thin wrapper around mount(2) with logging and error checks.
+ **/
+void sc_do_mount(const char *source, const char *target,
+ const char *fs_type, unsigned long mountflags,
+ const void *data);
+
+/**
+ * A thin wrapper around umount(2) with logging and error checks.
+ **/
+void sc_do_umount(const char *target, int flags);
+
#endif // SNAP_CONFINE_MOUNT_OPT_H
@@ -33,6 +33,7 @@
#include "../libsnap-confine-private/classic.h"
#include "../libsnap-confine-private/cleanup-funcs.h"
+#include "../libsnap-confine-private/mount-opt.h"
#include "../libsnap-confine-private/snap.h"
#include "../libsnap-confine-private/string-utils.h"
#include "../libsnap-confine-private/utils.h"