mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: b946001d3bb1 ("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>
			
			
This commit is contained in:
		
							parent
							
								
									fbafc3e621
								
							
						
					
					
						commit
						1997b3cb42
					
				
					 1 changed files with 9 additions and 10 deletions
				
			
		| 
						 | 
					@ -91,8 +91,6 @@ const struct cred *dns_resolver_cache;
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
dns_resolver_preparse(struct key_preparsed_payload *prep)
 | 
					dns_resolver_preparse(struct key_preparsed_payload *prep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct dns_server_list_v1_header *v1;
 | 
					 | 
				
			||||||
	const struct dns_payload_header *bin;
 | 
					 | 
				
			||||||
	struct user_key_payload *upayload;
 | 
						struct user_key_payload *upayload;
 | 
				
			||||||
	unsigned long derrno;
 | 
						unsigned long derrno;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
| 
						 | 
					@ -103,27 +101,28 @@ dns_resolver_preparse(struct key_preparsed_payload *prep)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data[0] == 0) {
 | 
						if (data[0] == 0) {
 | 
				
			||||||
 | 
							const struct dns_server_list_v1_header *v1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* It may be a server list. */
 | 
							/* It may be a server list. */
 | 
				
			||||||
		if (datalen <= sizeof(*bin))
 | 
							if (datalen <= sizeof(*v1))
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bin = (const struct dns_payload_header *)data;
 | 
							v1 = (const struct dns_server_list_v1_header *)data;
 | 
				
			||||||
		kenter("[%u,%u],%u", bin->content, bin->version, datalen);
 | 
							kenter("[%u,%u],%u", v1->hdr.content, v1->hdr.version, datalen);
 | 
				
			||||||
		if (bin->content != DNS_PAYLOAD_IS_SERVER_LIST) {
 | 
							if (v1->hdr.content != DNS_PAYLOAD_IS_SERVER_LIST) {
 | 
				
			||||||
			pr_warn_ratelimited(
 | 
								pr_warn_ratelimited(
 | 
				
			||||||
				"dns_resolver: Unsupported content type (%u)\n",
 | 
									"dns_resolver: Unsupported content type (%u)\n",
 | 
				
			||||||
				bin->content);
 | 
									v1->hdr.content);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (bin->version != 1) {
 | 
							if (v1->hdr.version != 1) {
 | 
				
			||||||
			pr_warn_ratelimited(
 | 
								pr_warn_ratelimited(
 | 
				
			||||||
				"dns_resolver: Unsupported server list version (%u)\n",
 | 
									"dns_resolver: Unsupported server list version (%u)\n",
 | 
				
			||||||
				bin->version);
 | 
									v1->hdr.version);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		v1 = (const struct dns_server_list_v1_header *)bin;
 | 
					 | 
				
			||||||
		if ((v1->status != DNS_LOOKUP_GOOD &&
 | 
							if ((v1->status != DNS_LOOKUP_GOOD &&
 | 
				
			||||||
		     v1->status != DNS_LOOKUP_GOOD_WITH_BAD)) {
 | 
							     v1->status != DNS_LOOKUP_GOOD_WITH_BAD)) {
 | 
				
			||||||
			if (prep->expiry == TIME64_MAX)
 | 
								if (prep->expiry == TIME64_MAX)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue