diff options
author | Adrian Stratulat <adrian.stratulat@enea.com> | 2019-10-30 12:15:27 +0100 |
---|---|---|
committer | Adrian Stratulat <adrian.stratulat@enea.com> | 2019-10-30 12:20:47 +0100 |
commit | cb5564e4b430ed587f73aae357ef4f3b15f4b2dc (patch) | |
tree | 4b74782b2c1034ae495bd3b82ae22cab5c0d391b | |
parent | af13b16401b4c2a033bd0f74162530b2d4587f5a (diff) | |
download | enea-kernel-cache-cb5564e4b430ed587f73aae357ef4f3b15f4b2dc.tar.gz |
keys: CVE-2017-15299
KEYS: don't let add_key() update an uninstantiated key
References:
https://nvd.nist.gov/vuln/detail/CVE-2017-15299
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=60ff5b2f547af3828aebafd54daded44cfb0807a
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.9.y&id=da0c7503c0b886784bf8bcb279c7d71c1e50c438
Change-Id: Ia6933016fae4fa49769ef37c340978ccb9caa422
Signed-off-by: Adrian Stratulat <adrian.stratulat@enea.com>
-rw-r--r-- | patches/cve/CVE-2017-15299.patch | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/patches/cve/CVE-2017-15299.patch b/patches/cve/CVE-2017-15299.patch new file mode 100644 index 0000000..8f60e35 --- /dev/null +++ b/patches/cve/CVE-2017-15299.patch | |||
@@ -0,0 +1,126 @@ | |||
1 | From da0c7503c0b886784bf8bcb279c7d71c1e50c438 Mon Sep 17 00:00:00 2001 | ||
2 | From: David Howells <dhowells@redhat.com> | ||
3 | Date: Thu, 12 Oct 2017 16:00:41 +0100 | ||
4 | Subject: KEYS: don't let add_key() update an uninstantiated key | ||
5 | |||
6 | commit 60ff5b2f547af3828aebafd54daded44cfb0807a upstream. | ||
7 | |||
8 | Currently, when passed a key that already exists, add_key() will call the | ||
9 | key's ->update() method if such exists. But this is heavily broken in the | ||
10 | case where the key is uninstantiated because it doesn't call | ||
11 | __key_instantiate_and_link(). Consequently, it doesn't do most of the | ||
12 | things that are supposed to happen when the key is instantiated, such as | ||
13 | setting the instantiation state, clearing KEY_FLAG_USER_CONSTRUCT and | ||
14 | awakening tasks waiting on it, and incrementing key->user->nikeys. | ||
15 | |||
16 | It also never takes key_construction_mutex, which means that | ||
17 | ->instantiate() can run concurrently with ->update() on the same key. In | ||
18 | the case of the "user" and "logon" key types this causes a memory leak, at | ||
19 | best. Maybe even worse, the ->update() methods of the "encrypted" and | ||
20 | "trusted" key types actually just dereference a NULL pointer when passed an | ||
21 | uninstantiated key. | ||
22 | |||
23 | Change key_create_or_update() to wait interruptibly for the key to finish | ||
24 | construction before continuing. | ||
25 | |||
26 | This patch only affects *uninstantiated* keys. For now we still allow a | ||
27 | negatively instantiated key to be updated (thereby positively | ||
28 | instantiating it), although that's broken too (the next patch fixes it) | ||
29 | and I'm not sure that anyone actually uses that functionality either. | ||
30 | |||
31 | Here is a simple reproducer for the bug using the "encrypted" key type | ||
32 | (requires CONFIG_ENCRYPTED_KEYS=y), though as noted above the bug | ||
33 | pertained to more than just the "encrypted" key type: | ||
34 | |||
35 | #include <stdlib.h> | ||
36 | #include <unistd.h> | ||
37 | #include <keyutils.h> | ||
38 | |||
39 | int main(void) | ||
40 | { | ||
41 | int ringid = keyctl_join_session_keyring(NULL); | ||
42 | |||
43 | if (fork()) { | ||
44 | for (;;) { | ||
45 | const char payload[] = "update user:foo 32"; | ||
46 | |||
47 | usleep(rand() % 10000); | ||
48 | add_key("encrypted", "desc", payload, sizeof(payload), ringid); | ||
49 | keyctl_clear(ringid); | ||
50 | } | ||
51 | } else { | ||
52 | for (;;) | ||
53 | request_key("encrypted", "desc", "callout_info", ringid); | ||
54 | } | ||
55 | } | ||
56 | |||
57 | It causes: | ||
58 | |||
59 | BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 | ||
60 | IP: encrypted_update+0xb0/0x170 | ||
61 | PGD 7a178067 P4D 7a178067 PUD 77269067 PMD 0 | ||
62 | PREEMPT SMP | ||
63 | CPU: 0 PID: 340 Comm: reproduce Tainted: G D 4.14.0-rc1-00025-g428490e38b2e #796 | ||
64 | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 | ||
65 | task: ffff8a467a39a340 task.stack: ffffb15c40770000 | ||
66 | RIP: 0010:encrypted_update+0xb0/0x170 | ||
67 | RSP: 0018:ffffb15c40773de8 EFLAGS: 00010246 | ||
68 | RAX: 0000000000000000 RBX: ffff8a467a275b00 RCX: 0000000000000000 | ||
69 | RDX: 0000000000000005 RSI: ffff8a467a275b14 RDI: ffffffffb742f303 | ||
70 | RBP: ffffb15c40773e20 R08: 0000000000000000 R09: ffff8a467a275b17 | ||
71 | R10: 0000000000000020 R11: 0000000000000000 R12: 0000000000000000 | ||
72 | R13: 0000000000000000 R14: ffff8a4677057180 R15: ffff8a467a275b0f | ||
73 | FS: 00007f5d7fb08700(0000) GS:ffff8a467f200000(0000) knlGS:0000000000000000 | ||
74 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | ||
75 | CR2: 0000000000000018 CR3: 0000000077262005 CR4: 00000000001606f0 | ||
76 | Call Trace: | ||
77 | key_create_or_update+0x2bc/0x460 | ||
78 | SyS_add_key+0x10c/0x1d0 | ||
79 | entry_SYSCALL_64_fastpath+0x1f/0xbe | ||
80 | RIP: 0033:0x7f5d7f211259 | ||
81 | RSP: 002b:00007ffed03904c8 EFLAGS: 00000246 ORIG_RAX: 00000000000000f8 | ||
82 | RAX: ffffffffffffffda RBX: 000000003b2a7955 RCX: 00007f5d7f211259 | ||
83 | RDX: 00000000004009e4 RSI: 00000000004009ff RDI: 0000000000400a04 | ||
84 | RBP: 0000000068db8bad R08: 000000003b2a7955 R09: 0000000000000004 | ||
85 | R10: 000000000000001a R11: 0000000000000246 R12: 0000000000400868 | ||
86 | R13: 00007ffed03905d0 R14: 0000000000000000 R15: 0000000000000000 | ||
87 | Code: 77 28 e8 64 34 1f 00 45 31 c0 31 c9 48 8d 55 c8 48 89 df 48 8d 75 d0 e8 ff f9 ff ff 85 c0 41 89 c4 0f 88 84 00 00 00 4c 8b 7d c8 <49> 8b 75 18 4c 89 ff e8 24 f8 ff ff 85 c0 41 89 c4 78 6d 49 8b | ||
88 | RIP: encrypted_update+0xb0/0x170 RSP: ffffb15c40773de8 | ||
89 | CR2: 0000000000000018 | ||
90 | |||
91 | Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.9.y&id=da0c7503c0b886784bf8bcb279c7d71c1e50c438] | ||
92 | CVE: CVE-2017-15299 | ||
93 | |||
94 | Reported-by: Eric Biggers <ebiggers@google.com> | ||
95 | Signed-off-by: David Howells <dhowells@redhat.com> | ||
96 | cc: Eric Biggers <ebiggers@google.com> | ||
97 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
98 | Signed-off-by: Adrian Stratulat <adrian.stratulat@enea.com> | ||
99 | --- | ||
100 | security/keys/key.c | 10 ++++++++++ | ||
101 | 1 file changed, 10 insertions(+) | ||
102 | |||
103 | diff --git a/security/keys/key.c b/security/keys/key.c | ||
104 | index 135e1eb7e468..dd6dcee02492 100644 | ||
105 | --- a/security/keys/key.c | ||
106 | +++ b/security/keys/key.c | ||
107 | @@ -905,6 +905,16 @@ error: | ||
108 | */ | ||
109 | __key_link_end(keyring, &index_key, edit); | ||
110 | |||
111 | + key = key_ref_to_ptr(key_ref); | ||
112 | + if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) { | ||
113 | + ret = wait_for_key_construction(key, true); | ||
114 | + if (ret < 0) { | ||
115 | + key_ref_put(key_ref); | ||
116 | + key_ref = ERR_PTR(ret); | ||
117 | + goto error_free_prep; | ||
118 | + } | ||
119 | + } | ||
120 | + | ||
121 | key_ref = __key_update(key_ref, &prep); | ||
122 | goto error_free_prep; | ||
123 | } | ||
124 | -- | ||
125 | cgit 1.2-0.3.lf.el7 | ||
126 | |||