aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsfs.c6
-rw-r--r--fs/cifs/dns_resolve.c69
-rw-r--r--fs/cifs/dns_resolve.h4
3 files changed, 74 insertions, 5 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 484e52bb40b..2cb1a70214d 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -923,7 +923,7 @@ init_cifs(void)
923 goto out_unregister_filesystem; 923 goto out_unregister_filesystem;
924#endif 924#endif
925#ifdef CONFIG_CIFS_DFS_UPCALL 925#ifdef CONFIG_CIFS_DFS_UPCALL
926 rc = register_key_type(&key_type_dns_resolver); 926 rc = cifs_init_dns_resolver();
927 if (rc) 927 if (rc)
928 goto out_unregister_key_type; 928 goto out_unregister_key_type;
929#endif 929#endif
@@ -935,7 +935,7 @@ init_cifs(void)
935 935
936 out_unregister_resolver_key: 936 out_unregister_resolver_key:
937#ifdef CONFIG_CIFS_DFS_UPCALL 937#ifdef CONFIG_CIFS_DFS_UPCALL
938 unregister_key_type(&key_type_dns_resolver); 938 cifs_exit_dns_resolver();
939 out_unregister_key_type: 939 out_unregister_key_type:
940#endif 940#endif
941#ifdef CONFIG_CIFS_UPCALL 941#ifdef CONFIG_CIFS_UPCALL
@@ -961,7 +961,7 @@ exit_cifs(void)
961 cifs_proc_clean(); 961 cifs_proc_clean();
962#ifdef CONFIG_CIFS_DFS_UPCALL 962#ifdef CONFIG_CIFS_DFS_UPCALL
963 cifs_dfs_release_automount_timer(); 963 cifs_dfs_release_automount_timer();
964 unregister_key_type(&key_type_dns_resolver); 964 cifs_exit_dns_resolver();
965#endif 965#endif
966#ifdef CONFIG_CIFS_UPCALL 966#ifdef CONFIG_CIFS_UPCALL
967 unregister_key_type(&cifs_spnego_key_type); 967 unregister_key_type(&cifs_spnego_key_type);
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index 4db2c5e7283..49315cbf742 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 __exit 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}
diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h
index 966e9288930..26b9eaa9f5e 100644
--- a/fs/cifs/dns_resolve.h
+++ b/fs/cifs/dns_resolve.h
@@ -24,8 +24,8 @@
24#define _DNS_RESOLVE_H 24#define _DNS_RESOLVE_H
25 25
26#ifdef __KERNEL__ 26#ifdef __KERNEL__
27#include <linux/key-type.h> 27extern int __init cifs_init_dns_resolver(void);
28extern struct key_type key_type_dns_resolver; 28extern void __exit cifs_exit_dns_resolver(void);
29extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr); 29extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
30#endif /* KERNEL */ 30#endif /* KERNEL */
31 31