xref: /openbmc/linux/fs/afs/security.c (revision e868d61272caa648214046a096e5a6bfc068dc8c)
1 /* AFS security handling
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/init.h>
13 #include <linux/slab.h>
14 #include <linux/fs.h>
15 #include <linux/ctype.h>
16 #include <keys/rxrpc-type.h>
17 #include "internal.h"
18 
19 /*
20  * get a key
21  */
22 struct key *afs_request_key(struct afs_cell *cell)
23 {
24 	struct key *key;
25 
26 	_enter("{%x}", key_serial(cell->anonymous_key));
27 
28 	_debug("key %s", cell->anonymous_key->description);
29 	key = request_key(&key_type_rxrpc, cell->anonymous_key->description,
30 			  NULL);
31 	if (IS_ERR(key)) {
32 		if (PTR_ERR(key) != -ENOKEY) {
33 			_leave(" = %ld", PTR_ERR(key));
34 			return key;
35 		}
36 
37 		/* act as anonymous user */
38 		_leave(" = {%x} [anon]", key_serial(cell->anonymous_key));
39 		return key_get(cell->anonymous_key);
40 	} else {
41 		/* act as authorised user */
42 		_leave(" = {%x} [auth]", key_serial(key));
43 		return key;
44 	}
45 }
46 
47 /*
48  * dispose of a permits list
49  */
50 void afs_zap_permits(struct rcu_head *rcu)
51 {
52 	struct afs_permits *permits =
53 		container_of(rcu, struct afs_permits, rcu);
54 	int loop;
55 
56 	_enter("{%d}", permits->count);
57 
58 	for (loop = permits->count - 1; loop >= 0; loop--)
59 		key_put(permits->permits[loop].key);
60 	kfree(permits);
61 }
62 
63 /*
64  * dispose of a permits list in which all the key pointers have been copied
65  */
66 static void afs_dispose_of_permits(struct rcu_head *rcu)
67 {
68 	struct afs_permits *permits =
69 		container_of(rcu, struct afs_permits, rcu);
70 
71 	_enter("{%d}", permits->count);
72 
73 	kfree(permits);
74 }
75 
76 /*
77  * get the authorising vnode - this is the specified inode itself if it's a
78  * directory or it's the parent directory if the specified inode is a file or
79  * symlink
80  * - the caller must release the ref on the inode
81  */
82 static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode,
83 					    struct key *key)
84 {
85 	struct afs_vnode *auth_vnode;
86 	struct inode *auth_inode;
87 
88 	_enter("");
89 
90 	if (S_ISDIR(vnode->vfs_inode.i_mode)) {
91 		auth_inode = igrab(&vnode->vfs_inode);
92 		ASSERT(auth_inode != NULL);
93 	} else {
94 		auth_inode = afs_iget(vnode->vfs_inode.i_sb, key,
95 				      &vnode->status.parent, NULL, NULL);
96 		if (IS_ERR(auth_inode))
97 			return ERR_PTR(PTR_ERR(auth_inode));
98 	}
99 
100 	auth_vnode = AFS_FS_I(auth_inode);
101 	_leave(" = {%x}", auth_vnode->fid.vnode);
102 	return auth_vnode;
103 }
104 
105 /*
106  * clear the permit cache on a directory vnode
107  */
108 void afs_clear_permits(struct afs_vnode *vnode)
109 {
110 	struct afs_permits *permits;
111 
112 	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
113 
114 	mutex_lock(&vnode->permits_lock);
115 	permits = vnode->permits;
116 	rcu_assign_pointer(vnode->permits, NULL);
117 	mutex_unlock(&vnode->permits_lock);
118 
119 	if (permits)
120 		call_rcu(&permits->rcu, afs_zap_permits);
121 	_leave("");
122 }
123 
124 /*
125  * add the result obtained for a vnode to its or its parent directory's cache
126  * for the key used to access it
127  */
128 void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order)
129 {
130 	struct afs_permits *permits, *xpermits;
131 	struct afs_permit *permit;
132 	struct afs_vnode *auth_vnode;
133 	int count, loop;
134 
135 	_enter("{%x:%u},%x,%lx",
136 	       vnode->fid.vid, vnode->fid.vnode, key_serial(key), acl_order);
137 
138 	auth_vnode = afs_get_auth_inode(vnode, key);
139 	if (IS_ERR(auth_vnode)) {
140 		_leave(" [get error %ld]", PTR_ERR(auth_vnode));
141 		return;
142 	}
143 
144 	mutex_lock(&auth_vnode->permits_lock);
145 
146 	/* guard against a rename being detected whilst we waited for the
147 	 * lock */
148 	if (memcmp(&auth_vnode->fid, &vnode->status.parent,
149 		   sizeof(struct afs_fid)) != 0) {
150 		_debug("renamed");
151 		goto out_unlock;
152 	}
153 
154 	/* have to be careful as the directory's callback may be broken between
155 	 * us receiving the status we're trying to cache and us getting the
156 	 * lock to update the cache for the status */
157 	if (auth_vnode->acl_order - acl_order > 0) {
158 		_debug("ACL changed?");
159 		goto out_unlock;
160 	}
161 
162 	/* always update the anonymous mask */
163 	_debug("anon access %x", vnode->status.anon_access);
164 	auth_vnode->status.anon_access = vnode->status.anon_access;
165 	if (key == vnode->volume->cell->anonymous_key)
166 		goto out_unlock;
167 
168 	xpermits = auth_vnode->permits;
169 	count = 0;
170 	if (xpermits) {
171 		/* see if the permit is already in the list
172 		 * - if it is then we just amend the list
173 		 */
174 		count = xpermits->count;
175 		permit = xpermits->permits;
176 		for (loop = count; loop > 0; loop--) {
177 			if (permit->key == key) {
178 				permit->access_mask =
179 					vnode->status.caller_access;
180 				goto out_unlock;
181 			}
182 			permit++;
183 		}
184 	}
185 
186 	permits = kmalloc(sizeof(*permits) + sizeof(*permit) * (count + 1),
187 			  GFP_NOFS);
188 	if (!permits)
189 		goto out_unlock;
190 
191 	memcpy(permits->permits, xpermits->permits,
192 	       count * sizeof(struct afs_permit));
193 
194 	_debug("key %x access %x",
195 	       key_serial(key), vnode->status.caller_access);
196 	permits->permits[count].access_mask = vnode->status.caller_access;
197 	permits->permits[count].key = key_get(key);
198 	permits->count = count + 1;
199 
200 	rcu_assign_pointer(auth_vnode->permits, permits);
201 	if (xpermits)
202 		call_rcu(&xpermits->rcu, afs_dispose_of_permits);
203 
204 out_unlock:
205 	mutex_unlock(&auth_vnode->permits_lock);
206 	iput(&auth_vnode->vfs_inode);
207 	_leave("");
208 }
209 
210 /*
211  * check with the fileserver to see if the directory or parent directory is
212  * permitted to be accessed with this authorisation, and if so, what access it
213  * is granted
214  */
215 static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
216 			    afs_access_t *_access)
217 {
218 	struct afs_permits *permits;
219 	struct afs_permit *permit;
220 	struct afs_vnode *auth_vnode;
221 	bool valid;
222 	int loop, ret;
223 
224 	_enter("{%x:%u},%x",
225 	       vnode->fid.vid, vnode->fid.vnode, key_serial(key));
226 
227 	auth_vnode = afs_get_auth_inode(vnode, key);
228 	if (IS_ERR(auth_vnode)) {
229 		*_access = 0;
230 		_leave(" = %ld", PTR_ERR(auth_vnode));
231 		return PTR_ERR(auth_vnode);
232 	}
233 
234 	ASSERT(S_ISDIR(auth_vnode->vfs_inode.i_mode));
235 
236 	/* check the permits to see if we've got one yet */
237 	if (key == auth_vnode->volume->cell->anonymous_key) {
238 		_debug("anon");
239 		*_access = auth_vnode->status.anon_access;
240 		valid = true;
241 	} else {
242 		valid = false;
243 		rcu_read_lock();
244 		permits = rcu_dereference(auth_vnode->permits);
245 		if (permits) {
246 			permit = permits->permits;
247 			for (loop = permits->count; loop > 0; loop--) {
248 				if (permit->key == key) {
249 					_debug("found in cache");
250 					*_access = permit->access_mask;
251 					valid = true;
252 					break;
253 				}
254 				permit++;
255 			}
256 		}
257 		rcu_read_unlock();
258 	}
259 
260 	if (!valid) {
261 		/* check the status on the file we're actually interested in
262 		 * (the post-processing will cache the result on auth_vnode) */
263 		_debug("no valid permit");
264 
265 		set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
266 		ret = afs_vnode_fetch_status(vnode, auth_vnode, key);
267 		if (ret < 0) {
268 			iput(&auth_vnode->vfs_inode);
269 			*_access = 0;
270 			_leave(" = %d", ret);
271 			return ret;
272 		}
273 		*_access = vnode->status.caller_access;
274 	}
275 
276 	iput(&auth_vnode->vfs_inode);
277 	_leave(" = 0 [access %x]", *_access);
278 	return 0;
279 }
280 
281 /*
282  * check the permissions on an AFS file
283  * - AFS ACLs are attached to directories only, and a file is controlled by its
284  *   parent directory's ACL
285  */
286 int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
287 {
288 	struct afs_vnode *vnode = AFS_FS_I(inode);
289 	afs_access_t access;
290 	struct key *key;
291 	int ret;
292 
293 	_enter("{{%x:%u},%lx},%x,",
294 	       vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
295 
296 	key = afs_request_key(vnode->volume->cell);
297 	if (IS_ERR(key)) {
298 		_leave(" = %ld [key]", PTR_ERR(key));
299 		return PTR_ERR(key);
300 	}
301 
302 	/* if the promise has expired, we need to check the server again */
303 	if (!vnode->cb_promised) {
304 		_debug("not promised");
305 		ret = afs_vnode_fetch_status(vnode, NULL, key);
306 		if (ret < 0)
307 			goto error;
308 		_debug("new promise [fl=%lx]", vnode->flags);
309 	}
310 
311 	/* check the permits to see if we've got one yet */
312 	ret = afs_check_permit(vnode, key, &access);
313 	if (ret < 0)
314 		goto error;
315 
316 	/* interpret the access mask */
317 	_debug("REQ %x ACC %x on %s",
318 	       mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file");
319 
320 	if (S_ISDIR(inode->i_mode)) {
321 		if (mask & MAY_EXEC) {
322 			if (!(access & AFS_ACE_LOOKUP))
323 				goto permission_denied;
324 		} else if (mask & MAY_READ) {
325 			if (!(access & AFS_ACE_READ))
326 				goto permission_denied;
327 		} else if (mask & MAY_WRITE) {
328 			if (!(access & (AFS_ACE_DELETE | /* rmdir, unlink, rename from */
329 					AFS_ACE_INSERT | /* create, mkdir, symlink, rename to */
330 					AFS_ACE_WRITE))) /* chmod */
331 				goto permission_denied;
332 		} else {
333 			BUG();
334 		}
335 	} else {
336 		if (!(access & AFS_ACE_LOOKUP))
337 			goto permission_denied;
338 		if (mask & (MAY_EXEC | MAY_READ)) {
339 			if (!(access & AFS_ACE_READ))
340 				goto permission_denied;
341 		} else if (mask & MAY_WRITE) {
342 			if (!(access & AFS_ACE_WRITE))
343 				goto permission_denied;
344 		}
345 	}
346 
347 	key_put(key);
348 	ret = generic_permission(inode, mask, NULL);
349 	_leave(" = %d", ret);
350 	return ret;
351 
352 permission_denied:
353 	ret = -EACCES;
354 error:
355 	key_put(key);
356 	_leave(" = %d", ret);
357 	return ret;
358 }
359