1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015, Joyent, Inc.
  25  */
  26 
  27 #include <sys/atomic.h>
  28 #include <sys/door.h>
  29 #include <sys/proc.h>
  30 #include <sys/cred_impl.h>
  31 #include <sys/policy.h>
  32 #include <sys/priv.h>
  33 #include <sys/klpd.h>
  34 #include <sys/errno.h>
  35 #include <sys/kmem.h>
  36 #include <sys/project.h>
  37 #include <sys/systm.h>
  38 #include <sys/sysmacros.h>
  39 #include <sys/pathname.h>
  40 #include <sys/varargs.h>
  41 #include <sys/zone.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/sdt.h>
  44 #include <netinet/in.h>
  45 
  46 #define ROUNDUP(a, n) (((a) + ((n) - 1)) & ~((n) - 1))
  47 
  48 static kmutex_t klpd_mutex;
  49 
  50 typedef struct klpd_reg {
  51         struct klpd_reg *klpd_next;
  52         struct klpd_reg **klpd_refp;
  53         door_handle_t   klpd_door;
  54         pid_t           klpd_door_pid;
  55         priv_set_t      klpd_pset;
  56         cred_t          *klpd_cred;
  57         int             klpd_indel;             /* Disabled */
  58         uint32_t        klpd_ref;
  59 } klpd_reg_t;
  60 
  61 
  62 /*
  63  * This data structure hangs off the credential of a process; the
  64  * credential is finalized and cannot be changed; but this structure
  65  * can be changed when a new door server for the particular group
  66  * needs to be registered.  It is refcounted and shared between
  67  * processes with common ancestry.
  68  *
  69  * The reference count is atomically updated.
  70  *
  71  * But the registration probably needs to be updated under a lock.
  72  */
  73 typedef struct credklpd {
  74         kmutex_t        crkl_lock;
  75         klpd_reg_t      *crkl_reg;
  76         uint32_t        crkl_ref;
  77 } credklpd_t;
  78 
  79 klpd_reg_t *klpd_list;
  80 
  81 static void klpd_unlink(klpd_reg_t *);
  82 static int klpd_unreg_dh(door_handle_t);
  83 
  84 static credklpd_t *crklpd_alloc(void);
  85 
  86 void crklpd_setreg(credklpd_t *, klpd_reg_t *);
  87 
  88 extern size_t max_vnode_path;
  89 
  90 void
  91 klpd_rele(klpd_reg_t *p)
  92 {
  93         if (atomic_dec_32_nv(&p->klpd_ref) == 0) {
  94                 if (p->klpd_refp != NULL)
  95                         klpd_unlink(p);
  96                 if (p->klpd_cred != NULL)
  97                         crfree(p->klpd_cred);
  98                 door_ki_rele(p->klpd_door);
  99                 kmem_free(p, sizeof (*p));
 100         }
 101 }
 102 
 103 /*
 104  * In order to be able to walk the lists, we can't unlink the entry
 105  * until the reference count drops to 0.  If we remove it too soon,
 106  * list walkers will terminate when they happen to call a now orphaned
 107  * entry.
 108  */
 109 static klpd_reg_t *
 110 klpd_rele_next(klpd_reg_t *p)
 111 {
 112         klpd_reg_t *r = p->klpd_next;
 113 
 114         klpd_rele(p);
 115         return (r);
 116 }
 117 
 118 
 119 static void
 120 klpd_hold(klpd_reg_t *p)
 121 {
 122         atomic_inc_32(&p->klpd_ref);
 123 }
 124 
 125 /*
 126  * Remove registration from where it is registered.  Returns next in list.
 127  */
 128 static void
 129 klpd_unlink(klpd_reg_t *p)
 130 {
 131         ASSERT(p->klpd_refp == NULL || *p->klpd_refp == p);
 132 
 133         if (p->klpd_refp != NULL)
 134                 *p->klpd_refp = p->klpd_next;
 135 
 136         if (p->klpd_next != NULL)
 137                 p->klpd_next->klpd_refp = p->klpd_refp;
 138         p->klpd_refp = NULL;
 139 }
 140 
 141 /*
 142  * Remove all elements of the klpd list and decrement their refcnts.
 143  * The lock guarding the list should be held; this function is
 144  * called when we are sure we want to destroy the list completely
 145  * list but not so sure that the reference counts of all elements have
 146  * dropped back to 1.
 147  */
 148 void
 149 klpd_freelist(klpd_reg_t **pp)
 150 {
 151         klpd_reg_t *p;
 152 
 153         while ((p = *pp) != NULL) {
 154                 klpd_unlink(p);
 155                 klpd_rele(p);
 156         }
 157 }
 158 
 159 /*
 160  * Link new entry in list.  The Boolean argument specifies whether this
 161  * list can contain only a single item or multiple items.
 162  * Returns the entry which needs to be released if single is B_TRUE.
 163  */
 164 static klpd_reg_t *
 165 klpd_link(klpd_reg_t *p, klpd_reg_t **listp, boolean_t single)
 166 {
 167         klpd_reg_t *old = *listp;
 168 
 169         ASSERT(p->klpd_ref == 1);
 170 
 171         ASSERT(old == NULL || *old->klpd_refp == old);
 172         p->klpd_refp = listp;
 173         p->klpd_next = single ? NULL : old;
 174         *listp = p;
 175         if (old != NULL) {
 176                 if (single) {
 177                         ASSERT(old->klpd_next == NULL);
 178                         old->klpd_refp = NULL;
 179                         return (old);
 180                 } else
 181                         old->klpd_refp = &p->klpd_next;
 182         }
 183         return (NULL);
 184 }
 185 
 186 /*
 187  * The typical call consists of:
 188  *      - priv_set_t
 189  *      - some integer data (type, value)
 190  * for now, it's just one bit.
 191  */
 192 static klpd_head_t *
 193 klpd_marshall(klpd_reg_t *p, const priv_set_t *rq, va_list ap)
 194 {
 195         char    *tmp;
 196         uint_t  type;
 197         vnode_t *vp;
 198         size_t  len = sizeof (priv_set_t) + sizeof (klpd_head_t);
 199         size_t  plen, clen;
 200         int     proto;
 201 
 202         klpd_arg_t *kap = NULL;
 203         klpd_head_t *khp;
 204 
 205         type = va_arg(ap, uint_t);
 206         switch (type) {
 207         case KLPDARG_NOMORE:
 208                 khp = kmem_zalloc(len, KM_SLEEP);
 209                 khp->klh_argoff = 0;
 210                 break;
 211         case KLPDARG_VNODE:
 212                 len += offsetof(klpd_arg_t, kla_str);
 213                 vp = va_arg(ap, vnode_t *);
 214                 if (vp == NULL)
 215                         return (NULL);
 216 
 217                 tmp = va_arg(ap, char *);
 218 
 219                 if (tmp != NULL && *tmp != '\0')
 220                         clen = strlen(tmp) + 1;
 221                 else
 222                         clen = 0;
 223 
 224                 len += ROUNDUP(MAXPATHLEN, sizeof (uint_t));
 225                 khp = kmem_zalloc(len, KM_SLEEP);
 226 
 227                 khp->klh_argoff = sizeof (klpd_head_t) + sizeof (priv_set_t);
 228                 kap = KLH_ARG(khp);
 229 
 230                 if (vnodetopath(crgetzone(p->klpd_cred)->zone_rootvp,
 231                     vp, kap->kla_str, MAXPATHLEN, p->klpd_cred) != 0) {
 232                         kmem_free(khp, len);
 233                         return (NULL);
 234                 }
 235                 if (clen != 0) {
 236                         plen = strlen(kap->kla_str);
 237                         if (plen + clen + 1 >= MAXPATHLEN) {
 238                                 kmem_free(khp, len);
 239                                 return (NULL);
 240                         }
 241                         /* Don't make root into a double "/" */
 242                         if (plen <= 2)
 243                                 plen = 0;
 244                         kap->kla_str[plen] = '/';
 245                         bcopy(tmp, &kap->kla_str[plen + 1], clen);
 246                 }
 247                 break;
 248         case KLPDARG_PORT:
 249                 proto = va_arg(ap, int);
 250                 switch (proto) {
 251                 case IPPROTO_TCP:       type = KLPDARG_TCPPORT;
 252                                         break;
 253                 case IPPROTO_UDP:       type = KLPDARG_UDPPORT;
 254                                         break;
 255                 case IPPROTO_SCTP:      type = KLPDARG_SCTPPORT;
 256                                         break;
 257                 case PROTO_SDP:         type = KLPDARG_SDPPORT;
 258                                         break;
 259                 }
 260                 /* FALLTHROUGH */
 261         case KLPDARG_INT:
 262         case KLPDARG_TCPPORT:
 263         case KLPDARG_UDPPORT:
 264         case KLPDARG_SCTPPORT:
 265         case KLPDARG_SDPPORT:
 266                 len += sizeof (*kap);
 267                 khp = kmem_zalloc(len, KM_SLEEP);
 268                 khp->klh_argoff = sizeof (klpd_head_t) + sizeof (priv_set_t);
 269                 kap = KLH_ARG(khp);
 270                 kap->kla_int = va_arg(ap, int);
 271                 break;
 272         default:
 273                 return (NULL);
 274         }
 275         khp->klh_vers = KLPDCALL_VERS;
 276         khp->klh_len = len;
 277         khp->klh_privoff = sizeof (*khp);
 278         *KLH_PRIVSET(khp) = *rq;
 279         if (kap != NULL) {
 280                 kap->kla_type = type;
 281                 kap->kla_dlen = len - khp->klh_argoff;
 282         }
 283         return (khp);
 284 }
 285 
 286 static int
 287 klpd_do_call(klpd_reg_t *p, const priv_set_t *req, va_list ap)
 288 {
 289         door_arg_t da;
 290         int res;
 291         int dres;
 292         klpd_head_t *klh;
 293 
 294         if (p->klpd_door_pid == curproc->p_pid)
 295                 return (-1);
 296 
 297         klh = klpd_marshall(p, req, ap);
 298 
 299         if (klh == NULL)
 300                 return (-1);
 301 
 302         da.data_ptr = (char *)klh;
 303         da.data_size = klh->klh_len;
 304         da.desc_ptr = NULL;
 305         da.desc_num = 0;
 306         da.rbuf = (char *)&res;
 307         da.rsize = sizeof (res);
 308 
 309         while ((dres = door_ki_upcall_limited(p->klpd_door, &da, NULL,
 310             SIZE_MAX, 0)) != 0) {
 311                 switch (dres) {
 312                 case EAGAIN:
 313                         delay(1);
 314                         continue;
 315                 case EINVAL:
 316                 case EBADF:
 317                         /* Bad door, don't call it again. */
 318                         (void) klpd_unreg_dh(p->klpd_door);
 319                         /* FALLTHROUGH */
 320                 case EINTR:
 321                         /* Pending signal, nothing we can do. */
 322                         /* FALLTHROUGH */
 323                 default:
 324                         kmem_free(klh, klh->klh_len);
 325                         return (-1);
 326                 }
 327         }
 328         kmem_free(klh, klh->klh_len);
 329         /* Bogus return value, must be a failure */
 330         if (da.rbuf != (char *)&res) {
 331                 kmem_free(da.rbuf, da.rsize);
 332                 return (-1);
 333         }
 334         return (res);
 335 }
 336 
 337 uint32_t klpd_bad_locks;
 338 
 339 int
 340 klpd_call(const cred_t *cr, const priv_set_t *req, va_list ap)
 341 {
 342         klpd_reg_t *p;
 343         int rv = -1;
 344         credklpd_t *ckp;
 345         zone_t *ckzone;
 346 
 347         /*
 348          * These locks must not be held when this code is called;
 349          * callbacks to userland with these locks held will result
 350          * in issues.  That said, the code at the call sides was
 351          * restructured not to call with any of the locks held and
 352          * no policies operate by default on most processes.
 353          */
 354         if (mutex_owned(&pidlock) || mutex_owned(&curproc->p_lock) ||
 355             mutex_owned(&curproc->p_crlock)) {
 356                 atomic_inc_32(&klpd_bad_locks);
 357                 return (-1);
 358         }
 359 
 360         /*
 361          * Enforce the limit set for the call process (still).
 362          */
 363         if (!priv_issubset(req, &CR_LPRIV(cr)))
 364                 return (-1);
 365 
 366         /* Try 1: get the credential specific klpd */
 367         if ((ckp = crgetcrklpd(cr)) != NULL) {
 368                 mutex_enter(&ckp->crkl_lock);
 369                 if ((p = ckp->crkl_reg) != NULL &&
 370                     p->klpd_indel == 0 &&
 371                     priv_issubset(req, &p->klpd_pset)) {
 372                         klpd_hold(p);
 373                         mutex_exit(&ckp->crkl_lock);
 374                         rv = klpd_do_call(p, req, ap);
 375                         mutex_enter(&ckp->crkl_lock);
 376                         klpd_rele(p);
 377                         mutex_exit(&ckp->crkl_lock);
 378                         if (rv != -1)
 379                                 return (rv == 0 ? 0 : -1);
 380                 } else {
 381                         mutex_exit(&ckp->crkl_lock);
 382                 }
 383         }
 384 
 385         /* Try 2: get the project specific klpd */
 386         mutex_enter(&klpd_mutex);
 387 
 388         if ((p = curproj->kpj_klpd) != NULL) {
 389                 klpd_hold(p);
 390                 mutex_exit(&klpd_mutex);
 391                 if (p->klpd_indel == 0 &&
 392                     priv_issubset(req, &p->klpd_pset)) {
 393                         rv = klpd_do_call(p, req, ap);
 394                 }
 395                 mutex_enter(&klpd_mutex);
 396                 klpd_rele(p);
 397                 mutex_exit(&klpd_mutex);
 398 
 399                 if (rv != -1)
 400                         return (rv == 0 ? 0 : -1);
 401         } else {
 402                 mutex_exit(&klpd_mutex);
 403         }
 404 
 405         /* Try 3: get the global klpd list */
 406         ckzone = crgetzone(cr);
 407         mutex_enter(&klpd_mutex);
 408 
 409         for (p = klpd_list; p != NULL; ) {
 410                 zone_t *kkzone = crgetzone(p->klpd_cred);
 411                 if ((kkzone == &zone0 || kkzone == ckzone) &&
 412                     p->klpd_indel == 0 &&
 413                     priv_issubset(req, &p->klpd_pset)) {
 414                         klpd_hold(p);
 415                         mutex_exit(&klpd_mutex);
 416                         rv = klpd_do_call(p, req, ap);
 417                         mutex_enter(&klpd_mutex);
 418 
 419                         p = klpd_rele_next(p);
 420 
 421                         if (rv != -1)
 422                                 break;
 423                 } else {
 424                         p = p->klpd_next;
 425                 }
 426         }
 427         mutex_exit(&klpd_mutex);
 428         return (rv == 0 ? 0 : -1);
 429 }
 430 
 431 /*
 432  * Register the klpd.
 433  * If the pid_t passed in is positive, update the registration for
 434  * the specific process; that is only possible if the process already
 435  * has a registration on it.  This change of registration will affect
 436  * all processes which share common ancestry.
 437  *
 438  * MY_PID (pid 0) can be used to create or change the context for
 439  * the current process, typically done after fork().
 440  *
 441  * A negative value can be used to register a klpd globally.
 442  *
 443  * The per-credential klpd needs to be cleaned up when entering
 444  * a zone or unsetting the flag.
 445  */
 446 int
 447 klpd_reg(int did, idtype_t type, id_t id, priv_set_t *psetbuf)
 448 {
 449         cred_t *cr = CRED();
 450         door_handle_t dh;
 451         klpd_reg_t *kpd;
 452         priv_set_t pset;
 453         door_info_t di;
 454         credklpd_t *ckp = NULL;
 455         pid_t pid = -1;
 456         projid_t proj = -1;
 457         kproject_t *kpp = NULL;
 458 
 459         if (CR_FLAGS(cr) & PRIV_XPOLICY)
 460                 return (set_errno(EINVAL));
 461 
 462         if (copyin(psetbuf, &pset, sizeof (priv_set_t)))
 463                 return (set_errno(EFAULT));
 464 
 465         if (!priv_issubset(&pset, &CR_OEPRIV(cr)))
 466                 return (set_errno(EPERM));
 467 
 468         switch (type) {
 469         case P_PID:
 470                 pid = (pid_t)id;
 471                 if (pid == P_MYPID)
 472                         pid = curproc->p_pid;
 473                 if (pid == curproc->p_pid)
 474                         ckp = crklpd_alloc();
 475                 break;
 476         case P_PROJID:
 477                 proj = (projid_t)id;
 478                 kpp = project_hold_by_id(proj, crgetzone(cr),
 479                     PROJECT_HOLD_FIND);
 480                 if (kpp == NULL)
 481                         return (set_errno(ESRCH));
 482                 break;
 483         default:
 484                 return (set_errno(ENOTSUP));
 485         }
 486 
 487 
 488         /*
 489          * Verify the door passed in; it must be a door and we won't
 490          * allow processes to be called on their own behalf.
 491          */
 492         dh = door_ki_lookup(did);
 493         if (dh == NULL || door_ki_info(dh, &di) != 0) {
 494                 if (ckp != NULL)
 495                         crklpd_rele(ckp);
 496                 if (kpp != NULL)
 497                         project_rele(kpp);
 498                 return (set_errno(EBADF));
 499         }
 500         if (type == P_PID && pid == di.di_target) {
 501                 if (ckp != NULL)
 502                         crklpd_rele(ckp);
 503                 ASSERT(kpp == NULL);
 504                 return (set_errno(EINVAL));
 505         }
 506 
 507         kpd = kmem_zalloc(sizeof (*kpd), KM_SLEEP);
 508         crhold(kpd->klpd_cred = cr);
 509         kpd->klpd_door = dh;
 510         kpd->klpd_door_pid = di.di_target;
 511         kpd->klpd_ref = 1;
 512         kpd->klpd_pset = pset;
 513 
 514         if (kpp != NULL) {
 515                 mutex_enter(&klpd_mutex);
 516                 kpd = klpd_link(kpd, &kpp->kpj_klpd, B_TRUE);
 517                 mutex_exit(&klpd_mutex);
 518                 if (kpd != NULL)
 519                         klpd_rele(kpd);
 520                 project_rele(kpp);
 521         } else if ((int)pid < 0) {
 522                 /* Global daemon */
 523                 mutex_enter(&klpd_mutex);
 524                 (void) klpd_link(kpd, &klpd_list, B_FALSE);
 525                 mutex_exit(&klpd_mutex);
 526         } else if (pid == curproc->p_pid) {
 527                 proc_t *p = curproc;
 528                 cred_t *newcr = cralloc();
 529 
 530                 /* No need to lock, sole reference to ckp */
 531                 kpd = klpd_link(kpd, &ckp->crkl_reg, B_TRUE);
 532 
 533                 if (kpd != NULL)
 534                         klpd_rele(kpd);
 535 
 536                 mutex_enter(&p->p_crlock);
 537                 cr = p->p_cred;
 538                 crdup_to(cr, newcr);
 539                 crsetcrklpd(newcr, ckp);
 540                 p->p_cred = newcr;   /* Already held for p_cred */
 541 
 542                 crhold(newcr);          /* Hold once for the current thread */
 543                 mutex_exit(&p->p_crlock);
 544                 crfree(cr);             /* One for the p_cred */
 545                 crset(p, newcr);
 546         } else {
 547                 proc_t *p;
 548                 cred_t *pcr;
 549                 mutex_enter(&pidlock);
 550                 p = prfind(pid);
 551                 if (p == NULL || !prochasprocperm(p, curproc, CRED())) {
 552                         mutex_exit(&pidlock);
 553                         klpd_rele(kpd);
 554                         return (set_errno(p == NULL ? ESRCH : EPERM));
 555                 }
 556                 mutex_enter(&p->p_crlock);
 557                 crhold(pcr = p->p_cred);
 558                 mutex_exit(&pidlock);
 559                 mutex_exit(&p->p_crlock);
 560                 /*
 561                  * We're going to update the credential's ckp in place;
 562                  * this requires that it exists.
 563                  */
 564                 ckp = crgetcrklpd(pcr);
 565                 if (ckp == NULL) {
 566                         crfree(pcr);
 567                         klpd_rele(kpd);
 568                         return (set_errno(EINVAL));
 569                 }
 570                 crklpd_setreg(ckp, kpd);
 571                 crfree(pcr);
 572         }
 573 
 574         return (0);
 575 }
 576 
 577 static int
 578 klpd_unreg_dh(door_handle_t dh)
 579 {
 580         klpd_reg_t *p;
 581 
 582         mutex_enter(&klpd_mutex);
 583         for (p = klpd_list; p != NULL; p = p->klpd_next) {
 584                 if (p->klpd_door == dh)
 585                         break;
 586         }
 587         if (p == NULL) {
 588                 mutex_exit(&klpd_mutex);
 589                 return (EINVAL);
 590         }
 591         if (p->klpd_indel != 0) {
 592                 mutex_exit(&klpd_mutex);
 593                 return (EAGAIN);
 594         }
 595         p->klpd_indel = 1;
 596         klpd_rele(p);
 597         mutex_exit(&klpd_mutex);
 598         return (0);
 599 }
 600 
 601 int
 602 klpd_unreg(int did, idtype_t type, id_t id)
 603 {
 604         door_handle_t dh;
 605         int res = 0;
 606         proc_t *p;
 607         pid_t pid;
 608         projid_t proj;
 609         kproject_t *kpp = NULL;
 610         credklpd_t *ckp;
 611 
 612         switch (type) {
 613         case P_PID:
 614                 pid = (pid_t)id;
 615                 break;
 616         case P_PROJID:
 617                 proj = (projid_t)id;
 618                 kpp = project_hold_by_id(proj, crgetzone(CRED()),
 619                     PROJECT_HOLD_FIND);
 620                 if (kpp == NULL)
 621                         return (set_errno(ESRCH));
 622                 break;
 623         default:
 624                 return (set_errno(ENOTSUP));
 625         }
 626 
 627         dh = door_ki_lookup(did);
 628         if (dh == NULL) {
 629                 if (kpp != NULL)
 630                         project_rele(kpp);
 631                 return (set_errno(EINVAL));
 632         }
 633 
 634         if (kpp != NULL) {
 635                 mutex_enter(&klpd_mutex);
 636                 if (kpp->kpj_klpd == NULL)
 637                         res = ESRCH;
 638                 else
 639                         klpd_freelist(&kpp->kpj_klpd);
 640                 mutex_exit(&klpd_mutex);
 641                 project_rele(kpp);
 642                 goto out;
 643         } else if ((int)pid > 0) {
 644                 mutex_enter(&pidlock);
 645                 p = prfind(pid);
 646                 if (p == NULL) {
 647                         mutex_exit(&pidlock);
 648                         door_ki_rele(dh);
 649                         return (set_errno(ESRCH));
 650                 }
 651                 mutex_enter(&p->p_crlock);
 652                 mutex_exit(&pidlock);
 653         } else if (pid == 0) {
 654                 p = curproc;
 655                 mutex_enter(&p->p_crlock);
 656         } else {
 657                 res = klpd_unreg_dh(dh);
 658                 goto out;
 659         }
 660 
 661         ckp = crgetcrklpd(p->p_cred);
 662         if (ckp != NULL) {
 663                 crklpd_setreg(ckp, NULL);
 664         } else {
 665                 res = ESRCH;
 666         }
 667         mutex_exit(&p->p_crlock);
 668 
 669 out:
 670         door_ki_rele(dh);
 671 
 672         if (res != 0)
 673                 return (set_errno(res));
 674         return (0);
 675 }
 676 
 677 void
 678 crklpd_hold(credklpd_t *crkpd)
 679 {
 680         atomic_inc_32(&crkpd->crkl_ref);
 681 }
 682 
 683 void
 684 crklpd_rele(credklpd_t *crkpd)
 685 {
 686         if (atomic_dec_32_nv(&crkpd->crkl_ref) == 0) {
 687                 if (crkpd->crkl_reg != NULL)
 688                         klpd_rele(crkpd->crkl_reg);
 689                 mutex_destroy(&crkpd->crkl_lock);
 690                 kmem_free(crkpd, sizeof (*crkpd));
 691         }
 692 }
 693 
 694 static credklpd_t *
 695 crklpd_alloc(void)
 696 {
 697         credklpd_t *res = kmem_alloc(sizeof (*res), KM_SLEEP);
 698 
 699         mutex_init(&res->crkl_lock, NULL, MUTEX_DEFAULT, NULL);
 700         res->crkl_ref = 1;
 701         res->crkl_reg = NULL;
 702 
 703         return (res);
 704 }
 705 
 706 void
 707 crklpd_setreg(credklpd_t *crk, klpd_reg_t *new)
 708 {
 709         klpd_reg_t *old;
 710 
 711         mutex_enter(&crk->crkl_lock);
 712         if (new == NULL) {
 713                 old = crk->crkl_reg;
 714                 if (old != NULL)
 715                         klpd_unlink(old);
 716         } else {
 717                 old = klpd_link(new, &crk->crkl_reg, B_TRUE);
 718         }
 719         mutex_exit(&crk->crkl_lock);
 720 
 721         if (old != NULL)
 722                 klpd_rele(old);
 723 }
 724 
 725 /* Allocate and register the pfexec specific callback */
 726 int
 727 pfexec_reg(int did)
 728 {
 729         door_handle_t dh;
 730         int err = secpolicy_pfexec_register(CRED());
 731         klpd_reg_t *pfx;
 732         door_info_t di;
 733         zone_t *myzone = crgetzone(CRED());
 734 
 735         if (err != 0)
 736                 return (set_errno(err));
 737 
 738         dh = door_ki_lookup(did);
 739         if (dh == NULL || door_ki_info(dh, &di) != 0)
 740                 return (set_errno(EBADF));
 741 
 742         pfx = kmem_zalloc(sizeof (*pfx), KM_SLEEP);
 743 
 744         pfx->klpd_door = dh;
 745         pfx->klpd_door_pid = di.di_target;
 746         pfx->klpd_ref = 1;
 747         pfx->klpd_cred = NULL;
 748         mutex_enter(&myzone->zone_lock);
 749         pfx = klpd_link(pfx, &myzone->zone_pfexecd, B_TRUE);
 750         mutex_exit(&myzone->zone_lock);
 751         if (pfx != NULL)
 752                 klpd_rele(pfx);
 753 
 754         return (0);
 755 }
 756 
 757 int
 758 pfexec_unreg(int did)
 759 {
 760         door_handle_t dh;
 761         int err = 0;
 762         zone_t *myzone = crgetzone(CRED());
 763         klpd_reg_t *pfd;
 764 
 765         dh = door_ki_lookup(did);
 766         if (dh == NULL)
 767                 return (set_errno(EBADF));
 768 
 769         mutex_enter(&myzone->zone_lock);
 770         pfd = myzone->zone_pfexecd;
 771         if (pfd != NULL && pfd->klpd_door == dh) {
 772                 klpd_unlink(pfd);
 773         } else {
 774                 pfd = NULL;
 775                 err = EINVAL;
 776         }
 777         mutex_exit(&myzone->zone_lock);
 778         door_ki_rele(dh);
 779         /*
 780          * crfree() cannot be called with zone_lock held; it is called
 781          * indirectly through closing the door handle
 782          */
 783         if (pfd != NULL)
 784                 klpd_rele(pfd);
 785         if (err != 0)
 786                 return (set_errno(err));
 787         return (0);
 788 }
 789 
 790 static int
 791 get_path(char *buf, const char *path, int len)
 792 {
 793         size_t lc;
 794         char *s;
 795 
 796         if (len < 0)
 797                 len = strlen(path);
 798 
 799         if (*path == '/' && len < MAXPATHLEN) {
 800                 (void) strcpy(buf, path);
 801                 return (0);
 802         }
 803         /*
 804          * Build the pathname using the current directory + resolve pathname.
 805          * The resolve pathname either starts with a normal component and
 806          * we can just concatenate them or it starts with one
 807          * or more ".." component and we can remove those; the
 808          * last one cannot be a ".." and the current directory has
 809          * more components than the number of ".." in the resolved pathname.
 810          */
 811         if (dogetcwd(buf, MAXPATHLEN) != 0)
 812                 return (-1);
 813 
 814         lc = strlen(buf);
 815 
 816         while (len > 3 && strncmp("../", path, 3) == 0) {
 817                 len -= 3;
 818                 path += 3;
 819 
 820                 s = strrchr(buf, '/');
 821                 if (s == NULL || s == buf)
 822                         return (-1);
 823 
 824                 *s = '\0';
 825                 lc = s - buf;
 826         }
 827         /* Add a "/" and a NUL */
 828         if (lc < 2 || lc + len + 2 >= MAXPATHLEN)
 829                 return (-1);
 830 
 831         buf[lc] = '/';
 832         (void) strcpy(buf + lc + 1, path);
 833 
 834         return (0);
 835 }
 836 
 837 /*
 838  * Perform the pfexec upcall.
 839  *
 840  * The pfexec upcall is different from the klpd_upcall in that a failure
 841  * will lead to a denial of execution.
 842  */
 843 int
 844 pfexec_call(const cred_t *cr, struct pathname *rpnp, cred_t **pfcr,
 845     boolean_t *scrub)
 846 {
 847         klpd_reg_t *pfd;
 848         pfexec_arg_t *pap;
 849         pfexec_reply_t pr, *prp;
 850         door_arg_t da;
 851         int dres;
 852         cred_t *ncr = NULL;
 853         int err = EACCES;
 854         priv_set_t *iset;
 855         priv_set_t *lset;
 856         zone_t *myzone = crgetzone(CRED());
 857         size_t pasize = PFEXEC_ARG_SIZE(MAXPATHLEN);
 858 
 859         /* Find registration */
 860         mutex_enter(&myzone->zone_lock);
 861         if ((pfd = myzone->zone_pfexecd) != NULL)
 862                 klpd_hold(pfd);
 863         mutex_exit(&myzone->zone_lock);
 864 
 865         if (pfd == NULL) {
 866                 DTRACE_PROBE2(pfexecd__not__running,
 867                     zone_t *, myzone, char *, rpnp->pn_path);
 868                 uprintf("pfexecd not running; pid %d privileges not "
 869                     "elevated\n", curproc->p_pid);
 870                 return (0);
 871         }
 872 
 873         if (pfd->klpd_door_pid == curproc->p_pid) {
 874                 klpd_rele(pfd);
 875                 return (0);
 876         }
 877 
 878         pap = kmem_zalloc(pasize, KM_SLEEP);
 879 
 880         if (get_path(pap->pfa_path, rpnp->pn_path, rpnp->pn_pathlen) == -1)
 881                 goto out1;
 882 
 883         pap->pfa_vers = PFEXEC_ARG_VERS;
 884         pap->pfa_call = PFEXEC_EXEC_ATTRS;
 885         pap->pfa_len = pasize;
 886         pap->pfa_uid = crgetruid(cr);
 887 
 888         da.data_ptr = (char *)pap;
 889         da.data_size = pap->pfa_len;
 890         da.desc_ptr = NULL;
 891         da.desc_num = 0;
 892         da.rbuf = (char *)&pr;
 893         da.rsize = sizeof (pr);
 894 
 895         while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) {
 896                 switch (dres) {
 897                 case EAGAIN:
 898                         delay(1);
 899                         continue;
 900                 case EINVAL:
 901                 case EBADF:
 902                         /* FALLTHROUGH */
 903                 case EINTR:
 904                         /* FALLTHROUGH */
 905                 default:
 906                         DTRACE_PROBE4(pfexecd__failure,
 907                             int, dres, zone_t *, myzone,
 908                             char *, rpnp->pn_path, klpd_reg_t *, pfd);
 909                         goto out;
 910                 }
 911         }
 912 
 913         prp = (pfexec_reply_t *)da.rbuf;
 914         /*
 915          * Check the size of the result and the alignment of the
 916          * privilege sets.
 917          */
 918         if (da.rsize < sizeof (pr) ||
 919             prp->pfr_ioff > da.rsize - sizeof (priv_set_t) ||
 920             prp->pfr_loff > da.rsize - sizeof (priv_set_t) ||
 921             (prp->pfr_loff & (sizeof (priv_chunk_t) - 1)) != 0 ||
 922             (prp->pfr_ioff & (sizeof (priv_chunk_t) - 1)) != 0)
 923                 goto out;
 924 
 925         /*
 926          * Get results:
 927          *      allow/allow with additional credentials/disallow[*]
 928          *
 929          *      euid, uid, egid, gid, privs, and limitprivs
 930          * We now have somewhat more flexibility we could even set E and P
 931          * judiciously but that would break some currently valid assumptions
 932          *      [*] Disallow is not readily supported by always including
 933          *      the Basic Solaris User profile in all user's profiles.
 934          */
 935 
 936         if (!prp->pfr_allowed) {
 937                 err = EACCES;
 938                 goto out;
 939         }
 940         if (!prp->pfr_setcred) {
 941                 err = 0;
 942                 goto out;
 943         }
 944         ncr = crdup((cred_t *)cr);
 945 
 946         /*
 947          * Generate the new credential set scrubenv if ruid != euid (or set)
 948          * the "I'm set-uid flag" but that is not inherited so scrubbing
 949          * the environment is a requirement.
 950          */
 951         /* Set uids or gids, note that -1 will do the right thing */
 952         if (crsetresuid(ncr, prp->pfr_ruid, prp->pfr_euid, prp->pfr_euid) != 0)
 953                 goto out;
 954         if (crsetresgid(ncr, prp->pfr_rgid, prp->pfr_egid, prp->pfr_egid) != 0)
 955                 goto out;
 956 
 957         *scrub = prp->pfr_scrubenv;
 958 
 959         if (prp->pfr_clearflag)
 960                 CR_FLAGS(ncr) &= ~PRIV_PFEXEC;
 961 
 962         /* We cannot exceed our Limit set, no matter what */
 963         iset = PFEXEC_REPLY_IPRIV(prp);
 964 
 965         if (iset != NULL) {
 966                 if (!priv_issubset(iset, &CR_LPRIV(ncr)))
 967                         goto out;
 968                 priv_union(iset, &CR_IPRIV(ncr));
 969         }
 970 
 971         /* Nor can we increate our Limit set itself */
 972         lset = PFEXEC_REPLY_LPRIV(prp);
 973 
 974         if (lset != NULL) {
 975                 if (!priv_issubset(lset, &CR_LPRIV(ncr)))
 976                         goto out;
 977                 CR_LPRIV(ncr) = *lset;
 978         }
 979 
 980         /* Exec will do the standard set operations */
 981 
 982         err = 0;
 983 out:
 984         if (da.rbuf != (char *)&pr)
 985                 kmem_free(da.rbuf, da.rsize);
 986 out1:
 987         kmem_free(pap, pasize);
 988         klpd_rele(pfd);
 989         if (ncr != NULL) {
 990                 if (err == 0)
 991                         *pfcr = ncr;
 992                 else
 993                         crfree(ncr);
 994         }
 995         return (err);
 996 }
 997 
 998 int
 999 get_forced_privs(const cred_t *cr, const char *respn, priv_set_t *set)
1000 {
1001         klpd_reg_t *pfd;
1002         pfexec_arg_t *pap;
1003         door_arg_t da;
1004         int dres;
1005         int err = -1;
1006         priv_set_t *fset, pmem;
1007         cred_t *zkcr;
1008         zone_t *myzone = crgetzone(cr);
1009         size_t pasize = PFEXEC_ARG_SIZE(MAXPATHLEN);
1010 
1011         mutex_enter(&myzone->zone_lock);
1012         if ((pfd = myzone->zone_pfexecd) != NULL)
1013                 klpd_hold(pfd);
1014         mutex_exit(&myzone->zone_lock);
1015 
1016         if (pfd == NULL)
1017                 return (-1);
1018 
1019         if (pfd->klpd_door_pid == curproc->p_pid) {
1020                 klpd_rele(pfd);
1021                 return (0);
1022         }
1023 
1024         pap = kmem_zalloc(pasize, KM_SLEEP);
1025 
1026         if (get_path(pap->pfa_path, respn, -1) == -1)
1027                 goto out1;
1028 
1029         pap->pfa_vers = PFEXEC_ARG_VERS;
1030         pap->pfa_call = PFEXEC_FORCED_PRIVS;
1031         pap->pfa_len = pasize;
1032         pap->pfa_uid = (uid_t)-1;                    /* Not relevant */
1033 
1034         da.data_ptr = (char *)pap;
1035         da.data_size = pap->pfa_len;
1036         da.desc_ptr = NULL;
1037         da.desc_num = 0;
1038         da.rbuf = (char *)&pmem;
1039         da.rsize = sizeof (pmem);
1040 
1041         while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) {
1042                 switch (dres) {
1043                 case EAGAIN:
1044                         delay(1);
1045                         continue;
1046                 case EINVAL:
1047                 case EBADF:
1048                 case EINTR:
1049                 default:
1050                         goto out;
1051                 }
1052         }
1053 
1054         /*
1055          * Check the size of the result, it's a privilege set.
1056          */
1057         if (da.rsize != sizeof (priv_set_t))
1058                 goto out;
1059 
1060         fset = (priv_set_t *)da.rbuf;
1061 
1062         /*
1063          * We restrict the forced privileges with whatever is available in
1064          * the current zone.
1065          */
1066         zkcr = zone_kcred();
1067         priv_intersect(&CR_LPRIV(zkcr), fset);
1068 
1069         /*
1070          * But we fail if the forced privileges are not found in the current
1071          * Limit set.
1072          */
1073         if (!priv_issubset(fset, &CR_LPRIV(cr))) {
1074                 err = EACCES;
1075         } else if (!priv_isemptyset(fset)) {
1076                 err = 0;
1077                 *set = *fset;
1078         }
1079 out:
1080         if (da.rbuf != (char *)&pmem)
1081                 kmem_free(da.rbuf, da.rsize);
1082 out1:
1083         kmem_free(pap, pasize);
1084         klpd_rele(pfd);
1085         return (err);
1086 }
1087 
1088 int
1089 check_user_privs(const cred_t *cr, const priv_set_t *set)
1090 {
1091         klpd_reg_t *pfd;
1092         pfexec_arg_t *pap;
1093         door_arg_t da;
1094         int dres;
1095         int err = -1;
1096         zone_t *myzone = crgetzone(cr);
1097         size_t pasize = PFEXEC_ARG_SIZE(sizeof (priv_set_t));
1098         uint32_t res;
1099 
1100         mutex_enter(&myzone->zone_lock);
1101         if ((pfd = myzone->zone_pfexecd) != NULL)
1102                 klpd_hold(pfd);
1103         mutex_exit(&myzone->zone_lock);
1104 
1105         if (pfd == NULL)
1106                 return (-1);
1107 
1108         if (pfd->klpd_door_pid == curproc->p_pid) {
1109                 klpd_rele(pfd);
1110                 return (0);
1111         }
1112 
1113         pap = kmem_zalloc(pasize, KM_SLEEP);
1114 
1115         *(priv_set_t *)&pap->pfa_buf = *set;
1116 
1117         pap->pfa_vers = PFEXEC_ARG_VERS;
1118         pap->pfa_call = PFEXEC_USER_PRIVS;
1119         pap->pfa_len = pasize;
1120         pap->pfa_uid = crgetruid(cr);
1121 
1122         da.data_ptr = (char *)pap;
1123         da.data_size = pap->pfa_len;
1124         da.desc_ptr = NULL;
1125         da.desc_num = 0;
1126         da.rbuf = (char *)&res;
1127         da.rsize = sizeof (res);
1128 
1129         while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) {
1130                 switch (dres) {
1131                 case EAGAIN:
1132                         delay(1);
1133                         continue;
1134                 case EINVAL:
1135                 case EBADF:
1136                 case EINTR:
1137                 default:
1138                         goto out;
1139                 }
1140         }
1141 
1142         /*
1143          * Check the size of the result.
1144          */
1145         if (da.rsize != sizeof (res))
1146                 goto out;
1147 
1148         if (*(uint32_t *)da.rbuf == 1)
1149                 err = 0;
1150 out:
1151         if (da.rbuf != (char *)&res)
1152                 kmem_free(da.rbuf, da.rsize);
1153 out1:
1154         kmem_free(pap, pasize);
1155         klpd_rele(pfd);
1156         return (err);
1157 }