This source file includes following definitions.
- dns_resolver_preparse
- dns_resolver_free_preparse
- dns_resolver_cmp
- dns_resolver_match_preparse
- dns_resolver_describe
- dns_resolver_read
- init_dns_resolver
- exit_dns_resolver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #include <linux/module.h>
25 #include <linux/moduleparam.h>
26 #include <linux/slab.h>
27 #include <linux/string.h>
28 #include <linux/kernel.h>
29 #include <linux/keyctl.h>
30 #include <linux/err.h>
31 #include <linux/seq_file.h>
32 #include <linux/dns_resolver.h>
33 #include <keys/dns_resolver-type.h>
34 #include <keys/user-type.h>
35 #include "internal.h"
36
37 MODULE_DESCRIPTION("DNS Resolver");
38 MODULE_AUTHOR("Wang Lei");
39 MODULE_LICENSE("GPL");
40
41 unsigned int dns_resolver_debug;
42 module_param_named(debug, dns_resolver_debug, uint, 0644);
43 MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
44
45 const struct cred *dns_resolver_cache;
46
47 #define DNS_ERRORNO_OPTION "dnserror"
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 static int
92 dns_resolver_preparse(struct key_preparsed_payload *prep)
93 {
94 const struct dns_payload_header *bin;
95 struct user_key_payload *upayload;
96 unsigned long derrno;
97 int ret;
98 int datalen = prep->datalen, result_len = 0;
99 const char *data = prep->data, *end, *opt;
100
101 if (datalen <= 1 || !data)
102 return -EINVAL;
103
104 if (data[0] == 0) {
105
106 if (datalen <= sizeof(*bin))
107 return -EINVAL;
108
109 bin = (const struct dns_payload_header *)data;
110 kenter("[%u,%u],%u", bin->content, bin->version, datalen);
111 if (bin->content != DNS_PAYLOAD_IS_SERVER_LIST) {
112 pr_warn_ratelimited(
113 "dns_resolver: Unsupported content type (%u)\n",
114 bin->content);
115 return -EINVAL;
116 }
117
118 if (bin->version != 1) {
119 pr_warn_ratelimited(
120 "dns_resolver: Unsupported server list version (%u)\n",
121 bin->version);
122 return -EINVAL;
123 }
124
125 result_len = datalen;
126 goto store_result;
127 }
128
129 kenter("'%*.*s',%u", datalen, datalen, data, datalen);
130
131 if (!data || data[datalen - 1] != '\0')
132 return -EINVAL;
133 datalen--;
134
135
136 end = data + datalen;
137 opt = memchr(data, '#', datalen);
138 if (!opt) {
139
140 kdebug("no options");
141 result_len = datalen;
142 } else {
143 const char *next_opt;
144
145 result_len = opt - data;
146 opt++;
147 kdebug("options: '%s'", opt);
148 do {
149 int opt_len, opt_nlen;
150 const char *eq;
151 char optval[128];
152
153 next_opt = memchr(opt, '#', end - opt) ?: end;
154 opt_len = next_opt - opt;
155 if (opt_len <= 0 || opt_len > sizeof(optval)) {
156 pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n",
157 opt_len);
158 return -EINVAL;
159 }
160
161 eq = memchr(opt, '=', opt_len);
162 if (eq) {
163 opt_nlen = eq - opt;
164 eq++;
165 memcpy(optval, eq, next_opt - eq);
166 optval[next_opt - eq] = '\0';
167 } else {
168 opt_nlen = opt_len;
169 optval[0] = '\0';
170 }
171
172 kdebug("option '%*.*s' val '%s'",
173 opt_nlen, opt_nlen, opt, optval);
174
175
176
177 if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 &&
178 memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) {
179 kdebug("dns error number option");
180
181 ret = kstrtoul(optval, 10, &derrno);
182 if (ret < 0)
183 goto bad_option_value;
184
185 if (derrno < 1 || derrno > 511)
186 goto bad_option_value;
187
188 kdebug("dns error no. = %lu", derrno);
189 prep->payload.data[dns_key_error] = ERR_PTR(-derrno);
190 continue;
191 }
192
193 bad_option_value:
194 pr_warn_ratelimited("Option '%*.*s' to dns_resolver key: bad/missing value\n",
195 opt_nlen, opt_nlen, opt);
196 return -EINVAL;
197 } while (opt = next_opt + 1, opt < end);
198 }
199
200
201
202 if (prep->payload.data[dns_key_error]) {
203 kleave(" = 0 [h_error %ld]", PTR_ERR(prep->payload.data[dns_key_error]));
204 return 0;
205 }
206
207 store_result:
208 kdebug("store result");
209 prep->quotalen = result_len;
210
211 upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
212 if (!upayload) {
213 kleave(" = -ENOMEM");
214 return -ENOMEM;
215 }
216
217 upayload->datalen = result_len;
218 memcpy(upayload->data, data, result_len);
219 upayload->data[result_len] = '\0';
220
221 prep->payload.data[dns_key_data] = upayload;
222 kleave(" = 0");
223 return 0;
224 }
225
226
227
228
229 static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
230 {
231 pr_devel("==>%s()\n", __func__);
232
233 kfree(prep->payload.data[dns_key_data]);
234 }
235
236
237
238
239
240
241
242 static bool dns_resolver_cmp(const struct key *key,
243 const struct key_match_data *match_data)
244 {
245 int slen, dlen, ret = 0;
246 const char *src = key->description, *dsp = match_data->raw_data;
247
248 kenter("%s,%s", src, dsp);
249
250 if (!src || !dsp)
251 goto no_match;
252
253 if (strcasecmp(src, dsp) == 0)
254 goto matched;
255
256 slen = strlen(src);
257 dlen = strlen(dsp);
258 if (slen <= 0 || dlen <= 0)
259 goto no_match;
260 if (src[slen - 1] == '.')
261 slen--;
262 if (dsp[dlen - 1] == '.')
263 dlen--;
264 if (slen != dlen || strncasecmp(src, dsp, slen) != 0)
265 goto no_match;
266
267 matched:
268 ret = 1;
269 no_match:
270 kleave(" = %d", ret);
271 return ret;
272 }
273
274
275
276
277 static int dns_resolver_match_preparse(struct key_match_data *match_data)
278 {
279 match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
280 match_data->cmp = dns_resolver_cmp;
281 return 0;
282 }
283
284
285
286
287 static void dns_resolver_describe(const struct key *key, struct seq_file *m)
288 {
289 seq_puts(m, key->description);
290 if (key_is_positive(key)) {
291 int err = PTR_ERR(key->payload.data[dns_key_error]);
292
293 if (err)
294 seq_printf(m, ": %d", err);
295 else
296 seq_printf(m, ": %u", key->datalen);
297 }
298 }
299
300
301
302
303
304 static long dns_resolver_read(const struct key *key,
305 char *buffer, size_t buflen)
306 {
307 int err = PTR_ERR(key->payload.data[dns_key_error]);
308
309 if (err)
310 return err;
311
312 return user_read(key, buffer, buflen);
313 }
314
315 struct key_type key_type_dns_resolver = {
316 .name = "dns_resolver",
317 .flags = KEY_TYPE_NET_DOMAIN,
318 .preparse = dns_resolver_preparse,
319 .free_preparse = dns_resolver_free_preparse,
320 .instantiate = generic_key_instantiate,
321 .match_preparse = dns_resolver_match_preparse,
322 .revoke = user_revoke,
323 .destroy = user_destroy,
324 .describe = dns_resolver_describe,
325 .read = dns_resolver_read,
326 };
327
328 static int __init init_dns_resolver(void)
329 {
330 struct cred *cred;
331 struct key *keyring;
332 int ret;
333
334
335
336
337
338
339
340 cred = prepare_kernel_cred(NULL);
341 if (!cred)
342 return -ENOMEM;
343
344 keyring = keyring_alloc(".dns_resolver",
345 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
346 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
347 KEY_USR_VIEW | KEY_USR_READ,
348 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
349 if (IS_ERR(keyring)) {
350 ret = PTR_ERR(keyring);
351 goto failed_put_cred;
352 }
353
354 ret = register_key_type(&key_type_dns_resolver);
355 if (ret < 0)
356 goto failed_put_key;
357
358
359
360 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
361 cred->thread_keyring = keyring;
362 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
363 dns_resolver_cache = cred;
364
365 kdebug("DNS resolver keyring: %d\n", key_serial(keyring));
366 return 0;
367
368 failed_put_key:
369 key_put(keyring);
370 failed_put_cred:
371 put_cred(cred);
372 return ret;
373 }
374
375 static void __exit exit_dns_resolver(void)
376 {
377 key_revoke(dns_resolver_cache->thread_keyring);
378 unregister_key_type(&key_type_dns_resolver);
379 put_cred(dns_resolver_cache);
380 }
381
382 module_init(init_dns_resolver)
383 module_exit(exit_dns_resolver)
384 MODULE_LICENSE("GPL");