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