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