aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsacl.c138
-rw-r--r--fs/cifs/cifsfs.c29
-rw-r--r--fs/cifs/cifsglob.h5
-rw-r--r--fs/cifs/cifsproto.h3
4 files changed, 167 insertions, 8 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index a0d11eab14e5..061fc3afd841 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -23,6 +23,10 @@
23 23
24#include <linux/fs.h> 24#include <linux/fs.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
26#include "cifspdu.h" 30#include "cifspdu.h"
27#include "cifsglob.h" 31#include "cifsglob.h"
28#include "cifsacl.h" 32#include "cifsacl.h"
@@ -50,6 +54,140 @@ static const struct cifs_sid sid_authusers = {
50/* group users */ 54/* group users */
51static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; 55static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
52 56
57static const struct cred *root_cred;
58
59/*
60 * Run idmap cache shrinker.
61 */
62static int
63cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
64{
65 /* Use a pruning scheme in a subsequent patch instead */
66 cifs_destroy_idmaptrees();
67 return 0;
68}
69
70static struct shrinker cifs_shrinker = {
71 .shrink = cifs_idmap_shrinker,
72 .seeks = DEFAULT_SEEKS,
73};
74
75static int
76cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
77{
78 char *payload;
79
80 payload = kmalloc(datalen, GFP_KERNEL);
81 if (!payload)
82 return -ENOMEM;
83
84 memcpy(payload, data, datalen);
85 key->payload.data = payload;
86 return 0;
87}
88
89static inline void
90cifs_idmap_key_destroy(struct key *key)
91{
92 kfree(key->payload.data);
93}
94
95static
96struct key_type cifs_idmap_key_type = {
97 .name = "cifs.cifs_idmap",
98 .instantiate = cifs_idmap_key_instantiate,
99 .destroy = cifs_idmap_key_destroy,
100 .describe = user_describe,
101 .match = user_match,
102};
103
104int
105init_cifs_idmap(void)
106{
107 struct cred *cred;
108 struct key *keyring;
109 int ret;
110
111 cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
112
113 /* create an override credential set with a special thread keyring in
114 * which requests are cached
115 *
116 * this is used to prevent malicious redirections from being installed
117 * with add_key().
118 */
119 cred = prepare_kernel_cred(NULL);
120 if (!cred)
121 return -ENOMEM;
122
123 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
124 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
125 KEY_USR_VIEW | KEY_USR_READ,
126 KEY_ALLOC_NOT_IN_QUOTA);
127 if (IS_ERR(keyring)) {
128 ret = PTR_ERR(keyring);
129 goto failed_put_cred;
130 }
131
132 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
133 if (ret < 0)
134 goto failed_put_key;
135
136 ret = register_key_type(&cifs_idmap_key_type);
137 if (ret < 0)
138 goto failed_put_key;
139
140 /* instruct request_key() to use this special keyring as a cache for
141 * the results it looks up */
142 cred->thread_keyring = keyring;
143 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
144 root_cred = cred;
145
146 spin_lock_init(&siduidlock);
147 uidtree = RB_ROOT;
148 spin_lock_init(&sidgidlock);
149 gidtree = RB_ROOT;
150
151 register_shrinker(&cifs_shrinker);
152
153 cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
154 return 0;
155
156failed_put_key:
157 key_put(keyring);
158failed_put_cred:
159 put_cred(cred);
160 return ret;
161}
162
163void
164exit_cifs_idmap(void)
165{
166 key_revoke(root_cred->thread_keyring);
167 unregister_key_type(&cifs_idmap_key_type);
168 put_cred(root_cred);
169 unregister_shrinker(&cifs_shrinker);
170 cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
171}
172
173void
174cifs_destroy_idmaptrees(void)
175{
176 struct rb_root *root;
177 struct rb_node *node;
178
179 root = &uidtree;
180 spin_lock(&siduidlock);
181 while ((node = rb_first(root)))
182 rb_erase(node, root);
183 spin_unlock(&siduidlock);
184
185 root = &gidtree;
186 spin_lock(&sidgidlock);
187 while ((node = rb_first(root)))
188 rb_erase(node, root);
189 spin_unlock(&sidgidlock);
190}
53 191
54int match_sid(struct cifs_sid *ctsid) 192int match_sid(struct cifs_sid *ctsid)
55{ 193{
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 30fc505b7ef1..6c1d738418f1 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1033,22 +1033,31 @@ init_cifs(void)
1033 if (rc) 1033 if (rc)
1034 goto out_destroy_mids; 1034 goto out_destroy_mids;
1035 1035
1036 rc = register_filesystem(&cifs_fs_type);
1037 if (rc)
1038 goto out_destroy_request_bufs;
1039#ifdef CONFIG_CIFS_UPCALL 1036#ifdef CONFIG_CIFS_UPCALL
1040 rc = register_key_type(&cifs_spnego_key_type); 1037 rc = register_key_type(&cifs_spnego_key_type);
1041 if (rc) 1038 if (rc)
1042 goto out_unregister_filesystem; 1039 goto out_destroy_request_bufs;
1043#endif 1040#endif /* CONFIG_CIFS_UPCALL */
1041
1042#ifdef CONFIG_CIFS_ACL
1043 rc = init_cifs_idmap();
1044 if (rc)
1045 goto out_destroy_request_bufs;
1046#endif /* CONFIG_CIFS_ACL */
1047
1048 rc = register_filesystem(&cifs_fs_type);
1049 if (rc)
1050 goto out_destroy_request_bufs;
1044 1051
1045 return 0; 1052 return 0;
1046 1053
1054out_destroy_request_bufs:
1055#ifdef CONFIG_CIFS_ACL
1056 exit_cifs_idmap();
1057#endif
1047#ifdef CONFIG_CIFS_UPCALL 1058#ifdef CONFIG_CIFS_UPCALL
1048out_unregister_filesystem: 1059 unregister_key_type(&cifs_spnego_key_type);
1049 unregister_filesystem(&cifs_fs_type);
1050#endif 1060#endif
1051out_destroy_request_bufs:
1052 cifs_destroy_request_bufs(); 1061 cifs_destroy_request_bufs();
1053out_destroy_mids: 1062out_destroy_mids:
1054 cifs_destroy_mids(); 1063 cifs_destroy_mids();
@@ -1070,6 +1079,10 @@ exit_cifs(void)
1070#ifdef CONFIG_CIFS_DFS_UPCALL 1079#ifdef CONFIG_CIFS_DFS_UPCALL
1071 cifs_dfs_release_automount_timer(); 1080 cifs_dfs_release_automount_timer();
1072#endif 1081#endif
1082#ifdef CONFIG_CIFS_ACL
1083 cifs_destroy_idmaptrees();
1084 exit_cifs_idmap();
1085#endif
1073#ifdef CONFIG_CIFS_UPCALL 1086#ifdef CONFIG_CIFS_UPCALL
1074 unregister_key_type(&cifs_spnego_key_type); 1087 unregister_key_type(&cifs_spnego_key_type);
1075#endif 1088#endif
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 108a1e99aa9f..76b4517e74b0 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -833,6 +833,11 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
833/* reconnect after this many failed echo attempts */ 833/* reconnect after this many failed echo attempts */
834GLOBAL_EXTERN unsigned short echo_retries; 834GLOBAL_EXTERN unsigned short echo_retries;
835 835
836GLOBAL_EXTERN struct rb_root uidtree;
837GLOBAL_EXTERN struct rb_root gidtree;
838GLOBAL_EXTERN spinlock_t siduidlock;
839GLOBAL_EXTERN spinlock_t sidgidlock;
840
836void cifs_oplock_break(struct work_struct *work); 841void cifs_oplock_break(struct work_struct *work);
837void cifs_oplock_break_get(struct cifsFileInfo *cfile); 842void cifs_oplock_break_get(struct cifsFileInfo *cfile);
838void cifs_oplock_break_put(struct cifsFileInfo *cfile); 843void cifs_oplock_break_put(struct cifsFileInfo *cfile);
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0e4e057e2891..7c1ed01d03f8 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -53,6 +53,9 @@ do { \
53 cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \ 53 cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \
54 __func__, curr_xid, (int)rc); \ 54 __func__, curr_xid, (int)rc); \
55} while (0) 55} while (0)
56extern int init_cifs_idmap(void);
57extern void exit_cifs_idmap(void);
58extern void cifs_destroy_idmaptrees(void);
56extern char *build_path_from_dentry(struct dentry *); 59extern char *build_path_from_dentry(struct dentry *);
57extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, 60extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
58 struct cifsTconInfo *tcon); 61 struct cifsTconInfo *tcon);