xref: /linux-6.15/fs/cachefiles/security.c (revision e5a8b644)
1254947d4SDavid Howells // SPDX-License-Identifier: GPL-2.0-or-later
2254947d4SDavid Howells /* CacheFiles security management
3254947d4SDavid Howells  *
4254947d4SDavid Howells  * Copyright (C) 2007, 2021 Red Hat, Inc. All Rights Reserved.
5254947d4SDavid Howells  * Written by David Howells ([email protected])
6254947d4SDavid Howells  */
7254947d4SDavid Howells 
8254947d4SDavid Howells #include <linux/fs.h>
9254947d4SDavid Howells #include <linux/cred.h>
10254947d4SDavid Howells #include "internal.h"
11254947d4SDavid Howells 
12254947d4SDavid Howells /*
13254947d4SDavid Howells  * determine the security context within which we access the cache from within
14254947d4SDavid Howells  * the kernel
15254947d4SDavid Howells  */
cachefiles_get_security_ID(struct cachefiles_cache * cache)16254947d4SDavid Howells int cachefiles_get_security_ID(struct cachefiles_cache *cache)
17254947d4SDavid Howells {
18254947d4SDavid Howells 	struct cred *new;
19254947d4SDavid Howells 	int ret;
20254947d4SDavid Howells 
21*e5a8b644SMax Kellermann 	_enter("{%u}", cache->have_secid ? cache->secid : 0);
22254947d4SDavid Howells 
23254947d4SDavid Howells 	new = prepare_kernel_cred(current);
24254947d4SDavid Howells 	if (!new) {
25254947d4SDavid Howells 		ret = -ENOMEM;
26254947d4SDavid Howells 		goto error;
27254947d4SDavid Howells 	}
28254947d4SDavid Howells 
29*e5a8b644SMax Kellermann 	if (cache->have_secid) {
30*e5a8b644SMax Kellermann 		ret = set_security_override(new, cache->secid);
31254947d4SDavid Howells 		if (ret < 0) {
32254947d4SDavid Howells 			put_cred(new);
33254947d4SDavid Howells 			pr_err("Security denies permission to nominate security context: error %d\n",
34254947d4SDavid Howells 			       ret);
35254947d4SDavid Howells 			goto error;
36254947d4SDavid Howells 		}
37254947d4SDavid Howells 	}
38254947d4SDavid Howells 
39254947d4SDavid Howells 	cache->cache_cred = new;
40254947d4SDavid Howells 	ret = 0;
41254947d4SDavid Howells error:
42254947d4SDavid Howells 	_leave(" = %d", ret);
43254947d4SDavid Howells 	return ret;
44254947d4SDavid Howells }
45254947d4SDavid Howells 
46254947d4SDavid Howells /*
47254947d4SDavid Howells  * see if mkdir and create can be performed in the root directory
48254947d4SDavid Howells  */
cachefiles_check_cache_dir(struct cachefiles_cache * cache,struct dentry * root)49254947d4SDavid Howells static int cachefiles_check_cache_dir(struct cachefiles_cache *cache,
50254947d4SDavid Howells 				      struct dentry *root)
51254947d4SDavid Howells {
52254947d4SDavid Howells 	int ret;
53254947d4SDavid Howells 
54254947d4SDavid Howells 	ret = security_inode_mkdir(d_backing_inode(root), root, 0);
55254947d4SDavid Howells 	if (ret < 0) {
56254947d4SDavid Howells 		pr_err("Security denies permission to make dirs: error %d",
57254947d4SDavid Howells 		       ret);
58254947d4SDavid Howells 		return ret;
59254947d4SDavid Howells 	}
60254947d4SDavid Howells 
61254947d4SDavid Howells 	ret = security_inode_create(d_backing_inode(root), root, 0);
62254947d4SDavid Howells 	if (ret < 0)
63254947d4SDavid Howells 		pr_err("Security denies permission to create files: error %d",
64254947d4SDavid Howells 		       ret);
65254947d4SDavid Howells 
66254947d4SDavid Howells 	return ret;
67254947d4SDavid Howells }
68254947d4SDavid Howells 
69254947d4SDavid Howells /*
70254947d4SDavid Howells  * check the security details of the on-disk cache
71254947d4SDavid Howells  * - must be called with security override in force
72254947d4SDavid Howells  * - must return with a security override in force - even in the case of an
73254947d4SDavid Howells  *   error
74254947d4SDavid Howells  */
cachefiles_determine_cache_security(struct cachefiles_cache * cache,struct dentry * root,const struct cred ** _saved_cred)75254947d4SDavid Howells int cachefiles_determine_cache_security(struct cachefiles_cache *cache,
76254947d4SDavid Howells 					struct dentry *root,
77254947d4SDavid Howells 					const struct cred **_saved_cred)
78254947d4SDavid Howells {
79254947d4SDavid Howells 	struct cred *new;
80254947d4SDavid Howells 	int ret;
81254947d4SDavid Howells 
82254947d4SDavid Howells 	_enter("");
83254947d4SDavid Howells 
84254947d4SDavid Howells 	/* duplicate the cache creds for COW (the override is currently in
85254947d4SDavid Howells 	 * force, so we can use prepare_creds() to do this) */
86254947d4SDavid Howells 	new = prepare_creds();
87254947d4SDavid Howells 	if (!new)
88254947d4SDavid Howells 		return -ENOMEM;
89254947d4SDavid Howells 
90254947d4SDavid Howells 	cachefiles_end_secure(cache, *_saved_cred);
91254947d4SDavid Howells 
92254947d4SDavid Howells 	/* use the cache root dir's security context as the basis with
93254947d4SDavid Howells 	 * which create files */
94254947d4SDavid Howells 	ret = set_create_files_as(new, d_backing_inode(root));
95254947d4SDavid Howells 	if (ret < 0) {
96254947d4SDavid Howells 		abort_creds(new);
97254947d4SDavid Howells 		cachefiles_begin_secure(cache, _saved_cred);
98254947d4SDavid Howells 		_leave(" = %d [cfa]", ret);
99254947d4SDavid Howells 		return ret;
100254947d4SDavid Howells 	}
101254947d4SDavid Howells 
102254947d4SDavid Howells 	put_cred(cache->cache_cred);
103254947d4SDavid Howells 	cache->cache_cred = new;
104254947d4SDavid Howells 
105254947d4SDavid Howells 	cachefiles_begin_secure(cache, _saved_cred);
106254947d4SDavid Howells 	ret = cachefiles_check_cache_dir(cache, root);
107254947d4SDavid Howells 
108254947d4SDavid Howells 	if (ret == -EOPNOTSUPP)
109254947d4SDavid Howells 		ret = 0;
110254947d4SDavid Howells 	_leave(" = %d", ret);
111254947d4SDavid Howells 	return ret;
112254947d4SDavid Howells }
113