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
46static uid_t uid;
47
48static 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
67static 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
97static 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
115static void setup(void)
116{
117	struct passwd *ltpuser;
118
119	ltpuser = SAFE_GETPWNAM("nobody");
120	uid = ltpuser->pw_uid;
121}
122
123static 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