Home | History | Annotate | Download | only in setregid
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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