xref: /freebsd-src/sys/contrib/openzfs/module/os/linux/zfs/policy.c (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * CDDL HEADER START
3eda14cbcSMatt Macy  *
4eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy  *
8eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11eda14cbcSMatt Macy  * and limitations under the License.
12eda14cbcSMatt Macy  *
13eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy  *
19eda14cbcSMatt Macy  * CDDL HEADER END
20eda14cbcSMatt Macy  */
21eda14cbcSMatt Macy 
22eda14cbcSMatt Macy /*
23eda14cbcSMatt Macy  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24eda14cbcSMatt Macy  * Copyright 2013, Joyent, Inc. All rights reserved.
25eda14cbcSMatt Macy  * Copyright (C) 2016 Lawrence Livermore National Security, LLC.
26eda14cbcSMatt Macy  *
27eda14cbcSMatt Macy  * For Linux the vast majority of this enforcement is already handled via
28eda14cbcSMatt Macy  * the standard Linux VFS permission checks.  However certain administrative
29eda14cbcSMatt Macy  * commands which bypass the standard mechanisms may need to make use of
30eda14cbcSMatt Macy  * this functionality.
31eda14cbcSMatt Macy  */
32eda14cbcSMatt Macy 
33eda14cbcSMatt Macy #include <sys/policy.h>
34eda14cbcSMatt Macy #include <linux/security.h>
35eda14cbcSMatt Macy #include <linux/vfs_compat.h>
36eda14cbcSMatt Macy 
37eda14cbcSMatt Macy /*
38eda14cbcSMatt Macy  * The passed credentials cannot be directly verified because Linux only
39eda14cbcSMatt Macy  * provides and interface to check the *current* process credentials.  In
40eda14cbcSMatt Macy  * order to handle this the capable() test is only run when the passed
41eda14cbcSMatt Macy  * credentials match the current process credentials or the kcred.  In
42eda14cbcSMatt Macy  * all other cases this function must fail and return the passed err.
43eda14cbcSMatt Macy  */
44eda14cbcSMatt Macy static int
45eda14cbcSMatt Macy priv_policy_ns(const cred_t *cr, int capability, int err,
46eda14cbcSMatt Macy     struct user_namespace *ns)
47eda14cbcSMatt Macy {
48eda14cbcSMatt Macy 	if (cr != CRED() && (cr != kcred))
49eda14cbcSMatt Macy 		return (err);
50eda14cbcSMatt Macy 
51eda14cbcSMatt Macy #if defined(CONFIG_USER_NS)
52eda14cbcSMatt Macy 	if (!(ns ? ns_capable(ns, capability) : capable(capability)))
53eda14cbcSMatt Macy #else
54eda14cbcSMatt Macy 	if (!capable(capability))
55eda14cbcSMatt Macy #endif
56eda14cbcSMatt Macy 		return (err);
57eda14cbcSMatt Macy 
58eda14cbcSMatt Macy 	return (0);
59eda14cbcSMatt Macy }
60eda14cbcSMatt Macy 
61eda14cbcSMatt Macy static int
62eda14cbcSMatt Macy priv_policy(const cred_t *cr, int capability, int err)
63eda14cbcSMatt Macy {
641f1e2261SMartin Matuska 	return (priv_policy_ns(cr, capability, err, cr->user_ns));
65eda14cbcSMatt Macy }
66eda14cbcSMatt Macy 
67eda14cbcSMatt Macy static int
68eda14cbcSMatt Macy priv_policy_user(const cred_t *cr, int capability, int err)
69eda14cbcSMatt Macy {
70eda14cbcSMatt Macy 	/*
71eda14cbcSMatt Macy 	 * All priv_policy_user checks are preceded by kuid/kgid_has_mapping()
72eda14cbcSMatt Macy 	 * checks. If we cannot do them, we shouldn't be using ns_capable()
73eda14cbcSMatt Macy 	 * since we don't know whether the affected files are valid in our
74eda14cbcSMatt Macy 	 * namespace.
75eda14cbcSMatt Macy 	 */
76eda14cbcSMatt Macy #if defined(CONFIG_USER_NS)
77eda14cbcSMatt Macy 	return (priv_policy_ns(cr, capability, err, cr->user_ns));
78eda14cbcSMatt Macy #else
79eda14cbcSMatt Macy 	return (priv_policy_ns(cr, capability, err, NULL));
80eda14cbcSMatt Macy #endif
81eda14cbcSMatt Macy }
82eda14cbcSMatt Macy 
83eda14cbcSMatt Macy /*
84eda14cbcSMatt Macy  * Checks for operations that are either client-only or are used by
85eda14cbcSMatt Macy  * both clients and servers.
86eda14cbcSMatt Macy  */
87eda14cbcSMatt Macy int
88eda14cbcSMatt Macy secpolicy_nfs(const cred_t *cr)
89eda14cbcSMatt Macy {
90eda14cbcSMatt Macy 	return (priv_policy(cr, CAP_SYS_ADMIN, EPERM));
91eda14cbcSMatt Macy }
92eda14cbcSMatt Macy 
93eda14cbcSMatt Macy /*
94eda14cbcSMatt Macy  * Catch all system configuration.
95eda14cbcSMatt Macy  */
96eda14cbcSMatt Macy int
97eda14cbcSMatt Macy secpolicy_sys_config(const cred_t *cr, boolean_t checkonly)
98eda14cbcSMatt Macy {
99eda14cbcSMatt Macy 	return (priv_policy(cr, CAP_SYS_ADMIN, EPERM));
100eda14cbcSMatt Macy }
101eda14cbcSMatt Macy 
102eda14cbcSMatt Macy /*
103eda14cbcSMatt Macy  * Like secpolicy_vnode_access() but we get the actual wanted mode and the
104eda14cbcSMatt Macy  * current mode of the file, not the missing bits.
105eda14cbcSMatt Macy  *
106eda14cbcSMatt Macy  * Enforced in the Linux VFS.
107eda14cbcSMatt Macy  */
108eda14cbcSMatt Macy int
109eda14cbcSMatt Macy secpolicy_vnode_access2(const cred_t *cr, struct inode *ip, uid_t owner,
110eda14cbcSMatt Macy     mode_t curmode, mode_t wantmode)
111eda14cbcSMatt Macy {
112eda14cbcSMatt Macy 	return (0);
113eda14cbcSMatt Macy }
114eda14cbcSMatt Macy 
115eda14cbcSMatt Macy /*
116eda14cbcSMatt Macy  * This is a special routine for ZFS; it is used to determine whether
117eda14cbcSMatt Macy  * any of the privileges in effect allow any form of access to the
118eda14cbcSMatt Macy  * file.  There's no reason to audit this or any reason to record
119eda14cbcSMatt Macy  * this.  More work is needed to do the "KPLD" stuff.
120eda14cbcSMatt Macy  */
121eda14cbcSMatt Macy int
122eda14cbcSMatt Macy secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner)
123eda14cbcSMatt Macy {
124da5137abSMartin Matuska 	if (crgetuid(cr) == owner)
125eda14cbcSMatt Macy 		return (0);
126eda14cbcSMatt Macy 
127*d411c1d6SMartin Matuska 	if (zpl_inode_owner_or_capable(zfs_init_idmap, ip))
128eda14cbcSMatt Macy 		return (0);
129eda14cbcSMatt Macy 
130eda14cbcSMatt Macy #if defined(CONFIG_USER_NS)
131eda14cbcSMatt Macy 	if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
132eda14cbcSMatt Macy 		return (EPERM);
133eda14cbcSMatt Macy #endif
134eda14cbcSMatt Macy 
135eda14cbcSMatt Macy 	if (priv_policy_user(cr, CAP_DAC_OVERRIDE, EPERM) == 0)
136eda14cbcSMatt Macy 		return (0);
137eda14cbcSMatt Macy 
138eda14cbcSMatt Macy 	if (priv_policy_user(cr, CAP_DAC_READ_SEARCH, EPERM) == 0)
139eda14cbcSMatt Macy 		return (0);
140eda14cbcSMatt Macy 
141eda14cbcSMatt Macy 	return (EPERM);
142eda14cbcSMatt Macy }
143eda14cbcSMatt Macy 
144eda14cbcSMatt Macy /*
145eda14cbcSMatt Macy  * Determine if subject can chown owner of a file.
146eda14cbcSMatt Macy  */
147eda14cbcSMatt Macy int
148eda14cbcSMatt Macy secpolicy_vnode_chown(const cred_t *cr, uid_t owner)
149eda14cbcSMatt Macy {
150da5137abSMartin Matuska 	if (crgetuid(cr) == owner)
151eda14cbcSMatt Macy 		return (0);
152eda14cbcSMatt Macy 
153eda14cbcSMatt Macy #if defined(CONFIG_USER_NS)
154eda14cbcSMatt Macy 	if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
155eda14cbcSMatt Macy 		return (EPERM);
156eda14cbcSMatt Macy #endif
157eda14cbcSMatt Macy 
158eda14cbcSMatt Macy 	return (priv_policy_user(cr, CAP_FOWNER, EPERM));
159eda14cbcSMatt Macy }
160eda14cbcSMatt Macy 
161eda14cbcSMatt Macy /*
162eda14cbcSMatt Macy  * Determine if subject can change group ownership of a file.
163eda14cbcSMatt Macy  */
164eda14cbcSMatt Macy int
165eda14cbcSMatt Macy secpolicy_vnode_create_gid(const cred_t *cr)
166eda14cbcSMatt Macy {
167eda14cbcSMatt Macy 	return (priv_policy(cr, CAP_SETGID, EPERM));
168eda14cbcSMatt Macy }
169eda14cbcSMatt Macy 
170eda14cbcSMatt Macy /*
171eda14cbcSMatt Macy  * Policy determines whether we can remove an entry from a directory,
172eda14cbcSMatt Macy  * regardless of permission bits.
173eda14cbcSMatt Macy  */
174eda14cbcSMatt Macy int
175eda14cbcSMatt Macy secpolicy_vnode_remove(const cred_t *cr)
176eda14cbcSMatt Macy {
177eda14cbcSMatt Macy 	return (priv_policy(cr, CAP_FOWNER, EPERM));
178eda14cbcSMatt Macy }
179eda14cbcSMatt Macy 
180eda14cbcSMatt Macy /*
181eda14cbcSMatt Macy  * Determine that subject can modify the mode of a file.  allzone privilege
182eda14cbcSMatt Macy  * needed when modifying root owned object.
183eda14cbcSMatt Macy  */
184eda14cbcSMatt Macy int
185eda14cbcSMatt Macy secpolicy_vnode_setdac(const cred_t *cr, uid_t owner)
186eda14cbcSMatt Macy {
187da5137abSMartin Matuska 	if (crgetuid(cr) == owner)
188eda14cbcSMatt Macy 		return (0);
189eda14cbcSMatt Macy 
190eda14cbcSMatt Macy #if defined(CONFIG_USER_NS)
191eda14cbcSMatt Macy 	if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
192eda14cbcSMatt Macy 		return (EPERM);
193eda14cbcSMatt Macy #endif
194eda14cbcSMatt Macy 
195eda14cbcSMatt Macy 	return (priv_policy_user(cr, CAP_FOWNER, EPERM));
196eda14cbcSMatt Macy }
197eda14cbcSMatt Macy 
198eda14cbcSMatt Macy /*
199eda14cbcSMatt Macy  * Are we allowed to retain the set-uid/set-gid bits when
200eda14cbcSMatt Macy  * changing ownership or when writing to a file?
201eda14cbcSMatt Macy  * "issuid" should be true when set-uid; only in that case
202eda14cbcSMatt Macy  * root ownership is checked (setgid is assumed).
203eda14cbcSMatt Macy  *
204eda14cbcSMatt Macy  * Enforced in the Linux VFS.
205eda14cbcSMatt Macy  */
206eda14cbcSMatt Macy int
2077877fdebSMatt Macy secpolicy_vnode_setid_retain(struct znode *zp __maybe_unused, const cred_t *cr,
2087877fdebSMatt Macy     boolean_t issuidroot)
209eda14cbcSMatt Macy {
210eda14cbcSMatt Macy 	return (priv_policy_user(cr, CAP_FSETID, EPERM));
211eda14cbcSMatt Macy }
212eda14cbcSMatt Macy 
213eda14cbcSMatt Macy /*
214eda14cbcSMatt Macy  * Determine that subject can set the file setgid flag.
215eda14cbcSMatt Macy  */
216eda14cbcSMatt Macy int
217*d411c1d6SMartin Matuska secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zidmap_t *mnt_ns,
218*d411c1d6SMartin Matuska     struct user_namespace *fs_ns)
219eda14cbcSMatt Macy {
220dbd5678dSMartin Matuska 	gid = zfs_gid_to_vfsgid(mnt_ns, fs_ns, gid);
221eda14cbcSMatt Macy #if defined(CONFIG_USER_NS)
222eda14cbcSMatt Macy 	if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid)))
223eda14cbcSMatt Macy 		return (EPERM);
224eda14cbcSMatt Macy #endif
225da5137abSMartin Matuska 	if (crgetgid(cr) != gid && !groupmember(gid, cr))
226eda14cbcSMatt Macy 		return (priv_policy_user(cr, CAP_FSETID, EPERM));
227eda14cbcSMatt Macy 
228eda14cbcSMatt Macy 	return (0);
229eda14cbcSMatt Macy }
230eda14cbcSMatt Macy 
231eda14cbcSMatt Macy /*
232eda14cbcSMatt Macy  * Determine if the subject can inject faults in the ZFS fault injection
233eda14cbcSMatt Macy  * framework.  Requires all privileges.
234eda14cbcSMatt Macy  */
235eda14cbcSMatt Macy int
236eda14cbcSMatt Macy secpolicy_zinject(const cred_t *cr)
237eda14cbcSMatt Macy {
238eda14cbcSMatt Macy 	return (priv_policy(cr, CAP_SYS_ADMIN, EACCES));
239eda14cbcSMatt Macy }
240eda14cbcSMatt Macy 
241eda14cbcSMatt Macy /*
242eda14cbcSMatt Macy  * Determine if the subject has permission to manipulate ZFS datasets
243eda14cbcSMatt Macy  * (not pools).  Equivalent to the SYS_MOUNT privilege.
244eda14cbcSMatt Macy  */
245eda14cbcSMatt Macy int
246eda14cbcSMatt Macy secpolicy_zfs(const cred_t *cr)
247eda14cbcSMatt Macy {
248eda14cbcSMatt Macy 	return (priv_policy(cr, CAP_SYS_ADMIN, EACCES));
249eda14cbcSMatt Macy }
250eda14cbcSMatt Macy 
251eda14cbcSMatt Macy /*
252eda14cbcSMatt Macy  * Equivalent to secpolicy_zfs(), but works even if the cred_t is not that of
253eda14cbcSMatt Macy  * the current process.  Takes both cred_t and proc_t so that this can work
254eda14cbcSMatt Macy  * easily on all platforms.
255eda14cbcSMatt Macy  */
256eda14cbcSMatt Macy int
257eda14cbcSMatt Macy secpolicy_zfs_proc(const cred_t *cr, proc_t *proc)
258eda14cbcSMatt Macy {
259eda14cbcSMatt Macy 	if (!has_capability(proc, CAP_SYS_ADMIN))
260eda14cbcSMatt Macy 		return (EACCES);
261eda14cbcSMatt Macy 	return (0);
262eda14cbcSMatt Macy }
263eda14cbcSMatt Macy 
264eda14cbcSMatt Macy void
265eda14cbcSMatt Macy secpolicy_setid_clear(vattr_t *vap, cred_t *cr)
266eda14cbcSMatt Macy {
267eda14cbcSMatt Macy 	if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 &&
2687877fdebSMatt Macy 	    secpolicy_vnode_setid_retain(NULL, cr,
269eda14cbcSMatt Macy 	    (vap->va_mode & S_ISUID) != 0 &&
270eda14cbcSMatt Macy 	    (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) {
271eda14cbcSMatt Macy 		vap->va_mask |= AT_MODE;
272eda14cbcSMatt Macy 		vap->va_mode &= ~(S_ISUID|S_ISGID);
273eda14cbcSMatt Macy 	}
274eda14cbcSMatt Macy }
275eda14cbcSMatt Macy 
276eda14cbcSMatt Macy /*
277eda14cbcSMatt Macy  * Determine that subject can set the file setid flags.
278eda14cbcSMatt Macy  */
279eda14cbcSMatt Macy static int
280*d411c1d6SMartin Matuska secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zidmap_t *mnt_ns,
281*d411c1d6SMartin Matuska     struct user_namespace *fs_ns)
282eda14cbcSMatt Macy {
283dbd5678dSMartin Matuska 	owner = zfs_uid_to_vfsuid(mnt_ns, fs_ns, owner);
284dbd5678dSMartin Matuska 
285da5137abSMartin Matuska 	if (crgetuid(cr) == owner)
286eda14cbcSMatt Macy 		return (0);
287eda14cbcSMatt Macy 
288eda14cbcSMatt Macy #if defined(CONFIG_USER_NS)
289eda14cbcSMatt Macy 	if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
290eda14cbcSMatt Macy 		return (EPERM);
291eda14cbcSMatt Macy #endif
292eda14cbcSMatt Macy 
293eda14cbcSMatt Macy 	return (priv_policy_user(cr, CAP_FSETID, EPERM));
294eda14cbcSMatt Macy }
295eda14cbcSMatt Macy 
296eda14cbcSMatt Macy /*
297eda14cbcSMatt Macy  * Determine that subject can make a file a "sticky".
298eda14cbcSMatt Macy  *
299eda14cbcSMatt Macy  * Enforced in the Linux VFS.
300eda14cbcSMatt Macy  */
301eda14cbcSMatt Macy static int
302eda14cbcSMatt Macy secpolicy_vnode_stky_modify(const cred_t *cr)
303eda14cbcSMatt Macy {
304eda14cbcSMatt Macy 	return (0);
305eda14cbcSMatt Macy }
306eda14cbcSMatt Macy 
307eda14cbcSMatt Macy int
308eda14cbcSMatt Macy secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap,
309*d411c1d6SMartin Matuska     const vattr_t *ovap, cred_t *cr, zidmap_t *mnt_ns,
310*d411c1d6SMartin Matuska     struct user_namespace *fs_ns)
311eda14cbcSMatt Macy {
312eda14cbcSMatt Macy 	int error;
313eda14cbcSMatt Macy 
314eda14cbcSMatt Macy 	if ((vap->va_mode & S_ISUID) != 0 &&
315eda14cbcSMatt Macy 	    (error = secpolicy_vnode_setid_modify(cr,
316dbd5678dSMartin Matuska 	    ovap->va_uid, mnt_ns, fs_ns)) != 0) {
317eda14cbcSMatt Macy 		return (error);
318eda14cbcSMatt Macy 	}
319eda14cbcSMatt Macy 
320eda14cbcSMatt Macy 	/*
321eda14cbcSMatt Macy 	 * Check privilege if attempting to set the
322eda14cbcSMatt Macy 	 * sticky bit on a non-directory.
323eda14cbcSMatt Macy 	 */
324eda14cbcSMatt Macy 	if (!S_ISDIR(ip->i_mode) && (vap->va_mode & S_ISVTX) != 0 &&
325eda14cbcSMatt Macy 	    secpolicy_vnode_stky_modify(cr) != 0) {
326eda14cbcSMatt Macy 		vap->va_mode &= ~S_ISVTX;
327eda14cbcSMatt Macy 	}
328eda14cbcSMatt Macy 
329eda14cbcSMatt Macy 	/*
330eda14cbcSMatt Macy 	 * Check for privilege if attempting to set the
331eda14cbcSMatt Macy 	 * group-id bit.
332eda14cbcSMatt Macy 	 */
333eda14cbcSMatt Macy 	if ((vap->va_mode & S_ISGID) != 0 &&
334dbd5678dSMartin Matuska 	    secpolicy_vnode_setids_setgids(cr, ovap->va_gid,
335dbd5678dSMartin Matuska 	    mnt_ns, fs_ns) != 0) {
336eda14cbcSMatt Macy 		vap->va_mode &= ~S_ISGID;
337eda14cbcSMatt Macy 	}
338eda14cbcSMatt Macy 
339eda14cbcSMatt Macy 	return (0);
340eda14cbcSMatt Macy }
341eda14cbcSMatt Macy 
342eda14cbcSMatt Macy /*
343eda14cbcSMatt Macy  * Check privileges for setting xvattr attributes
344eda14cbcSMatt Macy  */
345eda14cbcSMatt Macy int
346eda14cbcSMatt Macy secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, mode_t type)
347eda14cbcSMatt Macy {
348eda14cbcSMatt Macy 	return (secpolicy_vnode_chown(cr, owner));
349eda14cbcSMatt Macy }
350eda14cbcSMatt Macy 
351eda14cbcSMatt Macy /*
352eda14cbcSMatt Macy  * Check privileges for setattr attributes.
353eda14cbcSMatt Macy  *
354eda14cbcSMatt Macy  * Enforced in the Linux VFS.
355eda14cbcSMatt Macy  */
356eda14cbcSMatt Macy int
357eda14cbcSMatt Macy secpolicy_vnode_setattr(cred_t *cr, struct inode *ip, struct vattr *vap,
358eda14cbcSMatt Macy     const struct vattr *ovap, int flags,
359eda14cbcSMatt Macy     int unlocked_access(void *, int, cred_t *), void *node)
360eda14cbcSMatt Macy {
361eda14cbcSMatt Macy 	return (0);
362eda14cbcSMatt Macy }
363eda14cbcSMatt Macy 
364eda14cbcSMatt Macy /*
365eda14cbcSMatt Macy  * Check privileges for links.
366eda14cbcSMatt Macy  *
367eda14cbcSMatt Macy  * Enforced in the Linux VFS.
368eda14cbcSMatt Macy  */
369eda14cbcSMatt Macy int
370eda14cbcSMatt Macy secpolicy_basic_link(const cred_t *cr)
371eda14cbcSMatt Macy {
372eda14cbcSMatt Macy 	return (0);
373eda14cbcSMatt Macy }
374