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