Skip to content

Commit 1997b3c

Browse files
ea1davistorvalds
authored andcommitted
keys, dns: Fix missing size check of V1 server-list header
The dns_resolver_preparse() function has a check on the size of the payload for the basic header of the binary-style payload, but is missing a check for the size of the V1 server-list payload header after determining that's what we've been given. Fix this by getting rid of the the pointer to the basic header and just assuming that we have a V1 server-list payload and moving the V1 server list pointer inside the if-statement. Dealing with other types and versions can be left for when such have been defined. This can be tested by doing the following with KASAN enabled: echo -n -e '\x0\x0\x1\x2' | keyctl padd dns_resolver foo @p and produces an oops like the following: BUG: KASAN: slab-out-of-bounds in dns_resolver_preparse+0xc9f/0xd60 net/dns_resolver/dns_key.c:127 Read of size 1 at addr ffff888028894084 by task syz-executor265/5069 ... Call Trace: dns_resolver_preparse+0xc9f/0xd60 net/dns_resolver/dns_key.c:127 __key_create_or_update+0x453/0xdf0 security/keys/key.c:842 key_create_or_update+0x42/0x50 security/keys/key.c:1007 __do_sys_add_key+0x29c/0x450 security/keys/keyctl.c:134 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x62/0x6a This patch was originally by Edward Adam Davis, but was modified by Linus. Fixes: b946001 ("keys, dns: Allow key types (eg. DNS) to be reclaimed immediately on expiry") Reported-and-tested-by: syzbot+94bbb75204a05da3d89f@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/0000000000009b39bc060c73e209@google.com/ Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Edward Adam Davis <eadavis@qq.com> Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: David Howells <dhowells@redhat.com> Cc: Edward Adam Davis <eadavis@qq.com> Cc: Jarkko Sakkinen <jarkko@kernel.org> Cc: Jeffrey E Altman <jaltman@auristor.com> Cc: Wang Lei <wang840925@gmail.com> Cc: Jeff Layton <jlayton@redhat.com> Cc: Steve French <sfrench@us.ibm.com> Cc: Marc Dionne <marc.dionne@auristor.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Reviewed-by: Simon Horman <horms@kernel.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent fbafc3e commit 1997b3c

1 file changed

Lines changed: 9 additions & 10 deletions

File tree

net/dns_resolver/dns_key.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ const struct cred *dns_resolver_cache;
9191
static int
9292
dns_resolver_preparse(struct key_preparsed_payload *prep)
9393
{
94-
const struct dns_server_list_v1_header *v1;
95-
const struct dns_payload_header *bin;
9694
struct user_key_payload *upayload;
9795
unsigned long derrno;
9896
int ret;
@@ -103,27 +101,28 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
103101
return -EINVAL;
104102

105103
if (data[0] == 0) {
104+
const struct dns_server_list_v1_header *v1;
105+
106106
/* It may be a server list. */
107-
if (datalen <= sizeof(*bin))
107+
if (datalen <= sizeof(*v1))
108108
return -EINVAL;
109109

110-
bin = (const struct dns_payload_header *)data;
111-
kenter("[%u,%u],%u", bin->content, bin->version, datalen);
112-
if (bin->content != DNS_PAYLOAD_IS_SERVER_LIST) {
110+
v1 = (const struct dns_server_list_v1_header *)data;
111+
kenter("[%u,%u],%u", v1->hdr.content, v1->hdr.version, datalen);
112+
if (v1->hdr.content != DNS_PAYLOAD_IS_SERVER_LIST) {
113113
pr_warn_ratelimited(
114114
"dns_resolver: Unsupported content type (%u)\n",
115-
bin->content);
115+
v1->hdr.content);
116116
return -EINVAL;
117117
}
118118

119-
if (bin->version != 1) {
119+
if (v1->hdr.version != 1) {
120120
pr_warn_ratelimited(
121121
"dns_resolver: Unsupported server list version (%u)\n",
122-
bin->version);
122+
v1->hdr.version);
123123
return -EINVAL;
124124
}
125125

126-
v1 = (const struct dns_server_list_v1_header *)bin;
127126
if ((v1->status != DNS_LOOKUP_GOOD &&
128127
v1->status != DNS_LOOKUP_GOOD_WITH_BAD)) {
129128
if (prep->expiry == TIME64_MAX)

0 commit comments

Comments
 (0)