aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/dns_resolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/dns_resolve.c')
-rw-r--r--fs/cifs/dns_resolve.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 4db2c5e7283f..853a968e82d7 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -24,12 +24,16 @@
24 */ 24 */
25 25
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
27#include <keys/user-type.h> 29#include <keys/user-type.h>
28#include "dns_resolve.h" 30#include "dns_resolve.h"
29#include "cifsglob.h" 31#include "cifsglob.h"
30#include "cifsproto.h" 32#include "cifsproto.h"
31#include "cifs_debug.h" 33#include "cifs_debug.h"
32 34
35static const struct cred *dns_resolver_cache;
36
33/* Checks if supplied name is IP address 37/* Checks if supplied name is IP address
34 * returns: 38 * returns:
35 * 1 - name is IP 39 * 1 - name is IP
@@ -94,6 +98,7 @@ struct key_type key_type_dns_resolver = {
94int 98int
95dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) 99dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
96{ 100{
101 const struct cred *saved_cred;
97 int rc = -EAGAIN; 102 int rc = -EAGAIN;
98 struct key *rkey = ERR_PTR(-EAGAIN); 103 struct key *rkey = ERR_PTR(-EAGAIN);
99 char *name; 104 char *name;
@@ -133,8 +138,15 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
133 goto skip_upcall; 138 goto skip_upcall;
134 } 139 }
135 140
141 saved_cred = override_creds(dns_resolver_cache);
136 rkey = request_key(&key_type_dns_resolver, name, ""); 142 rkey = request_key(&key_type_dns_resolver, name, "");
143 revert_creds(saved_cred);
137 if (!IS_ERR(rkey)) { 144 if (!IS_ERR(rkey)) {
145 if (!(rkey->perm & KEY_USR_VIEW)) {
146 down_read(&rkey->sem);
147 rkey->perm |= KEY_USR_VIEW;
148 up_read(&rkey->sem);
149 }
138 len = rkey->type_data.x[0]; 150 len = rkey->type_data.x[0];
139 data = rkey->payload.data; 151 data = rkey->payload.data;
140 } else { 152 } else {
@@ -165,4 +177,61 @@ out:
165 return rc; 177 return rc;
166} 178}
167 179
180int __init cifs_init_dns_resolver(void)
181{
182 struct cred *cred;
183 struct key *keyring;
184 int ret;
185
186 printk(KERN_NOTICE "Registering the %s key type\n",
187 key_type_dns_resolver.name);
188
189 /* create an override credential set with a special thread keyring in
190 * which DNS requests are cached
191 *
192 * this is used to prevent malicious redirections from being installed
193 * with add_key().
194 */
195 cred = prepare_kernel_cred(NULL);
196 if (!cred)
197 return -ENOMEM;
198
199 keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
200 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
201 KEY_USR_VIEW | KEY_USR_READ,
202 KEY_ALLOC_NOT_IN_QUOTA);
203 if (IS_ERR(keyring)) {
204 ret = PTR_ERR(keyring);
205 goto failed_put_cred;
206 }
207
208 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
209 if (ret < 0)
210 goto failed_put_key;
211
212 ret = register_key_type(&key_type_dns_resolver);
213 if (ret < 0)
214 goto failed_put_key;
215
216 /* instruct request_key() to use this special keyring as a cache for
217 * the results it looks up */
218 cred->thread_keyring = keyring;
219 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
220 dns_resolver_cache = cred;
221 return 0;
222
223failed_put_key:
224 key_put(keyring);
225failed_put_cred:
226 put_cred(cred);
227 return ret;
228}
168 229
230void cifs_exit_dns_resolver(void)
231{
232 key_revoke(dns_resolver_cache->thread_keyring);
233 unregister_key_type(&key_type_dns_resolver);
234 put_cred(dns_resolver_cache);
235 printk(KERN_NOTICE "Unregistered %s key type\n",
236 key_type_dns_resolver.name);
237}