static ephemeral_zsd_t * get_ephemeral_zsd(zone_t *zone) { ephemeral_zsd_t *eph_zsd; eph_zsd = zone_getspecific(ephemeral_zone_key, zone); if (eph_zsd != NULL) { return (eph_zsd); } mutex_enter(&ephemeral_zone_mutex); eph_zsd = zone_getspecific(ephemeral_zone_key, zone); if (eph_zsd == NULL) { eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP); eph_zsd->min_uid = MAXUID; eph_zsd->last_uid = IDMAP_WK__MAX_UID; eph_zsd->min_gid = MAXUID; eph_zsd->last_gid = IDMAP_WK__MAX_GID; mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL); /* * nobody is used to map SID containing CRs. */ eph_zsd->eph_nobody = crdup(zone->zone_kcred); (void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY); CR_FLAGS(eph_zsd->eph_nobody) = 0; eph_zsd->eph_nobody->cr_zone = zone; (void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd); } mutex_exit(&ephemeral_zone_mutex); return (eph_zsd); }
/* * Get the client credential. Used for Renew and recovery. */ struct ucred * newnfs_getcred(void) { struct ucred *cred; struct thread *td = curthread; cred = crdup(td->td_ucred); newnfs_setroot(cred); return (cred); }
/* * If the reply status is NFSERR_EACCES, it may be because we are * root (no root net access). Check the real uid, if it isn't root * make that the uid instead and retry the call. * Private interface for NFS. */ cred_t * crnetadjust(cred_t *cr) { if (cr->cr_uid == 0 && cr->cr_ruid != 0) { cr = crdup(cr); cr->cr_uid = cr->cr_ruid; return (cr); } return (NULL); }
/* * XXX This is wrong */ static struct ucred * nnpfs_crcopy(struct ucred *cr) { struct ucred *ncr; if (crshared(cr)) { ncr = crdup(cr); crfree(cr); return ncr; } return cr; }
int linux_setgroups16(struct proc *p, struct linux_setgroups16_args *args) { struct ucred *newcred, *oldcred; l_gid16_t linux_gidset[NGROUPS]; gid_t *bsd_gidset; int ngrp, error; #ifdef DEBUG if (ldebug(setgroups16)) printf(ARGS(setgroups16, "%d, *"), args->gidsetsize); #endif ngrp = args->gidsetsize; oldcred = p->p_ucred; /* * cr_groups[0] holds egid. Setting the whole set from * the supplied set will cause egid to be changed too. * Keep cr_groups[0] unchanged to prevent that. */ if ((error = suser_xxx(oldcred, NULL, PRISON_ROOT)) != 0) return (error); if (ngrp >= NGROUPS) return (EINVAL); newcred = crdup(oldcred); if (ngrp > 0) { error = copyin((caddr_t)args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t)); if (error) return (error); newcred->cr_ngroups = ngrp + 1; bsd_gidset = newcred->cr_groups; ngrp--; while (ngrp >= 0) { bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; ngrp--; } } else newcred->cr_ngroups = 1; setsugid(p); p->p_ucred = newcred; crfree(oldcred); return (0); }
void osi_Init(void) { static int once = 0; if (once++ > 0) /* just in case */ return; osi_InitGlock(); /* Initialize a lock for the kernel hcrypto bits. */ #ifndef UKERNEL init_hckernel_mutex(); #endif if (!afs_osicred_initialized) { #if defined(AFS_DARWIN80_ENV) afs_osi_ctxtp_initialized = 0; afs_osi_ctxtp = NULL; /* initialized in afs_Daemon since it has a proc reference that cannot be changed */ #endif #if defined(AFS_XBSD_ENV) /* Can't just invent one, must use crget() because of mutex */ afs_osi_credp = crdup(osi_curcred()); #elif defined(AFS_SUN5_ENV) afs_osi_credp = kcred; #else memset(&afs_osi_cred, 0, sizeof(afs_ucred_t)); #if defined(AFS_LINUX26_ENV) afs_set_cr_group_info(&afs_osi_cred, groups_alloc(0)); #endif #if defined(AFS_DARWIN80_ENV) afs_osi_cred.cr_ref = 1; /* kauth_cred_get_ref needs 1 existing ref */ #else # if !(defined(AFS_LINUX26_ENV) && defined(STRUCT_TASK_STRUCT_HAS_CRED)) crhold(&afs_osi_cred); /* don't let it evaporate */ # endif #endif afs_osi_credp = &afs_osi_cred; #endif afs_osicred_initialized = 1; } #ifdef AFS_SGI64_ENV osi_flid.fl_pid = osi_flid.fl_sysid = 0; #endif init_et_to_sys_error(); }
void smb_credinit(struct smb_cred *scred, cred_t *cr) { /* cr arg is optional */ if (cr == NULL) cr = ddi_get_cred(); if (is_system_labeled()) { cr = crdup(cr); (void) setpflags(NET_MAC_AWARE, 1, cr); } else { crhold(cr); } scred->scr_cred = cr; }
CLIENT * clnt_reconnect_create( struct netconfig *nconf, /* network type */ struct sockaddr *svcaddr, /* servers address */ rpcprog_t program, /* program number */ rpcvers_t version, /* version number */ size_t sendsz, /* buffer recv size */ size_t recvsz) /* buffer send size */ { CLIENT *cl = NULL; /* client handle */ struct rc_data *rc = NULL; /* private data */ if (svcaddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; return (NULL); } cl = mem_alloc(sizeof (CLIENT)); rc = mem_alloc(sizeof (*rc)); mtx_init(&rc->rc_lock, "rc->rc_lock", NULL, MTX_DEF); (void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len); rc->rc_nconf = nconf; rc->rc_prog = program; rc->rc_vers = version; rc->rc_sendsz = sendsz; rc->rc_recvsz = recvsz; rc->rc_timeout.tv_sec = -1; rc->rc_timeout.tv_usec = -1; rc->rc_retry.tv_sec = 3; rc->rc_retry.tv_usec = 0; rc->rc_retries = INT_MAX; rc->rc_privport = FALSE; rc->rc_waitchan = "rpcrecv"; rc->rc_intr = 0; rc->rc_connecting = FALSE; rc->rc_closed = FALSE; rc->rc_ucred = crdup(curthread->td_ucred); rc->rc_client = NULL; cl->cl_refs = 1; cl->cl_ops = &clnt_reconnect_ops; cl->cl_private = (caddr_t)(void *)rc; cl->cl_auth = authnone_create(); cl->cl_tp = NULL; cl->cl_netid = NULL; return (cl); }
/* * Duplicate the current processes' credentials. Since we are called only * as the result of a SET ioctl and only root can do that, any future access * to this "disk" is essentially as root. Note that credentials may change * if some other uid can write directly to the mapped file (NFS). */ int vndsetcred(struct vnd_softc *sc, struct ucred *cred) { void *buf; size_t size; int error; sc->sc_cred = crdup(cred); buf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK); size = MIN(DEV_BSIZE, sc->sc_size * sc->sc_secsize); /* XXX: Horrible kludge to establish credentials for NFS */ error = vn_rdwr(UIO_READ, sc->sc_vp, buf, size, 0, UIO_SYSSPACE, 0, sc->sc_cred, NULL, curproc); free(buf, M_TEMP, DEV_BSIZE); return (error); }
/* * In-kernel implementation of execve(). All arguments are assumed to be * userspace pointers from the passed thread. */ static int do_execve(struct thread *td, struct image_args *args, struct mac *mac_p) { struct proc *p = td->td_proc; struct nameidata nd; struct ucred *oldcred; struct uidinfo *euip = NULL; register_t *stack_base; int error, i; struct image_params image_params, *imgp; struct vattr attr; int (*img_first)(struct image_params *); struct pargs *oldargs = NULL, *newargs = NULL; struct sigacts *oldsigacts = NULL, *newsigacts = NULL; #ifdef KTRACE struct vnode *tracevp = NULL; struct ucred *tracecred = NULL; #endif struct vnode *oldtextvp = NULL, *newtextvp; int credential_changing; int textset; #ifdef MAC struct label *interpvplabel = NULL; int will_transition; #endif #ifdef HWPMC_HOOKS struct pmckern_procexec pe; #endif static const char fexecv_proc_title[] = "(fexecv)"; imgp = &image_params; /* * Lock the process and set the P_INEXEC flag to indicate that * it should be left alone until we're done here. This is * necessary to avoid race conditions - e.g. in ptrace() - * that might allow a local user to illicitly obtain elevated * privileges. */ PROC_LOCK(p); KASSERT((p->p_flag & P_INEXEC) == 0, ("%s(): process already has P_INEXEC flag", __func__)); p->p_flag |= P_INEXEC; PROC_UNLOCK(p); /* * Initialize part of the common data */ bzero(imgp, sizeof(*imgp)); imgp->proc = p; imgp->attr = &attr; imgp->args = args; oldcred = p->p_ucred; #ifdef MAC error = mac_execve_enter(imgp, mac_p); if (error) goto exec_fail; #endif /* * Translate the file name. namei() returns a vnode pointer * in ni_vp among other things. * * XXXAUDIT: It would be desirable to also audit the name of the * interpreter if this is an interpreted binary. */ if (args->fname != NULL) { NDINIT(&nd, LOOKUP, ISOPEN | LOCKLEAF | FOLLOW | SAVENAME | AUDITVNODE1, UIO_SYSSPACE, args->fname, td); } SDT_PROBE1(proc, , , exec, args->fname); interpret: if (args->fname != NULL) { #ifdef CAPABILITY_MODE /* * While capability mode can't reach this point via direct * path arguments to execve(), we also don't allow * interpreters to be used in capability mode (for now). * Catch indirect lookups and return a permissions error. */ if (IN_CAPABILITY_MODE(td)) { error = ECAPMODE; goto exec_fail; } #endif error = namei(&nd); if (error) goto exec_fail; newtextvp = nd.ni_vp; imgp->vp = newtextvp; } else { AUDIT_ARG_FD(args->fd); /* * Descriptors opened only with O_EXEC or O_RDONLY are allowed. */ error = fgetvp_exec(td, args->fd, &cap_fexecve_rights, &newtextvp); if (error) goto exec_fail; vn_lock(newtextvp, LK_EXCLUSIVE | LK_RETRY); AUDIT_ARG_VNODE1(newtextvp); imgp->vp = newtextvp; } /* * Check file permissions (also 'opens' file) */ error = exec_check_permissions(imgp); if (error) goto exec_fail_dealloc; imgp->object = imgp->vp->v_object; if (imgp->object != NULL) vm_object_reference(imgp->object); /* * Set VV_TEXT now so no one can write to the executable while we're * activating it. * * Remember if this was set before and unset it in case this is not * actually an executable image. */ textset = VOP_IS_TEXT(imgp->vp); VOP_SET_TEXT(imgp->vp); error = exec_map_first_page(imgp); if (error) goto exec_fail_dealloc; imgp->proc->p_osrel = 0; imgp->proc->p_fctl0 = 0; /* * Implement image setuid/setgid. * * Determine new credentials before attempting image activators * so that it can be used by process_exec handlers to determine * credential/setid changes. * * Don't honor setuid/setgid if the filesystem prohibits it or if * the process is being traced. * * We disable setuid/setgid/etc in capability mode on the basis * that most setugid applications are not written with that * environment in mind, and will therefore almost certainly operate * incorrectly. In principle there's no reason that setugid * applications might not be useful in capability mode, so we may want * to reconsider this conservative design choice in the future. * * XXXMAC: For the time being, use NOSUID to also prohibit * transitions on the file system. */ credential_changing = 0; credential_changing |= (attr.va_mode & S_ISUID) && oldcred->cr_uid != attr.va_uid; credential_changing |= (attr.va_mode & S_ISGID) && oldcred->cr_gid != attr.va_gid; #ifdef MAC will_transition = mac_vnode_execve_will_transition(oldcred, imgp->vp, interpvplabel, imgp); credential_changing |= will_transition; #endif /* Don't inherit PROC_PDEATHSIG_CTL value if setuid/setgid. */ if (credential_changing) imgp->proc->p_pdeathsig = 0; if (credential_changing && #ifdef CAPABILITY_MODE ((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) && #endif (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 && (p->p_flag & P_TRACED) == 0) { imgp->credential_setid = true; VOP_UNLOCK(imgp->vp, 0); imgp->newcred = crdup(oldcred); if (attr.va_mode & S_ISUID) { euip = uifind(attr.va_uid); change_euid(imgp->newcred, euip); } vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); if (attr.va_mode & S_ISGID) change_egid(imgp->newcred, attr.va_gid); /* * Implement correct POSIX saved-id behavior. * * XXXMAC: Note that the current logic will save the * uid and gid if a MAC domain transition occurs, even * though maybe it shouldn't. */ change_svuid(imgp->newcred, imgp->newcred->cr_uid); change_svgid(imgp->newcred, imgp->newcred->cr_gid); } else { /* * Implement correct POSIX saved-id behavior. * * XXX: It's not clear that the existing behavior is * POSIX-compliant. A number of sources indicate that the * saved uid/gid should only be updated if the new ruid is * not equal to the old ruid, or the new euid is not equal * to the old euid and the new euid is not equal to the old * ruid. The FreeBSD code always updates the saved uid/gid. * Also, this code uses the new (replaced) euid and egid as * the source, which may or may not be the right ones to use. */ if (oldcred->cr_svuid != oldcred->cr_uid || oldcred->cr_svgid != oldcred->cr_gid) { VOP_UNLOCK(imgp->vp, 0); imgp->newcred = crdup(oldcred); vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); change_svuid(imgp->newcred, imgp->newcred->cr_uid); change_svgid(imgp->newcred, imgp->newcred->cr_gid); } } /* The new credentials are installed into the process later. */ /* * Do the best to calculate the full path to the image file. */ if (args->fname != NULL && args->fname[0] == '/') imgp->execpath = args->fname; else { VOP_UNLOCK(imgp->vp, 0); if (vn_fullpath(td, imgp->vp, &imgp->execpath, &imgp->freepath) != 0) imgp->execpath = args->fname; vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); } /* * If the current process has a special image activator it * wants to try first, call it. For example, emulating shell * scripts differently. */ error = -1; if ((img_first = imgp->proc->p_sysent->sv_imgact_try) != NULL) error = img_first(imgp); /* * Loop through the list of image activators, calling each one. * An activator returns -1 if there is no match, 0 on success, * and an error otherwise. */ for (i = 0; error == -1 && execsw[i]; ++i) { if (execsw[i]->ex_imgact == NULL || execsw[i]->ex_imgact == img_first) { continue; } error = (*execsw[i]->ex_imgact)(imgp); } if (error) { if (error == -1) { if (textset == 0) VOP_UNSET_TEXT(imgp->vp); error = ENOEXEC; } goto exec_fail_dealloc; } /* * Special interpreter operation, cleanup and loop up to try to * activate the interpreter. */ if (imgp->interpreted) { exec_unmap_first_page(imgp); /* * VV_TEXT needs to be unset for scripts. There is a short * period before we determine that something is a script where * VV_TEXT will be set. The vnode lock is held over this * entire period so nothing should illegitimately be blocked. */ VOP_UNSET_TEXT(imgp->vp); /* free name buffer and old vnode */ if (args->fname != NULL) NDFREE(&nd, NDF_ONLY_PNBUF); #ifdef MAC mac_execve_interpreter_enter(newtextvp, &interpvplabel); #endif if (imgp->opened) { VOP_CLOSE(newtextvp, FREAD, td->td_ucred, td); imgp->opened = 0; } vput(newtextvp); vm_object_deallocate(imgp->object); imgp->object = NULL; imgp->credential_setid = false; if (imgp->newcred != NULL) { crfree(imgp->newcred); imgp->newcred = NULL; } imgp->execpath = NULL; free(imgp->freepath, M_TEMP); imgp->freepath = NULL; /* set new name to that of the interpreter */ NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW | SAVENAME, UIO_SYSSPACE, imgp->interpreter_name, td); args->fname = imgp->interpreter_name; goto interpret; } /* * NB: We unlock the vnode here because it is believed that none * of the sv_copyout_strings/sv_fixup operations require the vnode. */ VOP_UNLOCK(imgp->vp, 0); if (disallow_high_osrel && P_OSREL_MAJOR(p->p_osrel) > P_OSREL_MAJOR(__FreeBSD_version)) { error = ENOEXEC; uprintf("Osrel %d for image %s too high\n", p->p_osrel, imgp->execpath != NULL ? imgp->execpath : "<unresolved>"); vn_lock(imgp->vp, LK_SHARED | LK_RETRY); goto exec_fail_dealloc; } /* ABI enforces the use of Capsicum. Switch into capabilities mode. */ if (SV_PROC_FLAG(p, SV_CAPSICUM)) sys_cap_enter(td, NULL); /* * Copy out strings (args and env) and initialize stack base. */ stack_base = (*p->p_sysent->sv_copyout_strings)(imgp); /* * Stack setup. */ error = (*p->p_sysent->sv_fixup)(&stack_base, imgp); if (error != 0) { vn_lock(imgp->vp, LK_SHARED | LK_RETRY); goto exec_fail_dealloc; } if (args->fdp != NULL) { /* Install a brand new file descriptor table. */ fdinstall_remapped(td, args->fdp); args->fdp = NULL; } else { /* * Keep on using the existing file descriptor table. For * security and other reasons, the file descriptor table * cannot be shared after an exec. */ fdunshare(td); /* close files on exec */ fdcloseexec(td); } /* * Malloc things before we need locks. */ i = exec_args_get_begin_envv(imgp->args) - imgp->args->begin_argv; /* Cache arguments if they fit inside our allowance */ if (ps_arg_cache_limit >= i + sizeof(struct pargs)) { newargs = pargs_alloc(i); bcopy(imgp->args->begin_argv, newargs->ar_args, i); } /* * For security and other reasons, signal handlers cannot * be shared after an exec. The new process gets a copy of the old * handlers. In execsigs(), the new process will have its signals * reset. */ if (sigacts_shared(p->p_sigacts)) { oldsigacts = p->p_sigacts; newsigacts = sigacts_alloc(); sigacts_copy(newsigacts, oldsigacts); } vn_lock(imgp->vp, LK_SHARED | LK_RETRY); PROC_LOCK(p); if (oldsigacts) p->p_sigacts = newsigacts; /* Stop profiling */ stopprofclock(p); /* reset caught signals */ execsigs(p); /* name this process - nameiexec(p, ndp) */ bzero(p->p_comm, sizeof(p->p_comm)); if (args->fname) bcopy(nd.ni_cnd.cn_nameptr, p->p_comm, min(nd.ni_cnd.cn_namelen, MAXCOMLEN)); else if (vn_commname(newtextvp, p->p_comm, sizeof(p->p_comm)) != 0) bcopy(fexecv_proc_title, p->p_comm, sizeof(fexecv_proc_title)); bcopy(p->p_comm, td->td_name, sizeof(td->td_name)); #ifdef KTR sched_clear_tdname(td); #endif /* * mark as execed, wakeup the process that vforked (if any) and tell * it that it now has its own resources back */ p->p_flag |= P_EXEC; if ((p->p_flag2 & P2_NOTRACE_EXEC) == 0) p->p_flag2 &= ~P2_NOTRACE; if (p->p_flag & P_PPWAIT) { p->p_flag &= ~(P_PPWAIT | P_PPTRACE); cv_broadcast(&p->p_pwait); /* STOPs are no longer ignored, arrange for AST */ signotify(td); } /* * Implement image setuid/setgid installation. */ if (imgp->credential_setid) { /* * Turn off syscall tracing for set-id programs, except for * root. Record any set-id flags first to make sure that * we do not regain any tracing during a possible block. */ setsugid(p); #ifdef KTRACE if (p->p_tracecred != NULL && priv_check_cred(p->p_tracecred, PRIV_DEBUG_DIFFCRED)) ktrprocexec(p, &tracecred, &tracevp); #endif /* * Close any file descriptors 0..2 that reference procfs, * then make sure file descriptors 0..2 are in use. * * Both fdsetugidsafety() and fdcheckstd() may call functions * taking sleepable locks, so temporarily drop our locks. */ PROC_UNLOCK(p); VOP_UNLOCK(imgp->vp, 0); fdsetugidsafety(td); error = fdcheckstd(td); vn_lock(imgp->vp, LK_SHARED | LK_RETRY); if (error != 0) goto exec_fail_dealloc; PROC_LOCK(p); #ifdef MAC if (will_transition) { mac_vnode_execve_transition(oldcred, imgp->newcred, imgp->vp, interpvplabel, imgp); } #endif } else { if (oldcred->cr_uid == oldcred->cr_ruid && oldcred->cr_gid == oldcred->cr_rgid) p->p_flag &= ~P_SUGID; } /* * Set the new credentials. */ if (imgp->newcred != NULL) { proc_set_cred(p, imgp->newcred); crfree(oldcred); oldcred = NULL; } /* * Store the vp for use in procfs. This vnode was referenced by namei * or fgetvp_exec. */ oldtextvp = p->p_textvp; p->p_textvp = newtextvp; #ifdef KDTRACE_HOOKS /* * Tell the DTrace fasttrap provider about the exec if it * has declared an interest. */ if (dtrace_fasttrap_exec) dtrace_fasttrap_exec(p); #endif /* * Notify others that we exec'd, and clear the P_INEXEC flag * as we're now a bona fide freshly-execed process. */ KNOTE_LOCKED(p->p_klist, NOTE_EXEC); p->p_flag &= ~P_INEXEC; /* clear "fork but no exec" flag, as we _are_ execing */ p->p_acflag &= ~AFORK; /* * Free any previous argument cache and replace it with * the new argument cache, if any. */ oldargs = p->p_args; p->p_args = newargs; newargs = NULL; PROC_UNLOCK(p); #ifdef HWPMC_HOOKS /* * Check if system-wide sampling is in effect or if the * current process is using PMCs. If so, do exec() time * processing. This processing needs to happen AFTER the * P_INEXEC flag is cleared. */ if (PMC_SYSTEM_SAMPLING_ACTIVE() || PMC_PROC_IS_USING_PMCS(p)) { VOP_UNLOCK(imgp->vp, 0); pe.pm_credentialschanged = credential_changing; pe.pm_entryaddr = imgp->entry_addr; PMC_CALL_HOOK_X(td, PMC_FN_PROCESS_EXEC, (void *) &pe); vn_lock(imgp->vp, LK_SHARED | LK_RETRY); } #endif /* Set values passed into the program in registers. */ (*p->p_sysent->sv_setregs)(td, imgp, (u_long)(uintptr_t)stack_base); vfs_mark_atime(imgp->vp, td->td_ucred); SDT_PROBE1(proc, , , exec__success, args->fname); exec_fail_dealloc: if (imgp->firstpage != NULL) exec_unmap_first_page(imgp); if (imgp->vp != NULL) { if (args->fname) NDFREE(&nd, NDF_ONLY_PNBUF); if (imgp->opened) VOP_CLOSE(imgp->vp, FREAD, td->td_ucred, td); if (error != 0) vput(imgp->vp); else VOP_UNLOCK(imgp->vp, 0); } if (imgp->object != NULL) vm_object_deallocate(imgp->object); free(imgp->freepath, M_TEMP); if (error == 0) { if (p->p_ptevents & PTRACE_EXEC) { PROC_LOCK(p); if (p->p_ptevents & PTRACE_EXEC) td->td_dbgflags |= TDB_EXEC; PROC_UNLOCK(p); } /* * Stop the process here if its stop event mask has * the S_EXEC bit set. */ STOPEVENT(p, S_EXEC, 0); } else { exec_fail: /* we're done here, clear P_INEXEC */ PROC_LOCK(p); p->p_flag &= ~P_INEXEC; PROC_UNLOCK(p); SDT_PROBE1(proc, , , exec__failure, error); } if (imgp->newcred != NULL && oldcred != NULL) crfree(imgp->newcred); #ifdef MAC mac_execve_exit(imgp); mac_execve_interpreter_exit(interpvplabel); #endif exec_free_args(args); /* * Handle deferred decrement of ref counts. */ if (oldtextvp != NULL) vrele(oldtextvp); #ifdef KTRACE if (tracevp != NULL) vrele(tracevp); if (tracecred != NULL) crfree(tracecred); #endif pargs_drop(oldargs); pargs_drop(newargs); if (oldsigacts != NULL) sigacts_free(oldsigacts); if (euip != NULL) uifree(euip); if (error && imgp->vmspace_destroyed) { /* sorry, no more process anymore. exit gracefully */ exit1(td, 0, SIGABRT); /* NOT REACHED */ } #ifdef KTRACE if (error == 0) ktrprocctor(p); #endif /* * We don't want cpu_set_syscall_retval() to overwrite any of * the register values put in place by exec_setregs(). * Implementations of cpu_set_syscall_retval() will leave * registers unmodified when returning EJUSTRETURN. */ return (error == 0 ? EJUSTRETURN : error); }
/* * task_join() * * Overview * task_join() contains the actions that must be executed when the first * member (curproc) of a newly created task joins it. It may never fail. * * The caller must make sure holdlwps() is called so that all other lwps are * stopped prior to calling this function. * * NB: It returns with curproc->p_lock held. * * Return values * Pointer to the old task. * * Caller's context * cpu_lock must be held entering the function. It will acquire pidlock, * p_crlock and p_lock during execution. */ task_t * task_join(task_t *tk, uint_t flags) { proc_t *p = ttoproc(curthread); task_t *prev_tk; void *projbuf, *zonebuf; zone_t *zone = tk->tk_zone; projid_t projid = tk->tk_proj->kpj_id; cred_t *oldcr; /* * We can't know for sure if holdlwps() was called, but we can check to * ensure we're single-threaded. */ ASSERT(curthread == p->p_agenttp || p->p_lwprcnt == 1); /* * Changing the credential is always hard because we cannot * allocate memory when holding locks but we don't know whether * we need to change it. We first get a reference to the current * cred if we need to change it. Then we create a credential * with an updated project id. Finally we install it, first * releasing the reference we had on the p_cred at the time we * acquired the lock the first time and later we release the * reference to p_cred at the time we acquired the lock the * second time. */ mutex_enter(&p->p_crlock); if (crgetprojid(p->p_cred) == projid) oldcr = NULL; else crhold(oldcr = p->p_cred); mutex_exit(&p->p_crlock); if (oldcr != NULL) { cred_t *newcr = crdup(oldcr); crsetprojid(newcr, projid); crfree(oldcr); mutex_enter(&p->p_crlock); oldcr = p->p_cred; p->p_cred = newcr; mutex_exit(&p->p_crlock); crfree(oldcr); } /* * Make sure that the number of processor sets is constant * across this operation. */ ASSERT(MUTEX_HELD(&cpu_lock)); projbuf = fss_allocbuf(FSS_NPSET_BUF, FSS_ALLOC_PROJ); zonebuf = fss_allocbuf(FSS_NPSET_BUF, FSS_ALLOC_ZONE); mutex_enter(&pidlock); mutex_enter(&p->p_lock); prev_tk = p->p_task; task_change(tk, p); /* * Now move threads one by one to their new project. */ changeproj(p, tk->tk_proj, zone, projbuf, zonebuf); if (flags & TASK_FINAL) p->p_task->tk_flags |= TASK_FINAL; mutex_exit(&pidlock); fss_freebuf(zonebuf, FSS_ALLOC_ZONE); fss_freebuf(projbuf, FSS_ALLOC_PROJ); return (prev_tk); }
/* * Guts of pr_spriv: * * Set the privileges of a process. * * In order to set the privileges, the setting process will need to * have those privileges in its effective set in order to prevent * specially privileged processes to easily gain additional privileges. * Pre-existing privileges can be retained. To change any privileges, * PRIV_PROC_OWNER needs to be asserted. * * In formula: * * S' <= S || S' <= S + Ea * * the new set must either be subset of the old set or a subset of * the oldset merged with the effective set of the acting process; or just: * * S' <= S + Ea * * It's not legal to grow the limit set this way. * */ int priv_pr_spriv(proc_t *p, prpriv_t *prpriv, const cred_t *cr) { cred_t *oldcred; cred_t *newcred; int i; int err = EPERM; cred_priv_t *cp, *ocp; priv_set_t eset; ASSERT(MUTEX_HELD(&p->p_lock)); /* * Set must have proper dimension; infosize must be absent * or properly sized. */ if (prpriv->pr_nsets != PRIV_NSET || prpriv->pr_setsize != PRIV_SETSIZE || (prpriv->pr_infosize & (sizeof (uint32_t) - 1)) != 0 || prpriv->pr_infosize > priv_info->priv_infosize || prpriv->pr_infosize < 0) return (EINVAL); mutex_exit(&p->p_lock); if (priv_proc_cred_perm(cr, p, &oldcred, VWRITE) != 0) { mutex_enter(&p->p_lock); return (EPERM); } newcred = crdup(oldcred); /* Copy the privilege sets from prpriv to newcred */ bcopy(prpriv->pr_sets, CR_PRIVSETS(newcred), PRIV_SETBYTES); cp = &newcred->cr_priv; ocp = &oldcred->cr_priv; eset = CR_OEPRIV(cr); priv_intersect(&CR_LPRIV(oldcred), &eset); /* * Verify the constraints laid out: * for the limit set, we require that the new set is a subset * of the old limit set. * for all other sets, we require that the new set is either a * subset of the old set or a subset of the intersection of * the old limit set and the effective set of the acting process. */ for (i = 0; i < PRIV_NSET; i++) if (!priv_issubset(&cp->crprivs[i], &ocp->crprivs[i]) && (i == PRIV_LIMIT || !priv_issubset(&cp->crprivs[i], &eset))) break; crfree(oldcred); if (i < PRIV_NSET || !priv_valid(newcred)) goto err; /* Load the settable privilege information */ if (prpriv->pr_infosize > 0) { char *x = (char *)prpriv + PRIV_PRPRIV_INFO_OFFSET(prpriv); char *lastx = x + prpriv->pr_infosize; while (x < lastx) { priv_info_t *pi = (priv_info_t *)x; priv_info_uint_t *pii; switch (pi->priv_info_type) { case PRIV_INFO_FLAGS: pii = (priv_info_uint_t *)x; if (pii->info.priv_info_size != sizeof (*pii)) { err = EINVAL; goto err; } CR_FLAGS(newcred) &= ~PRIV_USER; CR_FLAGS(newcred) |= (pii->val & PRIV_USER); break; default: err = EINVAL; goto err; } /* Guarantee alignment and forward progress */ if ((pi->priv_info_size & (sizeof (uint32_t) - 1)) || pi->priv_info_size < sizeof (*pi) || lastx - x > pi->priv_info_size) { err = EINVAL; goto err; } x += pi->priv_info_size; } } /* * We'll try to copy the privilege aware flag; but since the * privileges sets are all individually set, they are set * as if we're privilege aware. If PRIV_AWARE wasn't set * or was explicitely unset, we need to set the flag and then * try to get rid of it. */ if ((CR_FLAGS(newcred) & PRIV_AWARE) == 0) { CR_FLAGS(newcred) |= PRIV_AWARE; priv_adjust_PA(newcred); } mutex_enter(&p->p_crlock); oldcred = p->p_cred; p->p_cred = newcred; mutex_exit(&p->p_crlock); crfree(oldcred); mutex_enter(&p->p_lock); return (0); err: crfree(newcred); mutex_enter(&p->p_lock); return (err); }
void osi_Init(void) { static int once = 0; if (once++ > 0) /* just in case */ return; #if defined(AFS_HPUX_ENV) osi_InitGlock(); #else /* AFS_HPUX_ENV */ #if defined(AFS_GLOBAL_SUNLOCK) #if defined(AFS_SGI62_ENV) mutex_init(&afs_global_lock, MUTEX_DEFAULT, "afs_global_lock"); #elif defined(AFS_OSF_ENV) usimple_lock_init(&afs_global_lock); afs_global_owner = (thread_t) 0; #elif defined(AFS_FBSD50_ENV) #if defined(AFS_FBSD80_ENV) && defined(WITNESS) /* "lock_initalized" (sic) can panic, checks a flag bit * is unset _before_ init */ memset(&afs_global_mtx, 0, sizeof(struct mtx)); #endif mtx_init(&afs_global_mtx, "AFS global lock", NULL, MTX_DEF); #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV) #if !defined(AFS_DARWIN80_ENV) lockinit(&afs_global_lock, PLOCK, "afs global lock", 0, 0); #endif afs_global_owner = 0; #elif defined(AFS_AIX41_ENV) lock_alloc((void *)&afs_global_lock, LOCK_ALLOC_PIN, 1, 1); simple_lock_init((void *)&afs_global_lock); #elif !defined(AFS_LINUX22_ENV) /* Linux initialization in osi directory. Should move the others. */ mutex_init(&afs_global_lock, "afs_global_lock", MUTEX_DEFAULT, NULL); #endif #endif /* AFS_GLOBAL_SUNLOCK */ #endif /* AFS_HPUX_ENV */ if (!afs_osicred_initialized) { #if defined(AFS_DARWIN80_ENV) afs_osi_ctxtp_initialized = 0; afs_osi_ctxtp = NULL; /* initialized in afs_Daemon since it has a proc reference that cannot be changed */ #endif #if defined(AFS_XBSD_ENV) /* Can't just invent one, must use crget() because of mutex */ afs_osi_credp = crdup(osi_curcred()); #else memset(&afs_osi_cred, 0, sizeof(struct AFS_UCRED)); #if defined(AFS_LINUX26_ENV) afs_osi_cred.cr_group_info = groups_alloc(0); #endif #if defined(AFS_DARWIN80_ENV) afs_osi_cred.cr_ref = 1; /* kauth_cred_get_ref needs 1 existing ref */ #else crhold(&afs_osi_cred); /* don't let it evaporate */ #endif afs_osi_credp = &afs_osi_cred; #endif afs_osicred_initialized = 1; } #ifdef AFS_SGI64_ENV osi_flid.fl_pid = osi_flid.fl_sysid = 0; #endif init_et_to_sys_error(); }
int domount(kthread_t *td, vnode_t *vp, const char *fstype, char *fspath, char *fspec, int fsflags) { struct mount *mp; struct vfsconf *vfsp; struct ucred *newcr, *oldcr; int error; /* * Be ultra-paranoid about making sure the type and fspath * variables will fit in our mp buffers, including the * terminating NUL. */ if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN) return (ENAMETOOLONG); vfsp = vfs_byname_kld(fstype, td, &error); if (vfsp == NULL) return (ENODEV); if (vp->v_type != VDIR) return (ENOTDIR); simple_lock(&vp->v_interlock); if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { simple_unlock(&vp->v_interlock); return (EBUSY); } vp->v_iflag |= VI_MOUNT; simple_unlock(&vp->v_interlock); /* * Allocate and initialize the filesystem. */ vn_lock(vp, LK_SHARED | LK_RETRY); mp = vfs_mount_alloc(vp, vfsp, fspath, td); VOP_UNLOCK(vp); mp->mnt_optnew = NULL; vfs_setmntopt(mp, "from", fspec, 0); mp->mnt_optnew = mp->mnt_opt; mp->mnt_opt = NULL; /* * Set the mount level flags. * crdup() can sleep, so do it before acquiring a mutex. */ newcr = crdup(kcred); MNT_ILOCK(mp); if (fsflags & MNT_RDONLY) mp->mnt_flag |= MNT_RDONLY; mp->mnt_flag &=~ MNT_UPDATEMASK; mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS); /* * Unprivileged user can trigger mounting a snapshot, but we don't want * him to unmount it, so we switch to privileged credentials. */ oldcr = mp->mnt_cred; mp->mnt_cred = newcr; mp->mnt_stat.f_owner = mp->mnt_cred->cr_uid; MNT_IUNLOCK(mp); crfree(oldcr); /* * Mount the filesystem. * XXX The final recipients of VFS_MOUNT just overwrite the ndp they * get. No freeing of cn_pnbuf. */ error = VFS_MOUNT(mp, td); if (!error) { if (mp->mnt_opt != NULL) vfs_freeopts(mp->mnt_opt); mp->mnt_opt = mp->mnt_optnew; (void)VFS_STATFS(mp, &mp->mnt_stat, td); } /* * Prevent external consumers of mount options from reading * mnt_optnew. */ mp->mnt_optnew = NULL; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* * Put the new filesystem on the mount list after root. */ #ifdef FREEBSD_NAMECACHE cache_purge(vp); #endif if (!error) { vnode_t *mvp; simple_lock(&vp->v_interlock); vp->v_iflag &= ~VI_MOUNT; simple_unlock(&vp->v_interlock); vp->v_mountedhere = mp; mountlist_append(mp); vfs_event_signal(NULL, VQ_MOUNT, 0); if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp, td)) panic("mount: lost mount"); mountcheckdirs(vp, mvp); vput(mvp); VOP_UNLOCK(vp); if ((mp->mnt_flag & MNT_RDONLY) == 0) vfs_syncer_add_to_worklist(mp); vfs_unbusy(mp, td); vfs_mountedfrom(mp, fspec); } else { simple_lock(&vp->v_interlock); vp->v_iflag &= ~VI_MOUNT; simple_unlock(&vp->v_interlock); VOP_UNLOCK(vp); vfs_unbusy(mp, td); vfs_mount_destroy(mp); } return (error); }
int mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, char *fspec, int fsflags) { struct mount *mp; struct vfsconf *vfsp; struct ucred *cr; vnode_t *vp; int error; /* * Be ultra-paranoid about making sure the type and fspath * variables will fit in our mp buffers, including the * terminating NUL. */ if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN) return (ENAMETOOLONG); vfsp = vfs_byname_kld(fstype, td, &error); if (vfsp == NULL) return (ENODEV); vp = *vpp; if (vp->v_type != VDIR) return (ENOTDIR); /* * We need vnode lock to protect v_mountedhere and vnode interlock * to protect v_iflag. */ vn_lock(vp, LK_SHARED | LK_RETRY); VI_LOCK(vp); if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { VI_UNLOCK(vp); VOP_UNLOCK(vp, 0); return (EBUSY); } vp->v_iflag |= VI_MOUNT; VI_UNLOCK(vp); VOP_UNLOCK(vp, 0); /* * Allocate and initialize the filesystem. */ mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred); mp->mnt_optnew = NULL; vfs_setmntopt(mp, "from", fspec, 0); mp->mnt_optnew = mp->mnt_opt; mp->mnt_opt = NULL; /* * Set the mount level flags. */ mp->mnt_flag &= ~MNT_UPDATEMASK; mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS); /* * Snapshots are always read-only. */ mp->mnt_flag |= MNT_RDONLY; /* * We don't want snapshots to be visible in regular * mount(8) and df(1) output. */ mp->mnt_flag |= MNT_IGNORE; /* * Unprivileged user can trigger mounting a snapshot, but we don't want * him to unmount it, so we switch to privileged of original mount. */ crfree(mp->mnt_cred); mp->mnt_cred = crdup(vp->v_mount->mnt_cred); mp->mnt_stat.f_owner = mp->mnt_cred->cr_uid; /* * XXX: This is evil, but we can't mount a snapshot as a regular user. * XXX: Is is safe when snapshot is mounted from within a jail? */ cr = td->td_ucred; td->td_ucred = kcred; error = VFS_MOUNT(mp); td->td_ucred = cr; if (error == 0) { if (mp->mnt_opt != NULL) vfs_freeopts(mp->mnt_opt); mp->mnt_opt = mp->mnt_optnew; (void)VFS_STATFS(mp, &mp->mnt_stat); } /* * Prevent external consumers of mount options from reading * mnt_optnew. */ mp->mnt_optnew = NULL; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); #ifdef FREEBSD_NAMECACHE cache_purge(vp); #endif VI_LOCK(vp); vp->v_iflag &= ~VI_MOUNT; VI_UNLOCK(vp); if (error == 0) { vnode_t *mvp; vp->v_mountedhere = mp; /* * Put the new filesystem on the mount list. */ mtx_lock(&mountlist_mtx); TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); mtx_unlock(&mountlist_mtx); vfs_event_signal(NULL, VQ_MOUNT, 0); if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp)) panic("mount: lost mount"); vput(vp); vfs_unbusy(mp); *vpp = mvp; } else { vput(vp); vfs_unbusy(mp); vfs_mount_destroy(mp); *vpp = NULL; } return (error); }