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 }