]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/security/mac/mac_syscalls.c
Update to Zstandard 1.4.0
[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(&rights, CAP_MAC_GET), &fp);
257         if (error)
258                 goto out;
259
260         switch (fp->f_type) {
261         case DTYPE_FIFO:
262         case DTYPE_VNODE:
263                 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
264                         error = EINVAL;
265                         goto out_fdrop;
266                 }
267                 vp = fp->f_vnode;
268                 intlabel = mac_vnode_label_alloc();
269                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
270                 mac_vnode_copy_label(vp->v_label, intlabel);
271                 VOP_UNLOCK(vp, 0);
272                 error = mac_vnode_externalize_label(intlabel, elements,
273                     buffer, mac.m_buflen);
274                 mac_vnode_label_free(intlabel);
275                 break;
276
277         case DTYPE_PIPE:
278                 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
279                         error = EINVAL;
280                         goto out_fdrop;
281                 }
282                 pipe = fp->f_data;
283                 intlabel = mac_pipe_label_alloc();
284                 PIPE_LOCK(pipe);
285                 mac_pipe_copy_label(pipe->pipe_pair->pp_label, intlabel);
286                 PIPE_UNLOCK(pipe);
287                 error = mac_pipe_externalize_label(intlabel, elements,
288                     buffer, mac.m_buflen);
289                 mac_pipe_label_free(intlabel);
290                 break;
291
292         case DTYPE_SOCKET:
293                 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
294                         error = EINVAL;
295                         goto out_fdrop;
296                 }
297                 so = fp->f_data;
298                 intlabel = mac_socket_label_alloc(M_WAITOK);
299                 SOCK_LOCK(so);
300                 mac_socket_copy_label(so->so_label, intlabel);
301                 SOCK_UNLOCK(so);
302                 error = mac_socket_externalize_label(intlabel, elements,
303                     buffer, mac.m_buflen);
304                 mac_socket_label_free(intlabel);
305                 break;
306
307         default:
308                 error = EINVAL;
309         }
310         if (error == 0)
311                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
312 out_fdrop:
313         fdrop(fp, td);
314 out:
315         free(buffer, M_MACTEMP);
316         free(elements, M_MACTEMP);
317         return (error);
318 }
319
320 int
321 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
322 {
323
324         return (kern___mac_get_path(td, uap->path_p, uap->mac_p, FOLLOW));
325 }
326
327 int
328 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
329 {
330
331         return (kern___mac_get_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
332 }
333
334 static int
335 kern___mac_get_path(struct thread *td, const char *path_p, struct mac *mac_p,
336    int follow)
337 {
338         char *elements, *buffer;
339         struct nameidata nd;
340         struct label *intlabel;
341         struct mac mac;
342         int error;
343
344         if (!(mac_labeled & MPC_OBJECT_VNODE))
345                 return (EINVAL);
346
347         error = copyin(mac_p, &mac, sizeof(mac));
348         if (error)
349                 return (error);
350
351         error = mac_check_structmac_consistent(&mac);
352         if (error)
353                 return (error);
354
355         elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
356         error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
357         if (error) {
358                 free(elements, M_MACTEMP);
359                 return (error);
360         }
361
362         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
363         NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td);
364         error = namei(&nd);
365         if (error)
366                 goto out;
367
368         intlabel = mac_vnode_label_alloc();
369         mac_vnode_copy_label(nd.ni_vp->v_label, intlabel);
370         error = mac_vnode_externalize_label(intlabel, elements, buffer,
371             mac.m_buflen);
372         NDFREE(&nd, 0);
373         mac_vnode_label_free(intlabel);
374
375         if (error == 0)
376                 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
377
378 out:
379         free(buffer, M_MACTEMP);
380         free(elements, M_MACTEMP);
381
382         return (error);
383 }
384
385 int
386 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
387 {
388         struct label *intlabel;
389         struct pipe *pipe;
390         struct socket *so;
391         struct file *fp;
392         struct mount *mp;
393         struct vnode *vp;
394         struct mac mac;
395         cap_rights_t rights;
396         char *buffer;
397         int error;
398
399         error = copyin(uap->mac_p, &mac, sizeof(mac));
400         if (error)
401                 return (error);
402
403         error = mac_check_structmac_consistent(&mac);
404         if (error)
405                 return (error);
406
407         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
408         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
409         if (error) {
410                 free(buffer, M_MACTEMP);
411                 return (error);
412         }
413
414         error = fget(td, uap->fd, cap_rights_init(&rights, CAP_MAC_SET), &fp);
415         if (error)
416                 goto out;
417
418         switch (fp->f_type) {
419         case DTYPE_FIFO:
420         case DTYPE_VNODE:
421                 if (!(mac_labeled & MPC_OBJECT_VNODE)) {
422                         error = EINVAL;
423                         goto out_fdrop;
424                 }
425                 intlabel = mac_vnode_label_alloc();
426                 error = mac_vnode_internalize_label(intlabel, buffer);
427                 if (error) {
428                         mac_vnode_label_free(intlabel);
429                         break;
430                 }
431                 vp = fp->f_vnode;
432                 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
433                 if (error != 0) {
434                         mac_vnode_label_free(intlabel);
435                         break;
436                 }
437                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
438                 error = vn_setlabel(vp, intlabel, td->td_ucred);
439                 VOP_UNLOCK(vp, 0);
440                 vn_finished_write(mp);
441                 mac_vnode_label_free(intlabel);
442                 break;
443
444         case DTYPE_PIPE:
445                 if (!(mac_labeled & MPC_OBJECT_PIPE)) {
446                         error = EINVAL;
447                         goto out_fdrop;
448                 }
449                 intlabel = mac_pipe_label_alloc();
450                 error = mac_pipe_internalize_label(intlabel, buffer);
451                 if (error == 0) {
452                         pipe = fp->f_data;
453                         PIPE_LOCK(pipe);
454                         error = mac_pipe_label_set(td->td_ucred,
455                             pipe->pipe_pair, intlabel);
456                         PIPE_UNLOCK(pipe);
457                 }
458                 mac_pipe_label_free(intlabel);
459                 break;
460
461         case DTYPE_SOCKET:
462                 if (!(mac_labeled & MPC_OBJECT_SOCKET)) {
463                         error = EINVAL;
464                         goto out_fdrop;
465                 }
466                 intlabel = mac_socket_label_alloc(M_WAITOK);
467                 error = mac_socket_internalize_label(intlabel, buffer);
468                 if (error == 0) {
469                         so = fp->f_data;
470                         error = mac_socket_label_set(td->td_ucred, so,
471                             intlabel);
472                 }
473                 mac_socket_label_free(intlabel);
474                 break;
475
476         default:
477                 error = EINVAL;
478         }
479 out_fdrop:
480         fdrop(fp, td);
481 out:
482         free(buffer, M_MACTEMP);
483         return (error);
484 }
485
486 int
487 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
488 {
489
490         return (kern___mac_set_path(td, uap->path_p, uap->mac_p, FOLLOW));
491 }
492
493 int
494 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
495 {
496
497         return (kern___mac_set_path(td, uap->path_p, uap->mac_p, NOFOLLOW));
498 }
499
500 static int
501 kern___mac_set_path(struct thread *td, const char *path_p, struct mac *mac_p,
502     int follow)
503 {
504         struct label *intlabel;
505         struct nameidata nd;
506         struct mount *mp;
507         struct mac mac;
508         char *buffer;
509         int error;
510
511         if (!(mac_labeled & MPC_OBJECT_VNODE))
512                 return (EINVAL);
513
514         error = copyin(mac_p, &mac, sizeof(mac));
515         if (error)
516                 return (error);
517
518         error = mac_check_structmac_consistent(&mac);
519         if (error)
520                 return (error);
521
522         buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
523         error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
524         if (error) {
525                 free(buffer, M_MACTEMP);
526                 return (error);
527         }
528
529         intlabel = mac_vnode_label_alloc();
530         error = mac_vnode_internalize_label(intlabel, buffer);
531         free(buffer, M_MACTEMP);
532         if (error)
533                 goto out;
534
535         NDINIT(&nd, LOOKUP, LOCKLEAF | follow, UIO_USERSPACE, path_p, td);
536         error = namei(&nd);
537         if (error == 0) {
538                 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
539                 if (error == 0) {
540                         error = vn_setlabel(nd.ni_vp, intlabel,
541                             td->td_ucred);
542                         vn_finished_write(mp);
543                 }
544         }
545
546         NDFREE(&nd, 0);
547 out:
548         mac_vnode_label_free(intlabel);
549         return (error);
550 }
551
552 int
553 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
554 {
555         struct mac_policy_conf *mpc;
556         char target[MAC_MAX_POLICY_NAME];
557         int error;
558
559         error = copyinstr(uap->policy, target, sizeof(target), NULL);
560         if (error)
561                 return (error);
562
563         error = ENOSYS;
564         LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
565                 if (strcmp(mpc->mpc_name, target) == 0 &&
566                     mpc->mpc_ops->mpo_syscall != NULL) {
567                         error = mpc->mpc_ops->mpo_syscall(td,
568                             uap->call, uap->arg);
569                         goto out;
570                 }
571         }
572
573         if (!LIST_EMPTY(&mac_policy_list)) {
574                 mac_policy_slock_sleep();
575                 LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
576                         if (strcmp(mpc->mpc_name, target) == 0 &&
577                             mpc->mpc_ops->mpo_syscall != NULL) {
578                                 error = mpc->mpc_ops->mpo_syscall(td,
579                                     uap->call, uap->arg);
580                                 break;
581                         }
582                 }
583                 mac_policy_sunlock_sleep();
584         }
585 out:
586         return (error);
587 }
588
589 #else /* !MAC */
590
591 int
592 sys___mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
593 {
594
595         return (ENOSYS);
596 }
597
598 int
599 sys___mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
600 {
601
602         return (ENOSYS);
603 }
604
605 int
606 sys___mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
607 {
608
609         return (ENOSYS);
610 }
611
612 int
613 sys___mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
614 {
615
616         return (ENOSYS);
617 }
618
619 int
620 sys___mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
621 {
622
623         return (ENOSYS);
624 }
625
626 int
627 sys___mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
628 {
629
630         return (ENOSYS);
631 }
632
633 int
634 sys___mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
635 {
636
637         return (ENOSYS);
638 }
639
640 int
641 sys___mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
642 {
643
644         return (ENOSYS);
645 }
646
647 int
648 sys___mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
649 {
650
651         return (ENOSYS);
652 }
653
654 int
655 sys_mac_syscall(struct thread *td, struct mac_syscall_args *uap)
656 {
657
658         return (ENOSYS);
659 }
660
661 #endif /* !MAC */