github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/images/basic/integrationtest/test_sticky.c (about) 1 #include <err.h> 2 #include <errno.h> 3 #include <fcntl.h> 4 #include <stdlib.h> 5 #include <sys/stat.h> 6 #include <sys/types.h> 7 #include <sys/wait.h> 8 #include <unistd.h> 9 10 void createFile(const char* path) { 11 int fd = open(path, O_WRONLY | O_CREAT, 0777); 12 if (fd < 0) { 13 err(1, "open(%s)", path); 14 exit(1); 15 } else { 16 close(fd); 17 } 18 } 19 20 void waitAndCheckStatus(pid_t child) { 21 int status; 22 if (waitpid(child, &status, 0) == -1) { 23 err(1, "waitpid() failed"); 24 exit(1); 25 } 26 27 if (WIFEXITED(status)) { 28 int es = WEXITSTATUS(status); 29 if (es) { 30 err(1, "child exit status %d", es); 31 exit(1); 32 } 33 } else { 34 err(1, "child did not exit normally"); 35 exit(1); 36 } 37 } 38 39 void deleteFile(uid_t user, const char* path) { 40 pid_t child = fork(); 41 if (child == 0) { 42 if (setuid(user)) { 43 err(1, "setuid(%d)", user); 44 exit(1); 45 } 46 47 if (unlink(path)) { 48 err(1, "unlink(%s)", path); 49 exit(1); 50 } 51 exit(0); 52 } 53 waitAndCheckStatus(child); 54 } 55 56 int main(int argc, char** argv) { 57 const char kUser1Dir[] = "/user1dir"; 58 const char kUser2File[] = "/user1dir/user2file"; 59 const char kUser2File2[] = "/user1dir/user2file2"; 60 61 const uid_t user1 = 6666; 62 const uid_t user2 = 6667; 63 64 if (mkdir(kUser1Dir, 0755) != 0) { 65 err(1, "mkdir(%s)", kUser1Dir); 66 exit(1); 67 } 68 // Enable sticky bit for user1dir. 69 if (chmod(kUser1Dir, 01777) != 0) { 70 err(1, "chmod(%s)", kUser1Dir); 71 exit(1); 72 } 73 createFile(kUser2File); 74 createFile(kUser2File2); 75 76 if (chown(kUser1Dir, user1, getegid())) { 77 err(1, "chown(%s)", kUser1Dir); 78 exit(1); 79 } 80 if (chown(kUser2File, user2, getegid())) { 81 err(1, "chown(%s)", kUser2File); 82 exit(1); 83 } 84 if (chown(kUser2File2, user2, getegid())) { 85 err(1, "chown(%s)", kUser2File2); 86 exit(1); 87 } 88 89 // User1 should be able to delete any file inside user1dir, even files of 90 // other users due to the sticky bit. 91 deleteFile(user1, kUser2File); 92 93 // User2 should naturally be able to delete its own file even if the file is 94 // inside a sticky dir owned by someone else. 95 deleteFile(user2, kUser2File2); 96 }