1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * NAME
22  *	sysctl03.c
23  *
24  * DESCRIPTION
25  *	Testcase to check that sysctl(2) sets errno to EPERM correctly.
26  *
27  * ALGORITHM
28  *	a.	Call sysctl(2) as a root user, and attempt to write data
29  *		to the kernel_table[]. Since the table does not have write
30  *		permissions even for the root, it should fail EPERM.
31  *	b.	Call sysctl(2) as a non-root user, and attempt to write data
32  *		to the kernel_table[]. Since the table does not have write
33  *		permission for the regular user, it should fail with EPERM.
34  *
35  * NOTE: There is a documentation bug in 2.6.33-rc1 where unfortunately the
36  * behavior of sysctl(2) isn't properly documented, as discussed in detail in
37  * the following thread:
38  * http://sourceforge.net/mailarchive/message.php?msg_name=4B7BA24F.2010705%40linux.vnet.ibm.com.
39  *
40  * The documentation bug is filed as:
41  * https://bugzilla.kernel.org/show_bug.cgi?id=15446 . If you want the message
42  * removed, please ask your fellow kernel maintainer to fix his/her
43  * documentation.
44  *
45  * Thanks!
46  * -Garrett
47  *
48  * USAGE:  <for command-line>
49  *  sysctl03 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
50  *     where,  -c n : Run n copies concurrently.
51  *             -e   : Turn on errno logging.
52  *             -i n : Execute test n times.
53  *             -I x : Execute test for x seconds.
54  *             -P x : Pause for x seconds between iterations.
55  *             -t   : Turn on syscall timing.
56  *
57  * HISTORY
58  *	07/2001 Ported by Wayne Boyer
59  *	02/2010 Updated by shiwh@cn.fujitsu.com
60  *
61  * RESTRICTIONS
62  *	Test must be run as root.
63  */
64 #include "test.h"
65 #include <sys/types.h>
66 #include <sys/wait.h>
67 #include <stdio.h>
68 #include <errno.h>
69 #include <unistd.h>
70 #include <linux/unistd.h>
71 #include <linux/sysctl.h>
72 #include <pwd.h>
73 
74 char *TCID = "sysctl03";
75 
76 /* This is an older/deprecated syscall that newer arches are omitting */
77 #ifdef __NR_sysctl
78 
79 int TST_TOTAL = 2;
80 
sysctl(int * name,int nlen,void * oldval,size_t * oldlenp,void * newval,size_t newlen)81 int sysctl(int *name, int nlen, void *oldval, size_t * oldlenp,
82 	   void *newval, size_t newlen)
83 {
84 	struct __sysctl_args args =
85 	    { name, nlen, oldval, oldlenp, newval, newlen };
86 	return syscall(__NR__sysctl, &args);
87 }
88 
89 #define OSNAMESZ 100
90 
91 void setup(void);
92 void cleanup(void);
93 
main(int ac,char ** av)94 int main(int ac, char **av)
95 {
96 	int exp_eno;
97 	int lc;
98 
99 	char osname[OSNAMESZ];
100 	int osnamelth, status;
101 	int name[] = { CTL_KERN, KERN_OSTYPE };
102 	pid_t pid;
103 	struct passwd *ltpuser;
104 
105 	tst_parse_opts(ac, av, NULL, NULL);
106 
107 	setup();
108 
109 	if ((tst_kvercmp(2, 6, 32)) <= 0) {
110 		exp_eno = EPERM;
111 	} else {
112 		/* ^^ Look above this warning. ^^ */
113 		tst_resm(TINFO,
114 			 "this test's results are based on potentially undocumented behavior in the kernel. read the NOTE in the source file for more details");
115 		exp_eno = EACCES;
116 		exp_enos[0] = EACCES;
117 	}
118 
119 	for (lc = 0; TEST_LOOPING(lc); lc++) {
120 
121 		/* reset tst_count in case we are looping */
122 		tst_count = 0;
123 
124 		strcpy(osname, "Linux");
125 		osnamelth = sizeof(osname);
126 
127 		TEST(sysctl(name, ARRAY_SIZE(name), 0, 0, osname, osnamelth));
128 
129 		if (TEST_RETURN != -1) {
130 			tst_resm(TFAIL, "sysctl(2) succeeded unexpectedly");
131 		} else {
132 			if (TEST_ERRNO == exp_eno) {
133 				tst_resm(TPASS | TTERRNO, "Got expected error");
134 			} else if (errno == ENOSYS) {
135 				tst_resm(TCONF,
136 					 "You may need to make CONFIG_SYSCTL_SYSCALL=y"
137 					 " to your kernel config.");
138 			} else {
139 				tst_resm(TFAIL | TTERRNO,
140 					 "Got unexpected error");
141 			}
142 		}
143 
144 		osnamelth = sizeof(osname);
145 		if ((ltpuser = getpwnam("nobody")) == NULL) {
146 			tst_brkm(TBROK, cleanup, "getpwnam() failed");
147 		}
148 
149 		/* set process ID to "ltpuser1" */
150 		if (seteuid(ltpuser->pw_uid) == -1) {
151 			tst_brkm(TBROK, cleanup,
152 				 "seteuid() failed, errno %d", errno);
153 		}
154 
155 		if ((pid = FORK_OR_VFORK()) == -1) {
156 			tst_brkm(TBROK, cleanup, "fork() failed");
157 		}
158 
159 		if (pid == 0) {
160 			TEST(sysctl(name, ARRAY_SIZE(name), 0, 0, osname, osnamelth));
161 
162 			if (TEST_RETURN != -1) {
163 				tst_resm(TFAIL, "call succeeded unexpectedly");
164 			} else {
165 				if (TEST_ERRNO == exp_eno) {
166 					tst_resm(TPASS | TTERRNO,
167 						 "Got expected error");
168 				} else if (TEST_ERRNO == ENOSYS) {
169 					tst_resm(TCONF,
170 						 "You may need to make CONFIG_SYSCTL_SYSCALL=y"
171 						 " to your kernel config.");
172 				} else {
173 					tst_resm(TFAIL | TTERRNO,
174 						 "Got unexpected error");
175 				}
176 			}
177 
178 			cleanup();
179 
180 		} else {
181 			/* wait for the child to finish */
182 			wait(&status);
183 		}
184 
185 		/* set process ID back to root */
186 		if (seteuid(0) == -1) {
187 			tst_brkm(TBROK, cleanup, "seteuid() failed");
188 		}
189 	}
190 	cleanup();
191 	tst_exit();
192 }
193 
setup(void)194 void setup(void)
195 {
196 	tst_require_root();
197 
198 	tst_sig(FORK, DEF_HANDLER, cleanup);
199 
200 	TEST_PAUSE;
201 }
202 
cleanup(void)203 void cleanup(void)
204 {
205 }
206 
207 #else
208 int TST_TOTAL = 0;
209 
main(void)210 int main(void)
211 {
212 
213 	tst_brkm(TCONF, NULL,
214 		 "This test needs a kernel that has sysctl syscall.");
215 }
216 #endif
217