diff options
-rw-r--r-- | fs/cifs/cifsacl.c | 138 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 29 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 3 |
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 */ |
51 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; | 55 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; |
52 | 56 | ||
57 | static const struct cred *root_cred; | ||
58 | |||
59 | /* | ||
60 | * Run idmap cache shrinker. | ||
61 | */ | ||
62 | static int | ||
63 | cifs_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 | |||
70 | static struct shrinker cifs_shrinker = { | ||
71 | .shrink = cifs_idmap_shrinker, | ||
72 | .seeks = DEFAULT_SEEKS, | ||
73 | }; | ||
74 | |||
75 | static int | ||
76 | cifs_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 | |||
89 | static inline void | ||
90 | cifs_idmap_key_destroy(struct key *key) | ||
91 | { | ||
92 | kfree(key->payload.data); | ||
93 | } | ||
94 | |||
95 | static | ||
96 | struct 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 | |||
104 | int | ||
105 | init_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 | |||
156 | failed_put_key: | ||
157 | key_put(keyring); | ||
158 | failed_put_cred: | ||
159 | put_cred(cred); | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | void | ||
164 | exit_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 | |||
173 | void | ||
174 | cifs_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 | ||
54 | int match_sid(struct cifs_sid *ctsid) | 192 | int 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 | ||
1054 | out_destroy_request_bufs: | ||
1055 | #ifdef CONFIG_CIFS_ACL | ||
1056 | exit_cifs_idmap(); | ||
1057 | #endif | ||
1047 | #ifdef CONFIG_CIFS_UPCALL | 1058 | #ifdef CONFIG_CIFS_UPCALL |
1048 | out_unregister_filesystem: | 1059 | unregister_key_type(&cifs_spnego_key_type); |
1049 | unregister_filesystem(&cifs_fs_type); | ||
1050 | #endif | 1060 | #endif |
1051 | out_destroy_request_bufs: | ||
1052 | cifs_destroy_request_bufs(); | 1061 | cifs_destroy_request_bufs(); |
1053 | out_destroy_mids: | 1062 | out_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 */ |
834 | GLOBAL_EXTERN unsigned short echo_retries; | 834 | GLOBAL_EXTERN unsigned short echo_retries; |
835 | 835 | ||
836 | GLOBAL_EXTERN struct rb_root uidtree; | ||
837 | GLOBAL_EXTERN struct rb_root gidtree; | ||
838 | GLOBAL_EXTERN spinlock_t siduidlock; | ||
839 | GLOBAL_EXTERN spinlock_t sidgidlock; | ||
840 | |||
836 | void cifs_oplock_break(struct work_struct *work); | 841 | void cifs_oplock_break(struct work_struct *work); |
837 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); | 842 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); |
838 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); | 843 | void 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) |
56 | extern int init_cifs_idmap(void); | ||
57 | extern void exit_cifs_idmap(void); | ||
58 | extern void cifs_destroy_idmaptrees(void); | ||
56 | extern char *build_path_from_dentry(struct dentry *); | 59 | extern char *build_path_from_dentry(struct dentry *); |
57 | extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, | 60 | extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, |
58 | struct cifsTconInfo *tcon); | 61 | struct cifsTconInfo *tcon); |