1 /*
2  * Copyright (c) International Business Machines  Corp., 2001
3  *  03/2001 Written by Wayne Boyer
4  *  11/2016 Modified by Guangwen Feng <fenggw-fnst@cn.fujitsu.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /*
21  * Verify that,
22  *  1) setpriority(2) fails with -1 and sets errno to EINVAL if 'which'
23  *     argument was not one of PRIO_PROCESS, PRIO_PGRP, or PRIO_USER.
24  *  2) setpriority(2) fails with -1 and sets errno to ESRCH if no
25  *     process was located for 'which' and 'who' arguments.
26  *  3) setpriority(2) fails with -1 and sets errno to EACCES if an
27  *     unprivileged user attempted to lower a process priority.
28  *  4) setpriority(2) fails with -1 and sets errno to EPERM if an
29  *     unprivileged user attempted to change a process which ID is
30  *     different from the test process.
31  */
32 
33 #include <errno.h>
34 #include <pwd.h>
35 #include <stdlib.h>
36 #include <sys/resource.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include "tst_test.h"
40 
41 #define NEW_PRIO	-2
42 #define INVAL_FLAG	-1
43 #define INVAL_ID	-1
44 #define INIT_PID	1
45 
46 static uid_t uid;
47 
48 static struct tcase {
49 	int which;
50 	int who;
51 	int prio;
52 	int exp_errno;
53 	int unprivil;
54 } tcases[] = {
55 	{INVAL_FLAG, 0, NEW_PRIO, EINVAL, 0},
56 
57 	{PRIO_PROCESS, INVAL_ID, NEW_PRIO, ESRCH, 0},
58 	{PRIO_PGRP, INVAL_ID, NEW_PRIO, ESRCH, 0},
59 	{PRIO_USER, INVAL_ID, NEW_PRIO, ESRCH, 0},
60 
61 	{PRIO_PROCESS, 0, NEW_PRIO, EACCES, 1},
62 	{PRIO_PGRP, 0, NEW_PRIO, EACCES, 1},
63 
64 	{PRIO_PROCESS, INIT_PID, NEW_PRIO, EPERM, 1}
65 };
66 
67 static void setpriority_test(struct tcase *tc)
68 {
69 	char *desc = "";
70 
71 	if (tc->unprivil)
72 		desc = "as unprivileged user ";
73 
74 	TEST(setpriority(tc->which, tc->who, tc->prio));
75 
76 	if (TEST_RETURN != -1) {
77 		tst_res(TFAIL,
78 			"setpriority(%d, %d, %d) %ssucceeds unexpectedly "
79 			"returned %ld", tc->which, tc->who, tc->prio, desc,
80 			TEST_RETURN);
81 		return;
82 	}
83 
84 	if (TEST_ERRNO != tc->exp_errno) {
85 		tst_res(TFAIL | TTERRNO,
86 			"setpriority(%d, %d, %d) %sshould fail with %s",
87 			tc->which, tc->who, tc->prio, desc,
88 			tst_strerrno(tc->exp_errno));
89 		return;
90 	}
91 
92 	tst_res(TPASS | TTERRNO,
93 		"setpriority(%d, %d, %d) %sfails as expected",
94 		tc->which, tc->who, tc->prio, desc);
95 }
96 
97 static void verify_setpriority(unsigned int n)
98 {
99 	struct tcase *tc = &tcases[n];
100 
101 	if (tc->unprivil) {
102 		if (!SAFE_FORK()) {
103 			SAFE_SETUID(uid);
104 			SAFE_SETPGID(0, 0);
105 			setpriority_test(tc);
106 			exit(0);
107 		}
108 
109 		tst_reap_children();
110 	} else {
111 		setpriority_test(tc);
112 	}
113 }
114 
115 static void setup(void)
116 {
117 	struct passwd *ltpuser;
118 
119 	ltpuser = SAFE_GETPWNAM("nobody");
120 	uid = ltpuser->pw_uid;
121 }
122 
123 static struct tst_test test = {
124 	.tcnt = ARRAY_SIZE(tcases),
125 	.needs_root = 1,
126 	.forks_child = 1,
127 	.setup = setup,
128 	.test = verify_setpriority,
129 };
130