xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/keyctl/keyctl07.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2017 Google, Inc.
4  * Copyright (c) Linux Test Project, 2018-2024
5  */
6 
7 /*\
8  * [Description]
9  *
10  * Regression test for commit 37863c43b2c6 ("KEYS: prevent KEYCTL_READ on
11  * negative key").  This is CVE-2017-12192.
12  */
13 
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <sys/wait.h>
17 
18 #include "tst_test.h"
19 #include "lapi/keyctl.h"
20 
try_to_read_negative_key(void)21 static void try_to_read_negative_key(void)
22 {
23 	key_serial_t key_id;
24 	char buffer[128];
25 
26 	/*
27 	 * Create a negatively instantiated key of the "user" key type.  This
28 	 * key type is chosen because it has a ->read() method (which makes the
29 	 * bug reachable) and is available whenever CONFIG_KEYS is enabled.
30 	 *
31 	 * request_key() will result in the creation of a negative key provided
32 	 * that /sbin/request-key isn't configured to positively instantiate the
33 	 * key, based on the provided type, description, and callout_info.  If
34 	 * /sbin/request-key doesn't exist, errno will be ENOENT; while if it
35 	 * does exist and we specify some random unprefixed description, errno
36 	 * should be ENOKEY (since /sbin/request-key should not be configured to
37 	 * instantiate random user keys).  In either case a negative key should
38 	 * be created and we can continue on with the test.  Negative keys last
39 	 * for 60 seconds so there should be plenty of time for the test.
40 	 */
41 	TEST(request_key("user", "description", "callout_info",
42 			 KEY_SPEC_PROCESS_KEYRING));
43 	if (TST_RET != -1)
44 		tst_brk(TBROK, "request_key() unexpectedly succeeded");
45 
46 	if (TST_ERR != ENOKEY && TST_ERR != ENOENT) {
47 		tst_brk(TBROK | TTERRNO,
48 			"request_key() failed with unexpected error");
49 	}
50 
51 	/* Get the ID of the negative key by reading the keyring */
52 	TEST(keyctl(KEYCTL_READ, KEY_SPEC_PROCESS_KEYRING,
53 		    &key_id, sizeof(key_id)));
54 	if (TST_RET < 0)
55 		tst_brk(TBROK | TTERRNO, "KEYCTL_READ unexpectedly failed");
56 	if (TST_RET != sizeof(key_id)) {
57 		tst_brk(TBROK, "KEYCTL_READ returned %ld but expected %zu",
58 			TST_RET, sizeof(key_id));
59 	}
60 
61 	/*
62 	 * Now try to read the negative key.  Unpatched kernels will oops trying
63 	 * to read from memory address 0x00000000ffffff92.
64 	 */
65 	tst_res(TINFO, "trying to read from the negative key...");
66 	TEST(keyctl(KEYCTL_READ, key_id, buffer, sizeof(buffer)));
67 	if (TST_RET != -1) {
68 		tst_brk(TFAIL,
69 			"KEYCTL_READ on negative key unexpectedly succeeded");
70 	}
71 	if (TST_ERR != ENOKEY) {
72 		tst_brk(TFAIL | TTERRNO,
73 			"KEYCTL_READ on negative key failed with unexpected error");
74 	}
75 	tst_res(TPASS,
76 		"KEYCTL_READ on negative key expectedly failed with ENOKEY");
77 }
78 
do_test(void)79 static void do_test(void)
80 {
81 	int status;
82 
83 	if (SAFE_FORK() == 0) {
84 		try_to_read_negative_key();
85 		return;
86 	}
87 
88 	SAFE_WAIT(&status);
89 
90 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
91 		tst_res(TPASS, "didn't crash while reading from negative key");
92 		return;
93 	}
94 
95 	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
96 		tst_res(TFAIL, "reading from negative key caused kernel oops");
97 		return;
98 	}
99 
100 	if (WIFEXITED(status) && WEXITSTATUS(status) == TCONF)
101 		tst_brk(TCONF, "syscall not implemented");
102 
103 	tst_brk(TBROK, "Child %s", tst_strstatus(status));
104 }
105 
106 static struct tst_test test = {
107 	.test_all = do_test,
108 	.forks_child = 1,
109 	.tags = (const struct tst_tag[]) {
110 		{"CVE", "2017-12192"},
111 		{"linux-git", "37863c43b2c6"},
112 		{}
113 	}
114 };
115