1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@cn.fujitsu.com> 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Test unprivileged user can support the number of keys and the 7f08c3bdfSopenharmony_ci * number of bytes consumed in payloads of the keys. The default 8f08c3bdfSopenharmony_ci * value is 200 and 20000. 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This is also a regression test for 11f08c3bdfSopenharmony_ci * commit a08bf91ce28e ("KEYS: allow reaching the keys quotas exactly") 12f08c3bdfSopenharmony_ci * commit 2e356101e72a ("KEYS: reaching the keys quotas correctly") 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * If you run this test with -i > 5 then expect to see some sporadic failures 15f08c3bdfSopenharmony_ci * where add_key fails with EDQUOT. Keys are freed asynchronously and we only 16f08c3bdfSopenharmony_ci * create up to 10 users to avoid race conditions. 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#include <stdio.h> 20f08c3bdfSopenharmony_ci#include <stdlib.h> 21f08c3bdfSopenharmony_ci#include <pwd.h> 22f08c3bdfSopenharmony_ci#include "tst_test.h" 23f08c3bdfSopenharmony_ci#include "lapi/keyctl.h" 24f08c3bdfSopenharmony_ci 25f08c3bdfSopenharmony_ci#define MAX_USERS 10 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_cistatic char *user_buf; 28f08c3bdfSopenharmony_cistatic uid_t ltpuser[MAX_USERS]; 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_cistatic unsigned int usern; 31f08c3bdfSopenharmony_cistatic unsigned int useri; 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_cistatic void add_user(char n) 34f08c3bdfSopenharmony_ci{ 35f08c3bdfSopenharmony_ci char username[] = "ltp_add_key05_n"; 36f08c3bdfSopenharmony_ci const char *const cmd_useradd[] = {"useradd", username, NULL}; 37f08c3bdfSopenharmony_ci const char *const cmd_userdel[] = {"userdel", "-r", username, NULL}; 38f08c3bdfSopenharmony_ci const char *const cmd_groupdel[] = {"groupdel", username, NULL}; 39f08c3bdfSopenharmony_ci struct passwd *pw; 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci username[sizeof(username) - 2] = '0' + n; 42f08c3bdfSopenharmony_ci 43f08c3bdfSopenharmony_ci tst_cmd(cmd_userdel, NULL, "/dev/null", TST_CMD_PASS_RETVAL); 44f08c3bdfSopenharmony_ci tst_cmd(cmd_groupdel, NULL, "/dev/null", TST_CMD_PASS_RETVAL); 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci SAFE_CMD(cmd_useradd, NULL, NULL); 47f08c3bdfSopenharmony_ci pw = SAFE_GETPWNAM(username); 48f08c3bdfSopenharmony_ci ltpuser[(unsigned int)n] = pw->pw_uid; 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_ci tst_res(TINFO, "Created user %s", pw->pw_name); 51f08c3bdfSopenharmony_ci} 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic void clean_user(char n) 54f08c3bdfSopenharmony_ci{ 55f08c3bdfSopenharmony_ci char username[] = "ltp_add_key05_n"; 56f08c3bdfSopenharmony_ci const char *const cmd_userdel[] = {"userdel", "-r", username, NULL}; 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci username[sizeof(username) - 2] = '0' + n; 59f08c3bdfSopenharmony_ci 60f08c3bdfSopenharmony_ci if (tst_cmd(cmd_userdel, NULL, NULL, TST_CMD_PASS_RETVAL)) 61f08c3bdfSopenharmony_ci tst_res(TWARN | TERRNO, "'userdel -r %s' failed", username); 62f08c3bdfSopenharmony_ci} 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_cistatic inline void parse_proc_key_users(int *used_key, int *max_key, int *used_bytes, int *max_bytes) 65f08c3bdfSopenharmony_ci{ 66f08c3bdfSopenharmony_ci unsigned int val[4]; 67f08c3bdfSopenharmony_ci char fmt[1024]; 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_ci sprintf(fmt, "%5u: %%*5d %%*d/%%*d %%d/%%d %%d/%%d", ltpuser[useri]); 70f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF("/proc/key-users", fmt, &val[0], &val[1], &val[2], &val[3]); 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci if (used_key) 73f08c3bdfSopenharmony_ci *used_key = val[0]; 74f08c3bdfSopenharmony_ci if (max_key) 75f08c3bdfSopenharmony_ci *max_key = val[1]; 76f08c3bdfSopenharmony_ci if (used_bytes) 77f08c3bdfSopenharmony_ci *used_bytes = val[2]; 78f08c3bdfSopenharmony_ci if (max_bytes) 79f08c3bdfSopenharmony_ci *max_bytes = val[3]; 80f08c3bdfSopenharmony_ci} 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_cistatic void verify_max_bytes(void) 83f08c3bdfSopenharmony_ci{ 84f08c3bdfSopenharmony_ci char *buf; 85f08c3bdfSopenharmony_ci int plen, invalid_plen, delta; 86f08c3bdfSopenharmony_ci int used_bytes, max_bytes, tmp_used_bytes; 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci tst_res(TINFO, "test max bytes under unprivileged user"); 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ci parse_proc_key_users(NULL, NULL, &tmp_used_bytes, NULL); 91f08c3bdfSopenharmony_ci TEST(add_key("user", "test2", user_buf, 64, KEY_SPEC_THREAD_KEYRING)); 92f08c3bdfSopenharmony_ci if (TST_RET == -1) { 93f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add key test2 failed"); 94f08c3bdfSopenharmony_ci return; 95f08c3bdfSopenharmony_ci } 96f08c3bdfSopenharmony_ci parse_proc_key_users(NULL, NULL, &used_bytes, &max_bytes); 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_ci /* 99f08c3bdfSopenharmony_ci * Compute delta between default datalen(in key_alloc) and actual 100f08c3bdfSopenharmony_ci * datlen(in key_payload_reserve). 101f08c3bdfSopenharmony_ci * more info see kernel code: security/keys/key.c 102f08c3bdfSopenharmony_ci */ 103f08c3bdfSopenharmony_ci delta = used_bytes - tmp_used_bytes - strlen("test2") - 1 - 64; 104f08c3bdfSopenharmony_ci invalid_plen = max_bytes - used_bytes - delta - strlen("test_xxx"); 105f08c3bdfSopenharmony_ci buf = tst_alloc(invalid_plen); 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_ci TEST(add_key("user", "test_inv", buf, invalid_plen, KEY_SPEC_THREAD_KEYRING)); 108f08c3bdfSopenharmony_ci if (TST_RET != -1) { 109f08c3bdfSopenharmony_ci tst_res(TFAIL, "add_key(test_inv) succeeded unexpectedltly"); 110f08c3bdfSopenharmony_ci return; 111f08c3bdfSopenharmony_ci } 112f08c3bdfSopenharmony_ci if (TST_ERR == EDQUOT) 113f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "add_key(test_inv) failed as expected"); 114f08c3bdfSopenharmony_ci else 115f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add_key(test_inv) failed expected EDQUOT got"); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci /*Reset delta*/ 118f08c3bdfSopenharmony_ci TEST(add_key("user", "test3", user_buf, 64, KEY_SPEC_THREAD_KEYRING)); 119f08c3bdfSopenharmony_ci if (TST_RET == -1) { 120f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add key test3 failed"); 121f08c3bdfSopenharmony_ci return; 122f08c3bdfSopenharmony_ci } 123f08c3bdfSopenharmony_ci TEST(add_key("user", "test4", user_buf, 64, KEY_SPEC_THREAD_KEYRING)); 124f08c3bdfSopenharmony_ci if (TST_RET == -1) { 125f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add key test4 failed"); 126f08c3bdfSopenharmony_ci return; 127f08c3bdfSopenharmony_ci } 128f08c3bdfSopenharmony_ci parse_proc_key_users(NULL, NULL, &used_bytes, &max_bytes); 129f08c3bdfSopenharmony_ci plen = max_bytes - used_bytes - delta - strlen("test_xxx") - 1; 130f08c3bdfSopenharmony_ci TEST(add_key("user", "test_max", buf, plen, KEY_SPEC_THREAD_KEYRING)); 131f08c3bdfSopenharmony_ci if (TST_RET == -1) { 132f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add_key(test_max) failed unexpectedly"); 133f08c3bdfSopenharmony_ci return; 134f08c3bdfSopenharmony_ci } 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci tst_res(TPASS, "add_key(test_max) succeeded as expected"); 137f08c3bdfSopenharmony_ci parse_proc_key_users(NULL, NULL, &tmp_used_bytes, &max_bytes); 138f08c3bdfSopenharmony_ci if (tmp_used_bytes == max_bytes) 139f08c3bdfSopenharmony_ci tst_res(TPASS, "allow reaching the max bytes exactly"); 140f08c3bdfSopenharmony_ci else 141f08c3bdfSopenharmony_ci tst_res(TFAIL, "max used bytes %u, key allow max bytes %u", tmp_used_bytes, max_bytes); 142f08c3bdfSopenharmony_ci} 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_cistatic void verify_max_keys(void) 145f08c3bdfSopenharmony_ci{ 146f08c3bdfSopenharmony_ci int i, used_key, max_key; 147f08c3bdfSopenharmony_ci char desc[10]; 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_ci tst_res(TINFO, "test max keys under unprivileged user"); 150f08c3bdfSopenharmony_ci parse_proc_key_users(&used_key, &max_key, NULL, NULL); 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_ci for (i = used_key + 1; i <= max_key; i++) { 153f08c3bdfSopenharmony_ci sprintf(desc, "abc%d", i); 154f08c3bdfSopenharmony_ci TEST(add_key("user", desc, user_buf, 64, KEY_SPEC_THREAD_KEYRING)); 155f08c3bdfSopenharmony_ci if (TST_RET == -1) { 156f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add keyring key(%s) failed", desc); 157f08c3bdfSopenharmony_ci goto count; 158f08c3bdfSopenharmony_ci } 159f08c3bdfSopenharmony_ci } 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci TEST(add_key("user", "test_invalid_key", user_buf, 64, KEY_SPEC_THREAD_KEYRING)); 162f08c3bdfSopenharmony_ci if (TST_RET != -1) { 163f08c3bdfSopenharmony_ci tst_res(TFAIL, "add keyring key(test_invalid_key) succeeded unexpectedly"); 164f08c3bdfSopenharmony_ci goto count; 165f08c3bdfSopenharmony_ci } 166f08c3bdfSopenharmony_ci if (TST_ERR == EDQUOT) 167f08c3bdfSopenharmony_ci tst_res(TPASS | TTERRNO, "add_key(test_invalid_key) failed as expected"); 168f08c3bdfSopenharmony_ci else 169f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add_key(test_invalid_key) failed expected EDQUOT got"); 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_cicount: 172f08c3bdfSopenharmony_ci parse_proc_key_users(&used_key, &max_key, NULL, NULL); 173f08c3bdfSopenharmony_ci if (used_key == max_key) 174f08c3bdfSopenharmony_ci tst_res(TPASS, "allow reaching the max key(%u) exactly", max_key); 175f08c3bdfSopenharmony_ci else 176f08c3bdfSopenharmony_ci tst_res(TFAIL, "max used key %u, key allow max key %u", used_key, max_key); 177f08c3bdfSopenharmony_ci} 178f08c3bdfSopenharmony_ci 179f08c3bdfSopenharmony_cistatic void do_test(unsigned int n) 180f08c3bdfSopenharmony_ci{ 181f08c3bdfSopenharmony_ci if (usern < MAX_USERS) 182f08c3bdfSopenharmony_ci add_user(usern++); 183f08c3bdfSopenharmony_ci 184f08c3bdfSopenharmony_ci if (useri >= MAX_USERS) { 185f08c3bdfSopenharmony_ci sleep(1); 186f08c3bdfSopenharmony_ci useri = 0; 187f08c3bdfSopenharmony_ci } 188f08c3bdfSopenharmony_ci 189f08c3bdfSopenharmony_ci if (!SAFE_FORK()) { 190f08c3bdfSopenharmony_ci SAFE_SETUID(ltpuser[useri]); 191f08c3bdfSopenharmony_ci tst_res(TINFO, "User: %d, UID: %d", useri, ltpuser[useri]); 192f08c3bdfSopenharmony_ci TEST(add_key("user", "test1", user_buf, 64, KEY_SPEC_THREAD_KEYRING)); 193f08c3bdfSopenharmony_ci if (TST_RET == -1) { 194f08c3bdfSopenharmony_ci tst_res(TFAIL | TTERRNO, "add key test1 failed"); 195f08c3bdfSopenharmony_ci return; 196f08c3bdfSopenharmony_ci } 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_ci if (n) 199f08c3bdfSopenharmony_ci verify_max_keys(); 200f08c3bdfSopenharmony_ci else 201f08c3bdfSopenharmony_ci verify_max_bytes(); 202f08c3bdfSopenharmony_ci } 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci tst_reap_children(); 205f08c3bdfSopenharmony_ci useri++; 206f08c3bdfSopenharmony_ci 207f08c3bdfSopenharmony_ci return; 208f08c3bdfSopenharmony_ci} 209f08c3bdfSopenharmony_ci 210f08c3bdfSopenharmony_cistatic void cleanup(void) 211f08c3bdfSopenharmony_ci{ 212f08c3bdfSopenharmony_ci while (usern--) 213f08c3bdfSopenharmony_ci clean_user(usern); 214f08c3bdfSopenharmony_ci} 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_cistatic struct tst_test test = { 217f08c3bdfSopenharmony_ci .test = do_test, 218f08c3bdfSopenharmony_ci .tcnt = 2, 219f08c3bdfSopenharmony_ci .needs_root = 1, 220f08c3bdfSopenharmony_ci .forks_child = 1, 221f08c3bdfSopenharmony_ci .cleanup = cleanup, 222f08c3bdfSopenharmony_ci .save_restore = (const struct tst_path_val[]) { 223f08c3bdfSopenharmony_ci {"/proc/sys/kernel/keys/gc_delay", "1", 224f08c3bdfSopenharmony_ci TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, 225f08c3bdfSopenharmony_ci {"/proc/sys/kernel/keys/maxkeys", "200", 226f08c3bdfSopenharmony_ci TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, 227f08c3bdfSopenharmony_ci {"/proc/sys/kernel/keys/maxbytes", "20000", 228f08c3bdfSopenharmony_ci TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, 229f08c3bdfSopenharmony_ci {} 230f08c3bdfSopenharmony_ci }, 231f08c3bdfSopenharmony_ci .bufs = (struct tst_buffers []) { 232f08c3bdfSopenharmony_ci {&user_buf, .size = 64}, 233f08c3bdfSopenharmony_ci {} 234f08c3bdfSopenharmony_ci }, 235f08c3bdfSopenharmony_ci .needs_cmds = (const char *const []) { 236f08c3bdfSopenharmony_ci "useradd", 237f08c3bdfSopenharmony_ci "userdel", 238f08c3bdfSopenharmony_ci "groupdel", 239f08c3bdfSopenharmony_ci NULL 240f08c3bdfSopenharmony_ci }, 241f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 242f08c3bdfSopenharmony_ci {"linux-git", "a08bf91ce28"}, 243f08c3bdfSopenharmony_ci {"linux-git", "2e356101e72"}, 244f08c3bdfSopenharmony_ci {} 245f08c3bdfSopenharmony_ci } 246f08c3bdfSopenharmony_ci}; 247