xref: /illumos-gate/usr/src/uts/common/syscall/psecflags.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /* Copyright 2015, Richard Lowe. */
13 
14 #include <sys/ddi.h>
15 #include <sys/errno.h>
16 #include <sys/policy.h>
17 #include <sys/proc.h>
18 #include <sys/procset.h>
19 #include <sys/systm.h>
20 #include <sys/types.h>
21 #include <c2/audit.h>
22 
23 struct psdargs {
24 	psecflagwhich_t which;
25 	const secflagdelta_t *delta;
26 };
27 
28 void
29 secflags_apply_delta(secflagset_t *set, const secflagdelta_t *delta)
30 {
31 	if (delta->psd_ass_active) {
32 		secflags_copy(set, &delta->psd_assign);
33 	} else {
34 		if (!secflags_isempty(delta->psd_add)) {
35 			secflags_union(set, &delta->psd_add);
36 		}
37 		if (!secflags_isempty(delta->psd_rem)) {
38 			secflags_difference(set, &delta->psd_rem);
39 		}
40 	}
41 }
42 
43 
44 static int
45 psecdo(proc_t *p, struct psdargs *args)
46 {
47 	secflagset_t *set;
48 	int ret = 0;
49 
50 	mutex_enter(&p->p_lock);
51 
52 	if (secpolicy_psecflags(CRED(), p, curproc) != 0) {
53 		ret = EPERM;
54 		goto out;
55 	}
56 
57 	if (!psecflags_validate_delta(&p->p_secflags, args->delta)) {
58 		ret = EINVAL;
59 		goto out;
60 	}
61 
62 	if (AU_AUDITING())
63 		audit_psecflags(p, args->which, args->delta);
64 
65 	switch (args->which) {
66 	case PSF_INHERIT:
67 		set = &p->p_secflags.psf_inherit;
68 		break;
69 	case PSF_LOWER:
70 		set = &p->p_secflags.psf_lower;
71 		break;
72 	case PSF_UPPER:
73 		set = &p->p_secflags.psf_upper;
74 		break;
75 	default:
76 		ASSERT(0);
77 		goto out;
78 	}
79 
80 	secflags_apply_delta(set, args->delta);
81 
82 	/*
83 	 * Add any flag now in the lower that is not in the inheritable.
84 	 */
85 	secflags_union(&p->p_secflags.psf_inherit, &p->p_secflags.psf_lower);
86 
87 out:
88 	mutex_exit(&p->p_lock);
89 	return (ret);
90 }
91 
92 int
93 psecflags(procset_t *psp, psecflagwhich_t which, secflagdelta_t *ap)
94 {
95 	procset_t procset;
96 	secflagdelta_t args;
97 	int rv = 0;
98 	struct psdargs psd = {
99 		.which = which,
100 	};
101 
102 	/* Can never change the effective flags */
103 	if (psd.which == PSF_EFFECTIVE)
104 		return (EINVAL);
105 
106 	if (copyin(psp, &procset, sizeof (procset)) != 0)
107 		return (set_errno(EFAULT));
108 
109 	if (copyin(ap, &args, sizeof (secflagdelta_t)) != 0)
110 		return (set_errno(EFAULT));
111 
112 	psd.delta = &args;
113 
114 	/* secflags are per-process, procset must be in terms of processes */
115 	if ((procset.p_lidtype == P_LWPID) ||
116 	    (procset.p_ridtype == P_LWPID))
117 		return (set_errno(EINVAL));
118 
119 	rv = dotoprocs(&procset, psecdo, (caddr_t)&psd);
120 
121 	return (rv ? set_errno(rv) : 0);
122 }
123