0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/module.h>
0025 #include <linux/moduleparam.h>
0026 #include <linux/slab.h>
0027 #include <linux/string.h>
0028 #include <linux/kernel.h>
0029 #include <linux/keyctl.h>
0030 #include <linux/err.h>
0031 #include <linux/seq_file.h>
0032 #include <linux/dns_resolver.h>
0033 #include <keys/dns_resolver-type.h>
0034 #include <keys/user-type.h>
0035 #include "internal.h"
0036
0037 MODULE_DESCRIPTION("DNS Resolver");
0038 MODULE_AUTHOR("Wang Lei");
0039 MODULE_LICENSE("GPL");
0040
0041 unsigned int dns_resolver_debug;
0042 module_param_named(debug, dns_resolver_debug, uint, 0644);
0043 MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
0044
0045 const struct cred *dns_resolver_cache;
0046
0047 #define DNS_ERRORNO_OPTION "dnserror"
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091 static int
0092 dns_resolver_preparse(struct key_preparsed_payload *prep)
0093 {
0094 const struct dns_payload_header *bin;
0095 struct user_key_payload *upayload;
0096 unsigned long derrno;
0097 int ret;
0098 int datalen = prep->datalen, result_len = 0;
0099 const char *data = prep->data, *end, *opt;
0100
0101 if (datalen <= 1 || !data)
0102 return -EINVAL;
0103
0104 if (data[0] == 0) {
0105
0106 if (datalen <= sizeof(*bin))
0107 return -EINVAL;
0108
0109 bin = (const struct dns_payload_header *)data;
0110 kenter("[%u,%u],%u", bin->content, bin->version, datalen);
0111 if (bin->content != DNS_PAYLOAD_IS_SERVER_LIST) {
0112 pr_warn_ratelimited(
0113 "dns_resolver: Unsupported content type (%u)\n",
0114 bin->content);
0115 return -EINVAL;
0116 }
0117
0118 if (bin->version != 1) {
0119 pr_warn_ratelimited(
0120 "dns_resolver: Unsupported server list version (%u)\n",
0121 bin->version);
0122 return -EINVAL;
0123 }
0124
0125 result_len = datalen;
0126 goto store_result;
0127 }
0128
0129 kenter("'%*.*s',%u", datalen, datalen, data, datalen);
0130
0131 if (!data || data[datalen - 1] != '\0')
0132 return -EINVAL;
0133 datalen--;
0134
0135
0136 end = data + datalen;
0137 opt = memchr(data, '#', datalen);
0138 if (!opt) {
0139
0140 kdebug("no options");
0141 result_len = datalen;
0142 } else {
0143 const char *next_opt;
0144
0145 result_len = opt - data;
0146 opt++;
0147 kdebug("options: '%s'", opt);
0148 do {
0149 int opt_len, opt_nlen;
0150 const char *eq;
0151 char optval[128];
0152
0153 next_opt = memchr(opt, '#', end - opt) ?: end;
0154 opt_len = next_opt - opt;
0155 if (opt_len <= 0 || opt_len > sizeof(optval)) {
0156 pr_warn_ratelimited("Invalid option length (%d) for dns_resolver key\n",
0157 opt_len);
0158 return -EINVAL;
0159 }
0160
0161 eq = memchr(opt, '=', opt_len);
0162 if (eq) {
0163 opt_nlen = eq - opt;
0164 eq++;
0165 memcpy(optval, eq, next_opt - eq);
0166 optval[next_opt - eq] = '\0';
0167 } else {
0168 opt_nlen = opt_len;
0169 optval[0] = '\0';
0170 }
0171
0172 kdebug("option '%*.*s' val '%s'",
0173 opt_nlen, opt_nlen, opt, optval);
0174
0175
0176
0177 if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 &&
0178 memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) {
0179 kdebug("dns error number option");
0180
0181 ret = kstrtoul(optval, 10, &derrno);
0182 if (ret < 0)
0183 goto bad_option_value;
0184
0185 if (derrno < 1 || derrno > 511)
0186 goto bad_option_value;
0187
0188 kdebug("dns error no. = %lu", derrno);
0189 prep->payload.data[dns_key_error] = ERR_PTR(-derrno);
0190 continue;
0191 }
0192
0193 bad_option_value:
0194 pr_warn_ratelimited("Option '%*.*s' to dns_resolver key: bad/missing value\n",
0195 opt_nlen, opt_nlen, opt);
0196 return -EINVAL;
0197 } while (opt = next_opt + 1, opt < end);
0198 }
0199
0200
0201
0202 if (prep->payload.data[dns_key_error]) {
0203 kleave(" = 0 [h_error %ld]", PTR_ERR(prep->payload.data[dns_key_error]));
0204 return 0;
0205 }
0206
0207 store_result:
0208 kdebug("store result");
0209 prep->quotalen = result_len;
0210
0211 upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
0212 if (!upayload) {
0213 kleave(" = -ENOMEM");
0214 return -ENOMEM;
0215 }
0216
0217 upayload->datalen = result_len;
0218 memcpy(upayload->data, data, result_len);
0219 upayload->data[result_len] = '\0';
0220
0221 prep->payload.data[dns_key_data] = upayload;
0222 kleave(" = 0");
0223 return 0;
0224 }
0225
0226
0227
0228
0229 static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
0230 {
0231 pr_devel("==>%s()\n", __func__);
0232
0233 kfree(prep->payload.data[dns_key_data]);
0234 }
0235
0236
0237
0238
0239
0240
0241
0242 static bool dns_resolver_cmp(const struct key *key,
0243 const struct key_match_data *match_data)
0244 {
0245 int slen, dlen, ret = 0;
0246 const char *src = key->description, *dsp = match_data->raw_data;
0247
0248 kenter("%s,%s", src, dsp);
0249
0250 if (!src || !dsp)
0251 goto no_match;
0252
0253 if (strcasecmp(src, dsp) == 0)
0254 goto matched;
0255
0256 slen = strlen(src);
0257 dlen = strlen(dsp);
0258 if (slen <= 0 || dlen <= 0)
0259 goto no_match;
0260 if (src[slen - 1] == '.')
0261 slen--;
0262 if (dsp[dlen - 1] == '.')
0263 dlen--;
0264 if (slen != dlen || strncasecmp(src, dsp, slen) != 0)
0265 goto no_match;
0266
0267 matched:
0268 ret = 1;
0269 no_match:
0270 kleave(" = %d", ret);
0271 return ret;
0272 }
0273
0274
0275
0276
0277 static int dns_resolver_match_preparse(struct key_match_data *match_data)
0278 {
0279 match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
0280 match_data->cmp = dns_resolver_cmp;
0281 return 0;
0282 }
0283
0284
0285
0286
0287 static void dns_resolver_describe(const struct key *key, struct seq_file *m)
0288 {
0289 seq_puts(m, key->description);
0290 if (key_is_positive(key)) {
0291 int err = PTR_ERR(key->payload.data[dns_key_error]);
0292
0293 if (err)
0294 seq_printf(m, ": %d", err);
0295 else
0296 seq_printf(m, ": %u", key->datalen);
0297 }
0298 }
0299
0300
0301
0302
0303
0304 static long dns_resolver_read(const struct key *key,
0305 char *buffer, size_t buflen)
0306 {
0307 int err = PTR_ERR(key->payload.data[dns_key_error]);
0308
0309 if (err)
0310 return err;
0311
0312 return user_read(key, buffer, buflen);
0313 }
0314
0315 struct key_type key_type_dns_resolver = {
0316 .name = "dns_resolver",
0317 .flags = KEY_TYPE_NET_DOMAIN,
0318 .preparse = dns_resolver_preparse,
0319 .free_preparse = dns_resolver_free_preparse,
0320 .instantiate = generic_key_instantiate,
0321 .match_preparse = dns_resolver_match_preparse,
0322 .revoke = user_revoke,
0323 .destroy = user_destroy,
0324 .describe = dns_resolver_describe,
0325 .read = dns_resolver_read,
0326 };
0327
0328 static int __init init_dns_resolver(void)
0329 {
0330 struct cred *cred;
0331 struct key *keyring;
0332 int ret;
0333
0334
0335
0336
0337
0338
0339
0340 cred = prepare_kernel_cred(NULL);
0341 if (!cred)
0342 return -ENOMEM;
0343
0344 keyring = keyring_alloc(".dns_resolver",
0345 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
0346 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
0347 KEY_USR_VIEW | KEY_USR_READ,
0348 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
0349 if (IS_ERR(keyring)) {
0350 ret = PTR_ERR(keyring);
0351 goto failed_put_cred;
0352 }
0353
0354 ret = register_key_type(&key_type_dns_resolver);
0355 if (ret < 0)
0356 goto failed_put_key;
0357
0358
0359
0360 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
0361 cred->thread_keyring = keyring;
0362 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
0363 dns_resolver_cache = cred;
0364
0365 kdebug("DNS resolver keyring: %d\n", key_serial(keyring));
0366 return 0;
0367
0368 failed_put_key:
0369 key_put(keyring);
0370 failed_put_cred:
0371 put_cred(cred);
0372 return ret;
0373 }
0374
0375 static void __exit exit_dns_resolver(void)
0376 {
0377 key_revoke(dns_resolver_cache->thread_keyring);
0378 unregister_key_type(&key_type_dns_resolver);
0379 put_cred(dns_resolver_cache);
0380 }
0381
0382 module_init(init_dns_resolver)
0383 module_exit(exit_dns_resolver)
0384 MODULE_LICENSE("GPL");