1/*
2 * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include <sys/types.h>
31#include <sys/param.h>
32#include <sys/priv.h>
33#include <sys/vnode.h>
34#include <sys/mntent.h>
35#include <sys/mount.h>
36#include <sys/stat.h>
37#include <sys/jail.h>
38#include <sys/policy.h>
39#include <sys/zfs_vfsops.h>
40#include <sys/zfs_znode.h>
41
42
43int
44secpolicy_nfs(cred_t *cr)
45{
46
47	return (spl_priv_check_cred(cr, PRIV_NFS_DAEMON));
48}
49
50int
51secpolicy_zfs(cred_t *cr)
52{
53
54	return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT));
55}
56
57int
58secpolicy_zfs_proc(cred_t *cr, proc_t *proc)
59{
60
61	return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT));
62}
63
64int
65secpolicy_sys_config(cred_t *cr, int checkonly __unused)
66{
67
68	return (spl_priv_check_cred(cr, PRIV_ZFS_POOL_CONFIG));
69}
70
71int
72secpolicy_zinject(cred_t *cr)
73{
74
75	return (spl_priv_check_cred(cr, PRIV_ZFS_INJECT));
76}
77
78int
79secpolicy_fs_unmount(cred_t *cr, struct mount *vfsp __unused)
80{
81
82	return (spl_priv_check_cred(cr, PRIV_VFS_UNMOUNT));
83}
84
85int
86secpolicy_fs_owner(struct mount *mp, cred_t *cr)
87{
88
89	if (zfs_super_owner) {
90		if (cr->cr_uid == mp->mnt_cred->cr_uid &&
91		    cr->cr_prison == mp->mnt_cred->cr_prison) {
92			return (0);
93		}
94	}
95	return (EPERM);
96}
97
98/*
99 * This check is done in kern_link(), so we could just return 0 here.
100 */
101extern int hardlink_check_uid;
102int
103secpolicy_basic_link(vnode_t *vp, cred_t *cr)
104{
105
106	if (!hardlink_check_uid)
107		return (0);
108	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
109		return (0);
110	return (spl_priv_check_cred(cr, PRIV_VFS_LINK));
111}
112
113int
114secpolicy_vnode_stky_modify(cred_t *cr)
115{
116
117	return (EPERM);
118}
119
120int
121secpolicy_vnode_remove(vnode_t *vp, cred_t *cr)
122{
123
124	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
125		return (0);
126	return (spl_priv_check_cred(cr, PRIV_VFS_ADMIN));
127}
128
129int
130secpolicy_vnode_access(cred_t *cr, vnode_t *vp, uid_t owner, accmode_t accmode)
131{
132
133	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
134		return (0);
135
136	if ((accmode & VREAD) && spl_priv_check_cred(cr, PRIV_VFS_READ) != 0)
137		return (EACCES);
138	if ((accmode & VWRITE) &&
139	    spl_priv_check_cred(cr, PRIV_VFS_WRITE) != 0) {
140		return (EACCES);
141	}
142	if (accmode & VEXEC) {
143		if (vp->v_type == VDIR) {
144			if (spl_priv_check_cred(cr, PRIV_VFS_LOOKUP) != 0)
145				return (EACCES);
146		} else {
147			if (spl_priv_check_cred(cr, PRIV_VFS_EXEC) != 0)
148				return (EACCES);
149		}
150	}
151	return (0);
152}
153
154/*
155 * Like secpolicy_vnode_access() but we get the actual wanted mode and the
156 * current mode of the file, not the missing bits.
157 */
158int
159secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner,
160    accmode_t curmode, accmode_t wantmode)
161{
162	accmode_t mode;
163
164	mode = ~curmode & wantmode;
165
166	if (mode == 0)
167		return (0);
168
169	return (secpolicy_vnode_access(cr, vp, owner, mode));
170}
171
172int
173secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner)
174{
175	static int privs[] = {
176	    PRIV_VFS_ADMIN,
177	    PRIV_VFS_READ,
178	    PRIV_VFS_WRITE,
179	    PRIV_VFS_EXEC,
180	    PRIV_VFS_LOOKUP
181	};
182	int i;
183
184	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
185		return (0);
186
187	/* Same as secpolicy_vnode_setdac */
188	if (owner == cr->cr_uid)
189		return (0);
190
191	for (i = 0; i < sizeof (privs)/sizeof (int); i++) {
192		int priv;
193
194		switch (priv = privs[i]) {
195		case PRIV_VFS_EXEC:
196			if (vp->v_type == VDIR)
197				continue;
198			break;
199		case PRIV_VFS_LOOKUP:
200			if (vp->v_type != VDIR)
201				continue;
202			break;
203		}
204		if (spl_priv_check_cred(cr, priv) == 0)
205			return (0);
206	}
207	return (EPERM);
208}
209
210int
211secpolicy_vnode_setdac(vnode_t *vp, cred_t *cr, uid_t owner)
212{
213
214	if (owner == cr->cr_uid)
215		return (0);
216	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
217		return (0);
218	return (spl_priv_check_cred(cr, PRIV_VFS_ADMIN));
219}
220
221int
222secpolicy_vnode_setattr(cred_t *cr, vnode_t *vp, struct vattr *vap,
223    const struct vattr *ovap, int flags,
224    int unlocked_access(void *, int, cred_t *), void *node)
225{
226	int mask = vap->va_mask;
227	int error;
228
229	if (mask & AT_SIZE) {
230		if (vp->v_type == VDIR)
231			return (EISDIR);
232		error = unlocked_access(node, VWRITE, cr);
233		if (error)
234			return (error);
235	}
236	if (mask & AT_MODE) {
237		/*
238		 * If not the owner of the file then check privilege
239		 * for two things: the privilege to set the mode at all
240		 * and, if we're setting setuid, we also need permissions
241		 * to add the set-uid bit, if we're not the owner.
242		 * In the specific case of creating a set-uid root
243		 * file, we need even more permissions.
244		 */
245		error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
246		if (error)
247			return (error);
248		error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cr);
249		if (error)
250			return (error);
251	} else {
252		vap->va_mode = ovap->va_mode;
253	}
254	if (mask & (AT_UID | AT_GID)) {
255		error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
256		if (error)
257			return (error);
258
259		/*
260		 * To change the owner of a file, or change the group of
261		 * a file to a group of which we are not a member, the
262		 * caller must have privilege.
263		 */
264		if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
265		    ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
266		    !groupmember(vap->va_gid, cr))) {
267			if (secpolicy_fs_owner(vp->v_mount, cr) != 0) {
268				error = spl_priv_check_cred(cr, PRIV_VFS_CHOWN);
269				if (error)
270					return (error);
271			}
272		}
273
274		if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
275		    ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) {
276			secpolicy_setid_clear(vap, vp, cr);
277		}
278	}
279	if (mask & (AT_ATIME | AT_MTIME)) {
280		/*
281		 * From utimes(2):
282		 * If times is NULL, ... The caller must be the owner of
283		 * the file, have permission to write the file, or be the
284		 * super-user.
285		 * If times is non-NULL, ... The caller must be the owner of
286		 * the file or be the super-user.
287		 */
288		error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
289		if (error && (vap->va_vaflags & VA_UTIMES_NULL))
290			error = unlocked_access(node, VWRITE, cr);
291		if (error)
292			return (error);
293	}
294	return (0);
295}
296
297int
298secpolicy_vnode_create_gid(cred_t *cr)
299{
300
301	return (EPERM);
302}
303
304int
305secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cr, gid_t gid)
306{
307
308	if (groupmember(gid, cr))
309		return (0);
310	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
311		return (0);
312	return (spl_priv_check_cred(cr, PRIV_VFS_SETGID));
313}
314
315int
316secpolicy_vnode_setid_retain(znode_t *zp, cred_t *cr,
317    boolean_t issuidroot __unused)
318{
319
320	if (secpolicy_fs_owner(ZTOV(zp)->v_mount, cr) == 0)
321		return (0);
322	return (spl_priv_check_cred(cr, PRIV_VFS_RETAINSUGID));
323}
324
325void
326secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cr)
327{
328
329	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
330		return;
331
332	if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
333		if (spl_priv_check_cred(cr, PRIV_VFS_RETAINSUGID)) {
334			vap->va_mask |= AT_MODE;
335			vap->va_mode &= ~(S_ISUID|S_ISGID);
336		}
337	}
338}
339
340int
341secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap,
342    const struct vattr *ovap, cred_t *cr)
343{
344	int error;
345
346	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
347		return (0);
348
349	/*
350	 * Privileged processes may set the sticky bit on non-directories,
351	 * as well as set the setgid bit on a file with a group that the process
352	 * is not a member of. Both of these are allowed in jail(8).
353	 */
354	if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
355		if (spl_priv_check_cred(cr, PRIV_VFS_STICKYFILE))
356			return (EFTYPE);
357	}
358	/*
359	 * Check for privilege if attempting to set the
360	 * group-id bit.
361	 */
362	if ((vap->va_mode & S_ISGID) != 0) {
363		error = secpolicy_vnode_setids_setgids(vp, cr, ovap->va_gid);
364		if (error)
365			return (error);
366	}
367	/*
368	 * Deny setting setuid if we are not the file owner.
369	 */
370	if ((vap->va_mode & S_ISUID) && ovap->va_uid != cr->cr_uid) {
371		error = spl_priv_check_cred(cr, PRIV_VFS_ADMIN);
372		if (error)
373			return (error);
374	}
375	return (0);
376}
377
378int
379secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp)
380{
381
382	return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT));
383}
384
385int
386secpolicy_vnode_owner(vnode_t *vp, cred_t *cr, uid_t owner)
387{
388
389	if (owner == cr->cr_uid)
390		return (0);
391	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
392		return (0);
393
394	/* XXX: vfs_suser()? */
395	return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT_OWNER));
396}
397
398int
399secpolicy_vnode_chown(vnode_t *vp, cred_t *cr, uid_t owner)
400{
401
402	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
403		return (0);
404	return (spl_priv_check_cred(cr, PRIV_VFS_CHOWN));
405}
406
407void
408secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp)
409{
410
411	if (spl_priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER) != 0) {
412		MNT_ILOCK(vfsp);
413		vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER;
414		vfs_clearmntopt(vfsp, MNTOPT_SETUID);
415		vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0);
416		MNT_IUNLOCK(vfsp);
417	}
418}
419
420/*
421 * Check privileges for setting xvattr attributes
422 */
423int
424secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cr,
425    vtype_t vtype)
426{
427
428	if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
429		return (0);
430	return (spl_priv_check_cred(cr, PRIV_VFS_SYSFLAGS));
431}
432
433int
434secpolicy_smb(cred_t *cr)
435{
436
437	return (spl_priv_check_cred(cr, PRIV_NETSMB));
438}
439