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