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 "tst_uid.h" 16#include "compat_tst_16.h" 17 18static int fail = -1; 19static int pass; 20static gid_t primary_gid, secondary_gid, neg_one = -1; 21 22struct tcase { 23 gid_t *real_gid; 24 gid_t *eff_gid; 25 int *exp_ret; 26 gid_t *exp_real_usr; 27 gid_t *exp_eff_usr; 28 char *test_msg; 29} tcases[] = { 30 { 31 &primary_gid, &secondary_gid, &pass, &primary_gid, &secondary_gid, 32 "After setregid(primary, secondary),"}, { 33 &neg_one, &primary_gid, &pass, &primary_gid, &primary_gid, 34 "After setregid(-1, primary)"}, { 35 &neg_one, &secondary_gid, &pass, &primary_gid, &secondary_gid, 36 "After setregid(-1, secondary),"}, { 37 &secondary_gid, &neg_one, &pass, &secondary_gid, &secondary_gid, 38 "After setregid(secondary, -1),"}, { 39 &neg_one, &neg_one, &pass, &secondary_gid, &secondary_gid, 40 "After setregid(-1, -1),"}, { 41 &neg_one, &secondary_gid, &pass, &secondary_gid, &secondary_gid, 42 "After setregid(-1, secondary),"}, { 43 &secondary_gid, &neg_one, &pass, &secondary_gid, &secondary_gid, 44 "After setregid(secondary, -1),"}, { 45 &secondary_gid, &secondary_gid, &pass, &secondary_gid, &secondary_gid, 46 "After setregid(secondary, secondary),"}, { 47 &primary_gid, &neg_one, &fail, &secondary_gid, &secondary_gid, 48 "After setregid(primary, -1)"}, { 49 &neg_one, &primary_gid, &fail, &secondary_gid, &secondary_gid, 50 "After setregid(-1, primary)"}, { 51 &primary_gid, &primary_gid, &fail, &secondary_gid, &secondary_gid, 52 "After setregid(primary, primary)"},}; 53 54static void setup(void) 55{ 56 struct passwd *nobody; 57 gid_t test_groups[2]; 58 59 nobody = SAFE_GETPWNAM("nobody"); 60 61 tst_get_gids(test_groups, 0, 2); 62 primary_gid = test_groups[0]; 63 secondary_gid = test_groups[1]; 64 GID16_CHECK(primary_gid, setregid); 65 GID16_CHECK(secondary_gid, setregid); 66 67 /* set the appropriate ownership values */ 68 SAFE_SETREGID(primary_gid, secondary_gid); 69 SAFE_SETEUID(nobody->pw_uid); 70} 71 72static void test_success(struct tcase *tc) 73{ 74 if (TST_RET != 0) 75 tst_res(TFAIL | TTERRNO, "setregid(%d, %d) failed unexpectedly", 76 *tc->real_gid, *tc->eff_gid); 77 else 78 tst_res(TPASS, "setregid(%d, %d) succeeded as expected", 79 *tc->real_gid, *tc->eff_gid); 80} 81 82static void test_failure(struct tcase *tc) 83{ 84 if (TST_RET == 0) 85 tst_res(TFAIL, "setregid(%d, %d) succeeded unexpectedly", 86 *tc->real_gid, *tc->eff_gid); 87 else if (TST_ERR == EPERM) 88 tst_res(TPASS, "setregid(%d, %d) failed as expected", 89 *tc->real_gid, *tc->eff_gid); 90 else 91 tst_res(TFAIL | TTERRNO, 92 "setregid(%d, %d) did not set errno value as expected", 93 *tc->real_gid, *tc->eff_gid); 94} 95 96static void gid_verify(gid_t rg, gid_t eg, char *when) 97{ 98 if ((getgid() != rg) || (getegid() != eg)) { 99 tst_res(TFAIL, "ERROR: %s real gid = %d; effective gid = %d", 100 when, getgid(), getegid()); 101 tst_res(TINFO, "Expected: real gid = %d; effective gid = %d", 102 rg, eg); 103 } else { 104 tst_res(TPASS, 105 "real or effective gid was modified as expected"); 106 } 107} 108 109static void run(unsigned int i) 110{ 111 struct tcase *tc = &tcases[i]; 112 113 /* Set the real or effective group id */ 114 TEST(SETREGID(*tc->real_gid, *tc->eff_gid)); 115 116 if (*tc->exp_ret == 0) 117 test_success(tc); 118 else 119 test_failure(tc); 120 121 gid_verify(*tc->exp_real_usr, *tc->exp_eff_usr, tc->test_msg); 122} 123 124void run_all(void) 125{ 126 unsigned int i; 127 128 if (!SAFE_FORK()) { 129 for (i = 0; i < ARRAY_SIZE(tcases); i++) 130 run(i); 131 } 132} 133 134static struct tst_test test = { 135 .needs_root = 1, 136 .forks_child = 1, 137 .test_all = run_all, 138 .setup = setup, 139}; 140