minijail: Apply nosymfollow to /tmp
Symlinks can be used in the /tmp folder to trick crash_reporter into
deleting arbitrary files.
Mount the /tmp folder with nosymfollow flag to prevent an attacker with
write access to /tmp from confusing and redirecting code that uses
/tmp.
BUG=b:240740514
TEST=verify that /tmp mounted with nosymfollow using the command:
minijail0 -vt -P /mnt/empty -b / -k none,/proc,proc -- /bin/mount | grep /tmp
Cq-Depend: chromium:3852284
Change-Id: Ic991a0673cbaae21bd51ba18bccd049765bdab52
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minijail/+/3841218
Tested-by: Ryan Borzello <[email protected]>
Commit-Queue: Ryan Borzello <[email protected]>
Reviewed-by: Jorge Lucangeli Obes <[email protected]>
diff --git a/Makefile b/Makefile
index 3e41b5d..8c1e1c2 100644
--- a/Makefile
+++ b/Makefile
@@ -72,6 +72,14 @@
CPPFLAGS += -DBLOCK_SYMLINKS_IN_BINDMOUNT_PATHS
endif
+# Prevents symlinks from being followed in the /tmp folder.
+# Symlinks could be followed to modify arbitrary files when a process
+# had access to the /tmp folder.
+BLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP ?= no
+ifeq ($(BLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP),yes)
+CPPFLAGS += -DBLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP
+endif
+
ifeq ($(USE_ASAN),yes)
CPPFLAGS += -fsanitize=address -fno-omit-frame-pointer
LDFLAGS += -fsanitize=address -fno-omit-frame-pointer
diff --git a/libminijail.c b/libminijail.c
index 4252188..794a896 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -73,6 +73,15 @@
(MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_NODIRATIME | \
MS_RELATIME | MS_RDONLY)
+/*
+ * TODO(b/235960683): Drop this after CrOS upgrades to glibc >= 2.34
+ * because MS_NOSYMFOLLOW will be defined in sys/mount.h.
+ */
+#ifndef MS_NOSYMFOLLOW
+/* Added locally in kernels 4.x+. */
+#define MS_NOSYMFOLLOW 256
+#endif
+
struct minijail_rlimit {
int type;
rlim_t cur;
@@ -2007,8 +2016,14 @@
pdie("tmpfs size spec error");
else if ((size_t)ret >= sizeof(data))
pdie("tmpfs size spec too large");
- return mount("none", "/tmp", "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID,
- data);
+
+ unsigned long flags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
+
+ if (block_symlinks_in_noninit_mountns_tmp()) {
+ flags |= MS_NOSYMFOLLOW;
+ }
+
+ return mount("none", "/tmp", "tmpfs", flags, data);
}
static int remount_proc_readonly(const struct minijail *j)
diff --git a/util.h b/util.h
index 4c65bc2..0b1aecf 100644
--- a/util.h
+++ b/util.h
@@ -230,6 +230,15 @@
#endif
}
+static inline bool block_symlinks_in_noninit_mountns_tmp(void)
+{
+#if defined(BLOCK_SYMLINKS_IN_NONINIT_MOUNTNS_TMP)
+ return true;
+#else
+ return false;
+#endif
+}
+
static inline size_t get_num_syscalls(void)
{
return syscall_table_size;