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