xref: /linux/net/dns_resolver/dns_key.c (revision 77a6401a8722be20ea8db98ac900c93ccc7068ff)
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /* Key type used to cache DNS lookups made by the kernel
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 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/slab.h>
15 #include <linux/string.h>
16 #include <linux/kernel.h>
17 #include <linux/keyctl.h>
18 #include <linux/err.h>
19 #include <linux/seq_file.h>
20 #include <linux/dns_resolver.h>
21 #include <keys/dns_resolver-type.h>
22 #include <keys/user-type.h>
23 #include "internal.h"
24 
25 MODULE_DESCRIPTION("DNS Resolver");
26 MODULE_AUTHOR("Wang Lei");
27 MODULE_LICENSE("GPL");
28 
29 unsigned int dns_resolver_debug;
30 module_param_named(debug, dns_resolver_debug, uint, 0644);
31 MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
32 
33 const struct cred *dns_resolver_cache;
34 
35 #define	DNS_ERRORNO_OPTION	"dnserror"
36 
37 /*
38  * Preparse instantiation data for a dns_resolver key.
39  *
40  * For normal hostname lookups, the data must be a NUL-terminated string, with
41  * the NUL char accounted in datalen.
42  *
43  * If the data contains a '#' characters, then we take the clause after each
44  * one to be an option of the form 'key=value'.  The actual data of interest is
45  * the string leading up to the first '#'.  For instance:
46  *
47  *        "ip1,ip2,...#foo=bar"
48  *
49  * For server list requests, the data must begin with a NUL char and be
50  * followed by a byte indicating the version of the data format.  Version 1
51  * looks something like (note this is packed):
52  *
53  *	u8      Non-string marker (ie. 0)
54  *	u8	Content (DNS_PAYLOAD_IS_*)
55  *	u8	Version (e.g. 1)
56  *	u8	Source of server list
57  *	u8	Lookup status of server list
58  *	u8	Number of servers
59  *	foreach-server {
60  *		__le16	Name length
61  *		__le16	Priority (as per SRV record, low first)
62  *		__le16	Weight (as per SRV record, higher first)
63  *		__le16	Port
64  *		u8	Source of address list
65  *		u8	Lookup status of address list
66  *		u8	Protocol (DNS_SERVER_PROTOCOL_*)
67  *		u8	Number of addresses
68  *		char[]	Name (not NUL-terminated)
69  *		foreach-address {
70  *			u8		Family (DNS_ADDRESS_IS_*)
71  *			union {
72  *				u8[4]	ipv4_addr
73  *				u8[16]	ipv6_addr
74  *			}
75  *		}
76  *	}
77  *
78  */
79 static int
80 dns_resolver_preparse(struct key_preparsed_payload *prep)
81 {
82 	struct user_key_payload *upayload;
83 	unsigned long derrno;
84 	int ret;
85 	int datalen = prep->datalen, result_len = 0;
86 	const char *data = prep->data, *end, *opt;
87 
88 	if (datalen <= 1 || !data)
89 		return -EINVAL;
90 
91 	if (data[0] == 0) {
92 		const struct dns_server_list_v1_header *v1;
93 
94 		/* It may be a server list. */
95 		if (datalen < sizeof(*v1))
96 			return -EINVAL;
97 
98 		v1 = (const struct dns_server_list_v1_header *)data;
99 		kenter("[%u,%u],%u", v1->hdr.content, v1->hdr.version, datalen);
100 		if (v1->hdr.content != DNS_PAYLOAD_IS_SERVER_LIST) {
101 			pr_warn_ratelimited(
102 				"dns_resolver: Unsupported content type (%u)\n",
103 				v1->hdr.content);
104 			return -EINVAL;
105 		}
106 
107 		if (v1->hdr.version != 1) {
108 			pr_warn_ratelimited(
109 				"dns_resolver: Unsupported server list version (%u)\n",
110 				v1->hdr.version);
111 			return -EINVAL;
112 		}
113 
114 		if ((v1->status != DNS_LOOKUP_GOOD &&
115 		     v1->status != DNS_LOOKUP_GOOD_WITH_BAD)) {
116 			if (prep->expiry == TIME64_MAX)
117 				prep->expiry = ktime_get_real_seconds() + 1;
118 		}
119 
120 		result_len = datalen;
121 		goto store_result;
122 	}
123 
124 	kenter("'%*.*s',%u", datalen, datalen, data, datalen);
125 
126 	if (!data || data[datalen - 1] != '\0')
127 		return -EINVAL;
128 	datalen--;
129 
130 	/* deal with any options embedded in the data */
131 	end = data + datalen;
132 	opt = memchr(data, '#', datalen);
133 	if (!opt) {
134 		/* no options: the entire data is the result */
135 		kdebug("no options");
136 		result_len = datalen;
137 	} else {
138 		const char *next_opt;
139 
140 		result_len = opt - data;
141 		opt++;
142 		kdebug("options: '%s'", opt);
143 		do {
144 			int opt_len, opt_nlen;
145 			const char *eq;
146 			char optval[128];
147 
148 			next_opt = memchr(opt, '#', end - opt) ?: end;
149 			opt_len = next_opt - opt;
150 			if (opt_len <= 0 || opt_len > sizeof(optval)) {
151 				pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n",
152 						    opt_len);
153 				return -EINVAL;
154 			}
155 
156 			eq = memchr(opt, '=', opt_len);
157 			if (eq) {
158 				opt_nlen = eq - opt;
159 				eq++;
160 				memcpy(optval, eq, next_opt - eq);
161 				optval[next_opt - eq] = '\0';
162 			} else {
163 				opt_nlen = opt_len;
164 				optval[0] = '\0';
165 			}
166 
167 			kdebug("option '%*.*s' val '%s'",
168 			       opt_nlen, opt_nlen, opt, optval);
169 
170 			/* see if it's an error number representing a DNS error
171 			 * that's to be recorded as the result in this key */
172 			if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 &&
173 			    memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) {
174 				kdebug("dns error number option");
175 
176 				ret = kstrtoul(optval, 10, &derrno);
177 				if (ret < 0)
178 					goto bad_option_value;
179 
180 				if (derrno < 1 || derrno > 511)
181 					goto bad_option_value;
182 
183 				kdebug("dns error no. = %lu", derrno);
184 				prep->payload.data[dns_key_error] = ERR_PTR(-derrno);
185 				continue;
186 			}
187 
188 		bad_option_value:
189 			pr_warn_ratelimited("Option '%*.*s' to dns_resolver key: bad/missing value\n",
190 					    opt_nlen, opt_nlen, opt);
191 			return -EINVAL;
192 		} while (opt = next_opt + 1, opt < end);
193 	}
194 
195 	/* don't cache the result if we're caching an error saying there's no
196 	 * result */
197 	if (prep->payload.data[dns_key_error]) {
198 		kleave(" = 0 [h_error %ld]", PTR_ERR(prep->payload.data[dns_key_error]));
199 		return 0;
200 	}
201 
202 store_result:
203 	kdebug("store result");
204 	prep->quotalen = result_len;
205 
206 	upayload = kmalloc_flex(*upayload, data, result_len + 1);
207 	if (!upayload) {
208 		kleave(" = -ENOMEM");
209 		return -ENOMEM;
210 	}
211 
212 	upayload->datalen = result_len;
213 	memcpy(upayload->data, data, result_len);
214 	upayload->data[result_len] = '\0';
215 
216 	prep->payload.data[dns_key_data] = upayload;
217 	kleave(" = 0");
218 	return 0;
219 }
220 
221 /*
222  * Clean up the preparse data
223  */
224 static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
225 {
226 	pr_devel("==>%s()\n", __func__);
227 
228 	kfree(prep->payload.data[dns_key_data]);
229 }
230 
231 /*
232  * The description is of the form "[<type>:]<domain_name>"
233  *
234  * The domain name may be a simple name or an absolute domain name (which
235  * should end with a period).  The domain name is case-independent.
236  */
237 static bool dns_resolver_cmp(const struct key *key,
238 			     const struct key_match_data *match_data)
239 {
240 	int slen, dlen, ret = 0;
241 	const char *src = key->description, *dsp = match_data->raw_data;
242 
243 	kenter("%s,%s", src, dsp);
244 
245 	if (!src || !dsp)
246 		goto no_match;
247 
248 	if (strcasecmp(src, dsp) == 0)
249 		goto matched;
250 
251 	slen = strlen(src);
252 	dlen = strlen(dsp);
253 	if (slen <= 0 || dlen <= 0)
254 		goto no_match;
255 	if (src[slen - 1] == '.')
256 		slen--;
257 	if (dsp[dlen - 1] == '.')
258 		dlen--;
259 	if (slen != dlen || strncasecmp(src, dsp, slen) != 0)
260 		goto no_match;
261 
262 matched:
263 	ret = 1;
264 no_match:
265 	kleave(" = %d", ret);
266 	return ret;
267 }
268 
269 /*
270  * Preparse the match criterion.
271  */
272 static int dns_resolver_match_preparse(struct key_match_data *match_data)
273 {
274 	match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
275 	match_data->cmp = dns_resolver_cmp;
276 	return 0;
277 }
278 
279 /*
280  * Describe a DNS key
281  */
282 static void dns_resolver_describe(const struct key *key, struct seq_file *m)
283 {
284 	seq_puts(m, key->description);
285 	if (key_is_positive(key)) {
286 		int err = PTR_ERR(key->payload.data[dns_key_error]);
287 
288 		if (err)
289 			seq_printf(m, ": %d", err);
290 		else
291 			seq_printf(m, ": %u", key->datalen);
292 	}
293 }
294 
295 /*
296  * read the DNS data
297  * - the key's semaphore is read-locked
298  */
299 static long dns_resolver_read(const struct key *key,
300 			      char *buffer, size_t buflen)
301 {
302 	int err = PTR_ERR(key->payload.data[dns_key_error]);
303 
304 	if (err)
305 		return err;
306 
307 	return user_read(key, buffer, buflen);
308 }
309 
310 struct key_type key_type_dns_resolver = {
311 	.name		= "dns_resolver",
312 	.flags		= KEY_TYPE_NET_DOMAIN | KEY_TYPE_INSTANT_REAP,
313 	.preparse	= dns_resolver_preparse,
314 	.free_preparse	= dns_resolver_free_preparse,
315 	.instantiate	= generic_key_instantiate,
316 	.match_preparse	= dns_resolver_match_preparse,
317 	.revoke		= user_revoke,
318 	.destroy	= user_destroy,
319 	.describe	= dns_resolver_describe,
320 	.read		= dns_resolver_read,
321 };
322 
323 static int __init init_dns_resolver(void)
324 {
325 	struct cred *cred;
326 	struct key *keyring;
327 	int ret;
328 
329 	/* create an override credential set with a special thread keyring in
330 	 * which DNS requests are cached
331 	 *
332 	 * this is used to prevent malicious redirections from being installed
333 	 * with add_key().
334 	 */
335 	cred = prepare_kernel_cred(&init_task);
336 	if (!cred)
337 		return -ENOMEM;
338 
339 	keyring = keyring_alloc(".dns_resolver",
340 				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
341 				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
342 				KEY_USR_VIEW | KEY_USR_READ,
343 				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
344 	if (IS_ERR(keyring)) {
345 		ret = PTR_ERR(keyring);
346 		goto failed_put_cred;
347 	}
348 
349 	ret = register_key_type(&key_type_dns_resolver);
350 	if (ret < 0)
351 		goto failed_put_key;
352 
353 	/* instruct request_key() to use this special keyring as a cache for
354 	 * the results it looks up */
355 	set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
356 	cred->thread_keyring = keyring;
357 	cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
358 	dns_resolver_cache = cred;
359 
360 	kdebug("DNS resolver keyring: %d\n", key_serial(keyring));
361 	return 0;
362 
363 failed_put_key:
364 	key_put(keyring);
365 failed_put_cred:
366 	put_cred(cred);
367 	return ret;
368 }
369 
370 static void __exit exit_dns_resolver(void)
371 {
372 	key_revoke(dns_resolver_cache->thread_keyring);
373 	unregister_key_type(&key_type_dns_resolver);
374 	put_cred(dns_resolver_cache);
375 }
376 
377 module_init(init_dns_resolver)
378 module_exit(exit_dns_resolver)
379 MODULE_LICENSE("GPL");
380