mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 01:51:53 +00:00
1362fa078d
When a DNS resolver key is instantiated with an error indication, attempts to
read that key will result in an oops because user_read() is expecting there to
be a payload - and there isn't one [CVE-2011-1076].
Give the DNS resolver key its own read handler that returns the error cached in
key->type_data.x[0] as an error rather than crashing.
Also make the kenter() at the beginning of dns_resolver_instantiate() limit the
amount of data it prints, since the data is not necessarily NUL-terminated.
The buggy code was added in:
commit 4a2d789267
Author: Wang Lei <wang840925@gmail.com>
Date: Wed Aug 11 09:37:58 2010 +0100
Subject: DNS: If the DNS server returns an error, allow that to be cached [ver #2]
This can trivially be reproduced by any user with the following program
compiled with -lkeyutils:
#include <stdlib.h>
#include <keyutils.h>
#include <err.h>
static char payload[] = "#dnserror=6";
int main()
{
key_serial_t key;
key = add_key("dns_resolver", "a", payload, sizeof(payload),
KEY_SPEC_SESSION_KEYRING);
if (key == -1)
err(1, "add_key");
if (keyctl_read(key, NULL, 0) == -1)
err(1, "read_key");
return 0;
}
What should happen is that keyctl_read() reports error 6 (ENXIO) to the user:
dns-break: read_key: No such device or address
but instead the kernel oopses.
This cannot be reproduced with the 'keyutils add' or 'keyutils padd' commands
as both of those cut the data down below the NUL termination that must be
included in the data. Without this dns_resolver_instantiate() will return
-EINVAL and the key will not be instantiated such that it can be read.
The oops looks like:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000010
IP: [<ffffffff811b99f7>] user_read+0x4f/0x8f
PGD 3bdf8067 PUD 385b9067 PMD 0
Oops: 0000 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:19.0/irq
CPU 0
Modules linked in:
Pid: 2150, comm: dns-break Not tainted 2.6.38-rc7-cachefs+ #468 /DG965RY
RIP: 0010:[<ffffffff811b99f7>] [<ffffffff811b99f7>] user_read+0x4f/0x8f
RSP: 0018:ffff88003bf47f08 EFLAGS: 00010246
RAX: 0000000000000001 RBX: ffff88003b5ea378 RCX: ffffffff81972368
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88003b5ea378
RBP: ffff88003bf47f28 R08: ffff88003be56620 R09: 0000000000000000
R10: 0000000000000395 R11: 0000000000000002 R12: 0000000000000000
R13: 0000000000000000 R14: 0000000000000000 R15: ffffffffffffffa1
FS: 00007feab5751700(0000) GS:ffff88003e000000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000010 CR3: 000000003de40000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process dns-break (pid: 2150, threadinfo ffff88003bf46000, task ffff88003be56090)
Stack:
ffff88003b5ea378 ffff88003b5ea3a0 0000000000000000 0000000000000000
ffff88003bf47f68 ffffffff811b708e ffff88003c442bc8 0000000000000000
00000000004005a0 00007fffba368060 0000000000000000 0000000000000000
Call Trace:
[<ffffffff811b708e>] keyctl_read_key+0xac/0xcf
[<ffffffff811b7c07>] sys_keyctl+0x75/0xb6
[<ffffffff81001f7b>] system_call_fastpath+0x16/0x1b
Code: 75 1f 48 83 7b 28 00 75 18 c6 05 58 2b fb 00 01 be bb 00 00 00 48 c7 c7 76 1c 75 81 e8 13 c2 e9 ff 4c 8b b3 e0 00 00 00 4d 85 ed <41> 0f b7 5e 10 74 2d 4d 85 e4 74 28 e8 98 79 ee ff 49 39 dd 48
RIP [<ffffffff811b99f7>] user_read+0x4f/0x8f
RSP <ffff88003bf47f08>
CR2: 0000000000000010
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Jeff Layton <jlayton@redhat.com>
cc: Wang Lei <wang840925@gmail.com>
Signed-off-by: James Morris <jmorris@namei.org>
154 lines
4.9 KiB
Plaintext
154 lines
4.9 KiB
Plaintext
===================
|
|
DNS Resolver Module
|
|
===================
|
|
|
|
Contents:
|
|
|
|
- Overview.
|
|
- Compilation.
|
|
- Setting up.
|
|
- Usage.
|
|
- Mechanism.
|
|
- Debugging.
|
|
|
|
|
|
========
|
|
OVERVIEW
|
|
========
|
|
|
|
The DNS resolver module provides a way for kernel services to make DNS queries
|
|
by way of requesting a key of key type dns_resolver. These queries are
|
|
upcalled to userspace through /sbin/request-key.
|
|
|
|
These routines must be supported by userspace tools dns.upcall, cifs.upcall and
|
|
request-key. It is under development and does not yet provide the full feature
|
|
set. The features it does support include:
|
|
|
|
(*) Implements the dns_resolver key_type to contact userspace.
|
|
|
|
It does not yet support the following AFS features:
|
|
|
|
(*) Dns query support for AFSDB resource record.
|
|
|
|
This code is extracted from the CIFS filesystem.
|
|
|
|
|
|
===========
|
|
COMPILATION
|
|
===========
|
|
|
|
The module should be enabled by turning on the kernel configuration options:
|
|
|
|
CONFIG_DNS_RESOLVER - tristate "DNS Resolver support"
|
|
|
|
|
|
==========
|
|
SETTING UP
|
|
==========
|
|
|
|
To set up this facility, the /etc/request-key.conf file must be altered so that
|
|
/sbin/request-key can appropriately direct the upcalls. For example, to handle
|
|
basic dname to IPv4/IPv6 address resolution, the following line should be
|
|
added:
|
|
|
|
#OP TYPE DESC CO-INFO PROGRAM ARG1 ARG2 ARG3 ...
|
|
#====== ============ ======= ======= ==========================
|
|
create dns_resolver * * /usr/sbin/cifs.upcall %k
|
|
|
|
To direct a query for query type 'foo', a line of the following should be added
|
|
before the more general line given above as the first match is the one taken.
|
|
|
|
create dns_resolver foo:* * /usr/sbin/dns.foo %k
|
|
|
|
|
|
=====
|
|
USAGE
|
|
=====
|
|
|
|
To make use of this facility, one of the following functions that are
|
|
implemented in the module can be called after doing:
|
|
|
|
#include <linux/dns_resolver.h>
|
|
|
|
(1) int dns_query(const char *type, const char *name, size_t namelen,
|
|
const char *options, char **_result, time_t *_expiry);
|
|
|
|
This is the basic access function. It looks for a cached DNS query and if
|
|
it doesn't find it, it upcalls to userspace to make a new DNS query, which
|
|
may then be cached. The key description is constructed as a string of the
|
|
form:
|
|
|
|
[<type>:]<name>
|
|
|
|
where <type> optionally specifies the particular upcall program to invoke,
|
|
and thus the type of query to do, and <name> specifies the string to be
|
|
looked up. The default query type is a straight hostname to IP address
|
|
set lookup.
|
|
|
|
The name parameter is not required to be a NUL-terminated string, and its
|
|
length should be given by the namelen argument.
|
|
|
|
The options parameter may be NULL or it may be a set of options
|
|
appropriate to the query type.
|
|
|
|
The return value is a string appropriate to the query type. For instance,
|
|
for the default query type it is just a list of comma-separated IPv4 and
|
|
IPv6 addresses. The caller must free the result.
|
|
|
|
The length of the result string is returned on success, and a negative
|
|
error code is returned otherwise. -EKEYREJECTED will be returned if the
|
|
DNS lookup failed.
|
|
|
|
If _expiry is non-NULL, the expiry time (TTL) of the result will be
|
|
returned also.
|
|
|
|
|
|
===============================
|
|
READING DNS KEYS FROM USERSPACE
|
|
===============================
|
|
|
|
Keys of dns_resolver type can be read from userspace using keyctl_read() or
|
|
"keyctl read/print/pipe".
|
|
|
|
|
|
=========
|
|
MECHANISM
|
|
=========
|
|
|
|
The dnsresolver module registers a key type called "dns_resolver". Keys of
|
|
this type are used to transport and cache DNS lookup results from userspace.
|
|
|
|
When dns_query() is invoked, it calls request_key() to search the local
|
|
keyrings for a cached DNS result. If that fails to find one, it upcalls to
|
|
userspace to get a new result.
|
|
|
|
Upcalls to userspace are made through the request_key() upcall vector, and are
|
|
directed by means of configuration lines in /etc/request-key.conf that tell
|
|
/sbin/request-key what program to run to instantiate the key.
|
|
|
|
The upcall handler program is responsible for querying the DNS, processing the
|
|
result into a form suitable for passing to the keyctl_instantiate_key()
|
|
routine. This then passes the data to dns_resolver_instantiate() which strips
|
|
off and processes any options included in the data, and then attaches the
|
|
remainder of the string to the key as its payload.
|
|
|
|
The upcall handler program should set the expiry time on the key to that of the
|
|
lowest TTL of all the records it has extracted a result from. This means that
|
|
the key will be discarded and recreated when the data it holds has expired.
|
|
|
|
dns_query() returns a copy of the value attached to the key, or an error if
|
|
that is indicated instead.
|
|
|
|
See <file:Documentation/keys-request-key.txt> for further information about
|
|
request-key function.
|
|
|
|
|
|
=========
|
|
DEBUGGING
|
|
=========
|
|
|
|
Debugging messages can be turned on dynamically by writing a 1 into the
|
|
following file:
|
|
|
|
/sys/module/dnsresolver/parameters/debug
|