1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2017 Google, Inc. 4 */ 5 6/* 7 * Regression test for commit 63a0b0509e70 ("KEYS: fix freeing uninitialized 8 * memory in key_update()"). Try to reproduce the crash in two different ways: 9 * 10 * 1. Try to update a key of a type that has a ->preparse() method but not an 11 * ->update() method. Examples are the "asymmetric" and "dns_resolver" key 12 * types. It crashes reliably for the "asymmetric" key type, since the 13 * "asymmetric" key type's ->free_preparse() method will dereference a 14 * pointer in the uninitialized memory, whereas other key types often just 15 * free a pointer which tends be NULL in practice, depending on how the stack 16 * is laid out. However, to actually be able to add an "asymmetric" key, we 17 * need a specially-formatted payload and several kernel config options. We 18 * do try it, but for completeness we also try the "dns_resolver" key type 19 * (though that's not guaranteed to be available either). 20 * 21 * 2. Race keyctl_update() with another task removing write permission from the 22 * key using keyctl_setperm(). This can cause a crash with almost any key 23 * type. "user" is a good one to try, since it's always available if 24 * keyrings are supported at all. However, depending on how the stack is 25 * laid out the crash may not actually occur. 26 */ 27 28#include <errno.h> 29#include <stdlib.h> 30 31#include "tst_test.h" 32#include "lapi/keyctl.h" 33 34/* 35 * A valid payload for the "asymmetric" key type. This is an x509 certificate 36 * in DER format, generated using: 37 * 38 * openssl req -x509 -newkey rsa:512 -batch -nodes -outform der \ 39 * | ~/linux/scripts/bin2c 40 */ 41static const char x509_cert[] = 42 "\x30\x82\x01\xd3\x30\x82\x01\x7d\xa0\x03\x02\x01\x02\x02\x09\x00" 43 "\x92\x2a\x76\xff\x0c\x00\xfb\x9a\x30\x0d\x06\x09\x2a\x86\x48\x86" 44 "\xf7\x0d\x01\x01\x0b\x05\x00\x30\x45\x31\x0b\x30\x09\x06\x03\x55" 45 "\x04\x06\x13\x02\x41\x55\x31\x13\x30\x11\x06\x03\x55\x04\x08\x0c" 46 "\x0a\x53\x6f\x6d\x65\x2d\x53\x74\x61\x74\x65\x31\x21\x30\x1f\x06" 47 "\x03\x55\x04\x0a\x0c\x18\x49\x6e\x74\x65\x72\x6e\x65\x74\x20\x57" 48 "\x69\x64\x67\x69\x74\x73\x20\x50\x74\x79\x20\x4c\x74\x64\x30\x1e" 49 "\x17\x0d\x31\x37\x30\x37\x32\x38\x32\x31\x34\x31\x33\x34\x5a\x17" 50 "\x0d\x31\x37\x30\x38\x32\x37\x32\x31\x34\x31\x33\x34\x5a\x30\x45" 51 "\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x41\x55\x31\x13\x30" 52 "\x11\x06\x03\x55\x04\x08\x0c\x0a\x53\x6f\x6d\x65\x2d\x53\x74\x61" 53 "\x74\x65\x31\x21\x30\x1f\x06\x03\x55\x04\x0a\x0c\x18\x49\x6e\x74" 54 "\x65\x72\x6e\x65\x74\x20\x57\x69\x64\x67\x69\x74\x73\x20\x50\x74" 55 "\x79\x20\x4c\x74\x64\x30\x5c\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7" 56 "\x0d\x01\x01\x01\x05\x00\x03\x4b\x00\x30\x48\x02\x41\x00\xde\x0b" 57 "\x1c\x24\xe2\x0d\xf8\x17\xf2\xc3\x6f\xc9\x72\x3e\x9d\xb0\x2d\x47" 58 "\xe4\xc4\x85\x87\xed\xde\x06\xe3\xf3\xe9\x4c\x35\x6c\xe4\xcb\x0e" 59 "\x44\x28\x23\x66\x76\xec\x4e\xdf\x10\x93\x92\x1e\x52\xfb\xdf\x5c" 60 "\x08\xe7\x24\x04\x66\xe3\x06\x05\x27\x56\xfb\x3e\x91\x31\x02\x03" 61 "\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16" 62 "\x04\x14\x6f\x39\x3a\x46\xdf\x29\x63\xde\x54\x7b\x6c\x31\x06\xd0" 63 "\x9f\x36\x16\xfb\x9c\xbf\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30" 64 "\x16\x80\x14\x6f\x39\x3a\x46\xdf\x29\x63\xde\x54\x7b\x6c\x31\x06" 65 "\xd0\x9f\x36\x16\xfb\x9c\xbf\x30\x0c\x06\x03\x55\x1d\x13\x04\x05" 66 "\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01" 67 "\x01\x0b\x05\x00\x03\x41\x00\x73\xf0\x4b\x62\x56\xed\xf0\x8b\x7e" 68 "\xc4\x75\x78\x98\xa2\x7a\x6e\x75\x1f\xde\x9b\xa0\xbe\x1a\x1f\x86" 69 "\x44\x13\xcd\x45\x06\x7f\x86\xde\xf6\x36\x4e\xb6\x15\xfa\xf5\xb0" 70 "\x34\xd2\x5e\x0b\xb3\x2c\x03\x5a\x5a\x28\x97\x5e\x7b\xdf\x63\x75" 71 "\x83\x8d\x69\xda\xd6\x59\xbd" 72 ; 73 74 static int fips_enabled; 75 76static void new_session_keyring(void) 77{ 78 TEST(keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL)); 79 if (TST_RET < 0) 80 tst_brk(TBROK | TTERRNO, "failed to join new session keyring"); 81} 82 83static void test_update_nonupdatable(const char *type, 84 const void *payload, size_t plen) 85{ 86 key_serial_t keyid; 87 88 new_session_keyring(); 89 90 int is_asymmetric = !strcmp(type, "asymmetric"); 91 92 TEST(add_key(type, "desc", payload, plen, KEY_SPEC_SESSION_KEYRING)); 93 if (TST_RET < 0) { 94 if (TST_ERR == EINVAL && is_asymmetric && fips_enabled) { 95 tst_res(TCONF, "key size not allowed in FIPS mode"); 96 return; 97 } 98 if (TST_ERR == ENODEV) { 99 tst_res(TCONF, "kernel doesn't support key type '%s'", 100 type); 101 return; 102 } 103 if (TST_ERR == EBADMSG && is_asymmetric) { 104 tst_res(TCONF, "kernel is missing x509 cert parser " 105 "(CONFIG_X509_CERTIFICATE_PARSER)"); 106 return; 107 } 108 if (TST_ERR == ENOENT && is_asymmetric) { 109 tst_res(TCONF, "kernel is missing crypto algorithms " 110 "needed to parse x509 cert (CONFIG_CRYPTO_RSA " 111 "and/or CONFIG_CRYPTO_SHA256)"); 112 return; 113 } 114 tst_res(TFAIL | TTERRNO, "unexpected error adding '%s' key", 115 type); 116 return; 117 } 118 keyid = TST_RET; 119 120 /* 121 * Non-updatable keys don't start with write permission, so we must 122 * explicitly grant it. 123 */ 124 TEST(keyctl(KEYCTL_SETPERM, keyid, KEY_POS_ALL)); 125 if (TST_RET != 0) { 126 tst_res(TFAIL | TTERRNO, 127 "failed to grant write permission to '%s' key", type); 128 return; 129 } 130 131 tst_res(TINFO, "Try to update the '%s' key...", type); 132 TEST(keyctl(KEYCTL_UPDATE, keyid, payload, plen)); 133 if (TST_RET == 0) { 134 tst_res(TFAIL, 135 "updating '%s' key unexpectedly succeeded", type); 136 return; 137 } 138 if (TST_ERR != EOPNOTSUPP) { 139 tst_res(TFAIL | TTERRNO, 140 "updating '%s' key unexpectedly failed", type); 141 return; 142 } 143 tst_res(TPASS, "updating '%s' key expectedly failed with EOPNOTSUPP", 144 type); 145} 146 147/* 148 * Try to update a key, racing with removing write permission. 149 * This may crash buggy kernels. 150 */ 151static void test_update_setperm_race(void) 152{ 153 static const char payload[] = "payload"; 154 key_serial_t keyid; 155 int i; 156 157 new_session_keyring(); 158 159 TEST(add_key("user", "desc", payload, sizeof(payload), 160 KEY_SPEC_SESSION_KEYRING)); 161 if (TST_RET < 0) { 162 tst_res(TFAIL | TTERRNO, "failed to add 'user' key"); 163 return; 164 } 165 keyid = TST_RET; 166 167 if (SAFE_FORK() == 0) { 168 uint32_t perm = KEY_POS_ALL; 169 170 for (i = 0; i < 10000; i++) { 171 perm ^= KEY_POS_WRITE; 172 TEST(keyctl(KEYCTL_SETPERM, keyid, perm)); 173 if (TST_RET != 0) 174 tst_brk(TBROK | TTERRNO, "setperm failed"); 175 } 176 exit(0); 177 } 178 179 tst_res(TINFO, "Try to update the 'user' key..."); 180 for (i = 0; i < 10000; i++) { 181 TEST(keyctl(KEYCTL_UPDATE, keyid, payload, sizeof(payload))); 182 if (TST_RET != 0 && TST_ERR != EACCES) { 183 tst_res(TFAIL | TTERRNO, "failed to update 'user' key"); 184 return; 185 } 186 } 187 tst_reap_children(); 188 tst_res(TPASS, "didn't crash while racing to update 'user' key"); 189} 190 191static void setup(void) 192{ 193 fips_enabled = tst_fips_enabled(); 194} 195 196static void do_test(unsigned int i) 197{ 198 /* 199 * We need to pass check in dns_resolver_preparse(), 200 * give it dummy server list request. 201 */ 202 static char dns_res_payload[] = { 0x00, 0x00, 0x01, 0xff, 0x00 }; 203 204 switch (i) { 205 case 0: 206 test_update_nonupdatable("asymmetric", 207 x509_cert, sizeof(x509_cert)); 208 break; 209 case 1: 210 test_update_nonupdatable("dns_resolver", dns_res_payload, 211 sizeof(dns_res_payload)); 212 break; 213 case 2: 214 test_update_setperm_race(); 215 break; 216 } 217} 218 219static struct tst_test test = { 220 .tcnt = 3, 221 .setup = setup, 222 .test = do_test, 223 .forks_child = 1, 224 .tags = (const struct tst_tag[]) { 225 {"linux-git", "63a0b0509e70"}, 226 {} 227 } 228}; 229