keyctl02.c revision 974a9282b5bda74c221d0c998c949b1266e4efc5
1/* 2 * Copyright (c) 2017 Fujitsu Ltd. 3 * Ported: Guangwen Feng <fenggw-fnst@cn.fujitsu.com> 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program, if not, see <http://www.gnu.org/licenses/>. 17 */ 18 19/* 20 * This is a regression test for the race between keyctl_read() and 21 * keyctl_revoke(), if the revoke happens between keyctl_read() 22 * checking the validity of a key and the key's semaphore being taken, 23 * then the key type read method will see a revoked key. 24 * 25 * This causes a problem for the user-defined key type because it 26 * assumes in its read method that there will always be a payload 27 * in a non-revoked key and doesn't check for a NULL pointer. 28 * 29 * This test can crash the buggy kernel, and the bug was fixed in: 30 * 31 * commit b4a1b4f5047e4f54e194681125c74c0aa64d637d 32 * Author: David Howells <dhowells@redhat.com> 33 * Date: Fri Dec 18 01:34:26 2015 +0000 34 * 35 * KEYS: Fix race between read and revoke 36 */ 37 38#include <errno.h> 39#include <pthread.h> 40#include <sys/types.h> 41 42#include "tst_safe_pthread.h" 43#include "tst_test.h" 44#include "lapi/keyctl.h" 45 46#define LOOPS 20000 47#define PATH_KEY_COUNT_QUOTA "/proc/sys/kernel/keys/root_maxkeys" 48 49static int orig_maxkeys; 50 51static void *do_read(void *arg) 52{ 53 key_serial_t key = (unsigned long)arg; 54 char buffer[4] = { 0 }; 55 56 keyctl(KEYCTL_READ, key, buffer, 4); 57 58 return NULL; 59} 60 61static void *do_revoke(void *arg) 62{ 63 key_serial_t key = (unsigned long)arg; 64 65 keyctl(KEYCTL_REVOKE, key); 66 67 return NULL; 68} 69 70static void do_test(void) 71{ 72 int i; 73 key_serial_t key; 74 pthread_t pth[4]; 75 76 for (i = 0; i < LOOPS; i++) { 77 key = add_key("user", "ltptestkey", "foo", 3, 78 KEY_SPEC_PROCESS_KEYRING); 79 if (key == -1) 80 tst_brk(TBROK | TERRNO, "Failed to add key"); 81 82 SAFE_PTHREAD_CREATE(&pth[0], NULL, do_read, 83 (void *)(unsigned long)key); 84 SAFE_PTHREAD_CREATE(&pth[1], NULL, do_revoke, 85 (void *)(unsigned long)key); 86 SAFE_PTHREAD_CREATE(&pth[2], NULL, do_read, 87 (void *)(unsigned long)key); 88 SAFE_PTHREAD_CREATE(&pth[3], NULL, do_revoke, 89 (void *)(unsigned long)key); 90 91 SAFE_PTHREAD_JOIN(pth[0], NULL); 92 SAFE_PTHREAD_JOIN(pth[1], NULL); 93 SAFE_PTHREAD_JOIN(pth[2], NULL); 94 SAFE_PTHREAD_JOIN(pth[3], NULL); 95 } 96 97 tst_res(TPASS, "Bug not reproduced"); 98} 99 100static void setup(void) 101{ 102 SAFE_FILE_SCANF(PATH_KEY_COUNT_QUOTA, "%d", &orig_maxkeys); 103 SAFE_FILE_PRINTF(PATH_KEY_COUNT_QUOTA, "%d", orig_maxkeys + LOOPS); 104} 105 106static void cleanup(void) 107{ 108 if (orig_maxkeys > 0) 109 SAFE_FILE_PRINTF(PATH_KEY_COUNT_QUOTA, "%d", orig_maxkeys); 110} 111 112static struct tst_test test = { 113 .needs_root = 1, 114 .setup = setup, 115 .cleanup = cleanup, 116 .test_all = do_test, 117}; 118