1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Test the PR_CAP_AMBIENT of prctl(2). 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * Reads or changes the ambient capability set of the calling thread, 13f08c3bdfSopenharmony_ci * according to the value of arg2, which must be one of the following: 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * - PR_CAP_AMBIENT_RAISE: The capability specified in arg3 is added to the 16f08c3bdfSopenharmony_ci * ambient set. The specified capability must already be present in both pE 17f08c3bdfSopenharmony_ci * and pI. If we set SECBIT_NO_CAP_AMBIENT_RAISE bit, raise option will be 18f08c3bdfSopenharmony_ci * rejected and return EPERM. We also raise a CAP twice. 19f08c3bdfSopenharmony_ci * 20f08c3bdfSopenharmony_ci * - PR_CAP_AMBIENT_LOWER: The capability specified in arg3 is removed from the 21f08c3bdfSopenharmony_ci * ambient set. Even though this cap is not in set, it also should return 0. 22f08c3bdfSopenharmony_ci * 23f08c3bdfSopenharmony_ci * - PR_CAP_AMBIENT_IS_SET: Returns 1 if the capability in arg3 is in the 24f08c3bdfSopenharmony_ci * ambient set and 0 if it is not. 25f08c3bdfSopenharmony_ci * 26f08c3bdfSopenharmony_ci * - PR_CAP_AMBIENT_CLEAR_ALL: All capabilities will be removed from the 27f08c3bdfSopenharmony_ci * ambient set. This operation requires setting arg3 to zero. 28f08c3bdfSopenharmony_ci */ 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci#include <sys/prctl.h> 31f08c3bdfSopenharmony_ci#include <stdlib.h> 32f08c3bdfSopenharmony_ci#include "config.h" 33f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_CAPABILITY_H 34f08c3bdfSopenharmony_ci# include <sys/capability.h> 35f08c3bdfSopenharmony_ci#endif 36f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 37f08c3bdfSopenharmony_ci#include "lapi/prctl.h" 38f08c3bdfSopenharmony_ci#include "lapi/securebits.h" 39f08c3bdfSopenharmony_ci#include "tst_test.h" 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci#define PROC_STATUS "/proc/self/status" 42f08c3bdfSopenharmony_ci#define ZERO_STRING "0000000000000000" 43f08c3bdfSopenharmony_ci/*CAP_NET_BIND_SERVICE stored in the CapAmb field of PROC_STATUS*/ 44f08c3bdfSopenharmony_ci#define CAP_STRING "0000000000000400" 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic inline void check_cap_raise(unsigned int cap, char *message, int fail_flag) 47f08c3bdfSopenharmony_ci{ 48f08c3bdfSopenharmony_ci TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)); 49f08c3bdfSopenharmony_ci switch (fail_flag) { 50f08c3bdfSopenharmony_ci case 0: 51f08c3bdfSopenharmony_ci if (TST_RET == 0) 52f08c3bdfSopenharmony_ci tst_res(TPASS, "PR_CAP_AMBIENT_RAISE %s succeeded", message); 53f08c3bdfSopenharmony_ci else 54f08c3bdfSopenharmony_ci tst_res(TFAIL, "PR_CAP_AMBIENT_RAISE %s failed unexpectedly", 55f08c3bdfSopenharmony_ci message); 56f08c3bdfSopenharmony_ci break; 57f08c3bdfSopenharmony_ci case 1: 58f08c3bdfSopenharmony_ci if (TST_RET == 0) 59f08c3bdfSopenharmony_ci tst_res(TFAIL, 60f08c3bdfSopenharmony_ci "PR_CAP_AMBIENT_RAISE succeeded unexpectedly %s", 61f08c3bdfSopenharmony_ci message); 62f08c3bdfSopenharmony_ci else if (TST_ERR == EPERM) 63f08c3bdfSopenharmony_ci tst_res(TPASS, 64f08c3bdfSopenharmony_ci "PR_CAP_AMBIENT_RAISE failed with EPERM %s", message); 65f08c3bdfSopenharmony_ci else 66f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, 67f08c3bdfSopenharmony_ci "PR_CAP_AMBIENT_RAISE failed %s", message); 68f08c3bdfSopenharmony_ci break; 69f08c3bdfSopenharmony_ci } 70f08c3bdfSopenharmony_ci} 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_cistatic inline void check_cap_is_set(unsigned int cap, char *message, int val) 73f08c3bdfSopenharmony_ci{ 74f08c3bdfSopenharmony_ci TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, cap, 0, 0)); 75f08c3bdfSopenharmony_ci if (TST_RET == 1) 76f08c3bdfSopenharmony_ci tst_res(val ? TPASS : TFAIL, 77f08c3bdfSopenharmony_ci "PR_CAP_AMBIENT_IS_SET %s in AmbientCap", message); 78f08c3bdfSopenharmony_ci else if (TST_RET == 0) 79f08c3bdfSopenharmony_ci tst_res(val ? TFAIL : TPASS, 80f08c3bdfSopenharmony_ci "PR_CAP_AMBIENT_IS_SET %s not in AmbientCap", message); 81f08c3bdfSopenharmony_ci else 82f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "PR_CAP_AMBIENT_IS_SET failed"); 83f08c3bdfSopenharmony_ci} 84f08c3bdfSopenharmony_ci 85f08c3bdfSopenharmony_cistatic inline void check_cap_lower(unsigned int cap, char *message) 86f08c3bdfSopenharmony_ci{ 87f08c3bdfSopenharmony_ci TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0)); 88f08c3bdfSopenharmony_ci if (TST_RET == -1) 89f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, 90f08c3bdfSopenharmony_ci "PR_CAP_AMBIENT_LOWER %s failed", message); 91f08c3bdfSopenharmony_ci else 92f08c3bdfSopenharmony_ci tst_res(TPASS, "PR_CAP_AMBIENT_LOWER %s succeeded", message); 93f08c3bdfSopenharmony_ci} 94f08c3bdfSopenharmony_ci 95f08c3bdfSopenharmony_cistatic void verify_prctl(void) 96f08c3bdfSopenharmony_ci{ 97f08c3bdfSopenharmony_ci#ifdef HAVE_LIBCAP 98f08c3bdfSopenharmony_ci cap_t caps = cap_init(); 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci cap_value_t caplist[3] = {CAP_NET_RAW, CAP_NET_BIND_SERVICE, CAP_SETPCAP}; 101f08c3bdfSopenharmony_ci unsigned int numcaps = 3; 102f08c3bdfSopenharmony_ci 103f08c3bdfSopenharmony_ci cap_set_flag(caps, CAP_EFFECTIVE, numcaps, caplist, CAP_SET); 104f08c3bdfSopenharmony_ci cap_set_flag(caps, CAP_INHERITABLE, numcaps, caplist, CAP_SET); 105f08c3bdfSopenharmony_ci cap_set_flag(caps, CAP_PERMITTED, numcaps, caplist, CAP_SET); 106f08c3bdfSopenharmony_ci cap_set_proc(caps); 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci tst_res(TINFO, "At the beginning"); 109f08c3bdfSopenharmony_ci TST_ASSERT_FILE_STR(PROC_STATUS, "CapAmb", ZERO_STRING); 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_ci cap_clear_flag(caps, CAP_INHERITABLE); 112f08c3bdfSopenharmony_ci cap_set_proc(caps); 113f08c3bdfSopenharmony_ci check_cap_raise(CAP_NET_BIND_SERVICE, "on non-inheritable cap", 1); 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci cap_set_flag(caps, CAP_INHERITABLE, numcaps, caplist, CAP_SET); 116f08c3bdfSopenharmony_ci cap_clear_flag(caps, CAP_PERMITTED); 117f08c3bdfSopenharmony_ci cap_set_proc(caps); 118f08c3bdfSopenharmony_ci check_cap_raise(CAP_NET_RAW, "on non-permitted cap", 1); 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_ci cap_set_flag(caps, CAP_PERMITTED, numcaps, caplist, CAP_SET); 121f08c3bdfSopenharmony_ci cap_set_proc(caps); 122f08c3bdfSopenharmony_ci prctl(PR_SET_SECUREBITS, SECBIT_NO_CAP_AMBIENT_RAISE); 123f08c3bdfSopenharmony_ci check_cap_raise(CAP_NET_BIND_SERVICE, "because of NO_RAISE_SECBIT set", 1); 124f08c3bdfSopenharmony_ci prctl(PR_SET_SECUREBITS, 0); 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci check_cap_raise(CAP_NET_BIND_SERVICE, "CAP_NET_BIND_SERVICE", 0); 127f08c3bdfSopenharmony_ci /*Even this cap has been in ambient set, raise succeeds and return 0*/ 128f08c3bdfSopenharmony_ci check_cap_raise(CAP_NET_BIND_SERVICE, "CAP_NET_BIND_SERIVCE twice", 0); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci tst_res(TINFO, "After PR_CAP_AMBIENT_RAISE"); 131f08c3bdfSopenharmony_ci TST_ASSERT_FILE_STR(PROC_STATUS, "CapAmb", CAP_STRING); 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci check_cap_is_set(CAP_NET_BIND_SERVICE, "CAP_NET_BIND_SERVICE was", 1); 134f08c3bdfSopenharmony_ci check_cap_is_set(CAP_NET_RAW, "CAP_NET_RAW was", 0); 135f08c3bdfSopenharmony_ci /*move a cap what was not in ambient set, it also return 0*/ 136f08c3bdfSopenharmony_ci check_cap_lower(CAP_NET_RAW, "CAP_NET_RAW(it wasn't in ambient set)"); 137f08c3bdfSopenharmony_ci check_cap_lower(CAP_NET_BIND_SERVICE, "CAP_NET_BIND_SERVICE(it was in ambient set)"); 138f08c3bdfSopenharmony_ci 139f08c3bdfSopenharmony_ci tst_res(TINFO, "After PR_CAP_AMBIENT_LORWER"); 140f08c3bdfSopenharmony_ci TST_ASSERT_FILE_STR(PROC_STATUS, "CapAmb", ZERO_STRING); 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_ci prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0); 143f08c3bdfSopenharmony_ci tst_res(TINFO, "raise cap for clear"); 144f08c3bdfSopenharmony_ci TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0)); 145f08c3bdfSopenharmony_ci if (TST_RET == 0) 146f08c3bdfSopenharmony_ci tst_res(TPASS, "PR_CAP_AMBIENT_CLEAR ALL succeeded"); 147f08c3bdfSopenharmony_ci else 148f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "PR_AMBIENT_CLEAR_ALL failed"); 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci tst_res(TINFO, "After PR_CAP_AMBIENT_CLEAR_ALL"); 151f08c3bdfSopenharmony_ci TST_ASSERT_FILE_STR(PROC_STATUS, "CapAmb", ZERO_STRING); 152f08c3bdfSopenharmony_ci 153f08c3bdfSopenharmony_ci cap_free(caps); 154f08c3bdfSopenharmony_ci#else 155f08c3bdfSopenharmony_ci tst_res(TCONF, "libcap devel files missing during compilation"); 156f08c3bdfSopenharmony_ci#endif 157f08c3bdfSopenharmony_ci} 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_cistatic void setup(void) 160f08c3bdfSopenharmony_ci{ 161f08c3bdfSopenharmony_ci TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0)); 162f08c3bdfSopenharmony_ci if (TST_RET == 0) { 163f08c3bdfSopenharmony_ci tst_res(TINFO, "kernel supports PR_CAP_AMBIENT"); 164f08c3bdfSopenharmony_ci return; 165f08c3bdfSopenharmony_ci } 166f08c3bdfSopenharmony_ci 167f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL) 168f08c3bdfSopenharmony_ci tst_brk(TCONF, "kernel doesn't support PR_CAP_AMBIENT"); 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci tst_brk(TBROK | TERRNO, 171f08c3bdfSopenharmony_ci "current environment doesn't permit PR_CAP_AMBIENT"); 172f08c3bdfSopenharmony_ci} 173f08c3bdfSopenharmony_ci 174f08c3bdfSopenharmony_cistatic struct tst_test test = { 175f08c3bdfSopenharmony_ci .setup = setup, 176f08c3bdfSopenharmony_ci .test_all = verify_prctl, 177f08c3bdfSopenharmony_ci .needs_root = 1, 178f08c3bdfSopenharmony_ci}; 179