112 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * Copyright (c) 2017 Google, Inc.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Regression test for commit 37863c43b2c6 ("KEYS: prevent KEYCTL_READ on
 | |
|  * negative key").  This is CVE-2017-12192.
 | |
|  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <stdlib.h>
 | |
| #include <sys/wait.h>
 | |
| 
 | |
| #include "tst_test.h"
 | |
| #include "lapi/keyctl.h"
 | |
| 
 | |
| static void try_to_read_negative_key(void)
 | |
| {
 | |
| 	key_serial_t key_id;
 | |
| 	char buffer[128];
 | |
| 
 | |
| 	/*
 | |
| 	 * Create a negatively instantiated key of the "user" key type.  This
 | |
| 	 * key type is chosen because it has a ->read() method (which makes the
 | |
| 	 * bug reachable) and is available whenever CONFIG_KEYS is enabled.
 | |
| 	 *
 | |
| 	 * request_key() will result in the creation of a negative key provided
 | |
| 	 * that /sbin/request-key isn't configured to positively instantiate the
 | |
| 	 * key, based on the provided type, description, and callout_info.  If
 | |
| 	 * /sbin/request-key doesn't exist, errno will be ENOENT; while if it
 | |
| 	 * does exist and we specify some random unprefixed description, errno
 | |
| 	 * should be ENOKEY (since /sbin/request-key should not be configured to
 | |
| 	 * instantiate random user keys).  In either case a negative key should
 | |
| 	 * be created and we can continue on with the test.  Negative keys last
 | |
| 	 * for 60 seconds so there should be plenty of time for the test.
 | |
| 	 */
 | |
| 	TEST(request_key("user", "description", "callout_info",
 | |
| 			 KEY_SPEC_PROCESS_KEYRING));
 | |
| 	if (TST_RET != -1)
 | |
| 		tst_brk(TBROK, "request_key() unexpectedly succeeded");
 | |
| 
 | |
| 	if (TST_ERR != ENOKEY && TST_ERR != ENOENT) {
 | |
| 		tst_brk(TBROK | TTERRNO,
 | |
| 			"request_key() failed with unexpected error");
 | |
| 	}
 | |
| 
 | |
| 	/* Get the ID of the negative key by reading the keyring */
 | |
| 	TEST(keyctl(KEYCTL_READ, KEY_SPEC_PROCESS_KEYRING,
 | |
| 		    &key_id, sizeof(key_id)));
 | |
| 	if (TST_RET < 0)
 | |
| 		tst_brk(TBROK | TTERRNO, "KEYCTL_READ unexpectedly failed");
 | |
| 	if (TST_RET != sizeof(key_id)) {
 | |
| 		tst_brk(TBROK, "KEYCTL_READ returned %ld but expected %zu",
 | |
| 			TST_RET, sizeof(key_id));
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Now try to read the negative key.  Unpatched kernels will oops trying
 | |
| 	 * to read from memory address 0x00000000ffffff92.
 | |
| 	 */
 | |
| 	tst_res(TINFO, "trying to read from the negative key...");
 | |
| 	TEST(keyctl(KEYCTL_READ, key_id, buffer, sizeof(buffer)));
 | |
| 	if (TST_RET != -1) {
 | |
| 		tst_brk(TFAIL,
 | |
| 			"KEYCTL_READ on negative key unexpectedly succeeded");
 | |
| 	}
 | |
| 	if (TST_ERR != ENOKEY) {
 | |
| 		tst_brk(TFAIL | TTERRNO,
 | |
| 			"KEYCTL_READ on negative key failed with unexpected error");
 | |
| 	}
 | |
| 	tst_res(TPASS,
 | |
| 		"KEYCTL_READ on negative key expectedly failed with ENOKEY");
 | |
| }
 | |
| 
 | |
| static void do_test(void)
 | |
| {
 | |
| 	int status;
 | |
| 
 | |
| 	if (SAFE_FORK() == 0) {
 | |
| 		try_to_read_negative_key();
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	SAFE_WAIT(&status);
 | |
| 
 | |
| 	if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
 | |
| 		tst_res(TPASS, "didn't crash while reading from negative key");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) {
 | |
| 		tst_res(TFAIL, "reading from negative key caused kernel oops");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (WIFEXITED(status) && WEXITSTATUS(status) == TCONF)
 | |
| 		tst_brk(TCONF, "syscall not implemented");
 | |
| 
 | |
| 	tst_brk(TBROK, "Child %s", tst_strstatus(status));
 | |
| }
 | |
| 
 | |
| static struct tst_test test = {
 | |
| 	.test_all = do_test,
 | |
| 	.forks_child = 1,
 | |
| 	.tags = (const struct tst_tag[]) {
 | |
| 		{"CVE", "2017-12912"},
 | |
| 		{"linux-git", "37863c43b2c6"},
 | |
| 		{}
 | |
| 	}
 | |
| };
 |