1 /* 1 /* 2 * Copyright © 2018 Alexey Dobriyan <adobriya 2 * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com> 3 * 3 * 4 * Permission to use, copy, modify, and distri 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby grant 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice 6 * copyright notice and this permission notice appear in all copies. 7 * 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AU 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SH 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUEN 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TOR 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANC 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 15 */ 16 // Test /proc/*/fd lookup. 16 // Test /proc/*/fd lookup. 17 17 18 #undef NDEBUG 18 #undef NDEBUG 19 #include <assert.h> 19 #include <assert.h> 20 #include <dirent.h> 20 #include <dirent.h> 21 #include <errno.h> 21 #include <errno.h> 22 #include <limits.h> 22 #include <limits.h> 23 #include <sched.h> 23 #include <sched.h> 24 #include <stdio.h> 24 #include <stdio.h> 25 #include <unistd.h> 25 #include <unistd.h> 26 #include <sys/types.h> 26 #include <sys/types.h> 27 #include <sys/stat.h> 27 #include <sys/stat.h> 28 #include <fcntl.h> 28 #include <fcntl.h> 29 29 30 #include "proc.h" 30 #include "proc.h" 31 31 32 /* lstat(2) has more "coverage" in case non-sy 32 /* lstat(2) has more "coverage" in case non-symlink pops up somehow. */ 33 static void test_lookup_pass(const char *pathn 33 static void test_lookup_pass(const char *pathname) 34 { 34 { 35 struct stat st; 35 struct stat st; 36 ssize_t rv; 36 ssize_t rv; 37 37 38 memset(&st, 0, sizeof(struct stat)); 38 memset(&st, 0, sizeof(struct stat)); 39 rv = lstat(pathname, &st); 39 rv = lstat(pathname, &st); 40 assert(rv == 0); 40 assert(rv == 0); 41 assert(S_ISLNK(st.st_mode)); 41 assert(S_ISLNK(st.st_mode)); 42 } 42 } 43 43 44 static void test_lookup_fail(const char *pathn 44 static void test_lookup_fail(const char *pathname) 45 { 45 { 46 struct stat st; 46 struct stat st; 47 ssize_t rv; 47 ssize_t rv; 48 48 49 rv = lstat(pathname, &st); 49 rv = lstat(pathname, &st); 50 assert(rv == -1 && errno == ENOENT); 50 assert(rv == -1 && errno == ENOENT); 51 } 51 } 52 52 53 static void test_lookup(unsigned int fd) 53 static void test_lookup(unsigned int fd) 54 { 54 { 55 char buf[64]; 55 char buf[64]; 56 unsigned int c; 56 unsigned int c; 57 unsigned int u; 57 unsigned int u; 58 int i; 58 int i; 59 59 60 snprintf(buf, sizeof(buf), "/proc/self 60 snprintf(buf, sizeof(buf), "/proc/self/fd/%u", fd); 61 test_lookup_pass(buf); 61 test_lookup_pass(buf); 62 62 63 /* leading junk */ 63 /* leading junk */ 64 for (c = 1; c <= 255; c++) { 64 for (c = 1; c <= 255; c++) { 65 if (c == '/') 65 if (c == '/') 66 continue; 66 continue; 67 snprintf(buf, sizeof(buf), "/p 67 snprintf(buf, sizeof(buf), "/proc/self/fd/%c%u", c, fd); 68 test_lookup_fail(buf); 68 test_lookup_fail(buf); 69 } 69 } 70 70 71 /* trailing junk */ 71 /* trailing junk */ 72 for (c = 1; c <= 255; c++) { 72 for (c = 1; c <= 255; c++) { 73 if (c == '/') 73 if (c == '/') 74 continue; 74 continue; 75 snprintf(buf, sizeof(buf), "/p 75 snprintf(buf, sizeof(buf), "/proc/self/fd/%u%c", fd, c); 76 test_lookup_fail(buf); 76 test_lookup_fail(buf); 77 } 77 } 78 78 79 for (i = INT_MIN; i < INT_MIN + 1024; 79 for (i = INT_MIN; i < INT_MIN + 1024; i++) { 80 snprintf(buf, sizeof(buf), "/p 80 snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i); 81 test_lookup_fail(buf); 81 test_lookup_fail(buf); 82 } 82 } 83 for (i = -1024; i < 0; i++) { 83 for (i = -1024; i < 0; i++) { 84 snprintf(buf, sizeof(buf), "/p 84 snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i); 85 test_lookup_fail(buf); 85 test_lookup_fail(buf); 86 } 86 } 87 for (u = INT_MAX - 1024; u <= (unsigne 87 for (u = INT_MAX - 1024; u <= (unsigned int)INT_MAX + 1024; u++) { 88 snprintf(buf, sizeof(buf), "/p 88 snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u); 89 test_lookup_fail(buf); 89 test_lookup_fail(buf); 90 } 90 } 91 for (u = UINT_MAX - 1024; u != 0; u++) 91 for (u = UINT_MAX - 1024; u != 0; u++) { 92 snprintf(buf, sizeof(buf), "/p 92 snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u); 93 test_lookup_fail(buf); 93 test_lookup_fail(buf); 94 } 94 } 95 95 96 96 97 } 97 } 98 98 99 int main(void) 99 int main(void) 100 { 100 { 101 struct dirent *de; 101 struct dirent *de; 102 unsigned int fd, target_fd; 102 unsigned int fd, target_fd; 103 103 104 if (unshare(CLONE_FILES) == -1) 104 if (unshare(CLONE_FILES) == -1) 105 return 1; 105 return 1; 106 106 107 /* Wipe fdtable. */ 107 /* Wipe fdtable. */ 108 do { 108 do { 109 DIR *d; 109 DIR *d; 110 110 111 d = opendir("/proc/self/fd"); 111 d = opendir("/proc/self/fd"); 112 if (!d) 112 if (!d) 113 return 1; 113 return 1; 114 114 115 de = xreaddir(d); 115 de = xreaddir(d); 116 assert(de->d_type == DT_DIR); 116 assert(de->d_type == DT_DIR); 117 assert(streq(de->d_name, ".")) 117 assert(streq(de->d_name, ".")); 118 118 119 de = xreaddir(d); 119 de = xreaddir(d); 120 assert(de->d_type == DT_DIR); 120 assert(de->d_type == DT_DIR); 121 assert(streq(de->d_name, "..") 121 assert(streq(de->d_name, "..")); 122 next: 122 next: 123 de = xreaddir(d); 123 de = xreaddir(d); 124 if (de) { 124 if (de) { 125 unsigned long long fd_ 125 unsigned long long fd_ull; 126 unsigned int fd; 126 unsigned int fd; 127 char *end; 127 char *end; 128 128 129 assert(de->d_type == D 129 assert(de->d_type == DT_LNK); 130 130 131 fd_ull = xstrtoull(de- 131 fd_ull = xstrtoull(de->d_name, &end); 132 assert(*end == '\0'); 132 assert(*end == '\0'); 133 assert(fd_ull == (unsi 133 assert(fd_ull == (unsigned int)fd_ull); 134 134 135 fd = fd_ull; 135 fd = fd_ull; 136 if (fd == dirfd(d)) 136 if (fd == dirfd(d)) 137 goto next; 137 goto next; 138 close(fd); 138 close(fd); 139 } 139 } 140 140 141 closedir(d); 141 closedir(d); 142 } while (de); 142 } while (de); 143 143 144 /* Now fdtable is clean. */ 144 /* Now fdtable is clean. */ 145 145 146 fd = open("/", O_PATH|O_DIRECTORY); 146 fd = open("/", O_PATH|O_DIRECTORY); 147 assert(fd == 0); 147 assert(fd == 0); 148 test_lookup(fd); 148 test_lookup(fd); 149 close(fd); 149 close(fd); 150 150 151 /* Clean again! */ 151 /* Clean again! */ 152 152 153 fd = open("/", O_PATH|O_DIRECTORY); 153 fd = open("/", O_PATH|O_DIRECTORY); 154 assert(fd == 0); 154 assert(fd == 0); 155 /* Default RLIMIT_NOFILE-1 */ 155 /* Default RLIMIT_NOFILE-1 */ 156 target_fd = 1023; 156 target_fd = 1023; 157 while (target_fd > 0) { 157 while (target_fd > 0) { 158 if (dup2(fd, target_fd) == tar 158 if (dup2(fd, target_fd) == target_fd) 159 break; 159 break; 160 target_fd /= 2; 160 target_fd /= 2; 161 } 161 } 162 assert(target_fd > 0); 162 assert(target_fd > 0); 163 close(fd); 163 close(fd); 164 test_lookup(target_fd); 164 test_lookup(target_fd); 165 close(target_fd); 165 close(target_fd); 166 166 167 return 0; 167 return 0; 168 } 168 } 169 169
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.