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