]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/vfs_acl.c
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r303571, and update
[FreeBSD/FreeBSD.git] / sys / kern / vfs_acl.c
1 /*-
2  * Copyright (c) 1999-2006, 2016-2017 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * This software was developed by Robert Watson for the TrustedBSD Project.
6  *
7  * Portions of this software were developed by BAE Systems, the University of
8  * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
9  * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
10  * Computing (TC) research program.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 /*
34  * Developed by the TrustedBSD Project.
35  *
36  * ACL system calls and other functions common across different ACL types.
37  * Type-specific routines go into subr_acl_<type>.c.
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/sysproto.h>
46 #include <sys/capsicum.h>
47 #include <sys/fcntl.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mount.h>
51 #include <sys/vnode.h>
52 #include <sys/lock.h>
53 #include <sys/mutex.h>
54 #include <sys/namei.h>
55 #include <sys/file.h>
56 #include <sys/filedesc.h>
57 #include <sys/proc.h>
58 #include <sys/sysent.h>
59 #include <sys/acl.h>
60
61 #include <security/audit/audit.h>
62 #include <security/mac/mac_framework.h>
63
64 CTASSERT(ACL_MAX_ENTRIES >= OLDACL_MAX_ENTRIES);
65
66 MALLOC_DEFINE(M_ACL, "acl", "Access Control Lists");
67
68 static int      vacl_set_acl(struct thread *td, struct vnode *vp,
69                     acl_type_t type, struct acl *aclp);
70 static int      vacl_get_acl(struct thread *td, struct vnode *vp,
71                     acl_type_t type, struct acl *aclp);
72 static int      vacl_aclcheck(struct thread *td, struct vnode *vp,
73                     acl_type_t type, struct acl *aclp);
74
75 int
76 acl_copy_oldacl_into_acl(const struct oldacl *source, struct acl *dest)
77 {
78         int i;
79
80         if (source->acl_cnt < 0 || source->acl_cnt > OLDACL_MAX_ENTRIES)
81                 return (EINVAL);
82         
83         bzero(dest, sizeof(*dest));
84
85         dest->acl_cnt = source->acl_cnt;
86         dest->acl_maxcnt = ACL_MAX_ENTRIES;
87
88         for (i = 0; i < dest->acl_cnt; i++) {
89                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
90                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
91                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
92         }
93
94         return (0);
95 }
96
97 int
98 acl_copy_acl_into_oldacl(const struct acl *source, struct oldacl *dest)
99 {
100         int i;
101
102         if (source->acl_cnt > OLDACL_MAX_ENTRIES)
103                 return (EINVAL);
104
105         bzero(dest, sizeof(*dest));
106
107         dest->acl_cnt = source->acl_cnt;
108
109         for (i = 0; i < dest->acl_cnt; i++) {
110                 dest->acl_entry[i].ae_tag = source->acl_entry[i].ae_tag;
111                 dest->acl_entry[i].ae_id = source->acl_entry[i].ae_id;
112                 dest->acl_entry[i].ae_perm = source->acl_entry[i].ae_perm;
113         }
114
115         return (0);
116 }
117
118 /*
119  * At one time, "struct ACL" was extended in order to add support for NFSv4
120  * ACLs.  Instead of creating compatibility versions of all the ACL-related
121  * syscalls, they were left intact.  It's possible to find out what the code
122  * calling these syscalls (libc) expects basing on "type" argument - if it's
123  * either ACL_TYPE_ACCESS_OLD or ACL_TYPE_DEFAULT_OLD (which previously were
124  * known as ACL_TYPE_ACCESS and ACL_TYPE_DEFAULT), then it's the "struct
125  * oldacl".  If it's something else, then it's the new "struct acl".  In the
126  * latter case, the routines below just copyin/copyout the contents.  In the
127  * former case, they copyin the "struct oldacl" and convert it to the new
128  * format.
129  */
130 static int
131 acl_copyin(void *user_acl, struct acl *kernel_acl, acl_type_t type)
132 {
133         int error;
134         struct oldacl old;
135
136         switch (type) {
137         case ACL_TYPE_ACCESS_OLD:
138         case ACL_TYPE_DEFAULT_OLD:
139                 error = copyin(user_acl, &old, sizeof(old));
140                 if (error != 0)
141                         break;
142                 acl_copy_oldacl_into_acl(&old, kernel_acl);
143                 break;
144
145         default:
146                 error = copyin(user_acl, kernel_acl, sizeof(*kernel_acl));
147                 if (kernel_acl->acl_maxcnt != ACL_MAX_ENTRIES)
148                         return (EINVAL);
149         }
150
151         return (error);
152 }
153
154 static int
155 acl_copyout(struct acl *kernel_acl, void *user_acl, acl_type_t type)
156 {
157         uint32_t am;
158         int error;
159         struct oldacl old;
160
161         switch (type) {
162         case ACL_TYPE_ACCESS_OLD:
163         case ACL_TYPE_DEFAULT_OLD:
164                 error = acl_copy_acl_into_oldacl(kernel_acl, &old);
165                 if (error != 0)
166                         break;
167
168                 error = copyout(&old, user_acl, sizeof(old));
169                 break;
170
171         default:
172                 error = fueword32((char *)user_acl +
173                     offsetof(struct acl, acl_maxcnt), &am);
174                 if (error == -1)
175                         return (EFAULT);
176                 if (am != ACL_MAX_ENTRIES)
177                         return (EINVAL);
178
179                 error = copyout(kernel_acl, user_acl, sizeof(*kernel_acl));
180         }
181
182         return (error);
183 }
184
185 /*
186  * Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
187  * counterpart.  It's required for old (pre-NFSv4 ACLs) libc to work
188  * with new kernel.  Fixing 'type' for old binaries with new libc
189  * is being done in lib/libc/posix1e/acl_support.c:_acl_type_unold().
190  */
191 static int
192 acl_type_unold(int type)
193 {
194         switch (type) {
195         case ACL_TYPE_ACCESS_OLD:
196                 return (ACL_TYPE_ACCESS);
197
198         case ACL_TYPE_DEFAULT_OLD:
199                 return (ACL_TYPE_DEFAULT);
200
201         default:
202                 return (type);
203         }
204 }
205
206 /*
207  * These calls wrap the real vnode operations, and are called by the syscall
208  * code once the syscall has converted the path or file descriptor to a vnode
209  * (unlocked).  The aclp pointer is assumed still to point to userland, so
210  * this should not be consumed within the kernel except by syscall code.
211  * Other code should directly invoke VOP_{SET,GET}ACL.
212  */
213
214 /*
215  * Given a vnode, set its ACL.
216  */
217 static int
218 vacl_set_acl(struct thread *td, struct vnode *vp, acl_type_t type,
219     struct acl *aclp)
220 {
221         struct acl *inkernelacl;
222         struct mount *mp;
223         int error;
224
225         AUDIT_ARG_VALUE(type);
226         inkernelacl = acl_alloc(M_WAITOK);
227         error = acl_copyin(aclp, inkernelacl, type);
228         if (error != 0)
229                 goto out;
230         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
231         if (error != 0)
232                 goto out;
233         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
234         AUDIT_ARG_VNODE1(vp);
235 #ifdef MAC
236         error = mac_vnode_check_setacl(td->td_ucred, vp, type, inkernelacl);
237         if (error != 0)
238                 goto out_unlock;
239 #endif
240         error = VOP_SETACL(vp, acl_type_unold(type), inkernelacl,
241             td->td_ucred, td);
242 #ifdef MAC
243 out_unlock:
244 #endif
245         VOP_UNLOCK(vp, 0);
246         vn_finished_write(mp);
247 out:
248         acl_free(inkernelacl);
249         return (error);
250 }
251
252 /*
253  * Given a vnode, get its ACL.
254  */
255 static int
256 vacl_get_acl(struct thread *td, struct vnode *vp, acl_type_t type,
257     struct acl *aclp)
258 {
259         struct acl *inkernelacl;
260         int error;
261
262         AUDIT_ARG_VALUE(type);
263         inkernelacl = acl_alloc(M_WAITOK | M_ZERO);
264         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
265         AUDIT_ARG_VNODE1(vp);
266 #ifdef MAC
267         error = mac_vnode_check_getacl(td->td_ucred, vp, type);
268         if (error != 0)
269                 goto out;
270 #endif
271         error = VOP_GETACL(vp, acl_type_unold(type), inkernelacl,
272             td->td_ucred, td);
273
274 #ifdef MAC
275 out:
276 #endif
277         VOP_UNLOCK(vp, 0);
278         if (error == 0)
279                 error = acl_copyout(inkernelacl, aclp, type);
280         acl_free(inkernelacl);
281         return (error);
282 }
283
284 /*
285  * Given a vnode, delete its ACL.
286  */
287 static int
288 vacl_delete(struct thread *td, struct vnode *vp, acl_type_t type)
289 {
290         struct mount *mp;
291         int error;
292
293         AUDIT_ARG_VALUE(type);
294         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
295         if (error != 0)
296                 return (error);
297         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
298         AUDIT_ARG_VNODE1(vp);
299 #ifdef MAC
300         error = mac_vnode_check_deleteacl(td->td_ucred, vp, type);
301         if (error != 0)
302                 goto out;
303 #endif
304         error = VOP_SETACL(vp, acl_type_unold(type), 0, td->td_ucred, td);
305 #ifdef MAC
306 out:
307 #endif
308         VOP_UNLOCK(vp, 0);
309         vn_finished_write(mp);
310         return (error);
311 }
312
313 /*
314  * Given a vnode, check whether an ACL is appropriate for it
315  *
316  * XXXRW: No vnode lock held so can't audit vnode state...?
317  */
318 static int
319 vacl_aclcheck(struct thread *td, struct vnode *vp, acl_type_t type,
320     struct acl *aclp)
321 {
322         struct acl *inkernelacl;
323         int error;
324
325         inkernelacl = acl_alloc(M_WAITOK);
326         error = acl_copyin(aclp, inkernelacl, type);
327         if (error != 0)
328                 goto out;
329         error = VOP_ACLCHECK(vp, acl_type_unold(type), inkernelacl,
330             td->td_ucred, td);
331 out:
332         acl_free(inkernelacl);
333         return (error);
334 }
335
336 /*
337  * syscalls -- convert the path/fd to a vnode, and call vacl_whatever.  Don't
338  * need to lock, as the vacl_ code will get/release any locks required.
339  */
340
341 /*
342  * Given a file path, get an ACL for it
343  */
344 int
345 sys___acl_get_file(struct thread *td, struct __acl_get_file_args *uap)
346 {
347         struct nameidata nd;
348         int error;
349
350         NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
351             td);
352         error = namei(&nd);
353         if (error == 0) {
354                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
355                 NDFREE(&nd, 0);
356         }
357         return (error);
358 }
359
360 /*
361  * Given a file path, get an ACL for it; don't follow links.
362  */
363 int
364 sys___acl_get_link(struct thread *td, struct __acl_get_link_args *uap)
365 {
366         struct nameidata nd;
367         int error;
368
369         NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
370             td);
371         error = namei(&nd);
372         if (error == 0) {
373                 error = vacl_get_acl(td, nd.ni_vp, uap->type, uap->aclp);
374                 NDFREE(&nd, 0);
375         }
376         return (error);
377 }
378
379 /*
380  * Given a file path, set an ACL for it.
381  */
382 int
383 sys___acl_set_file(struct thread *td, struct __acl_set_file_args *uap)
384 {
385         struct nameidata nd;
386         int error;
387
388         NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
389             td);
390         error = namei(&nd);
391         if (error == 0) {
392                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
393                 NDFREE(&nd, 0);
394         }
395         return (error);
396 }
397
398 /*
399  * Given a file path, set an ACL for it; don't follow links.
400  */
401 int
402 sys___acl_set_link(struct thread *td, struct __acl_set_link_args *uap)
403 {
404         struct nameidata nd;
405         int error;
406
407         NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
408             td);
409         error = namei(&nd);
410         if (error == 0) {
411                 error = vacl_set_acl(td, nd.ni_vp, uap->type, uap->aclp);
412                 NDFREE(&nd, 0);
413         }
414         return (error);
415 }
416
417 /*
418  * Given a file descriptor, get an ACL for it.
419  */
420 int
421 sys___acl_get_fd(struct thread *td, struct __acl_get_fd_args *uap)
422 {
423         struct file *fp;
424         cap_rights_t rights;
425         int error;
426
427         AUDIT_ARG_FD(uap->filedes);
428         error = getvnode(td, uap->filedes,
429             cap_rights_init(&rights, CAP_ACL_GET), &fp);
430         if (error == 0) {
431                 error = vacl_get_acl(td, fp->f_vnode, uap->type, uap->aclp);
432                 fdrop(fp, td);
433         }
434         return (error);
435 }
436
437 /*
438  * Given a file descriptor, set an ACL for it.
439  */
440 int
441 sys___acl_set_fd(struct thread *td, struct __acl_set_fd_args *uap)
442 {
443         struct file *fp;
444         cap_rights_t rights;
445         int error;
446
447         AUDIT_ARG_FD(uap->filedes);
448         error = getvnode(td, uap->filedes,
449             cap_rights_init(&rights, CAP_ACL_SET), &fp);
450         if (error == 0) {
451                 error = vacl_set_acl(td, fp->f_vnode, uap->type, uap->aclp);
452                 fdrop(fp, td);
453         }
454         return (error);
455 }
456
457 /*
458  * Given a file path, delete an ACL from it.
459  */
460 int
461 sys___acl_delete_file(struct thread *td, struct __acl_delete_file_args *uap)
462 {
463         struct nameidata nd;
464         int error;
465
466         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
467         error = namei(&nd);
468         if (error == 0) {
469                 error = vacl_delete(td, nd.ni_vp, uap->type);
470                 NDFREE(&nd, 0);
471         }
472         return (error);
473 }
474
475 /*
476  * Given a file path, delete an ACL from it; don't follow links.
477  */
478 int
479 sys___acl_delete_link(struct thread *td, struct __acl_delete_link_args *uap)
480 {
481         struct nameidata nd;
482         int error;
483
484         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
485         error = namei(&nd);
486         if (error == 0) {
487                 error = vacl_delete(td, nd.ni_vp, uap->type);
488                 NDFREE(&nd, 0);
489         }
490         return (error);
491 }
492
493 /*
494  * Given a file path, delete an ACL from it.
495  */
496 int
497 sys___acl_delete_fd(struct thread *td, struct __acl_delete_fd_args *uap)
498 {
499         struct file *fp;
500         cap_rights_t rights;
501         int error;
502
503         AUDIT_ARG_FD(uap->filedes);
504         error = getvnode(td, uap->filedes,
505             cap_rights_init(&rights, CAP_ACL_DELETE), &fp);
506         if (error == 0) {
507                 error = vacl_delete(td, fp->f_vnode, uap->type);
508                 fdrop(fp, td);
509         }
510         return (error);
511 }
512
513 /*
514  * Given a file path, check an ACL for it.
515  */
516 int
517 sys___acl_aclcheck_file(struct thread *td, struct __acl_aclcheck_file_args *uap)
518 {
519         struct nameidata nd;
520         int error;
521
522         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
523         error = namei(&nd);
524         if (error == 0) {
525                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
526                 NDFREE(&nd, 0);
527         }
528         return (error);
529 }
530
531 /*
532  * Given a file path, check an ACL for it; don't follow links.
533  */
534 int
535 sys___acl_aclcheck_link(struct thread *td, struct __acl_aclcheck_link_args *uap)
536 {
537         struct nameidata nd;
538         int error;
539
540         NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
541         error = namei(&nd);
542         if (error == 0) {
543                 error = vacl_aclcheck(td, nd.ni_vp, uap->type, uap->aclp);
544                 NDFREE(&nd, 0);
545         }
546         return (error);
547 }
548
549 /*
550  * Given a file descriptor, check an ACL for it.
551  */
552 int
553 sys___acl_aclcheck_fd(struct thread *td, struct __acl_aclcheck_fd_args *uap)
554 {
555         struct file *fp;
556         cap_rights_t rights;
557         int error;
558
559         AUDIT_ARG_FD(uap->filedes);
560         error = getvnode(td, uap->filedes,
561             cap_rights_init(&rights, CAP_ACL_CHECK), &fp);
562         if (error == 0) {
563                 error = vacl_aclcheck(td, fp->f_vnode, uap->type, uap->aclp);
564                 fdrop(fp, td);
565         }
566         return (error);
567 }
568
569 struct acl *
570 acl_alloc(int flags)
571 {
572         struct acl *aclp;
573
574         aclp = malloc(sizeof(*aclp), M_ACL, flags);
575         if (aclp == NULL)
576                 return (NULL);
577
578         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
579
580         return (aclp);
581 }
582
583 void
584 acl_free(struct acl *aclp)
585 {
586
587         free(aclp, M_ACL);
588 }