]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - module/os/freebsd/spl/spl_policy.c
Vendor import of openzfs master @ 184df27eef0abdc7ab2105b21257f753834b936b
[FreeBSD/FreeBSD.git] / module / os / freebsd / spl / spl_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/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
41
42 int
43 secpolicy_nfs(cred_t *cr)
44 {
45
46         return (spl_priv_check_cred(cr, PRIV_NFS_DAEMON));
47 }
48
49 int
50 secpolicy_zfs(cred_t *cr)
51 {
52
53         return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT));
54 }
55
56 int
57 secpolicy_zfs_proc(cred_t *cr, proc_t *proc)
58 {
59
60         return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT));
61 }
62
63 int
64 secpolicy_sys_config(cred_t *cr, int checkonly __unused)
65 {
66
67         return (spl_priv_check_cred(cr, PRIV_ZFS_POOL_CONFIG));
68 }
69
70 int
71 secpolicy_zinject(cred_t *cr)
72 {
73
74         return (spl_priv_check_cred(cr, PRIV_ZFS_INJECT));
75 }
76
77 int
78 secpolicy_fs_unmount(cred_t *cr, struct mount *vfsp __unused)
79 {
80
81         return (spl_priv_check_cred(cr, PRIV_VFS_UNMOUNT));
82 }
83
84 int
85 secpolicy_fs_owner(struct mount *mp, cred_t *cr)
86 {
87
88         if (zfs_super_owner) {
89                 if (cr->cr_uid == mp->mnt_cred->cr_uid &&
90                     cr->cr_prison == mp->mnt_cred->cr_prison) {
91                         return (0);
92                 }
93         }
94         return (EPERM);
95 }
96
97 /*
98  * This check is done in kern_link(), so we could just return 0 here.
99  */
100 extern int hardlink_check_uid;
101 int
102 secpolicy_basic_link(vnode_t *vp, cred_t *cr)
103 {
104
105         if (!hardlink_check_uid)
106                 return (0);
107         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
108                 return (0);
109         return (spl_priv_check_cred(cr, PRIV_VFS_LINK));
110 }
111
112 int
113 secpolicy_vnode_stky_modify(cred_t *cr)
114 {
115
116         return (EPERM);
117 }
118
119 int
120 secpolicy_vnode_remove(vnode_t *vp, cred_t *cr)
121 {
122
123         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
124                 return (0);
125         return (spl_priv_check_cred(cr, PRIV_VFS_ADMIN));
126 }
127
128 int
129 secpolicy_vnode_access(cred_t *cr, vnode_t *vp, uid_t owner, accmode_t accmode)
130 {
131
132         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
133                 return (0);
134
135         if ((accmode & VREAD) && spl_priv_check_cred(cr, PRIV_VFS_READ) != 0)
136                 return (EACCES);
137         if ((accmode & VWRITE) &&
138             spl_priv_check_cred(cr, PRIV_VFS_WRITE) != 0) {
139                 return (EACCES);
140         }
141         if (accmode & VEXEC) {
142                 if (vp->v_type == VDIR) {
143                         if (spl_priv_check_cred(cr, PRIV_VFS_LOOKUP) != 0)
144                                 return (EACCES);
145                 } else {
146                         if (spl_priv_check_cred(cr, PRIV_VFS_EXEC) != 0)
147                                 return (EACCES);
148                 }
149         }
150         return (0);
151 }
152
153 /*
154  * Like secpolicy_vnode_access() but we get the actual wanted mode and the
155  * current mode of the file, not the missing bits.
156  */
157 int
158 secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner,
159     accmode_t curmode, accmode_t wantmode)
160 {
161         accmode_t mode;
162
163         mode = ~curmode & wantmode;
164
165         if (mode == 0)
166                 return (0);
167
168         return (secpolicy_vnode_access(cr, vp, owner, mode));
169 }
170
171 int
172 secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner)
173 {
174         static int privs[] = {
175             PRIV_VFS_ADMIN,
176             PRIV_VFS_READ,
177             PRIV_VFS_WRITE,
178             PRIV_VFS_EXEC,
179             PRIV_VFS_LOOKUP
180         };
181         int i;
182
183         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
184                 return (0);
185
186         /* Same as secpolicy_vnode_setdac */
187         if (owner == cr->cr_uid)
188                 return (0);
189
190         for (i = 0; i < sizeof (privs)/sizeof (int); i++) {
191                 int priv;
192
193                 switch (priv = privs[i]) {
194                 case PRIV_VFS_EXEC:
195                         if (vp->v_type == VDIR)
196                                 continue;
197                         break;
198                 case PRIV_VFS_LOOKUP:
199                         if (vp->v_type != VDIR)
200                                 continue;
201                         break;
202                 }
203                 if (spl_priv_check_cred(cr, priv) == 0)
204                         return (0);
205         }
206         return (EPERM);
207 }
208
209 int
210 secpolicy_vnode_setdac(vnode_t *vp, cred_t *cr, uid_t owner)
211 {
212
213         if (owner == cr->cr_uid)
214                 return (0);
215         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
216                 return (0);
217         return (spl_priv_check_cred(cr, PRIV_VFS_ADMIN));
218 }
219
220 int
221 secpolicy_vnode_setattr(cred_t *cr, vnode_t *vp, struct vattr *vap,
222     const struct vattr *ovap, int flags,
223     int unlocked_access(void *, int, cred_t *), void *node)
224 {
225         int mask = vap->va_mask;
226         int error;
227
228         if (mask & AT_SIZE) {
229                 if (vp->v_type == VDIR)
230                         return (EISDIR);
231                 error = unlocked_access(node, VWRITE, cr);
232                 if (error)
233                         return (error);
234         }
235         if (mask & AT_MODE) {
236                 /*
237                  * If not the owner of the file then check privilege
238                  * for two things: the privilege to set the mode at all
239                  * and, if we're setting setuid, we also need permissions
240                  * to add the set-uid bit, if we're not the owner.
241                  * In the specific case of creating a set-uid root
242                  * file, we need even more permissions.
243                  */
244                 error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
245                 if (error)
246                         return (error);
247                 error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cr);
248                 if (error)
249                         return (error);
250         } else {
251                 vap->va_mode = ovap->va_mode;
252         }
253         if (mask & (AT_UID | AT_GID)) {
254                 error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
255                 if (error)
256                         return (error);
257
258                 /*
259                  * To change the owner of a file, or change the group of
260                  * a file to a group of which we are not a member, the
261                  * caller must have privilege.
262                  */
263                 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
264                     ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
265                     !groupmember(vap->va_gid, cr))) {
266                         if (secpolicy_fs_owner(vp->v_mount, cr) != 0) {
267                                 error = spl_priv_check_cred(cr, PRIV_VFS_CHOWN);
268                                 if (error)
269                                         return (error);
270                         }
271                 }
272
273                 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
274                     ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) {
275                         secpolicy_setid_clear(vap, vp, cr);
276                 }
277         }
278         if (mask & (AT_ATIME | AT_MTIME)) {
279                 /*
280                  * From utimes(2):
281                  * If times is NULL, ... The caller must be the owner of
282                  * the file, have permission to write the file, or be the
283                  * super-user.
284                  * If times is non-NULL, ... The caller must be the owner of
285                  * the file or be the super-user.
286                  */
287                 error = secpolicy_vnode_setdac(vp, cr, ovap->va_uid);
288                 if (error && (vap->va_vaflags & VA_UTIMES_NULL))
289                         error = unlocked_access(node, VWRITE, cr);
290                 if (error)
291                         return (error);
292         }
293         return (0);
294 }
295
296 int
297 secpolicy_vnode_create_gid(cred_t *cr)
298 {
299
300         return (EPERM);
301 }
302
303 int
304 secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cr, gid_t gid)
305 {
306
307         if (groupmember(gid, cr))
308                 return (0);
309         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
310                 return (0);
311         return (spl_priv_check_cred(cr, PRIV_VFS_SETGID));
312 }
313
314 int
315 secpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cr,
316     boolean_t issuidroot __unused)
317 {
318
319         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
320                 return (0);
321         return (spl_priv_check_cred(cr, PRIV_VFS_RETAINSUGID));
322 }
323
324 void
325 secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cr)
326 {
327
328         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
329                 return;
330
331         if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
332                 if (spl_priv_check_cred(cr, PRIV_VFS_RETAINSUGID)) {
333                         vap->va_mask |= AT_MODE;
334                         vap->va_mode &= ~(S_ISUID|S_ISGID);
335                 }
336         }
337 }
338
339 int
340 secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap,
341     const struct vattr *ovap, cred_t *cr)
342 {
343         int error;
344
345         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
346                 return (0);
347
348         /*
349          * Privileged processes may set the sticky bit on non-directories,
350          * as well as set the setgid bit on a file with a group that the process
351          * is not a member of. Both of these are allowed in jail(8).
352          */
353         if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
354                 if (spl_priv_check_cred(cr, PRIV_VFS_STICKYFILE))
355                         return (EFTYPE);
356         }
357         /*
358          * Check for privilege if attempting to set the
359          * group-id bit.
360          */
361         if ((vap->va_mode & S_ISGID) != 0) {
362                 error = secpolicy_vnode_setids_setgids(vp, cr, ovap->va_gid);
363                 if (error)
364                         return (error);
365         }
366         /*
367          * Deny setting setuid if we are not the file owner.
368          */
369         if ((vap->va_mode & S_ISUID) && ovap->va_uid != cr->cr_uid) {
370                 error = spl_priv_check_cred(cr, PRIV_VFS_ADMIN);
371                 if (error)
372                         return (error);
373         }
374         return (0);
375 }
376
377 int
378 secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp)
379 {
380
381         return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT));
382 }
383
384 int
385 secpolicy_vnode_owner(vnode_t *vp, cred_t *cr, uid_t owner)
386 {
387
388         if (owner == cr->cr_uid)
389                 return (0);
390         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
391                 return (0);
392
393         /* XXX: vfs_suser()? */
394         return (spl_priv_check_cred(cr, PRIV_VFS_MOUNT_OWNER));
395 }
396
397 int
398 secpolicy_vnode_chown(vnode_t *vp, cred_t *cr, uid_t owner)
399 {
400
401         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
402                 return (0);
403         return (spl_priv_check_cred(cr, PRIV_VFS_CHOWN));
404 }
405
406 void
407 secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp)
408 {
409
410         if (spl_priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER) != 0) {
411                 MNT_ILOCK(vfsp);
412                 vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER;
413                 vfs_clearmntopt(vfsp, MNTOPT_SETUID);
414                 vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0);
415                 MNT_IUNLOCK(vfsp);
416         }
417 }
418
419 /*
420  * Check privileges for setting xvattr attributes
421  */
422 int
423 secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cr,
424     vtype_t vtype)
425 {
426
427         if (secpolicy_fs_owner(vp->v_mount, cr) == 0)
428                 return (0);
429         return (spl_priv_check_cred(cr, PRIV_VFS_SYSFLAGS));
430 }
431
432 int
433 secpolicy_smb(cred_t *cr)
434 {
435
436         return (spl_priv_check_cred(cr, PRIV_NETSMB));
437 }