xref: /illumos-gate/usr/src/uts/common/syscall/psecflags.c (revision c160bf3613805cfb4a89a0433ae896d3594f551f)
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 	ASSERT(args->which != PSF_EFFECTIVE);
58 
59 	if (!psecflags_validate_delta(&p->p_secflags, args->delta)) {
60 		ret = EINVAL;
61 		goto out;
62 	}
63 
64 	if (AU_AUDITING())
65 		audit_psecflags(p, args->which, args->delta);
66 
67 	switch (args->which) {
68 	case PSF_INHERIT:
69 		set = &p->p_secflags.psf_inherit;
70 		break;
71 	case PSF_LOWER:
72 		set = &p->p_secflags.psf_lower;
73 		break;
74 	case PSF_UPPER:
75 		set = &p->p_secflags.psf_upper;
76 		break;
77 	}
78 
79 	secflags_apply_delta(set, args->delta);
80 
81 	/*
82 	 * Add any flag now in the lower that is not in the inheritable.
83 	 */
84 	secflags_union(&p->p_secflags.psf_inherit, &p->p_secflags.psf_lower);
85 
86 out:
87 	mutex_exit(&p->p_lock);
88 	return (ret);
89 }
90 
91 int
92 psecflags(procset_t *psp, psecflagwhich_t which, secflagdelta_t *ap)
93 {
94 	procset_t procset;
95 	secflagdelta_t args;
96 	int rv = 0;
97 	struct psdargs psd = {
98 		.which = which,
99 	};
100 
101 	/* Can never change the effective flags */
102 	if (psd.which == PSF_EFFECTIVE)
103 		return (EINVAL);
104 
105 	if (copyin(psp, &procset, sizeof (procset)) != 0)
106 		return (set_errno(EFAULT));
107 
108 	if (copyin(ap, &args, sizeof (secflagdelta_t)) != 0)
109 		return (set_errno(EFAULT));
110 
111 	psd.delta = &args;
112 
113 	/* secflags are per-process, procset must be in terms of processes */
114 	if ((procset.p_lidtype == P_LWPID) ||
115 	    (procset.p_ridtype == P_LWPID))
116 		return (set_errno(EINVAL));
117 
118 	rv = dotoprocs(&procset, psecdo, (caddr_t)&psd);
119 
120 	return (rv ? set_errno(rv) : 0);
121 }
122