opensolaris_policy.c revision 184413
1168404Spjd/*-
2168404Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3168404Spjd * All rights reserved.
4168404Spjd *
5168404Spjd * Redistribution and use in source and binary forms, with or without
6168404Spjd * modification, are permitted provided that the following conditions
7168404Spjd * are met:
8168404Spjd * 1. Redistributions of source code must retain the above copyright
9168404Spjd *    notice, this list of conditions and the following disclaimer.
10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
11168404Spjd *    notice, this list of conditions and the following disclaimer in the
12168404Spjd *    documentation and/or other materials provided with the distribution.
13168404Spjd *
14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24168404Spjd * SUCH DAMAGE.
25168404Spjd */
26168404Spjd
27168404Spjd#include <sys/cdefs.h>
28168404Spjd__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c 184413 2008-10-28 13:44:11Z trasz $");
29168404Spjd
30168404Spjd#include <sys/param.h>
31168404Spjd#include <sys/priv.h>
32168404Spjd#include <sys/vnode.h>
33168404Spjd#include <sys/mount.h>
34168404Spjd#include <sys/stat.h>
35168404Spjd#include <sys/policy.h>
36168404Spjd
37168404Spjdint
38168404Spjdsecpolicy_zfs(struct ucred *cred)
39168404Spjd{
40168404Spjd
41168404Spjd	return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0));
42168404Spjd}
43168404Spjd
44168404Spjdint
45168404Spjdsecpolicy_sys_config(struct ucred *cred, int checkonly __unused)
46168404Spjd{
47168404Spjd
48168404Spjd	return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0));
49168404Spjd}
50168404Spjd
51168404Spjdint
52168404Spjdsecpolicy_zinject(struct ucred *cred)
53168404Spjd{
54168404Spjd
55168404Spjd	return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0));
56168404Spjd}
57168404Spjd
58168404Spjdint
59168404Spjdsecpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused)
60168404Spjd{
61168404Spjd
62168404Spjd	return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0));
63168404Spjd}
64168404Spjd
65168404Spjd/*
66168404Spjd * This check is done in kern_link(), so we could just return 0 here.
67168404Spjd */
68168404Spjdextern int hardlink_check_uid;
69168404Spjdint
70168404Spjdsecpolicy_basic_link(struct ucred *cred)
71168404Spjd{
72168404Spjd
73168404Spjd	if (!hardlink_check_uid)
74168404Spjd		return (0);
75170587Srwatson	return (priv_check_cred(cred, PRIV_VFS_LINK, 0));
76168404Spjd}
77168404Spjd
78168404Spjdint
79168404Spjdsecpolicy_vnode_stky_modify(struct ucred *cred)
80168404Spjd{
81168404Spjd
82168404Spjd	return (EPERM);
83168404Spjd}
84168404Spjd
85168404Spjdint
86168404Spjdsecpolicy_vnode_remove(struct ucred *cred)
87168404Spjd{
88168404Spjd
89170587Srwatson	return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
90168404Spjd}
91168404Spjd
92168404Spjdint
93168404Spjdsecpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner,
94184413Strasz    accmode_t accmode)
95168404Spjd{
96168404Spjd
97184413Strasz	if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) {
98168404Spjd		return (EACCES);
99168404Spjd	}
100184413Strasz	if ((accmode & VWRITE) &&
101170587Srwatson	    priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) {
102168404Spjd		return (EACCES);
103168404Spjd	}
104184413Strasz	if (accmode & VEXEC) {
105168404Spjd		if (vp->v_type == VDIR) {
106170587Srwatson			if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) {
107168404Spjd				return (EACCES);
108168404Spjd			}
109168404Spjd		} else {
110170587Srwatson			if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) {
111168404Spjd				return (EACCES);
112168404Spjd			}
113168404Spjd		}
114168404Spjd	}
115168404Spjd	return (0);
116168404Spjd}
117168404Spjd
118168404Spjdint
119168404Spjdsecpolicy_vnode_setdac(struct ucred *cred, uid_t owner)
120168404Spjd{
121168404Spjd
122168404Spjd	if (owner == cred->cr_uid)
123168404Spjd		return (0);
124170587Srwatson	return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
125168404Spjd}
126168404Spjd
127168404Spjdint
128168404Spjdsecpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
129168404Spjd    const struct vattr *ovap, int flags,
130168404Spjd    int unlocked_access(void *, int, struct ucred *), void *node)
131168404Spjd{
132168404Spjd	int mask = vap->va_mask;
133168404Spjd	int error;
134168404Spjd
135168404Spjd	if (mask & AT_SIZE) {
136168404Spjd		if (vp->v_type == VDIR)
137168404Spjd			return (EISDIR);
138168404Spjd		error = unlocked_access(node, VWRITE, cred);
139168404Spjd		if (error)
140168404Spjd			return (error);
141168404Spjd	}
142168404Spjd	if (mask & AT_MODE) {
143168404Spjd		/*
144168404Spjd		 * If not the owner of the file then check privilege
145168404Spjd		 * for two things: the privilege to set the mode at all
146168404Spjd		 * and, if we're setting setuid, we also need permissions
147168404Spjd		 * to add the set-uid bit, if we're not the owner.
148168404Spjd		 * In the specific case of creating a set-uid root
149168404Spjd		 * file, we need even more permissions.
150168404Spjd		 */
151168404Spjd		error = secpolicy_vnode_setdac(cred, ovap->va_uid);
152168404Spjd		if (error)
153168404Spjd			return (error);
154168404Spjd		error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred);
155168404Spjd		if (error)
156168404Spjd			return (error);
157168404Spjd	} else {
158168404Spjd		vap->va_mode = ovap->va_mode;
159168404Spjd	}
160168404Spjd	if (mask & (AT_UID | AT_GID)) {
161168404Spjd		error = secpolicy_vnode_setdac(cred, ovap->va_uid);
162168404Spjd		if (error)
163168404Spjd			return (error);
164168404Spjd
165168404Spjd		/*
166168404Spjd		 * To change the owner of a file, or change the group of a file to a
167168404Spjd		 * group of which we are not a member, the caller must have
168168404Spjd		 * privilege.
169168404Spjd		 */
170168404Spjd		if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
171168404Spjd		    ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
172168404Spjd		     !groupmember(vap->va_gid, cred))) {
173170587Srwatson			error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
174168404Spjd			if (error)
175168404Spjd				return (error);
176168404Spjd		}
177168404Spjd
178168404Spjd		if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
179168404Spjd		    ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) {
180168404Spjd			secpolicy_setid_clear(vap, cred);
181168404Spjd		}
182168404Spjd	}
183168404Spjd	if (mask & (AT_ATIME | AT_MTIME)) {
184168404Spjd		/*
185168404Spjd		 * From utimes(2):
186168404Spjd		 * If times is NULL, ... The caller must be the owner of
187168404Spjd		 * the file, have permission to write the file, or be the
188168404Spjd		 * super-user.
189168404Spjd		 * If times is non-NULL, ... The caller must be the owner of
190168404Spjd		 * the file or be the super-user.
191168404Spjd		 */
192168404Spjd		error = secpolicy_vnode_setdac(cred, ovap->va_uid);
193168404Spjd		if (error && (vap->va_vaflags & VA_UTIMES_NULL))
194168404Spjd			error = unlocked_access(node, VWRITE, cred);
195168404Spjd		if (error)
196168404Spjd			return (error);
197168404Spjd	}
198168404Spjd	return (0);
199168404Spjd}
200168404Spjd
201168404Spjdint
202168404Spjdsecpolicy_vnode_create_gid(struct ucred *cred)
203168404Spjd{
204168404Spjd
205168404Spjd	return (EPERM);
206168404Spjd}
207168404Spjd
208168404Spjdint
209168404Spjdsecpolicy_vnode_setids_setgids(struct ucred *cred, gid_t gid)
210168404Spjd{
211168404Spjd
212168404Spjd	if (!groupmember(gid, cred))
213170587Srwatson		return (priv_check_cred(cred, PRIV_VFS_SETGID, 0));
214168404Spjd	return (0);
215168404Spjd}
216168404Spjd
217168404Spjdint
218168404Spjdsecpolicy_vnode_setid_retain(struct ucred *cred, boolean_t issuidroot __unused)
219168404Spjd{
220168404Spjd
221170587Srwatson	return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0));
222168404Spjd}
223168404Spjd
224168404Spjdvoid
225168404Spjdsecpolicy_setid_clear(struct vattr *vap, struct ucred *cred)
226168404Spjd{
227168404Spjd
228168404Spjd	if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
229170587Srwatson		if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) {
230168404Spjd			vap->va_mask |= AT_MODE;
231168404Spjd			vap->va_mode &= ~(S_ISUID|S_ISGID);
232168404Spjd		}
233168404Spjd	}
234168404Spjd}
235168404Spjd
236168404Spjdint
237168404Spjdsecpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
238168404Spjd    const struct vattr *ovap, struct ucred *cred)
239168404Spjd{
240168404Spjd        int error;
241168404Spjd
242168404Spjd	/*
243168404Spjd	 * Privileged processes may set the sticky bit on non-directories,
244168404Spjd	 * as well as set the setgid bit on a file with a group that the process
245168404Spjd	 * is not a member of. Both of these are allowed in jail(8).
246168404Spjd	 */
247168404Spjd	if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
248170587Srwatson		if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
249168404Spjd			return (EFTYPE);
250168404Spjd	}
251168404Spjd	/*
252168404Spjd	 * Check for privilege if attempting to set the
253168404Spjd	 * group-id bit.
254168404Spjd	 */
255168404Spjd	if ((vap->va_mode & S_ISGID) != 0) {
256168404Spjd		error = secpolicy_vnode_setids_setgids(cred, ovap->va_gid);
257168404Spjd		if (error)
258168404Spjd			return (error);
259168404Spjd	}
260168404Spjd	return (0);
261168404Spjd}
262