Merge pull request #156822 from xfix/wrapper-assert-argc-at-least-one

nixos/wrappers: require argc to be at least one

authored by Linus Heckemann and committed by GitHub 7c035dbb 0659e76d

+21 -17
+21 -17
nixos/modules/security/wrappers/wrapper.c
··· 2 2 #include <stdio.h> 3 3 #include <string.h> 4 4 #include <unistd.h> 5 + #include <stdnoreturn.h> 5 6 #include <sys/types.h> 6 7 #include <sys/stat.h> 7 8 #include <sys/xattr.h> 8 9 #include <fcntl.h> 9 10 #include <dirent.h> 10 - #include <assert.h> 11 11 #include <errno.h> 12 12 #include <linux/capability.h> 13 13 #include <sys/prctl.h> ··· 16 16 #include <syscall.h> 17 17 #include <byteswap.h> 18 18 19 - // Make sure assertions are not compiled out, we use them to codify 20 - // invariants about this program and we want it to fail fast and 21 - // loudly if they are violated. 22 - #undef NDEBUG 19 + #define ASSERT(expr) ((expr) ? (void) 0 : assert_failure(#expr)) 23 20 24 21 extern char **environ; 25 22 ··· 37 34 #else 38 35 #define LE32_TO_H(x) (x) 39 36 #endif 37 + 38 + static noreturn void assert_failure(const char *assertion) { 39 + fprintf(stderr, "Assertion `%s` in NixOS's wrapper.c failed.\n", assertion); 40 + fflush(stderr); 41 + abort(); 42 + } 40 43 41 44 int get_last_cap(unsigned *last_cap) { 42 45 FILE* file = fopen("/proc/sys/kernel/cap_last_cap", "r"); ··· 167 170 } 168 171 169 172 int main(int argc, char **argv) { 173 + ASSERT(argc >= 1); 170 174 char *self_path = NULL; 171 175 int self_path_size = readlink_malloc("/proc/self/exe", &self_path); 172 176 if (self_path_size < 0) { ··· 181 185 int len = strlen(wrapper_dir); 182 186 if (len > 0 && '/' == wrapper_dir[len - 1]) 183 187 --len; 184 - assert(!strncmp(self_path, wrapper_dir, len)); 185 - assert('/' == wrapper_dir[0]); 186 - assert('/' == self_path[len]); 188 + ASSERT(!strncmp(self_path, wrapper_dir, len)); 189 + ASSERT('/' == wrapper_dir[0]); 190 + ASSERT('/' == self_path[len]); 187 191 188 192 // Make *really* *really* sure that we were executed as 189 193 // `self_path', and not, say, as some other setuid program. That 190 194 // is, our effective uid/gid should match the uid/gid of 191 195 // `self_path'. 192 196 struct stat st; 193 - assert(lstat(self_path, &st) != -1); 197 + ASSERT(lstat(self_path, &st) != -1); 194 198 195 - assert(!(st.st_mode & S_ISUID) || (st.st_uid == geteuid())); 196 - assert(!(st.st_mode & S_ISGID) || (st.st_gid == getegid())); 199 + ASSERT(!(st.st_mode & S_ISUID) || (st.st_uid == geteuid())); 200 + ASSERT(!(st.st_mode & S_ISGID) || (st.st_gid == getegid())); 197 201 198 202 // And, of course, we shouldn't be writable. 199 - assert(!(st.st_mode & (S_IWGRP | S_IWOTH))); 203 + ASSERT(!(st.st_mode & (S_IWGRP | S_IWOTH))); 200 204 201 205 // Read the path of the real (wrapped) program from <self>.real. 202 206 char real_fn[PATH_MAX + 10]; 203 207 int real_fn_size = snprintf(real_fn, sizeof(real_fn), "%s.real", self_path); 204 - assert(real_fn_size < sizeof(real_fn)); 208 + ASSERT(real_fn_size < sizeof(real_fn)); 205 209 206 210 int fd_self = open(real_fn, O_RDONLY); 207 - assert(fd_self != -1); 211 + ASSERT(fd_self != -1); 208 212 209 213 char source_prog[PATH_MAX]; 210 214 len = read(fd_self, source_prog, PATH_MAX); 211 - assert(len != -1); 212 - assert(len < sizeof(source_prog)); 213 - assert(len > 0); 215 + ASSERT(len != -1); 216 + ASSERT(len < sizeof(source_prog)); 217 + ASSERT(len > 0); 214 218 source_prog[len] = 0; 215 219 216 220 close(fd_self);