1// SPDX-License-Identifier: GPL-2.0-or-later
2/* CacheFiles security management
3 *
4 * Copyright (C) 2007, 2021 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 */
7
8#include <linux/fs.h>
9#include <linux/cred.h>
10#include "internal.h"
11
12/*
13 * determine the security context within which we access the cache from within
14 * the kernel
15 */
16int cachefiles_get_security_ID(struct cachefiles_cache *cache)
17{
18	struct cred *new;
19	int ret;
20
21	_enter("{%s}", cache->secctx);
22
23	new = prepare_kernel_cred(current);
24	if (!new) {
25		ret = -ENOMEM;
26		goto error;
27	}
28
29	if (cache->secctx) {
30		ret = set_security_override_from_ctx(new, cache->secctx);
31		if (ret < 0) {
32			put_cred(new);
33			pr_err("Security denies permission to nominate security context: error %d\n",
34			       ret);
35			goto error;
36		}
37	}
38
39	cache->cache_cred = new;
40	ret = 0;
41error:
42	_leave(" = %d", ret);
43	return ret;
44}
45
46/*
47 * see if mkdir and create can be performed in the root directory
48 */
49static int cachefiles_check_cache_dir(struct cachefiles_cache *cache,
50				      struct dentry *root)
51{
52	int ret;
53
54	ret = security_inode_mkdir(d_backing_inode(root), root, 0);
55	if (ret < 0) {
56		pr_err("Security denies permission to make dirs: error %d",
57		       ret);
58		return ret;
59	}
60
61	ret = security_inode_create(d_backing_inode(root), root, 0);
62	if (ret < 0)
63		pr_err("Security denies permission to create files: error %d",
64		       ret);
65
66	return ret;
67}
68
69/*
70 * check the security details of the on-disk cache
71 * - must be called with security override in force
72 * - must return with a security override in force - even in the case of an
73 *   error
74 */
75int cachefiles_determine_cache_security(struct cachefiles_cache *cache,
76					struct dentry *root,
77					const struct cred **_saved_cred)
78{
79	struct cred *new;
80	int ret;
81
82	_enter("");
83
84	/* duplicate the cache creds for COW (the override is currently in
85	 * force, so we can use prepare_creds() to do this) */
86	new = prepare_creds();
87	if (!new)
88		return -ENOMEM;
89
90	cachefiles_end_secure(cache, *_saved_cred);
91
92	/* use the cache root dir's security context as the basis with
93	 * which create files */
94	ret = set_create_files_as(new, d_backing_inode(root));
95	if (ret < 0) {
96		abort_creds(new);
97		cachefiles_begin_secure(cache, _saved_cred);
98		_leave(" = %d [cfa]", ret);
99		return ret;
100	}
101
102	put_cred(cache->cache_cred);
103	cache->cache_cred = new;
104
105	cachefiles_begin_secure(cache, _saved_cred);
106	ret = cachefiles_check_cache_dir(cache, root);
107
108	if (ret == -EOPNOTSUPP)
109		ret = 0;
110	_leave(" = %d", ret);
111	return ret;
112}
113