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