aboutsummaryrefslogtreecommitdiffstats
path: root/net/dns_resolver
diff options
context:
space:
mode:
Diffstat (limited to 'net/dns_resolver')
-rw-r--r--net/dns_resolver/dns_key.c92
-rw-r--r--net/dns_resolver/dns_query.c5
2 files changed, 92 insertions, 5 deletions
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index 400a04d5c9a1..739435a6af39 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -29,6 +29,7 @@
29#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/keyctl.h> 30#include <linux/keyctl.h>
31#include <linux/err.h> 31#include <linux/err.h>
32#include <linux/seq_file.h>
32#include <keys/dns_resolver-type.h> 33#include <keys/dns_resolver-type.h>
33#include <keys/user-type.h> 34#include <keys/user-type.h>
34#include "internal.h" 35#include "internal.h"
@@ -43,6 +44,8 @@ MODULE_PARM_DESC(debug, "DNS Resolver debugging mask");
43 44
44const struct cred *dns_resolver_cache; 45const struct cred *dns_resolver_cache;
45 46
47#define DNS_ERRORNO_OPTION "dnserror"
48
46/* 49/*
47 * Instantiate a user defined key for dns_resolver. 50 * Instantiate a user defined key for dns_resolver.
48 * 51 *
@@ -59,9 +62,10 @@ static int
59dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen) 62dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
60{ 63{
61 struct user_key_payload *upayload; 64 struct user_key_payload *upayload;
65 unsigned long derrno;
62 int ret; 66 int ret;
63 size_t result_len = 0; 67 size_t result_len = 0;
64 const char *data = _data, *opt; 68 const char *data = _data, *end, *opt;
65 69
66 kenter("%%%d,%s,'%s',%zu", 70 kenter("%%%d,%s,'%s',%zu",
67 key->serial, key->description, data, datalen); 71 key->serial, key->description, data, datalen);
@@ -71,13 +75,77 @@ dns_resolver_instantiate(struct key *key, const void *_data, size_t datalen)
71 datalen--; 75 datalen--;
72 76
73 /* deal with any options embedded in the data */ 77 /* deal with any options embedded in the data */
78 end = data + datalen;
74 opt = memchr(data, '#', datalen); 79 opt = memchr(data, '#', datalen);
75 if (!opt) { 80 if (!opt) {
76 kdebug("no options currently supported"); 81 /* no options: the entire data is the result */
77 return -EINVAL; 82 kdebug("no options");
83 result_len = datalen;
84 } else {
85 const char *next_opt;
86
87 result_len = opt - data;
88 opt++;
89 kdebug("options: '%s'", opt);
90 do {
91 const char *eq;
92 int opt_len, opt_nlen, opt_vlen, tmp;
93
94 next_opt = memchr(opt, '#', end - opt) ?: end;
95 opt_len = next_opt - opt;
96 if (!opt_len) {
97 printk(KERN_WARNING
98 "Empty option to dns_resolver key %d\n",
99 key->serial);
100 return -EINVAL;
101 }
102
103 eq = memchr(opt, '=', opt_len) ?: end;
104 opt_nlen = eq - opt;
105 eq++;
106 opt_vlen = next_opt - eq; /* will be -1 if no value */
107
108 tmp = opt_vlen >= 0 ? opt_vlen : 0;
109 kdebug("option '%*.*s' val '%*.*s'",
110 opt_nlen, opt_nlen, opt, tmp, tmp, eq);
111
112 /* see if it's an error number representing a DNS error
113 * that's to be recorded as the result in this key */
114 if (opt_nlen == sizeof(DNS_ERRORNO_OPTION) - 1 &&
115 memcmp(opt, DNS_ERRORNO_OPTION, opt_nlen) == 0) {
116 kdebug("dns error number option");
117 if (opt_vlen <= 0)
118 goto bad_option_value;
119
120 ret = strict_strtoul(eq, 10, &derrno);
121 if (ret < 0)
122 goto bad_option_value;
123
124 if (derrno < 1 || derrno > 511)
125 goto bad_option_value;
126
127 kdebug("dns error no. = %lu", derrno);
128 key->type_data.x[0] = -derrno;
129 continue;
130 }
131
132 bad_option_value:
133 printk(KERN_WARNING
134 "Option '%*.*s' to dns_resolver key %d:"
135 " bad/missing value\n",
136 opt_nlen, opt_nlen, opt, key->serial);
137 return -EINVAL;
138 } while (opt = next_opt + 1, opt < end);
139 }
140
141 /* don't cache the result if we're caching an error saying there's no
142 * result */
143 if (key->type_data.x[0]) {
144 kleave(" = 0 [h_error %ld]", key->type_data.x[0]);
145 return 0;
78 } 146 }
79 147
80 result_len = datalen; 148 kdebug("store result");
81 ret = key_payload_reserve(key, result_len); 149 ret = key_payload_reserve(key, result_len);
82 if (ret < 0) 150 if (ret < 0)
83 return -EINVAL; 151 return -EINVAL;
@@ -135,13 +203,27 @@ no_match:
135 return ret; 203 return ret;
136} 204}
137 205
206/*
207 * Describe a DNS key
208 */
209static void dns_resolver_describe(const struct key *key, struct seq_file *m)
210{
211 int err = key->type_data.x[0];
212
213 seq_puts(m, key->description);
214 if (err)
215 seq_printf(m, ": %d", err);
216 else
217 seq_printf(m, ": %u", key->datalen);
218}
219
138struct key_type key_type_dns_resolver = { 220struct key_type key_type_dns_resolver = {
139 .name = "dns_resolver", 221 .name = "dns_resolver",
140 .instantiate = dns_resolver_instantiate, 222 .instantiate = dns_resolver_instantiate,
141 .match = dns_resolver_match, 223 .match = dns_resolver_match,
142 .revoke = user_revoke, 224 .revoke = user_revoke,
143 .destroy = user_destroy, 225 .destroy = user_destroy,
144 .describe = user_describe, 226 .describe = dns_resolver_describe,
145 .read = user_read, 227 .read = user_read,
146}; 228};
147 229
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c
index 03d5255f5cf2..c32be292c7e3 100644
--- a/net/dns_resolver/dns_query.c
+++ b/net/dns_resolver/dns_query.c
@@ -136,6 +136,11 @@ int dns_query(const char *type, const char *name, size_t namelen,
136 if (ret < 0) 136 if (ret < 0)
137 goto put; 137 goto put;
138 138
139 /* If the DNS server gave an error, return that to the caller */
140 ret = rkey->type_data.x[0];
141 if (ret)
142 goto put;
143
139 upayload = rcu_dereference_protected(rkey->payload.data, 144 upayload = rcu_dereference_protected(rkey->payload.data,
140 lockdep_is_held(&rkey->sem)); 145 lockdep_is_held(&rkey->sem));
141 len = upayload->datalen; 146 len = upayload->datalen;