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