1 /*
2  * Copyright (c) 2017 Google, Inc.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program, if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Regression test for commit 237bbd29f7a0 ("KEYS: prevent creating a different
20  * user's keyrings").  The bug allowed any random user to create a keyring named
21  * "_uid.$UID" (or "_uid_ses.$UID"), and it would become the user keyring (or
22  * user session keyring) for user $UID, provided that it hadn't already been
23  * created.
24  *
25  * This test must be run as root so that it has permission to switch to another
26  * user ID and check whether the keyrings are wrong.  However, the underlying
27  * bug is actually reachable/exploitable by a non-root user.
28  */
29 
30 #include <errno.h>
31 #include <pwd.h>
32 #include <stdio.h>
33 
34 #include "tst_test.h"
35 #include "lapi/keyctl.h"
36 
create_keyring(const char * description)37 static key_serial_t create_keyring(const char *description)
38 {
39 	TEST(add_key("keyring", description, NULL, 0,
40 		     KEY_SPEC_PROCESS_KEYRING));
41 	if (TEST_RETURN < 0) {
42 		tst_brk(TBROK | TTERRNO,
43 			"unable to create keyring '%s'", description);
44 	}
45 	return TEST_RETURN;
46 }
47 
get_keyring_id(key_serial_t special_id)48 static key_serial_t get_keyring_id(key_serial_t special_id)
49 {
50 	TEST(keyctl(KEYCTL_GET_KEYRING_ID, special_id, 1));
51 	if (TEST_RETURN < 0) {
52 		tst_brk(TBROK | TTERRNO,
53 			"unable to get ID of keyring %d", special_id);
54 	}
55 	return TEST_RETURN;
56 }
57 
do_test(void)58 static void do_test(void)
59 {
60 	uid_t uid = 1;
61 	char description[32];
62 	key_serial_t fake_user_keyring;
63 	key_serial_t fake_user_session_keyring;
64 
65 	/*
66 	 * We need a user to forge the keyrings for.  But the bug is not
67 	 * reproducible for a UID which already has its keyrings, so find an
68 	 * unused UID.  Note that it would be better to directly check for the
69 	 * presence of the UID's keyrings than to search the passwd file.
70 	 * However, that's not easy to do given that even if we assumed the UID
71 	 * temporarily to check, KEYCTL_GET_KEYRING_ID for the user and user
72 	 * session keyrings will create them rather than failing (even if the
73 	 * 'create' argument is 0).
74 	 */
75 	while (getpwuid(uid))
76 		uid++;
77 
78 	sprintf(description, "_uid.%u", uid);
79 	fake_user_keyring = create_keyring(description);
80 	sprintf(description, "_uid_ses.%u", uid);
81 	fake_user_session_keyring = create_keyring(description);
82 
83 	SAFE_SETUID(uid);
84 
85 	if (fake_user_keyring == get_keyring_id(KEY_SPEC_USER_KEYRING))
86 		tst_brk(TFAIL, "created user keyring for another user");
87 
88 	if (fake_user_session_keyring ==
89 	    get_keyring_id(KEY_SPEC_USER_SESSION_KEYRING))
90 		tst_brk(TFAIL, "created user session keyring for another user");
91 
92 	tst_res(TPASS, "expectedly could not create another user's keyrings");
93 }
94 
95 static struct tst_test test = {
96 	.test_all = do_test,
97 	.needs_root = 1,
98 };
99