1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 The FreeBSD Foundation 5 * 6 * This software was developed by Mark Johnston under sponsorship from 7 * the FreeBSD Foundation. 8 */ 9 10 #include <sys/param.h> 11 #include <sys/stat.h> 12 #include <sys/sysctl.h> 13 #include <sys/user.h> 14 #include <sys/wait.h> 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 21 #include <atf-c.h> 22 23 /* 24 * These tests exercise the KERN_PROC_* sysctls. 25 */ 26 27 /* 28 * Loop through all valid PIDs and try to fetch info for each one. 29 */ 30 static void 31 sysctl_kern_proc_all(int cmd) 32 { 33 int mib[4], pid_max; 34 void *buf; 35 size_t sz; 36 37 sz = sizeof(pid_max); 38 ATF_REQUIRE(sysctlbyname("kern.pid_max", &pid_max, &sz, NULL, 0) == 0); 39 40 mib[0] = CTL_KERN; 41 mib[1] = KERN_PROC; 42 mib[2] = cmd; 43 for (int i = 1; i <= pid_max; i++) { 44 mib[3] = i; 45 46 if (sysctl(mib, 4, NULL, &sz, NULL, 0) == 0) { 47 buf = malloc(sz); 48 ATF_REQUIRE(buf != NULL); 49 (void)sysctl(mib, 4, buf, &sz, NULL, 0); 50 free(buf); 51 } 52 } 53 54 mib[3] = -1; 55 ATF_REQUIRE_ERRNO(ESRCH, sysctl(mib, 4, NULL, &sz, NULL, 0) != 0); 56 } 57 58 /* 59 * Validate behaviour of the KERN_PROC_CWD sysctl. 60 */ 61 ATF_TC_WITHOUT_HEAD(sysctl_kern_proc_cwd); 62 ATF_TC_BODY(sysctl_kern_proc_cwd, tc) 63 { 64 struct kinfo_file kfile; 65 char cwd[PATH_MAX]; 66 int cmd, mib[4]; 67 size_t sz; 68 pid_t child; 69 int status; 70 71 cmd = KERN_PROC_CWD; 72 73 mib[0] = CTL_KERN; 74 mib[1] = KERN_PROC; 75 mib[2] = cmd; 76 mib[3] = getpid(); 77 78 /* Try querying the kernel for the output buffer size. */ 79 sz = 0; 80 ATF_REQUIRE(sysctl(mib, 4, NULL, &sz, NULL, 0) == 0); 81 ATF_REQUIRE(sz <= sizeof(kfile)); 82 83 sz = sizeof(kfile); 84 memset(&kfile, 0, sz); 85 ATF_REQUIRE(sysctl(mib, 4, &kfile, &sz, NULL, 0) == 0); 86 ATF_REQUIRE(sz <= sizeof(kfile)); 87 ATF_REQUIRE(sz == (u_int)kfile.kf_structsize); 88 89 /* Make sure that we get the same result from getcwd(2). */ 90 ATF_REQUIRE(getcwd(cwd, sizeof(cwd)) == cwd); 91 ATF_REQUIRE(strcmp(cwd, kfile.kf_path) == 0); 92 93 /* Spot-check some of the kinfo fields. */ 94 ATF_REQUIRE(kfile.kf_type == KF_TYPE_VNODE); 95 ATF_REQUIRE(kfile.kf_fd == KF_FD_TYPE_CWD); 96 ATF_REQUIRE(S_ISDIR(kfile.kf_un.kf_file.kf_file_mode)); 97 ATF_REQUIRE((kfile.kf_status & KF_ATTR_VALID) != 0); 98 99 /* 100 * Verify that a child process can get our CWD info, and that it 101 * matches the info we got above. 102 */ 103 child = fork(); 104 ATF_REQUIRE(child != -1); 105 if (child == 0) { 106 struct kinfo_file pkfile; 107 108 mib[0] = CTL_KERN; 109 mib[1] = KERN_PROC; 110 mib[2] = KERN_PROC_CWD; 111 mib[3] = getppid(); 112 113 sz = sizeof(pkfile); 114 memset(&pkfile, 0, sz); 115 if (sysctl(mib, 4, &pkfile, &sz, NULL, 0) != 0) 116 _exit(1); 117 if (memcmp(&kfile, &pkfile, sizeof(kfile)) != 0) 118 _exit(2); 119 _exit(0); 120 } 121 ATF_REQUIRE(waitpid(child, &status, 0) == child); 122 ATF_REQUIRE(WIFEXITED(status)); 123 ATF_REQUIRE(WEXITSTATUS(status) == 0); 124 125 /* 126 * Truncate the output buffer ever so slightly and make sure that we get 127 * an error. 128 */ 129 sz--; 130 ATF_REQUIRE_ERRNO(ENOMEM, sysctl(mib, 4, &kfile, &sz, NULL, 0) != 0); 131 132 sysctl_kern_proc_all(cmd); 133 } 134 135 /* 136 * Validate behaviour of the KERN_PROC_FILEDESC sysctl. 137 */ 138 ATF_TC_WITHOUT_HEAD(sysctl_kern_proc_filedesc); 139 ATF_TC_BODY(sysctl_kern_proc_filedesc, tc) 140 { 141 int cmd, fd, mib[4]; 142 struct kinfo_file *kfile; 143 char *buf, tmp[16]; 144 size_t sz, sz1; 145 146 cmd = KERN_PROC_FILEDESC; 147 148 mib[0] = CTL_KERN; 149 mib[1] = KERN_PROC; 150 mib[2] = cmd; 151 mib[3] = getpid(); 152 153 sz = 0; 154 ATF_REQUIRE(sysctl(mib, 4, NULL, &sz, NULL, 0) == 0); 155 ATF_REQUIRE(sz >= __offsetof(struct kinfo_file, kf_structsize) + 156 sizeof(kfile->kf_structsize)); 157 158 buf = malloc(sz); 159 ATF_REQUIRE(buf != NULL); 160 161 ATF_REQUIRE(sysctl(mib, 4, buf, &sz, NULL, 0) == 0); 162 163 /* Walk over the list of returned files. */ 164 for (sz1 = 0; sz1 < sz; sz1 += kfile->kf_structsize) { 165 kfile = (void *)(buf + sz1); 166 167 ATF_REQUIRE((unsigned int)kfile->kf_structsize <= sz); 168 ATF_REQUIRE((unsigned int)kfile->kf_structsize + sz1 <= sz); 169 170 ATF_REQUIRE((kfile->kf_status & KF_ATTR_VALID) != 0); 171 } 172 /* We shouldn't have any trailing bytes. */ 173 ATF_REQUIRE(sz1 == sz); 174 175 /* 176 * Open a file. This increases the size of the output buffer, so an 177 * attempt to re-fetch the records without increasing the buffer size 178 * should fail with ENOMEM. 179 */ 180 snprintf(tmp, sizeof(tmp), "tmp.XXXXXX"); 181 fd = mkstemp(tmp); 182 ATF_REQUIRE(fd >= 0); 183 ATF_REQUIRE_ERRNO(ENOMEM, sysctl(mib, 4, buf, &sz, NULL, 0) != 0); 184 185 ATF_REQUIRE(unlink(tmp) == 0); 186 ATF_REQUIRE(close(fd) == 0); 187 188 free(buf); 189 190 sysctl_kern_proc_all(cmd); 191 } 192 193 ATF_TP_ADD_TCS(tp) 194 { 195 ATF_TP_ADD_TC(tp, sysctl_kern_proc_cwd); 196 ATF_TP_ADD_TC(tp, sysctl_kern_proc_filedesc); 197 198 return (atf_no_error()); 199 } 200