/* * Privilege system call entry point */ int privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize, int itype) { int retv; extern int issetugid(void); switch (code) { case PRIVSYS_SETPPRIV: if (bufsize < sizeof (priv_set_t)) return (set_errno(ENOMEM)); return (setppriv(op, type, buf)); case PRIVSYS_GETPPRIV: if (bufsize < sizeof (priv_set_t)) return (set_errno(ENOMEM)); return (getppriv(type, buf)); case PRIVSYS_GETIMPLINFO: return (getprivimplinfo(buf, bufsize)); case PRIVSYS_SETPFLAGS: retv = setpflags((uint_t)op, (uint_t)type, NULL); return (retv != 0 ? set_errno(retv) : 0); case PRIVSYS_GETPFLAGS: retv = (int)getpflags((uint_t)op, CRED()); return (retv == -1 ? set_errno(EINVAL) : retv); case PRIVSYS_ISSETUGID: return (issetugid()); case PRIVSYS_KLPD_REG: if (bufsize < sizeof (priv_set_t)) return (set_errno(ENOMEM)); return ((int)klpd_reg((int)op, (idtype_t)itype, (id_t)type, buf)); case PRIVSYS_KLPD_UNREG: return ((int)klpd_unreg((int)op, (idtype_t)itype, (id_t)type)); case PRIVSYS_PFEXEC_REG: return ((int)pfexec_reg((int)op)); case PRIVSYS_PFEXEC_UNREG: return ((int)pfexec_unreg((int)op)); } return (set_errno(EINVAL)); }
/*ARGSUSED*/ static int lo_mount(struct vfs *vfsp, struct vnode *vp, struct mounta *uap, struct cred *cr) { int error; struct vnode *srootvp = NULL; /* the server's root */ struct vnode *realrootvp; struct loinfo *li; int nodev; nodev = vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL); if ((error = secpolicy_fs_mount(cr, vp, vfsp)) != 0) return (EPERM); /* * Loopback devices which get "nodevices" added can be done without * "nodevices" set because we cannot import devices into a zone * with loopback. Note that we have all zone privileges when * this happens; if not, we'd have gotten "nosuid". */ if (!nodev && vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) vfs_setmntopt(vfsp, MNTOPT_DEVICES, NULL, VFS_NODISPLAY); mutex_enter(&vp->v_lock); if (!(uap->flags & MS_OVERLAY) && (vp->v_count != 1 || (vp->v_flag & VROOT))) { mutex_exit(&vp->v_lock); return (EBUSY); } mutex_exit(&vp->v_lock); /* * Find real root, and make vfs point to real vfs */ if (error = lookupname(uap->spec, (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, &realrootvp)) return (error); /* * Enforce MAC policy if needed. * * Loopback mounts must not allow writing up. The dominance test * is intended to prevent a global zone caller from accidentally * creating write-up conditions between two labeled zones. * Local zones can't violate MAC on their own without help from * the global zone because they can't name a pathname that * they don't already have. * * The special case check for the NET_MAC_AWARE process flag is * to support the case of the automounter in the global zone. We * permit automounting of local zone directories such as home * directories, into the global zone as required by setlabel, * zonecopy, and saving of desktop sessions. Such mounts are * trusted not to expose the contents of one zone's directories * to another by leaking them through the global zone. */ if (is_system_labeled() && crgetzoneid(cr) == GLOBAL_ZONEID) { char specname[MAXPATHLEN]; zone_t *from_zptr; zone_t *to_zptr; if (vnodetopath(NULL, realrootvp, specname, sizeof (specname), CRED()) != 0) { VN_RELE(realrootvp); return (EACCES); } from_zptr = zone_find_by_path(specname); to_zptr = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); /* * Special case for zone devfs: the zone for /dev will * incorrectly appear as the global zone since it's not * under the zone rootpath. So for zone devfs check allow * read-write mounts. * * Second special case for scratch zones used for Live Upgrade: * this is used to mount the zone's root from /root to /a in * the scratch zone. As with the other special case, this * appears to be outside of the zone because it's not under * the zone rootpath, which is $ZONEPATH/lu in the scratch * zone case. */ if (from_zptr != to_zptr && !(to_zptr->zone_flags & ZF_IS_SCRATCH)) { /* * We know at this point that the labels aren't equal * because the zone pointers aren't equal, and zones * can't share a label. * * If the source is the global zone then making * it available to a local zone must be done in * read-only mode as the label will become admin_low. * * If it is a mount between local zones then if * the current process is in the global zone and has * the NET_MAC_AWARE flag, then regular read-write * access is allowed. If it's in some other zone, but * the label on the mount point dominates the original * source, then allow the mount as read-only * ("read-down"). */ if (from_zptr->zone_id == GLOBAL_ZONEID) { /* make the mount read-only */ vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); } else { /* cross-zone mount */ if (to_zptr->zone_id == GLOBAL_ZONEID && /* LINTED: no consequent */ getpflags(NET_MAC_AWARE, cr) != 0) { /* Allow the mount as read-write */ } else if (bldominates( label2bslabel(to_zptr->zone_slabel), label2bslabel(from_zptr->zone_slabel))) { /* make the mount read-only */ vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); } else { VN_RELE(realrootvp); zone_rele(to_zptr); zone_rele(from_zptr); return (EACCES); } } } zone_rele(to_zptr); zone_rele(from_zptr); } /* * realrootvp may be an AUTOFS node, in which case we * perform a VOP_ACCESS() to trigger the mount of the * intended filesystem, so we loopback mount the intended * filesystem instead of the AUTOFS filesystem. */ (void) VOP_ACCESS(realrootvp, 0, 0, cr, NULL); /* * We're interested in the top most filesystem. * This is specially important when uap->spec is a trigger * AUTOFS node, since we're really interested in mounting the * filesystem AUTOFS mounted as result of the VOP_ACCESS() * call not the AUTOFS node itself. */ if (vn_mountedvfs(realrootvp) != NULL) { if (error = traverse(&realrootvp)) { VN_RELE(realrootvp); return (error); } } /* * Allocate a vfs info struct and attach it */ li = kmem_zalloc(sizeof (struct loinfo), KM_SLEEP); li->li_realvfs = realrootvp->v_vfsp; li->li_mountvfs = vfsp; /* * Set mount flags to be inherited by loopback vfs's */ if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) { li->li_mflag |= VFS_RDONLY; } if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { li->li_mflag |= (VFS_NOSETUID|VFS_NODEVICES); } if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) { li->li_mflag |= VFS_NODEVICES; } if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) { li->li_mflag |= VFS_NOSETUID; } /* * Permissive flags are added to the "deny" bitmap. */ if (vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL)) { li->li_dflag |= VFS_XATTR; } if (vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) { li->li_dflag |= VFS_NBMAND; } /* * Propagate inheritable mount flags from the real vfs. */ if ((li->li_realvfs->vfs_flag & VFS_RDONLY) && !vfs_optionisset(vfsp, MNTOPT_RO, NULL)) vfs_setmntopt(vfsp, MNTOPT_RO, NULL, VFS_NODISPLAY); if ((li->li_realvfs->vfs_flag & VFS_NOSETUID) && !vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, VFS_NODISPLAY); if ((li->li_realvfs->vfs_flag & VFS_NODEVICES) && !vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) vfs_setmntopt(vfsp, MNTOPT_NODEVICES, NULL, VFS_NODISPLAY); /* * Permissive flags such as VFS_XATTR, as opposed to restrictive flags * such as VFS_RDONLY, are handled differently. An explicit * MNTOPT_NOXATTR should override the underlying filesystem's VFS_XATTR. */ if ((li->li_realvfs->vfs_flag & VFS_XATTR) && !vfs_optionisset(vfsp, MNTOPT_NOXATTR, NULL) && !vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) vfs_setmntopt(vfsp, MNTOPT_XATTR, NULL, VFS_NODISPLAY); if ((li->li_realvfs->vfs_flag & VFS_NBMAND) && !vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL) && !vfs_optionisset(vfsp, MNTOPT_NONBMAND, NULL)) vfs_setmntopt(vfsp, MNTOPT_NBMAND, NULL, VFS_NODISPLAY); li->li_refct = 0; vfsp->vfs_data = (caddr_t)li; vfsp->vfs_bcount = 0; vfsp->vfs_fstype = lofsfstype; vfsp->vfs_bsize = li->li_realvfs->vfs_bsize; vfsp->vfs_dev = li->li_realvfs->vfs_dev; vfsp->vfs_fsid.val[0] = li->li_realvfs->vfs_fsid.val[0]; vfsp->vfs_fsid.val[1] = li->li_realvfs->vfs_fsid.val[1]; if (vfs_optionisset(vfsp, MNTOPT_LOFS_NOSUB, NULL)) { li->li_flag |= LO_NOSUB; } /* * Propagate any VFS features */ vfs_propagate_features(li->li_realvfs, vfsp); /* * Setup the hashtable. If the root of this mount isn't a directory, * there's no point in allocating a large hashtable. A table with one * bucket is sufficient. */ if (realrootvp->v_type != VDIR) lsetup(li, 1); else lsetup(li, 0); /* * Make the root vnode */ srootvp = makelonode(realrootvp, li, 0); srootvp->v_flag |= VROOT; li->li_rootvp = srootvp; #ifdef LODEBUG lo_dprint(4, "lo_mount: vfs %p realvfs %p root %p realroot %p li %p\n", vfsp, li->li_realvfs, srootvp, realrootvp, li); #endif return (0); }
int main(int argc, char **argv) { char *cmd; char *pset = NULL; char pathbuf[MAXPATHLEN]; int c; priv_set_t *wanted; int oflag; oflag = getpflags(PRIV_PFEXEC); if (setpflags(PRIV_PFEXEC, 1) != 0) { perror("setpflags(PRIV_PFEXEC)"); exit(1); } if (*argv[0] == '-') cmd = argv[0] + 1; else cmd = argv[0]; /* Strip "pf" from argv[0], it confuses some shells. */ if (strncmp(cmd, "pf", 2) == 0) { argv[0] += 2; /* argv[0] will need to start with '-' again. */ if (argv[0][-2] == '-') *argv[0] = '-'; } /* If this fails, we just continue with plan B */ if (shellname(getexecname(), pathbuf) == RES_OK) (void) execv(pathbuf, argv); switch (shellname(cmd, pathbuf)) { case RES_OK: (void) execv(pathbuf, argv); perror(pathbuf); return (1); case RES_PFEXEC: case RES_FAILURE: while ((c = getopt(argc, argv, "P:")) != EOF) { switch (c) { case 'P': if (pset == NULL) { pset = optarg; break; } /* FALLTHROUGH */ default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); if (pset != NULL) { wanted = priv_str_to_set(pset, ",", NULL); if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) { (void) fprintf(stderr, gettext("setppriv(): %s\n"), strerror(errno)); exit(EXIT_FAILURE); } (void) setpflags(PRIV_PFEXEC, oflag); } (void) execvp(argv[0], argv); perror(argv[0]); return (1); } return (1); }
int mtev_security_usergroup(const char *user, const char *group, mtev_boolean effective) { static long pwnam_buflen = 0; static long grnam_buflen = 0; uid_t uid = 0; gid_t gid = 0; if(pwnam_buflen == 0) #ifdef _SC_GETPW_R_SIZE_MAX pwnam_buflen = sysconf(_SC_GETPW_R_SIZE_MAX); #else pwnam_buflen = 100; /* This shouldn't be used, so size is not important. */ #endif if(grnam_buflen == 0) #ifdef _SC_GETGR_R_SIZE_MAX grnam_buflen = sysconf(_SC_GETGR_R_SIZE_MAX); #else grnam_buflen = 100; #endif if(user) { if(isuinteger(user)) uid = atoi(user); else { struct passwd *pw, _pw; char *buf; if(NULL == (buf = alloca(pwnam_buflen))) BAIL("alloca failed\n"); if(NULL == (pw = __getpwnam_r(user, &_pw, buf, pwnam_buflen))) BAIL("Cannot find user '%s'\n", user); uid = pw->pw_uid; } } if(group) { if(isuinteger(group)) gid = atoi(group); else { struct group *gr, _gr; char *buf; if(NULL == (buf = alloca(grnam_buflen))) BAIL("alloca failed\n"); if(NULL == (gr = __getgrnam_r(group, &_gr, buf, grnam_buflen))) BAIL("Cannot find group '%s'\n", group); gid = gr->gr_gid; } } if(!user && !group) return 0; #if defined(CAP_SUPPORTED) && defined(HAVE_SETPPRIV) if(!effective && getpflags(PRIV_AWARE)) { int rv; priv_set_t *set; set = priv_allocset(); priv_addset(set, "proc_setid"); rv = setppriv(PRIV_ON, PRIV_EFFECTIVE, set); priv_freeset(set); if(rv) BAIL("setppriv(proc_setid) failed"); } #endif if(group) { if(!effective && gid == 0) BAIL("Cannot use this function to setgid(0)\n"); if((effective ? setegid(gid) : setgid(gid)) != 0) BAIL("setgid(%d) failed: %s\n", (int)gid, strerror(errno)); } if(user) { if(!effective && uid == 0) BAIL("Cannot use this function to setuid(0)\n"); if((effective ? seteuid(uid) : setuid(uid)) != 0) BAIL("setgid(%d) failed: %s\n", (int)gid, strerror(errno)); if(!effective) { #if defined(CAP_SUPPORTED) && defined(HAVE_SETPPRIV) if(getpflags(PRIV_AWARE)) { int rv; priv_set_t *set; set = priv_allocset(); priv_addset(set, "proc_setid"); rv = setppriv(PRIV_OFF, PRIV_EFFECTIVE, set); if(rv) BAIL("setppriv(off, effective, proc_setid) failed"); getppriv(PRIV_EFFECTIVE, set); rv = setppriv(PRIV_SET, PRIV_PERMITTED, set); if(rv) BAIL("setppriv(effective -> permitted) failed"); priv_freeset(set); } #endif if(setuid(0) == 0) BAIL("setuid(0) worked, and it shouldn't have.\n"); if(setgid(0) == 0) BAIL("setgid(0) worked, and it shouldn't have.\n"); } } return 0; }
/* * smbfs_mount_label_policy: * Determine whether the mount is allowed according to MAC check, * by comparing (where appropriate) label of the remote server * against the label of the zone being mounted into. * * Returns: * 0 : access allowed * -1 : read-only access allowed (i.e., read-down) * >0 : error code, such as EACCES * * NB: * NFS supports Cipso labels by parsing the vfs_resource * to see what the Solaris server global zone has shared. * We can't support that for CIFS since resource names * contain share names, not paths. */ static int smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr) { bslabel_t *server_sl, *mntlabel; zone_t *mntzone = NULL; ts_label_t *zlabel; tsol_tpc_t *tp; ts_label_t *tsl = NULL; int retv; /* * Get the zone's label. Each zone on a labeled system has a label. */ mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); zlabel = mntzone->zone_slabel; ASSERT(zlabel != NULL); label_hold(zlabel); retv = EACCES; /* assume the worst */ /* * Next, get the assigned label of the remote server. */ tp = find_tpc(ipaddr, addr_type, B_FALSE); if (tp == NULL) goto out; /* error getting host entry */ if (tp->tpc_tp.tp_doi != zlabel->tsl_doi) goto rel_tpc; /* invalid domain */ if ((tp->tpc_tp.host_type != UNLABELED)) goto rel_tpc; /* invalid hosttype */ server_sl = &tp->tpc_tp.tp_def_label; mntlabel = label2bslabel(zlabel); /* * Now compare labels to complete the MAC check. If the labels * are equal or if the requestor is in the global zone and has * NET_MAC_AWARE, then allow read-write access. (Except for * mounts into the global zone itself; restrict these to * read-only.) * * If the requestor is in some other zone, but his label * dominates the server, then allow read-down. * * Otherwise, access is denied. */ if (blequal(mntlabel, server_sl) || (crgetzoneid(cr) == GLOBAL_ZONEID && getpflags(NET_MAC_AWARE, cr) != 0)) { if ((mntzone == global_zone) || !blequal(mntlabel, server_sl)) retv = -1; /* read-only */ else retv = 0; /* access OK */ } else if (bldominates(mntlabel, server_sl)) { retv = -1; /* read-only */ } else { retv = EACCES; } if (tsl != NULL) label_rele(tsl); rel_tpc: /*LINTED*/ TPC_RELE(tp); out: if (mntzone) zone_rele(mntzone); label_rele(zlabel); return (retv); }