• 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 ea6789980fda ("assoc_array: Fix a buggy
8  * node-splitting case"), or CVE-2017-12193.
9  *
10  * Reproducing this bug requires adding keys to a keyring in a certain way that
11  * triggers a corner case in the kernel's "associative array" implementation,
12  * which is the data structure used to hold keys in a keyring, indexed by type
13  * and description.
14  *
15  * Specifically, the root node of a keyring's associative array must be
16  * completely filled with keys that all cluster together within the same slot.
17  * Then a key must be added which goes in a different slot.  On broken kernels,
18  * this caused a NULL pointer dereference in assoc_array_apply_edit().
19  *
20  * This can be done by carefully crafting key descriptions.  However, an easier
21  * way is to just add 16 keyrings and then a non-keyring, since keyrings all go
22  * into their own top-level slot.  This test takes the easier approach.
23  */
24 
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/wait.h>
29 
30 #include "tst_test.h"
31 #include "lapi/keyctl.h"
32 
33 #define ASSOC_ARRAY_FAN_OUT 16
34 
35 #define PAYLOAD "payload"
36 
37 static char *payload;
38 
do_test(void)39 static void do_test(void)
40 {
41 	int status;
42 
43 	TEST(keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL));
44 	if (TST_RET < 0)
45 		tst_brk(TBROK | TTERRNO, "failed to join new session keyring");
46 
47 	if (SAFE_FORK() == 0) {
48 		char description[32];
49 		int i;
50 
51 		for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
52 			sprintf(description, "keyring%d", i);
53 			TEST(add_key("keyring", description, NULL, 0,
54 				     KEY_SPEC_SESSION_KEYRING));
55 			if (TST_RET < 0) {
56 				tst_brk(TBROK | TTERRNO,
57 					"unable to create keyring %d", i);
58 			}
59 		}
60 
61 		TEST(add_key("user", "userkey", payload, sizeof(PAYLOAD),
62 			     KEY_SPEC_SESSION_KEYRING));
63 		if (TST_RET < 0)
64 			tst_brk(TBROK | TTERRNO, "unable to create user key");
65 
66 		exit(0);
67 	}
68 
69 	SAFE_WAIT(&status);
70 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
71 		tst_res(TPASS, "didn't crash while filling keyring");
72 	else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL)
73 		tst_res(TFAIL, "kernel oops while filling keyring");
74 	else
75 		tst_brk(TBROK, "Child %s", tst_strstatus(status));
76 }
77 
setup(void)78 static void setup(void)
79 {
80 	payload = tst_strdup(PAYLOAD);
81 }
82 
83 static struct tst_test test = {
84 	.setup = setup,
85 	.test_all = do_test,
86 	.forks_child = 1,
87 	.tags = (const struct tst_tag[]) {
88 		{"CVE", "2017-12193"},
89 		{"linux-git", "ea6789980fda"},
90 		{}
91 	}
92 };
93