1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * Ported by John George
6 */
7
8 /*
9 * Test setregid() when executed by a non-root user.
10 */
11
12 #include <pwd.h>
13
14 #include "tst_test.h"
15 #include "compat_tst_16.h"
16
17 static int fail = -1;
18 static int pass;
19 static gid_t neg_one = -1;
20
21 struct group nobody_gr, daemon_gr, root_gr, bin_gr;
22 struct passwd nobody;
23
24 struct tcase {
25 gid_t *real_gid;
26 gid_t *eff_gid;
27 int *exp_ret;
28 struct group *exp_real_usr;
29 struct group *exp_eff_usr;
30 char *test_msg;
31 } tcases[] = {
32 {
33 &daemon_gr.gr_gid, &bin_gr.gr_gid, &pass, &daemon_gr, &bin_gr,
34 "After setregid(daemon, bin),"}, {
35 &neg_one, &daemon_gr.gr_gid, &pass, &daemon_gr, &daemon_gr,
36 "After setregid(-1, daemon)"}, {
37 &neg_one, &bin_gr.gr_gid, &pass, &daemon_gr, &bin_gr,
38 "After setregid(-1, bin),"}, {
39 &bin_gr.gr_gid, &neg_one, &pass, &bin_gr, &bin_gr,
40 "After setregid(bin, -1),"}, {
41 &neg_one, &neg_one, &pass, &bin_gr, &bin_gr,
42 "After setregid(-1, -1),"}, {
43 &neg_one, &bin_gr.gr_gid, &pass, &bin_gr, &bin_gr,
44 "After setregid(-1, bin),"}, {
45 &bin_gr.gr_gid, &neg_one, &pass, &bin_gr, &bin_gr,
46 "After setregid(bin, -1),"}, {
47 &bin_gr.gr_gid, &bin_gr.gr_gid, &pass, &bin_gr, &bin_gr,
48 "After setregid(bin, bin),"}, {
49 &daemon_gr.gr_gid, &neg_one, &fail, &bin_gr, &bin_gr,
50 "After setregid(daemon, -1)"}, {
51 &neg_one, &daemon_gr.gr_gid, &fail, &bin_gr, &bin_gr,
52 "After setregid(-1, daemon)"}, {
53 &daemon_gr.gr_gid, &daemon_gr.gr_gid, &fail, &bin_gr, &bin_gr,
54 "After setregid(daemon, daemon)"},};
55
56
get_group_fallback(const char * gr1,const char * gr2)57 static struct group get_group_fallback(const char *gr1, const char *gr2)
58 {
59 struct group *junk;
60
61 junk = SAFE_GETGRNAM_FALLBACK(gr1, gr2);
62 GID16_CHECK(junk->gr_gid, setregid);
63 return *junk;
64 }
65
get_group(const char * group)66 static struct group get_group(const char *group)
67 {
68 struct group *junk;
69
70 junk = SAFE_GETGRNAM(group);
71 GID16_CHECK(junk->gr_gid, setregid);
72 return *junk;
73 }
74
setup(void)75 static void setup(void)
76 {
77 nobody = *SAFE_GETPWNAM("nobody");
78
79 nobody_gr = get_group_fallback("nobody", "nogroup");
80 daemon_gr = get_group("daemon");
81 bin_gr = get_group("bin");
82
83 /* set the appropriate ownership values */
84 SAFE_SETREGID(daemon_gr.gr_gid, bin_gr.gr_gid);
85 SAFE_SETEUID(nobody.pw_uid);
86 }
87
test_success(struct tcase * tc)88 static void test_success(struct tcase *tc)
89 {
90 if (TST_RET != 0)
91 tst_res(TFAIL | TTERRNO, "setregid(%d, %d) failed unexpectedly",
92 *tc->real_gid, *tc->eff_gid);
93 else
94 tst_res(TPASS, "setregid(%d, %d) succeeded as expected",
95 *tc->real_gid, *tc->eff_gid);
96 }
97
test_failure(struct tcase * tc)98 static void test_failure(struct tcase *tc)
99 {
100 if (TST_RET == 0)
101 tst_res(TFAIL, "setregid(%d, %d) succeeded unexpectedly",
102 *tc->real_gid, *tc->eff_gid);
103 else if (TST_ERR == EPERM)
104 tst_res(TPASS, "setregid(%d, %d) failed as expected",
105 *tc->real_gid, *tc->eff_gid);
106 else
107 tst_res(TFAIL | TTERRNO,
108 "setregid(%d, %d) did not set errno value as expected",
109 *tc->real_gid, *tc->eff_gid);
110 }
111
gid_verify(struct group * rg,struct group * eg,char * when)112 static void gid_verify(struct group *rg, struct group *eg, char *when)
113 {
114 if ((getgid() != rg->gr_gid) || (getegid() != eg->gr_gid)) {
115 tst_res(TFAIL, "ERROR: %s real gid = %d; effective gid = %d",
116 when, getgid(), getegid());
117 tst_res(TINFO, "Expected: real gid = %d; effective gid = %d",
118 rg->gr_gid, eg->gr_gid);
119 } else {
120 tst_res(TPASS,
121 "real or effective gid was modified as expected");
122 }
123 }
124
run(unsigned int i)125 static void run(unsigned int i)
126 {
127 struct tcase *tc = &tcases[i];
128
129 /* Set the real or effective group id */
130 TEST(SETREGID(*tc->real_gid, *tc->eff_gid));
131
132 if (*tc->exp_ret == 0)
133 test_success(tc);
134 else
135 test_failure(tc);
136
137 gid_verify(tc->exp_real_usr, tc->exp_eff_usr, tc->test_msg);
138 }
139
run_all(void)140 void run_all(void)
141 {
142 unsigned int i;
143
144 if (!SAFE_FORK()) {
145 for (i = 0; i < ARRAY_SIZE(tcases); i++)
146 run(i);
147 }
148 }
149
150 static struct tst_test test = {
151 .needs_root = 1,
152 .forks_child = 1,
153 .test_all = run_all,
154 .setup = setup,
155 };
156