cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dns_query.c (4853B)


      1/* Upcall routine, designed to work as a key type and working through
      2 * /sbin/request-key to contact userspace when handling DNS queries.
      3 *
      4 * See Documentation/networking/dns_resolver.rst
      5 *
      6 *   Copyright (c) 2007 Igor Mammedov
      7 *   Author(s): Igor Mammedov (niallain@gmail.com)
      8 *              Steve French (sfrench@us.ibm.com)
      9 *              Wang Lei (wang840925@gmail.com)
     10 *		David Howells (dhowells@redhat.com)
     11 *
     12 *   The upcall wrapper used to make an arbitrary DNS query.
     13 *
     14 *   This function requires the appropriate userspace tool dns.upcall to be
     15 *   installed and something like the following lines should be added to the
     16 *   /etc/request-key.conf file:
     17 *
     18 *	create dns_resolver * * /sbin/dns.upcall %k
     19 *
     20 *   For example to use this module to query AFSDB RR:
     21 *
     22 *	create dns_resolver afsdb:* * /sbin/dns.afsdb %k
     23 *
     24 *   This library is free software; you can redistribute it and/or modify
     25 *   it under the terms of the GNU Lesser General Public License as published
     26 *   by the Free Software Foundation; either version 2.1 of the License, or
     27 *   (at your option) any later version.
     28 *
     29 *   This library is distributed in the hope that it will be useful,
     30 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     31 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     32 *   the GNU Lesser General Public License for more details.
     33 *
     34 *   You should have received a copy of the GNU Lesser General Public License
     35 *   along with this library; if not, see <http://www.gnu.org/licenses/>.
     36 */
     37
     38#include <linux/module.h>
     39#include <linux/slab.h>
     40#include <linux/cred.h>
     41#include <linux/dns_resolver.h>
     42#include <linux/err.h>
     43#include <net/net_namespace.h>
     44
     45#include <keys/dns_resolver-type.h>
     46#include <keys/user-type.h>
     47
     48#include "internal.h"
     49
     50/**
     51 * dns_query - Query the DNS
     52 * @net: The network namespace to operate in.
     53 * @type: Query type (or NULL for straight host->IP lookup)
     54 * @name: Name to look up
     55 * @namelen: Length of name
     56 * @options: Request options (or NULL if no options)
     57 * @_result: Where to place the returned data (or NULL)
     58 * @_expiry: Where to store the result expiry time (or NULL)
     59 * @invalidate: Always invalidate the key after use
     60 *
     61 * The data will be returned in the pointer at *result, if provided, and the
     62 * caller is responsible for freeing it.
     63 *
     64 * The description should be of the form "[<query_type>:]<domain_name>", and
     65 * the options need to be appropriate for the query type requested.  If no
     66 * query_type is given, then the query is a straight hostname to IP address
     67 * lookup.
     68 *
     69 * The DNS resolution lookup is performed by upcalling to userspace by way of
     70 * requesting a key of type dns_resolver.
     71 *
     72 * Returns the size of the result on success, -ve error code otherwise.
     73 */
     74int dns_query(struct net *net,
     75	      const char *type, const char *name, size_t namelen,
     76	      const char *options, char **_result, time64_t *_expiry,
     77	      bool invalidate)
     78{
     79	struct key *rkey;
     80	struct user_key_payload *upayload;
     81	const struct cred *saved_cred;
     82	size_t typelen, desclen;
     83	char *desc, *cp;
     84	int ret, len;
     85
     86	kenter("%s,%*.*s,%zu,%s",
     87	       type, (int)namelen, (int)namelen, name, namelen, options);
     88
     89	if (!name || namelen == 0)
     90		return -EINVAL;
     91
     92	/* construct the query key description as "[<type>:]<name>" */
     93	typelen = 0;
     94	desclen = 0;
     95	if (type) {
     96		typelen = strlen(type);
     97		if (typelen < 1)
     98			return -EINVAL;
     99		desclen += typelen + 1;
    100	}
    101
    102	if (namelen < 3 || namelen > 255)
    103		return -EINVAL;
    104	desclen += namelen + 1;
    105
    106	desc = kmalloc(desclen, GFP_KERNEL);
    107	if (!desc)
    108		return -ENOMEM;
    109
    110	cp = desc;
    111	if (type) {
    112		memcpy(cp, type, typelen);
    113		cp += typelen;
    114		*cp++ = ':';
    115	}
    116	memcpy(cp, name, namelen);
    117	cp += namelen;
    118	*cp = '\0';
    119
    120	if (!options)
    121		options = "";
    122	kdebug("call request_key(,%s,%s)", desc, options);
    123
    124	/* make the upcall, using special credentials to prevent the use of
    125	 * add_key() to preinstall malicious redirections
    126	 */
    127	saved_cred = override_creds(dns_resolver_cache);
    128	rkey = request_key_net(&key_type_dns_resolver, desc, net, options);
    129	revert_creds(saved_cred);
    130	kfree(desc);
    131	if (IS_ERR(rkey)) {
    132		ret = PTR_ERR(rkey);
    133		goto out;
    134	}
    135
    136	down_read(&rkey->sem);
    137	set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
    138	rkey->perm |= KEY_USR_VIEW;
    139
    140	ret = key_validate(rkey);
    141	if (ret < 0)
    142		goto put;
    143
    144	/* If the DNS server gave an error, return that to the caller */
    145	ret = PTR_ERR(rkey->payload.data[dns_key_error]);
    146	if (ret)
    147		goto put;
    148
    149	upayload = user_key_payload_locked(rkey);
    150	len = upayload->datalen;
    151
    152	if (_result) {
    153		ret = -ENOMEM;
    154		*_result = kmemdup_nul(upayload->data, len, GFP_KERNEL);
    155		if (!*_result)
    156			goto put;
    157	}
    158
    159	if (_expiry)
    160		*_expiry = rkey->expiry;
    161
    162	ret = len;
    163put:
    164	up_read(&rkey->sem);
    165	if (invalidate)
    166		key_invalidate(rkey);
    167	key_put(rkey);
    168out:
    169	kleave(" = %d", ret);
    170	return ret;
    171}
    172EXPORT_SYMBOL(dns_query);