]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/security/mac/mac_syscalls.c
Merge llvm-project 12.0.1 rc2
[FreeBSD/FreeBSD.git] / sys / security / mac / mac_syscalls.c
1 /*-
2  * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson
3  * Copyright (c) 2001 Ilmar S. Habibulin
4  * Copyright (c) 2001-2005 Networks Associates Technology, Inc.
5  * Copyright (c) 2005-2006 SPARTA, Inc.
6  * Copyright (c) 2008 Apple Inc.
7  * All rights reserved.
8  *
9  * This software was developed by Robert Watson and Ilmar Habibulin for the
10  * TrustedBSD Project.
11  *
12  * This software was developed for the FreeBSD Project in part by Network
13  * Associates Laboratories, the Security Research Division of Network
14  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
15  * as part of the DARPA CHATS research program.
16  *
17  * This software was enhanced by SPARTA ISSO under SPAWAR contract 
18  * N66001-04-C-6019 ("SEFOS").
19  *
20  * This software was developed at the University of Cambridge Computer
21  * Laboratory with support from a grant from Google, Inc.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  */
44
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
47
48 #include "opt_mac.h"
49
50 #include <sys/param.h>
51 #include <sys/capsicum.h>
52 #include <sys/fcntl.h>
53 #include <sys/kernel.h>
54 #include <sys/lock.h>
55 #include <sys/malloc.h>
56 #include <sys/mutex.h>
57 #include <sys/mac.h>
58 #include <sys/proc.h>
59 #include <sys/systm.h>
60 #include <sys/sysctl.h>
61 #include <sys/sysproto.h>
62 #include <sys/sysent.h>
63 #include <sys/vnode.h>
64 #include <sys/mount.h>
65 #include <sys/file.h>
66 #include <sys/namei.h>
67 #include <sys/socket.h>
68 #include <sys/pipe.h>
69 #include <sys/socketvar.h>
70
71 #include <security/mac/mac_framework.h>
72 #include <security/mac/mac_internal.h>
73 #include <security/mac/mac_policy.h>
74
75 #ifdef MAC
76
77 FEATURE(security_mac, "Mandatory Access Control Framework support");
78
79 static int      kern___mac_get_path(struct thread *td, const char *path_p,
80                     struct mac *mac_p, int follow);
81 static int      kern___mac_set_path(struct thread *td, const char *path_p,
82                     struct mac *mac_p, int follow);
83
84 int
85 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
86 {
87         char *elements, *buffer;
88         struct mac mac;
89         struct proc *tproc;
90         struct ucred *tcred;
91         int error;
92
93         error = copyin(uap->mac_p, &mac, sizeof(mac));
94         if (error)
95                 return (error);
96
97         error = mac_check_structmac_consistent(&mac);
98         if (error)
99                 return (error);
100
101         tproc = pfind(uap->pid);
102         if (tproc == NULL)
103                 return (ESRCH);
104
105         tcred = NULL;                           /* Satisfy gcc. */
106         error = p_cansee(td, tproc);
107         if (error == 0)
108                 tcred = crhold(tproc->p_ucred);
109         PROC_UNLOCK(tproc);
110         if (error)
111                 return (error);
112
113         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
114         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
115         if (error) {
116                 free(elements, M_MACTEMP);
117                 crfree(tcred);
118                 return (error);
119         }
120
121         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
122         error = mac_cred_externalize_label(tcred->cr_label, elements,
123             buffer, mac.m_buflen);
124         if (error == 0)
125                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
126
127         free(buffer, M_MACTEMP);
128         free(elements, M_MACTEMP);
129         crfree(tcred);
130         return (error);
131 }
132
133 int
134 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
135 {
136         char *elements, *buffer;
137         struct mac mac;
138         int error;
139
140         error = copyin(uap->mac_p, &mac, sizeof(mac));
141         if (error)
142                 return (error);
143
144         error = mac_check_structmac_consistent(&mac);
145         if (error)
146                 return (error);
147
148         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
149         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
150         if (error) {
151                 free(elements, M_MACTEMP);
152                 return (error);
153         }
154
155         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
156         error = mac_cred_externalize_label(td->td_ucred->cr_label,
157             elements, buffer, mac.m_buflen);
158         if (error == 0)
159                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
160
161         free(buffer, M_MACTEMP);
162         free(elements, M_MACTEMP);
163         return (error);
164 }
165
166 int
167 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
168 {
169         struct ucred *newcred, *oldcred;
170         struct label *intlabel;
171         struct proc *p;
172         struct mac mac;
173         char *buffer;
174         int error;
175
176         if (!(mac_labeled & MPC_OBJECT_CRED))
177                 return (EINVAL);
178
179         error = copyin(uap->mac_p, &mac, sizeof(mac));
180         if (error)
181                 return (error);
182
183         error = mac_check_structmac_consistent(&mac);
184         if (error)
185                 return (error);
186
187         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
188         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
189         if (error) {
190                 free(buffer, M_MACTEMP);
191                 return (error);
192         }
193
194         intlabel = mac_cred_label_alloc();
195         error = mac_cred_internalize_label(intlabel, buffer);
196         free(buffer, M_MACTEMP);
197         if (error)
198                 goto out;
199
200         newcred = crget();
201
202         p = td->td_proc;
203         PROC_LOCK(p);
204         oldcred = p->p_ucred;
205
206         error = mac_cred_check_relabel(oldcred, intlabel);
207         if (error) {
208                 PROC_UNLOCK(p);
209                 crfree(newcred);
210                 goto out;
211         }
212
213         setsugid(p);
214         crcopy(newcred, oldcred);
215         mac_cred_relabel(newcred, intlabel);
216         proc_set_cred(p, newcred);
217
218         PROC_UNLOCK(p);
219         crfree(oldcred);
220         mac_proc_vm_revoke(td);
221
222 out:
223         mac_cred_label_free(intlabel);
224         return (error);
225 }
226
227 int
228 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
229 {
230         char *elements, *buffer;
231         struct label *intlabel;
232         struct file *fp;
233         struct mac mac;
234         struct vnode *vp;
235         struct pipe *pipe;
236         struct socket *so;
237         cap_rights_t rights;
238         int error;
239
240         error = copyin(uap->mac_p, &mac, sizeof(mac));
241         if (error)
242                 return (error);
243
244         error = mac_check_structmac_consistent(&mac);
245         if (error)
246                 return (error);
247
248         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
249         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
250         if (error) {
251                 free(elements, M_MACTEMP);
252                 return (error);
253         }
254
255         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
256         error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_GET),
257             &fp);
258         if (error)
259                 goto out;
260
261         switch (fp->f_type) {
262         case DTYPE_FIFO:
263         case DTYPE_VNODE:
264                 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
265                         error = EINVAL;
266                         goto out_fdrop;
267                 }
268                 vp = fp->f_vnode;
269                 intlabel = mac_vnode_label_alloc();
270                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
271                 mac_vnode_copy_label(vp->v_label, intlabel);
272                 VOP_UNLOCK(vp);
273                 error = mac_vnode_externalize_label(intlabel, elements,
274                     buffer, mac.m_buflen);
275                 mac_vnode_label_free(intlabel);
276                 break;
277
278         case DTYPE_PIPE:
279                 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
280                         error = EINVAL;
281                         goto out_fdrop;
282                 }
283                 pipe = fp->f_data;
284                 intlabel = mac_pipe_label_alloc();
285                 PIPE_LOCK(pipe);
286                 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
287                 PIPE_UNLOCK(pipe);
288                 error = mac_pipe_externalize_label(intlabel, elements,
289                     buffer, mac.m_buflen);
290                 mac_pipe_label_free(intlabel);
291                 break;
292
293         case DTYPE_SOCKET:
294                 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
295                         error = EINVAL;
296                         goto out_fdrop;
297                 }
298                 so = fp->f_data;
299                 intlabel = mac_socket_label_alloc(M_WAITOK);
300                 SOCK_LOCK(so);
301                 mac_socket_copy_label(so->so_label, intlabel);
302                 SOCK_UNLOCK(so);
303                 error = mac_socket_externalize_label(intlabel, elements,
304                     buffer, mac.m_buflen);
305                 mac_socket_label_free(intlabel);
306                 break;
307
308         default:
309                 error = EINVAL;
310         }
311         if (error == 0)
312                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
313 out_fdrop:
314         fdrop(fp, td);
315 out:
316         free(buffer, M_MACTEMP);
317         free(elements, M_MACTEMP);
318         return (error);
319 }
320
321 int
322 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
323 {
324
325         return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW));
326 }
327
328 int
329 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
330 {
331
332         return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
333 }
334
335 static int
336 kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p,
337    int follow)
338 {
339         char *elements, *buffer;
340         struct nameidata nd;
341         struct label *intlabel;
342         struct mac mac;
343         int error;
344
345         if (!(mac_labeled & MPC_OBJECT_VNODE))
346                 return (EINVAL);
347
348         error = copyin(mac_p, &mac, sizeof(mac));
349         if (error)
350                 return (error);
351
352         error = mac_check_structmac_consistent(&mac);
353         if (error)
354                 return (error);
355
356         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
357         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
358         if (error) {
359                 free(elements, M_MACTEMP);
360                 return (error);
361         }
362
363         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
364         NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td);
365         error = namei(&nd);
366         if (error)
367                 goto out;
368
369         intlabel = mac_vnode_label_alloc();
370         mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
371         error = mac_vnode_externalize_label(intlabel, elements, buffer,
372             mac.m_buflen);
373         NDFREE(&nd, 0);
374         mac_vnode_label_free(intlabel);
375
376         if (error == 0)
377                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
378
379 out:
380         free(buffer, M_MACTEMP);
381         free(elements, M_MACTEMP);
382
383         return (error);
384 }
385
386 int
387 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
388 {
389         struct label *intlabel;
390         struct pipe *pipe;
391         struct socket *so;
392         struct file *fp;
393         struct mount *mp;
394         struct vnode *vp;
395         struct mac mac;
396         cap_rights_t rights;
397         char *buffer;
398         int error;
399
400         error = copyin(uap->mac_p, &mac, sizeof(mac));
401         if (error)
402                 return (error);
403
404         error = mac_check_structmac_consistent(&mac);
405         if (error)
406                 return (error);
407
408         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
409         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
410         if (error) {
411                 free(buffer, M_MACTEMP);
412                 return (error);
413         }
414
415         error = fget(td, uap->fd, cap_rights_init_one(&rights, CAP_MAC_SET),
416             &fp);
417         if (error)
418                 goto out;
419
420         switch (fp->f_type) {
421         case DTYPE_FIFO:
422         case DTYPE_VNODE:
423                 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
424                         error = EINVAL;
425                         goto out_fdrop;
426                 }
427                 intlabel = mac_vnode_label_alloc();
428                 error = mac_vnode_internalize_label(intlabel, buffer);
429                 if (error) {
430                         mac_vnode_label_free(intlabel);
431                         break;
432                 }
433                 vp = fp->f_vnode;
434                 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
435                 if (error != 0) {
436                         mac_vnode_label_free(intlabel);
437                         break;
438                 }
439                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
440                 error = vn_setlabel(vp, intlabel, td->td_ucred);
441                 VOP_UNLOCK(vp);
442                 vn_finished_write(mp);
443                 mac_vnode_label_free(intlabel);
444                 break;
445
446         case DTYPE_PIPE:
447                 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
448                         error = EINVAL;
449                         goto out_fdrop;
450                 }
451                 intlabel = mac_pipe_label_alloc();
452                 error = mac_pipe_internalize_label(intlabel, buffer);
453                 if (error == 0) {
454                         pipe = fp->f_data;
455                         PIPE_LOCK(pipe);
456                         error = mac_pipe_label_set(td->td_ucred,
457                             pipe->pipe_pair, intlabel);
458                         PIPE_UNLOCK(pipe);
459                 }
460                 mac_pipe_label_free(intlabel);
461                 break;
462
463         case DTYPE_SOCKET:
464                 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
465                         error = EINVAL;
466                         goto out_fdrop;
467                 }
468                 intlabel = mac_socket_label_alloc(M_WAITOK);
469                 error = mac_socket_internalize_label(intlabel, buffer);
470                 if (error == 0) {
471                         so = fp->f_data;
472                         error = mac_socket_label_set(td->td_ucred, so,
473                             intlabel);
474                 }
475                 mac_socket_label_free(intlabel);
476                 break;
477
478         default:
479                 error = EINVAL;
480         }
481 out_fdrop:
482         fdrop(fp, td);
483 out:
484         free(buffer, M_MACTEMP);
485         return (error);
486 }
487
488 int
489 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
490 {
491
492         return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
493 }
494
495 int
496 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
497 {
498
499         return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
500 }
501
502 static int
503 kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
504     int follow)
505 {
506         struct label *intlabel;
507         struct nameidata nd;
508         struct mount *mp;
509         struct mac mac;
510         char *buffer;
511         int error;
512
513         if (!(mac_labeled & MPC_OBJECT_VNODE))
514                 return (EINVAL);
515
516         error = copyin(mac_p, &mac, sizeof(mac));
517         if (error)
518                 return (error);
519
520         error = mac_check_structmac_consistent(&mac);
521         if (error)
522                 return (error);
523
524         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
525         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
526         if (error) {
527                 free(buffer, M_MACTEMP);
528                 return (error);
529         }
530
531         intlabel = mac_vnode_label_alloc();
532         error = mac_vnode_internalize_label(intlabel, buffer);
533         free(buffer, M_MACTEMP);
534         if (error)
535                 goto out;
536
537         NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td);
538         error = namei(&nd);
539         if (error == 0) {
540                 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
541                 if (error == 0) {
542                         error = vn_setlabel(nd.ni_vp, intlabel,
543                             td->td_ucred);
544                         vn_finished_write(mp);
545                 }
546         }
547
548         NDFREE(&nd, 0);
549 out:
550         mac_vnode_label_free(intlabel);
551         return (error);
552 }
553
554 int
555 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
556 {
557         struct mac_policy_conf *mpc;
558         char target[MAC_MAX_POLICY_NAME];
559         int error;
560
561         error = copyinstr(uap->policy, target, sizeof(target), NULL);
562         if (error)
563                 return (error);
564
565         error = ENOSYS;
566         LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
567                 if (strcmp(mpc->mpc_name, target) == 0 &&
568                     mpc->mpc_ops->mpo_syscall != NULL) {
569                         error = mpc->mpc_ops->mpo_syscall(td,
570                             uap->call, uap->arg);
571                         goto out;
572                 }
573         }
574
575         if (!LIST_EMPTY(&mac_policy_list)) {
576                 mac_policy_slock_sleep();
577                 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
578                         if (strcmp(mpc->mpc_name, target) == 0 &&
579                             mpc->mpc_ops->mpo_syscall != NULL) {
580                                 error = mpc->mpc_ops->mpo_syscall(td,
581                                     uap->call, uap->arg);
582                                 break;
583                         }
584                 }
585                 mac_policy_sunlock_sleep();
586         }
587 out:
588         return (error);
589 }
590
591 #else /* !MAC */
592
593 int
594 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
595 {
596
597         return (ENOSYS);
598 }
599
600 int
601 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
602 {
603
604         return (ENOSYS);
605 }
606
607 int
608 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
609 {
610
611         return (ENOSYS);
612 }
613
614 int
615 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
616 {
617
618         return (ENOSYS);
619 }
620
621 int
622 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
623 {
624
625         return (ENOSYS);
626 }
627
628 int
629 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
630 {
631
632         return (ENOSYS);
633 }
634
635 int
636 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
637 {
638
639         return (ENOSYS);
640 }
641
642 int
643 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
644 {
645
646         return (ENOSYS);
647 }
648
649 int
650 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
651 {
652
653         return (ENOSYS);
654 }
655
656 int
657 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
658 {
659
660         return (ENOSYS);
661 }
662
663 #endif /* !MAC */