1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * A pre-opened interpreter - what 'F' gives a static entry and what a 'B' 4 * entry binds - keeps a file open for as long as the entry lives, so it pins 5 * the mount it came from. It costs no file descriptor, and binfmt_misc is 6 * FS_USERNS_MOUNT, so an unprivileged user namespace can create them without 7 * bound. Check that UCOUNT_BINFMT_MISC_INTERPRETERS bounds it, that an entry 8 * that pre-opens nothing is not charged, that removing an entry gives the 9 * charge back, and that nesting a user namespace does not evade it. 10 * 11 * Runs unprivileged in a user namespace. 12 */ 13 #define _GNU_SOURCE 14 #include <errno.h> 15 #include <fcntl.h> 16 #include <limits.h> 17 #include <stdio.h> 18 #include <string.h> 19 #include <sys/mount.h> 20 #include <sys/stat.h> 21 #include <unistd.h> 22 23 #include "../filesystems/utils.h" 24 #include "kselftest_harness.h" 25 26 #define MNT "/tmp/binfmt_interplimit" 27 #define NESTED_MNT "/tmp/binfmt_interplimit_nested" 28 #define LIMIT_SYSCTL "/proc/sys/user/max_binfmt_misc_interpreters" 29 30 #define MAGIC "\\xde\\xad" 31 /* Not on the instance, and unlike /bin/true it always exists. */ 32 #define INTERP "/proc/self/exe" 33 34 /* Small enough to fill by hand, big enough that a refund is visible. */ 35 #define LIMIT 4 36 37 /* What UCOUNT_ENTRY() lets a namespace raise its own limit to. */ 38 #define LIMIT_MAX "2147483647" 39 40 static int ensure_dir(const char *path) 41 { 42 if (mkdir(path, 0755) && errno != EEXIST) 43 return -1; 44 return 0; 45 } 46 47 /* Write @val to @path, preserving write(2)'s errno for the caller. */ 48 static int write_keep_errno(const char *path, const char *val) 49 { 50 int fd, saved; 51 ssize_t n; 52 53 fd = open(path, O_WRONLY | O_CLOEXEC); 54 if (fd < 0) 55 return -1; 56 n = write(fd, val, strlen(val)); 57 saved = errno; 58 close(fd); 59 errno = saved; 60 return n < 0 ? -1 : 0; 61 } 62 63 static int set_limit(const char *val) 64 { 65 return write_keep_errno(LIMIT_SYSCTL, val); 66 } 67 68 static int register_at(const char *mnt, const char *rule) 69 { 70 char path[PATH_MAX]; 71 72 snprintf(path, sizeof(path), "%s/register", mnt); 73 return write_keep_errno(path, rule); 74 } 75 76 /* An 'F' entry: one interpreter pre-opened at registration, one charge. */ 77 static int register_fixed(const char *mnt, const char *name) 78 { 79 char rule[PATH_MAX]; 80 81 snprintf(rule, sizeof(rule), ":%s:M::" MAGIC "::" INTERP ":F", name); 82 return register_at(mnt, rule); 83 } 84 85 /* The same entry without 'F': the interpreter is opened per exec instead. */ 86 static int register_plain(const char *mnt, const char *name) 87 { 88 char rule[PATH_MAX]; 89 90 snprintf(rule, sizeof(rule), ":%s:M::" MAGIC "::" INTERP ":", name); 91 return register_at(mnt, rule); 92 } 93 94 static int remove_entry(const char *mnt, const char *name) 95 { 96 char path[PATH_MAX]; 97 98 snprintf(path, sizeof(path), "%s/%s", mnt, name); 99 return write_keep_errno(path, "-1\n"); 100 } 101 102 static bool entry_exists(const char *mnt, const char *name) 103 { 104 char path[PATH_MAX]; 105 106 snprintf(path, sizeof(path), "%s/%s", mnt, name); 107 return access(path, F_OK) == 0; 108 } 109 110 /* Register @n 'F' entries, each with a name of its own. */ 111 static int fill_budget(const char *mnt, unsigned int n) 112 { 113 char name[32]; 114 unsigned int i; 115 116 for (i = 0; i < n; i++) { 117 snprintf(name, sizeof(name), "fixed%u", i); 118 if (register_fixed(mnt, name)) 119 return -1; 120 } 121 return 0; 122 } 123 124 FIXTURE(interp_limit) { 125 }; 126 127 FIXTURE_SETUP(interp_limit) 128 { 129 /* setup_userns() exits rather than returns if this is not there. */ 130 if (access("/proc/self/ns/user", F_OK)) 131 SKIP(return, "kernel without user namespaces"); 132 ASSERT_EQ(setup_userns(), 0); 133 134 /* CAP_SYS_RESOURCE in this namespace is what makes it writable. */ 135 if (set_limit(LIMIT_MAX)) { 136 if (errno == ENOENT) 137 SKIP(return, "kernel without " LIMIT_SYSCTL); 138 SKIP(return, "cannot set the limit: %s", strerror(errno)); 139 } 140 141 ASSERT_EQ(ensure_dir(MNT), 0); 142 if (mount("binfmt_misc", MNT, "binfmt_misc", 0, NULL)) { 143 int saved = errno; 144 145 /* Teardown doesn't run when setup skips, so clean up here. */ 146 rmdir(MNT); 147 SKIP(return, "no binfmt_misc: %s", strerror(saved)); 148 } 149 } 150 151 FIXTURE_TEARDOWN(interp_limit) 152 { 153 /* The namespaces go with the process; just don't litter /tmp. */ 154 umount2(NESTED_MNT, MNT_DETACH); 155 umount2(MNT, MNT_DETACH); 156 rmdir(NESTED_MNT); 157 rmdir(MNT); 158 } 159 160 /* Every pre-opened interpreter is charged, and the budget is a hard stop. */ 161 TEST_F(interp_limit, fixed_interpreters_are_charged) 162 { 163 char buf[32]; 164 165 snprintf(buf, sizeof(buf), "%u", LIMIT); 166 ASSERT_EQ(set_limit(buf), 0); 167 168 ASSERT_EQ(fill_budget(MNT, LIMIT), 0); 169 170 EXPECT_NE(register_fixed(MNT, "over"), 0); 171 EXPECT_EQ(errno, ENOSPC); 172 173 /* A refused registration leaves nothing behind. */ 174 EXPECT_FALSE(entry_exists(MNT, "over")); 175 } 176 177 /* An entry that pre-opens nothing pins nothing, so it is not charged. */ 178 TEST_F(interp_limit, plain_entries_are_not_charged) 179 { 180 ASSERT_EQ(set_limit("0"), 0); 181 182 EXPECT_EQ(register_plain(MNT, "plain"), 0); 183 EXPECT_TRUE(entry_exists(MNT, "plain")); 184 185 /* ... while the same entry with 'F' has nothing to spend. */ 186 EXPECT_NE(register_fixed(MNT, "fixed"), 0); 187 EXPECT_EQ(errno, ENOSPC); 188 } 189 190 /* Removing an entry closes its interpreters and gives the charge back. */ 191 TEST_F(interp_limit, removal_refunds_the_charge) 192 { 193 char buf[32]; 194 195 snprintf(buf, sizeof(buf), "%u", LIMIT); 196 ASSERT_EQ(set_limit(buf), 0); 197 198 ASSERT_EQ(fill_budget(MNT, LIMIT), 0); 199 ASSERT_NE(register_fixed(MNT, "over"), 0); 200 201 ASSERT_EQ(remove_entry(MNT, "fixed0"), 0); 202 EXPECT_EQ(register_fixed(MNT, "over"), 0); 203 } 204 205 /* 206 * The charge walks the ancestors, so a namespace cannot buy itself budget by 207 * nesting: it may raise only its own limit, and the parent it was created 208 * from is charged for every binding made below it. 209 */ 210 TEST_F(interp_limit, nesting_does_not_evade_it) 211 { 212 char buf[32]; 213 214 snprintf(buf, sizeof(buf), "%u", LIMIT); 215 ASSERT_EQ(set_limit(buf), 0); 216 ASSERT_EQ(fill_budget(MNT, LIMIT), 0); 217 218 ASSERT_EQ(setup_userns(), 0); 219 ASSERT_EQ(set_limit(LIMIT_MAX), 0); 220 221 ASSERT_EQ(ensure_dir(NESTED_MNT), 0); 222 ASSERT_EQ(mount("binfmt_misc", NESTED_MNT, "binfmt_misc", 0, NULL), 0); 223 224 /* A fresh instance with an unlimited budget of its own, and yet: */ 225 EXPECT_NE(register_fixed(NESTED_MNT, "nested"), 0); 226 EXPECT_EQ(errno, ENOSPC); 227 228 /* The nested instance works for anything that pins no file. */ 229 EXPECT_EQ(register_plain(NESTED_MNT, "nested_plain"), 0); 230 } 231 232 TEST_HARNESS_MAIN 233