]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/cddl/compat/opensolaris/kern/opensolaris_policy.c
Copy head to stable/8 as part of 8.0 Release cycle.
[FreeBSD/stable/8.git] / sys / cddl / compat / opensolaris / kern / opensolaris_policy.c
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/param.h>
31 #include <sys/priv.h>
32 #include <sys/vnode.h>
33 #include <sys/mntent.h>
34 #include <sys/mount.h>
35 #include <sys/stat.h>
36 #include <sys/jail.h>
37 #include <sys/policy.h>
38 #include <sys/zfs_vfsops.h>
39
40 int
41 secpolicy_nfs(struct ucred *cred)
42 {
43
44         return (priv_check_cred(cred, PRIV_NFS_DAEMON, 0));
45 }
46
47 int
48 secpolicy_zfs(struct ucred *cred)
49 {
50
51         return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0));
52 }
53
54 int
55 secpolicy_sys_config(struct ucred *cred, int checkonly __unused)
56 {
57
58         return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0));
59 }
60
61 int
62 secpolicy_zinject(struct ucred *cred)
63 {
64
65         return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0));
66 }
67
68 int
69 secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused)
70 {
71
72         return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0));
73 }
74
75 int
76 secpolicy_fs_owner(struct mount *mp, struct ucred *cred)
77 {
78
79         if (zfs_super_owner) {
80                 if (cred->cr_uid == mp->mnt_cred->cr_uid &&
81                     (!jailed(cred) ||
82                      cred->cr_prison == mp->mnt_cred->cr_prison)) {
83                         return (0);
84                 }
85         }
86         return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0));
87 }
88
89 /*
90  * This check is done in kern_link(), so we could just return 0 here.
91  */
92 extern int hardlink_check_uid;
93 int
94 secpolicy_basic_link(struct vnode *vp, struct ucred *cred)
95 {
96
97         if (!hardlink_check_uid)
98                 return (0);
99         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
100                 return (0);
101         return (priv_check_cred(cred, PRIV_VFS_LINK, 0));
102 }
103
104 int
105 secpolicy_vnode_stky_modify(struct ucred *cred)
106 {
107
108         return (EPERM);
109 }
110
111 int
112 secpolicy_vnode_remove(struct vnode *vp, struct ucred *cred)
113 {
114
115         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
116                 return (0);
117         return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
118 }
119
120 int
121 secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner,
122     accmode_t accmode)
123 {
124
125         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
126                 return (0);
127
128         if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0)
129                 return (EACCES);
130         if ((accmode & VWRITE) &&
131             priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) {
132                 return (EACCES);
133         }
134         if (accmode & VEXEC) {
135                 if (vp->v_type == VDIR) {
136                         if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) {
137                                 return (EACCES);
138                         }
139                 } else {
140                         if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) {
141                                 return (EACCES);
142                         }
143                 }
144         }
145         return (0);
146 }
147
148 int
149 secpolicy_vnode_setdac(struct vnode *vp, struct ucred *cred, uid_t owner)
150 {
151
152         if (owner == cred->cr_uid)
153                 return (0);
154         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
155                 return (0);
156         return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
157 }
158
159 int
160 secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
161     const struct vattr *ovap, int flags,
162     int unlocked_access(void *, int, struct ucred *), void *node)
163 {
164         int mask = vap->va_mask;
165         int error;
166
167         if (mask & AT_SIZE) {
168                 if (vp->v_type == VDIR)
169                         return (EISDIR);
170                 error = unlocked_access(node, VWRITE, cred);
171                 if (error)
172                         return (error);
173         }
174         if (mask & AT_MODE) {
175                 /*
176                  * If not the owner of the file then check privilege
177                  * for two things: the privilege to set the mode at all
178                  * and, if we're setting setuid, we also need permissions
179                  * to add the set-uid bit, if we're not the owner.
180                  * In the specific case of creating a set-uid root
181                  * file, we need even more permissions.
182                  */
183                 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid);
184                 if (error)
185                         return (error);
186                 error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred);
187                 if (error)
188                         return (error);
189         } else {
190                 vap->va_mode = ovap->va_mode;
191         }
192         if (mask & (AT_UID | AT_GID)) {
193                 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid);
194                 if (error)
195                         return (error);
196
197                 /*
198                  * To change the owner of a file, or change the group of a file to a
199                  * group of which we are not a member, the caller must have
200                  * privilege.
201                  */
202                 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
203                     ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
204                      !groupmember(vap->va_gid, cred))) {
205                         if (secpolicy_fs_owner(vp->v_mount, cred) != 0) {
206                                 error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
207                                 if (error)
208                                         return (error);
209                         }
210                 }
211
212                 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
213                     ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) {
214                         secpolicy_setid_clear(vap, vp, cred);
215                 }
216         }
217         if (mask & (AT_ATIME | AT_MTIME)) {
218                 /*
219                  * From utimes(2):
220                  * If times is NULL, ... The caller must be the owner of
221                  * the file, have permission to write the file, or be the
222                  * super-user.
223                  * If times is non-NULL, ... The caller must be the owner of
224                  * the file or be the super-user.
225                  */
226                 error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid);
227                 if (error && (vap->va_vaflags & VA_UTIMES_NULL))
228                         error = unlocked_access(node, VWRITE, cred);
229                 if (error)
230                         return (error);
231         }
232         return (0);
233 }
234
235 int
236 secpolicy_vnode_create_gid(struct ucred *cred)
237 {
238
239         return (EPERM);
240 }
241
242 int
243 secpolicy_vnode_setids_setgids(struct vnode *vp, struct ucred *cred, gid_t gid)
244 {
245
246         if (groupmember(gid, cred))
247                 return (0);
248         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
249                 return (0);
250         return (priv_check_cred(cred, PRIV_VFS_SETGID, 0));
251 }
252
253 int
254 secpolicy_vnode_setid_retain(struct vnode *vp, struct ucred *cred,
255     boolean_t issuidroot __unused)
256 {
257
258         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
259                 return (0);
260         return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0));
261 }
262
263 void
264 secpolicy_setid_clear(struct vattr *vap, struct vnode *vp, struct ucred *cred)
265 {
266
267         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
268                 return;
269
270         if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
271                 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) {
272                         vap->va_mask |= AT_MODE;
273                         vap->va_mode &= ~(S_ISUID|S_ISGID);
274                 }
275         }
276 }
277
278 int
279 secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
280     const struct vattr *ovap, struct ucred *cred)
281 {
282         int error;
283
284         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
285                 return (0);
286
287         /*
288          * Privileged processes may set the sticky bit on non-directories,
289          * as well as set the setgid bit on a file with a group that the process
290          * is not a member of. Both of these are allowed in jail(8).
291          */
292         if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
293                 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
294                         return (EFTYPE);
295         }
296         /*
297          * Check for privilege if attempting to set the
298          * group-id bit.
299          */
300         if ((vap->va_mode & S_ISGID) != 0) {
301                 error = secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid);
302                 if (error)
303                         return (error);
304         }
305         /*
306          * Deny setting setuid if we are not the file owner.
307          */
308         if ((vap->va_mode & S_ISUID) && ovap->va_uid != cred->cr_uid) {
309                 error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0);
310                 if (error)
311                         return (error);
312         }
313         return (0);
314 }
315
316 int
317 secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp)
318 {
319
320         return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0));
321 }
322
323 int
324 secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner)
325 {
326
327         if (owner == cred->cr_uid)
328                 return (0);
329         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
330                 return (0);
331
332         /* XXX: vfs_suser()? */
333         return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0));
334 }
335
336 int
337 secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, boolean_t check_self)
338 {
339
340         if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
341                 return (0);
342         return (priv_check_cred(cred, PRIV_VFS_CHOWN, 0));
343 }
344
345 void
346 secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp)
347 {
348
349         if (priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER, 0) != 0) {
350                 MNT_ILOCK(vfsp);
351                 vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER;
352                 vfs_clearmntopt(vfsp, MNTOPT_SETUID);
353                 vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0);
354                 MNT_IUNLOCK(vfsp);
355         }
356 }
357
358 /*
359  * Check privileges for setting xvattr attributes
360  */
361 int
362 secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype)
363 {
364
365         return (priv_check_cred(cr, PRIV_VFS_SYSFLAGS, 0));
366 }