1*25757bc8SChristian Brauner // SPDX-License-Identifier: GPL-2.0 2*25757bc8SChristian Brauner /* 3*25757bc8SChristian Brauner * An 'F' entry keeps its interpreter open for as long as the entry exists, 4*25757bc8SChristian Brauner * and the entry only goes away when the binfmt_misc superblock is destroyed. 5*25757bc8SChristian Brauner * An interpreter that lives on a mount which in turn keeps that superblock 6*25757bc8SChristian Brauner * alive therefore pins the instance that owns it, and nothing can break the 7*25757bc8SChristian Brauner * cycle. Check the two ways userspace could arrange for that: an interpreter 8*25757bc8SChristian Brauner * on the binfmt_misc instance itself, and one on a filesystem stacked on it. 9*25757bc8SChristian Brauner * 10*25757bc8SChristian Brauner * Runs unprivileged in a user namespace; binfmt_misc is FS_USERNS_MOUNT. 11*25757bc8SChristian Brauner */ 12*25757bc8SChristian Brauner #define _GNU_SOURCE 13*25757bc8SChristian Brauner #include <fcntl.h> 14*25757bc8SChristian Brauner #include <limits.h> 15*25757bc8SChristian Brauner #include <sched.h> 16*25757bc8SChristian Brauner #include <sys/mount.h> 17*25757bc8SChristian Brauner #include <sys/stat.h> 18*25757bc8SChristian Brauner 19*25757bc8SChristian Brauner #include "../filesystems/utils.h" 20*25757bc8SChristian Brauner #include "kselftest_harness.h" 21*25757bc8SChristian Brauner 22*25757bc8SChristian Brauner #define MNT "/tmp/binfmt_selfpin" 23*25757bc8SChristian Brauner #define BACKING "/tmp/binfmt_selfpin_back" 24*25757bc8SChristian Brauner #define LOWER BACKING "/lower" 25*25757bc8SChristian Brauner #define MERGED "/tmp/binfmt_selfpin_merged" 26*25757bc8SChristian Brauner 27*25757bc8SChristian Brauner #define MAGIC "\\xde\\xad" 28*25757bc8SChristian Brauner #define RULE(interp) ":selfpin:M::" MAGIC "::" interp ":F" 29*25757bc8SChristian Brauner /* Not on the instance, and unlike /bin/true it always exists. */ 30*25757bc8SChristian Brauner #define INTERP "/proc/self/exe" 31*25757bc8SChristian Brauner 32*25757bc8SChristian Brauner #define OPTS_MAX (3 * PATH_MAX + 64) 33*25757bc8SChristian Brauner 34*25757bc8SChristian Brauner static int ensure_dir(const char *path) 35*25757bc8SChristian Brauner { 36*25757bc8SChristian Brauner if (mkdir(path, 0755) && errno != EEXIST) 37*25757bc8SChristian Brauner return -1; 38*25757bc8SChristian Brauner return 0; 39*25757bc8SChristian Brauner } 40*25757bc8SChristian Brauner 41*25757bc8SChristian Brauner /* Write @rule to this instance's register file, preserving write(2)'s errno. */ 42*25757bc8SChristian Brauner static int register_at(struct __test_metadata *_metadata, const char *rule) 43*25757bc8SChristian Brauner { 44*25757bc8SChristian Brauner int fd, saved; 45*25757bc8SChristian Brauner ssize_t n; 46*25757bc8SChristian Brauner 47*25757bc8SChristian Brauner fd = open(MNT "/register", O_WRONLY); 48*25757bc8SChristian Brauner ASSERT_GE(fd, 0); 49*25757bc8SChristian Brauner n = write(fd, rule, strlen(rule)); 50*25757bc8SChristian Brauner saved = errno; 51*25757bc8SChristian Brauner close(fd); 52*25757bc8SChristian Brauner errno = saved; 53*25757bc8SChristian Brauner return n < 0 ? -1 : 0; 54*25757bc8SChristian Brauner } 55*25757bc8SChristian Brauner 56*25757bc8SChristian Brauner /* 57*25757bc8SChristian Brauner * Mount an overlay over @lower using a private upper/work pair, so the two 58*25757bc8SChristian Brauner * mounts this test performs cannot interfere with each other and neither 59*25757bc8SChristian Brauner * overlaps the lower layer. 60*25757bc8SChristian Brauner */ 61*25757bc8SChristian Brauner static int mount_overlay(const char *lower, int nr) 62*25757bc8SChristian Brauner { 63*25757bc8SChristian Brauner char opts[OPTS_MAX], upper[PATH_MAX], work[PATH_MAX]; 64*25757bc8SChristian Brauner 65*25757bc8SChristian Brauner snprintf(upper, sizeof(upper), "%s/upper%d", BACKING, nr); 66*25757bc8SChristian Brauner snprintf(work, sizeof(work), "%s/work%d", BACKING, nr); 67*25757bc8SChristian Brauner if (mkdir(upper, 0755) || mkdir(work, 0755)) 68*25757bc8SChristian Brauner return -1; 69*25757bc8SChristian Brauner 70*25757bc8SChristian Brauner snprintf(opts, sizeof(opts), "lowerdir=%s,upperdir=%s,workdir=%s", 71*25757bc8SChristian Brauner lower, upper, work); 72*25757bc8SChristian Brauner return mount("ovl", MERGED, "overlay", 0, opts); 73*25757bc8SChristian Brauner } 74*25757bc8SChristian Brauner 75*25757bc8SChristian Brauner FIXTURE(selfpin) { 76*25757bc8SChristian Brauner }; 77*25757bc8SChristian Brauner 78*25757bc8SChristian Brauner FIXTURE_SETUP(selfpin) 79*25757bc8SChristian Brauner { 80*25757bc8SChristian Brauner /* setup_userns() exits rather than returns if this is not there. */ 81*25757bc8SChristian Brauner if (access("/proc/self/ns/user", F_OK)) 82*25757bc8SChristian Brauner SKIP(return, "kernel without user namespaces"); 83*25757bc8SChristian Brauner ASSERT_EQ(setup_userns(), 0); 84*25757bc8SChristian Brauner 85*25757bc8SChristian Brauner ASSERT_EQ(ensure_dir(MNT), 0); 86*25757bc8SChristian Brauner if (mount("binfmt_misc", MNT, "binfmt_misc", 0, NULL)) { 87*25757bc8SChristian Brauner int saved = errno; 88*25757bc8SChristian Brauner 89*25757bc8SChristian Brauner /* Teardown doesn't run when setup skips, so clean up here. */ 90*25757bc8SChristian Brauner rmdir(MNT); 91*25757bc8SChristian Brauner SKIP(return, "no binfmt_misc: %s", strerror(saved)); 92*25757bc8SChristian Brauner } 93*25757bc8SChristian Brauner } 94*25757bc8SChristian Brauner 95*25757bc8SChristian Brauner FIXTURE_TEARDOWN(selfpin) 96*25757bc8SChristian Brauner { 97*25757bc8SChristian Brauner /* The namespaces go with the process; just don't litter /tmp. */ 98*25757bc8SChristian Brauner umount2(MERGED, MNT_DETACH); 99*25757bc8SChristian Brauner umount2(BACKING, MNT_DETACH); 100*25757bc8SChristian Brauner umount2(MNT, MNT_DETACH); 101*25757bc8SChristian Brauner rmdir(MERGED); 102*25757bc8SChristian Brauner rmdir(BACKING); 103*25757bc8SChristian Brauner rmdir(MNT); 104*25757bc8SChristian Brauner } 105*25757bc8SChristian Brauner 106*25757bc8SChristian Brauner /* 107*25757bc8SChristian Brauner * The instance's own files are regular files the mounter owns, so they can be 108*25757bc8SChristian Brauner * made executable. Opening one for exec still has to fail, otherwise the entry 109*25757bc8SChristian Brauner * pins the very superblock it lives in. 110*25757bc8SChristian Brauner */ 111*25757bc8SChristian Brauner TEST_F(selfpin, interpreter_on_the_instance) 112*25757bc8SChristian Brauner { 113*25757bc8SChristian Brauner ASSERT_EQ(chmod(MNT "/status", 0755), 0); 114*25757bc8SChristian Brauner 115*25757bc8SChristian Brauner ASSERT_NE(register_at(_metadata, RULE(MNT "/status")), 0); 116*25757bc8SChristian Brauner EXPECT_EQ(errno, EACCES); 117*25757bc8SChristian Brauner } 118*25757bc8SChristian Brauner 119*25757bc8SChristian Brauner /* Same for an entry file rather than one of the control files. */ 120*25757bc8SChristian Brauner TEST_F(selfpin, interpreter_on_an_entry) 121*25757bc8SChristian Brauner { 122*25757bc8SChristian Brauner ASSERT_EQ(register_at(_metadata, ":victim:M::" MAGIC "::" INTERP ":"), 0); 123*25757bc8SChristian Brauner ASSERT_EQ(chmod(MNT "/victim", 0755), 0); 124*25757bc8SChristian Brauner 125*25757bc8SChristian Brauner ASSERT_NE(register_at(_metadata, RULE(MNT "/victim")), 0); 126*25757bc8SChristian Brauner EXPECT_EQ(errno, EACCES); 127*25757bc8SChristian Brauner } 128*25757bc8SChristian Brauner 129*25757bc8SChristian Brauner /* 130*25757bc8SChristian Brauner * A stacking filesystem holds a private clone of each layer for its whole 131*25757bc8SChristian Brauner * lifetime, so an instance used as a layer can be pinned by an interpreter 132*25757bc8SChristian Brauner * that does not live on it at all. Refuse to be a layer. 133*25757bc8SChristian Brauner */ 134*25757bc8SChristian Brauner TEST_F(selfpin, refuses_to_be_stacked_on) 135*25757bc8SChristian Brauner { 136*25757bc8SChristian Brauner ASSERT_EQ(ensure_dir(BACKING), 0); 137*25757bc8SChristian Brauner ASSERT_EQ(mount("tmpfs", BACKING, "tmpfs", 0, NULL), 0); 138*25757bc8SChristian Brauner ASSERT_EQ(mkdir(LOWER, 0755), 0); 139*25757bc8SChristian Brauner ASSERT_EQ(ensure_dir(MERGED), 0); 140*25757bc8SChristian Brauner 141*25757bc8SChristian Brauner /* Nothing to prove unless overlayfs works here at all. */ 142*25757bc8SChristian Brauner if (mount_overlay(LOWER, 1)) { 143*25757bc8SChristian Brauner if (errno == ENODEV || errno == EPERM) 144*25757bc8SChristian Brauner SKIP(return, "no unprivileged overlayfs"); 145*25757bc8SChristian Brauner SKIP(return, "overlayfs unusable here: %s", strerror(errno)); 146*25757bc8SChristian Brauner } 147*25757bc8SChristian Brauner ASSERT_EQ(umount(MERGED), 0); 148*25757bc8SChristian Brauner 149*25757bc8SChristian Brauner EXPECT_NE(mount_overlay(MNT, 2), 0); 150*25757bc8SChristian Brauner } 151*25757bc8SChristian Brauner 152*25757bc8SChristian Brauner /* An ordinary interpreter still registers with 'F'. */ 153*25757bc8SChristian Brauner TEST_F(selfpin, ordinary_interpreter_still_works) 154*25757bc8SChristian Brauner { 155*25757bc8SChristian Brauner EXPECT_EQ(register_at(_metadata, RULE(INTERP)), 0); 156*25757bc8SChristian Brauner } 157*25757bc8SChristian Brauner 158*25757bc8SChristian Brauner TEST_HARNESS_MAIN 159