Exemple #1
0
/*
 * Construct an audit record for the passed thread.
 */
static void
audit_record_ctor(proc_t p, struct kaudit_record *ar)
{
	kauth_cred_t cred;

	bzero(ar, sizeof(*ar));
	ar->k_ar.ar_magic = AUDIT_RECORD_MAGIC;
	nanotime(&ar->k_ar.ar_starttime);

	if (PROC_NULL != p) {
		cred = kauth_cred_proc_ref(p);

		/*
	 	 * Export the subject credential.
	 	 */
		cru2x(cred, &ar->k_ar.ar_subj_cred);
		ar->k_ar.ar_subj_ruid = kauth_cred_getruid(cred);
		ar->k_ar.ar_subj_rgid = kauth_cred_getrgid(cred);
		ar->k_ar.ar_subj_egid = kauth_cred_getgid(cred);
		ar->k_ar.ar_subj_pid = p->p_pid;
		ar->k_ar.ar_subj_auid = cred->cr_audit.as_aia_p->ai_auid;
		ar->k_ar.ar_subj_asid = cred->cr_audit.as_aia_p->ai_asid;
		bcopy(&cred->cr_audit.as_mask, &ar->k_ar.ar_subj_amask,
    		    sizeof(struct au_mask));
		bcopy(&cred->cr_audit.as_aia_p->ai_termid,
		    &ar->k_ar.ar_subj_term_addr, sizeof(struct au_tid_addr));
		kauth_cred_unref(&cred);
	}
}
Exemple #2
0
int
reboot(struct proc *p, register struct reboot_args *uap, __unused int32_t *retval)
{
	char command[64];
	int error=0;
	size_t dummy=0;
#if CONFIG_MACF
	kauth_cred_t my_cred;
#endif

	AUDIT_ARG(cmd, uap->opt);

	command[0] = '\0';

	if ((error = suser(kauth_cred_get(), &p->p_acflag)))
		return(error);	
	
	if (uap->opt & RB_COMMAND)
		error = copyinstr(uap->command,
					(void *)command, sizeof(command), (size_t *)&dummy);
#if CONFIG_MACF
	if (error)
		return (error);
	my_cred = kauth_cred_proc_ref(p);
	error = mac_system_check_reboot(my_cred, uap->opt);
	kauth_cred_unref(&my_cred);
#endif
	if (!error) {
		OSBitOrAtomic(P_REBOOT, &p->p_flag);  /* No more signals for this proc */
		error = boot(RB_BOOT, uap->opt, command);
	}
	return(error);
}
Exemple #3
0
/*
 *	Routine:	task_for_pid_posix_check
 *	Purpose:
 *			Verify that the current process should be allowed to
 *			get the target process's task port. This is only 
 *			permitted if:
 *			- The current process is root
 *			OR all of the following are true:
 *			- The target process's real, effective, and saved uids
 *			  are the same as the current proc's euid,
 *			- The target process's group set is a subset of the
 *			  calling process's group set, and
 *			- The target process hasn't switched credentials.
 *
 *	Returns:	TRUE: permitted
 *			FALSE: denied
 */
static int
task_for_pid_posix_check(proc_t target)
{
	kauth_cred_t targetcred, mycred;
	uid_t myuid;
	int allowed; 

	/* No task_for_pid on bad targets */
	if (target->p_stat == SZOMB) {
		return FALSE;
	}

	mycred = kauth_cred_get();
	myuid = kauth_cred_getuid(mycred);

	/* If we're running as root, the check passes */
	if (kauth_cred_issuser(mycred))
		return TRUE;

	/* We're allowed to get our own task port */
	if (target == current_proc())
		return TRUE;

	/* 
	 * Under DENY, only root can get another proc's task port,
	 * so no more checks are needed.
	 */
	if (tfp_policy == KERN_TFP_POLICY_DENY) { 
		return FALSE;
	}

	targetcred = kauth_cred_proc_ref(target);
	allowed = TRUE;

	/* Do target's ruid, euid, and saved uid match my euid? */
	if ((kauth_cred_getuid(targetcred) != myuid) || 
			(kauth_cred_getruid(targetcred) != myuid) ||
			(kauth_cred_getsvuid(targetcred) != myuid)) {
		allowed = FALSE;
		goto out;
	}

	/* Are target's groups a subset of my groups? */
	if (kauth_cred_gid_subset(targetcred, mycred, &allowed) ||
			allowed == 0) {
		allowed = FALSE;
		goto out;
	}

	/* Has target switched credentials? */
	if (target->p_flag & P_SUGID) {
		allowed = FALSE;
		goto out;
	}
	
out:
	kauth_cred_unref(&targetcred);
	return allowed;
}
Exemple #4
0
/* ARGSUSED */
int
setaudit_addr(proc_t p, struct setaudit_addr_args *uap,
    __unused int32_t *retval)
{
	struct auditinfo_addr aia;
	kauth_cred_t scred;
	int error;

	bzero(&aia, sizeof(auditinfo_addr_t));
	error = copyin(uap->auditinfo_addr, &aia, 
	    min(sizeof(aia), uap->length));
	if (error)
		return (error);
	AUDIT_ARG(auditinfo_addr, &aia);
	if (aia.ai_termid.at_type != AU_IPv6 &&
	    aia.ai_termid.at_type != AU_IPv4)
		return (EINVAL);
	if (aia.ai_asid != AU_ASSIGN_ASID && 
	    (uint32_t)aia.ai_asid > ASSIGNED_ASID_MAX)
		return (EINVAL);

#if CONFIG_MACF
	error = mac_proc_check_setaudit(p, &aia);
	if (error)
		return (error);
#endif

	scred = kauth_cred_proc_ref(p);
	error = suser(scred, &p->p_acflag);
	if (error) {
		kauth_cred_unref(&scred);
		return (error);
	}

	WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t),
	    "setaudit_addr(2)", "auditinfo_addr_t");
	WARN_IF_BAD_ASID(aia.ai_asid, "setaudit_addr(2)");
	kauth_cred_unref(&scred);

	AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
	if (aia.ai_asid == AU_DEFAUDITSID)
		aia.ai_asid = AU_ASSIGN_ASID;

	error = audit_session_setaia(p, &aia);
	if (error)
		return (error);

	/*
	 * If asked to assign an ASID then let the user know what the ASID is
	 * by copying the auditinfo_addr struct back out.
	 */
	if (aia.ai_asid == AU_ASSIGN_ASID)
		error = getaudit_addr_internal(p, uap->auditinfo_addr,
		    uap->length);

	return (error);
}
/**
 * Device open. Called on open /dev/vboxguest and (later) /dev/vboxguestu.
 *
 * @param   Dev         The device number.
 * @param   fFlags      ???.
 * @param   fDevType    ???.
 * @param   pProcess    The process issuing this request.
 */
static int VbgdDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
{
    /*
     * Only two minor devices numbers are allowed.
     */
    if (minor(Dev) != 0 && minor(Dev) != 1)
        return EACCES;

    /*
     * Find the session created by org_virtualbox_VBoxGuestClient, fail
     * if no such session, and mark it as opened. We set the uid & gid
     * here too, since that is more straight forward at this point.
     */
    //const bool          fUnrestricted = minor(Dev) == 0;
    int                 rc = VINF_SUCCESS;
    PVBOXGUESTSESSION   pSession = NULL;
    kauth_cred_t        pCred = kauth_cred_proc_ref(pProcess);
    if (pCred)
    {
        RTPROCESS       Process = RTProcSelf();
        unsigned        iHash = SESSION_HASH(Process);
        RTSpinlockAcquire(g_Spinlock);

        pSession = g_apSessionHashTab[iHash];
        while (pSession && pSession->Process != Process)
            pSession = pSession->pNextHash;
        if (pSession)
        {
            if (!pSession->fOpened)
            {
                pSession->fOpened = true;
                /*pSession->fUnrestricted = fUnrestricted; - later */
            }
            else
                rc = VERR_ALREADY_LOADED;
        }
        else
            rc = VERR_GENERAL_FAILURE;

        RTSpinlockRelease(g_Spinlock);
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
        kauth_cred_unref(&pCred);
#else  /* 10.4 */
        /* The 10.4u SDK headers and 10.4.11 kernel source have inconsistent definitions
           of kauth_cred_unref(), so use the other (now deprecated) API for releasing it. */
        kauth_cred_rele(pCred);
#endif /* 10.4 */
    }
    else
        rc = VERR_INVALID_PARAMETER;

    Log(("VbgdDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
    return VbgdDarwinErr2DarwinErr(rc);
}
Exemple #6
0
int
reboot(struct proc *p, struct reboot_args *uap, __unused int32_t *retval)
{
	char message[128];
	int error=0;
	size_t dummy=0;
#if CONFIG_MACF
	kauth_cred_t my_cred;
#endif

	AUDIT_ARG(cmd, uap->opt);

	message[0] = '\0';

	if ((error = suser(kauth_cred_get(), &p->p_acflag))) {
#if (DEVELOPMENT || DEBUG)
		/* allow non-root user to call panic on dev/debug kernels */
		if (!(uap->opt & RB_PANIC))
			return error;
#else
		return error;
#endif
	}

	if (uap->opt & RB_COMMAND)
                return ENOSYS;

        if (uap->opt & RB_PANIC) {
		error = copyinstr(uap->command, (void *)message, sizeof(message), (size_t *)&dummy);
        }

#if CONFIG_MACF
#if (DEVELOPMENT || DEBUG)
        if (uap->opt & RB_PANIC) {
		/* on dev/debug kernels: allow anyone to call panic */
		goto skip_cred_check;
	}
#endif
	if (error)
		return (error);
	my_cred = kauth_cred_proc_ref(p);
	error = mac_system_check_reboot(my_cred, uap->opt);
	kauth_cred_unref(&my_cred);
#if (DEVELOPMENT || DEBUG)
skip_cred_check:
#endif
#endif
	if (!error) {
		OSBitOrAtomic(P_REBOOT, &p->p_flag);  /* No more signals for this proc */
		error = reboot_kernel(uap->opt, message);
	}
	return(error);
}
Exemple #7
0
int
mac_cred_label_externalize_audit(struct proc *p, struct mac *mac)
{
    kauth_cred_t cr;
    int error;

    cr = kauth_cred_proc_ref(p);

    error = MAC_EXTERNALIZE_AUDIT(cred, cr->cr_label,
                                  mac->m_string, mac->m_buflen);

    kauth_cred_unref(&cr);
    return (error);
}
Exemple #8
0
int
mac_task_check_set_host_special_port(struct task *task, int id, struct ipc_port *port)
{
	int error;

	struct proc *p = mac_task_get_proc(task);
	if (p == NULL)
		return ESRCH;

	kauth_cred_t cred = kauth_cred_proc_ref(p);
	MAC_CHECK(proc_check_set_host_special_port, cred, id, port);
	kauth_cred_unref(&cred);
	proc_rele(p);
	return (error);
}
Exemple #9
0
int
mac_task_check_set_host_exception_port(struct task *task, unsigned int exception)
{
	int error;

	struct proc *p = mac_task_get_proc(task);
	if (p == NULL)
		return ESRCH;

	kauth_cred_t cred = kauth_cred_proc_ref(p);
	MAC_CHECK(proc_check_set_host_exception_port, cred, exception);
	kauth_cred_unref(&cred);
	proc_rele(p);
	return (error);
}
Exemple #10
0
int
mac_proc_check_fork(proc_t curp)
{
    kauth_cred_t cred;
    int error;

    if (!mac_proc_enforce ||
            !mac_proc_check_enforce(curp, MAC_PROC_ENFORCE))
        return (0);

    cred = kauth_cred_proc_ref(curp);
    MAC_CHECK(proc_check_fork, cred, curp);
    kauth_cred_unref(&cred);

    return (error);
}
Exemple #11
0
int
mac_proc_check_ledger(proc_t curp, proc_t proc, int ledger_op)
{
	kauth_cred_t cred;
	int error = 0;

	if (!mac_proc_enforce ||
	    !mac_proc_check_enforce(curp, MAC_PROC_ENFORCE))
		return (0);

	cred = kauth_cred_proc_ref(curp);
	MAC_CHECK(proc_check_ledger, cred, proc, ledger_op);
	kauth_cred_unref(&cred);

	return (error);
}
Exemple #12
0
int
mac_proc_check_mprotect(proc_t proc,
                        user_addr_t addr, user_size_t size, int prot)
{
    kauth_cred_t cred;
    int error;

    if (!mac_vm_enforce ||
            !mac_proc_check_enforce(proc, MAC_VM_ENFORCE))
        return (0);

    cred = kauth_cred_proc_ref(proc);
    MAC_CHECK(proc_check_mprotect, cred, proc, addr, size, prot);
    kauth_cred_unref(&cred);

    return (error);
}
Exemple #13
0
/*
 * The type of maxprot in proc_check_map_anon must be equivalent to vm_prot_t
 * (defined in <mach/vm_prot.h>). mac_policy.h does not include any header
 * files, so cannot use the typedef itself.
 */
int
mac_proc_check_map_anon(proc_t proc, user_addr_t u_addr,
    user_size_t u_size, int prot, int flags, int *maxprot)
{
	kauth_cred_t cred;
	int error;

	if (!mac_vm_enforce ||
	    !mac_proc_check_enforce(proc, MAC_VM_ENFORCE))
		return (0);

	cred = kauth_cred_proc_ref(proc);
	MAC_CHECK(proc_check_map_anon, proc, cred, u_addr, u_size, prot, flags, maxprot);
	kauth_cred_unref(&cred);

	return (error);
}
Exemple #14
0
int
mac_proc_check_signal(proc_t curp, struct proc *proc, int signum)
{
    kauth_cred_t cred;
    int error;



    if (!mac_proc_enforce ||
            !mac_proc_check_enforce(curp, MAC_PROC_ENFORCE))
        return (0);

    cred = kauth_cred_proc_ref(curp);
    MAC_CHECK(proc_check_signal, cred, proc, signum);
    kauth_cred_unref(&cred);

    return (error);
}
Exemple #15
0
int
cttyopen(__unused dev_t dev, int flag, __unused int mode, proc_t p)
{
	vnode_t ttyvp = cttyvp(p);
	struct vfs_context context;
	int error;

	if (ttyvp == NULL)
		return (ENXIO);

	context.vc_thread = current_thread();
	context.vc_ucred = kauth_cred_proc_ref(p);

	error = VNOP_OPEN(ttyvp, flag, &context);
	vnode_put(ttyvp);
	kauth_cred_unref(&context.vc_ucred);

	return (error);
}
Exemple #16
0
static int
getaudit_addr_internal(proc_t p, user_addr_t user_addr, size_t length)
{
	kauth_cred_t scred;
	auditinfo_addr_t aia;

	scred = kauth_cred_proc_ref(p);
	bcopy(scred->cr_audit.as_aia_p, &aia, sizeof (auditinfo_addr_t));
	/*
	 * Only superuser gets to see the real mask.
	 */
	if (suser(scred, &p->p_acflag)) {
		aia.ai_mask.am_success = ~0;
		aia.ai_mask.am_failure = ~0;
	}
	kauth_cred_unref(&scred);

	return (copyout(&aia, user_addr, min(sizeof(aia), length)));
}
Exemple #17
0
int
reboot(struct proc *p, struct reboot_args *uap, __unused int32_t *retval)
{
	char message[128];
	int error=0;
	size_t dummy=0;
#if CONFIG_MACF
	kauth_cred_t my_cred;
#endif

	AUDIT_ARG(cmd, uap->opt);

	message[0] = '\0';

	if ((error = suser(kauth_cred_get(), &p->p_acflag)))
		return(error);	
	
	if (uap->opt & RB_COMMAND)
                return ENOSYS;

        if (uap->opt & RB_PANIC) {
#if !(DEVELOPMENT || DEBUG)
		if (p != initproc) {
                        return EPERM;
                }
#endif
		error = copyinstr(uap->command, (void *)message, sizeof(message), (size_t *)&dummy);
        }

#if CONFIG_MACF
	if (error)
		return (error);
	my_cred = kauth_cred_proc_ref(p);
	error = mac_system_check_reboot(my_cred, uap->opt);
	kauth_cred_unref(&my_cred);
#endif
	if (!error) {
		OSBitOrAtomic(P_REBOOT, &p->p_flag);  /* No more signals for this proc */
		error = reboot_kernel(uap->opt, message);
	}
	return(error);
}
Exemple #18
0
int
mac_task_check_set_host_exception_ports(struct task *task, unsigned int exception_mask)
{
	int error = 0;
	int exception;

	struct proc *p = mac_task_get_proc(task);
	if (p == NULL)
		return ESRCH;

	kauth_cred_t cred = kauth_cred_proc_ref(p);
	for (exception = FIRST_EXCEPTION; exception < EXC_TYPES_COUNT; exception++) {
		if (exception_mask & (1 << exception)) {
			MAC_CHECK(proc_check_set_host_exception_port, cred, exception);
			if (error)
				break;
		}
	}
	kauth_cred_unref(&cred);
	proc_rele(p);
	return (error);
}
Exemple #19
0
/* ARGSUSED */
int
getauid(proc_t p, struct getauid_args *uap, __unused int32_t *retval)
{
	au_id_t id;
	int error;
	kauth_cred_t scred;

#if CONFIG_MACF
	error = mac_proc_check_getauid(p);
	if (error)
		return (error);
#endif
	scred = kauth_cred_proc_ref(p);
	id = scred->cr_audit.as_aia_p->ai_auid;
	kauth_cred_unref(&scred);

	error = copyout((void *)&id, uap->auid, sizeof(id));
	if (error)
		return (error);

	return (0);
}
Exemple #20
0
/* ARGSUSED */
int
setauid(proc_t p, struct setauid_args *uap, __unused int32_t *retval)
{
	int error;
	au_id_t	id;
	kauth_cred_t scred;
	struct auditinfo_addr aia;

	error = copyin(uap->auid, &id, sizeof(id));
	if (error)
		return (error);
	AUDIT_ARG(auid, id);

#if CONFIG_MACF
	error = mac_proc_check_setauid(p, id);
	if (error)
		return (error);
#endif

	scred = kauth_cred_proc_ref(p);
	error = suser(scred, &p->p_acflag);
	if (error) {
		kauth_cred_unref(&scred);
		return (error);
	}

	bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
	if (aia.ai_asid == AU_DEFAUDITSID) {
		aia.ai_asid = AU_ASSIGN_ASID;
	}
	bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t));
	kauth_cred_unref(&scred);
	aia.ai_auid = id;
	error = audit_session_setaia(p, &aia);

	return (error);
}
Exemple #21
0
/* system call implementation */
int
process_policy(__unused struct proc *p, struct process_policy_args * uap, __unused int32_t *retval)
{
	int error = 0;
	int scope = uap->scope;
	int policy = uap->policy;
	int action = uap->action;
	int policy_subtype = uap->policy_subtype;
	user_addr_t attrp = uap->attrp;
	pid_t target_pid = uap->target_pid;
	uint64_t target_threadid = uap->target_threadid;
	proc_t target_proc = PROC_NULL;
#if CONFIG_MACF || !CONFIG_EMBEDDED
	proc_t curp = current_proc();
#endif
	kauth_cred_t my_cred;
#if CONFIG_EMBEDDED
	kauth_cred_t target_cred;
#endif

	if ((scope != PROC_POLICY_SCOPE_PROCESS) && (scope != PROC_POLICY_SCOPE_THREAD)) {
		return(EINVAL);
	}

	if (target_pid == 0 || target_pid == proc_selfpid())
		target_proc = proc_self();
	else
		target_proc = proc_find(target_pid);

	if (target_proc == PROC_NULL)
		return(ESRCH);

	my_cred = kauth_cred_get();

#if CONFIG_EMBEDDED
	target_cred = kauth_cred_proc_ref(target_proc);

	if (!kauth_cred_issuser(my_cred) && kauth_cred_getruid(my_cred) &&
	    kauth_cred_getuid(my_cred) != kauth_cred_getuid(target_cred) &&
	    kauth_cred_getruid(my_cred) != kauth_cred_getuid(target_cred))
#else
	/* 
	 * Resoure starvation control can be used by unpriv resource owner but priv at the time of ownership claim. This is
	 * checked in low resource handle routine. So bypass the checks here.
	 */
	if ((policy != PROC_POLICY_RESOURCE_STARVATION) && 
		(policy != PROC_POLICY_APPTYPE) && 
		(!kauth_cred_issuser(my_cred) && curp != p))
#endif
	{
		error = EPERM;
		goto out;
	}

#if CONFIG_MACF
	switch (policy) {
		case PROC_POLICY_BOOST:
		case PROC_POLICY_RESOURCE_USAGE:
#if CONFIG_EMBEDDED
		case PROC_POLICY_APPTYPE:
		case PROC_POLICY_APP_LIFECYCLE:
#endif
			/* These policies do their own appropriate mac checks */
			break;
		default:
			error = mac_proc_check_sched(curp, target_proc);
			if (error) goto out;
			break;
	}
#endif /* CONFIG_MACF */

	switch(policy) {
		case PROC_POLICY_BACKGROUND:
			error = ENOTSUP;
			break;
		case PROC_POLICY_HARDWARE_ACCESS:
			error = ENOTSUP;
			break;
		case PROC_POLICY_RESOURCE_STARVATION:
			error = handle_lowresource(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
			break;
		case PROC_POLICY_RESOURCE_USAGE:
			switch(policy_subtype) {
				case PROC_POLICY_RUSAGE_NONE:
				case PROC_POLICY_RUSAGE_WIREDMEM:
				case PROC_POLICY_RUSAGE_VIRTMEM:
				case PROC_POLICY_RUSAGE_DISK:
				case PROC_POLICY_RUSAGE_NETWORK:
				case PROC_POLICY_RUSAGE_POWER:
					error = ENOTSUP;
					goto out;
				default:
					error = EINVAL;
					goto out;
				case PROC_POLICY_RUSAGE_CPU:
					break;
			}

			error = handle_cpuuse(action, attrp, target_proc, target_threadid);
			break;
#if CONFIG_EMBEDDED
		case PROC_POLICY_APP_LIFECYCLE:
			error = handle_applifecycle(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
			break;
#endif /* CONFIG_EMBEDDED */
		case PROC_POLICY_APPTYPE:
			error = handle_apptype(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
			break;
		case PROC_POLICY_BOOST:
			error = handle_boost(scope, action, policy, policy_subtype, attrp, target_proc, target_threadid);
			break;
		default:
			error = EINVAL;
			break;
	}

out:
	proc_rele(target_proc);
#if CONFIG_EMBEDDED
        kauth_cred_unref(&target_cred);
#endif
	return(error);
}
Exemple #22
0
static int
vniocattach_file(struct vn_softc *vn,
		 struct vn_ioctl_64 *vniop,
		 dev_t dev,
		 int in_kernel,
		 proc_t p)
{
	dev_t	cdev;
	vfs_context_t ctx = vfs_context_current();
	kauth_cred_t cred;
	struct nameidata nd;
	off_t file_size;
	int error, flags;

	flags = FREAD|FWRITE;
	if (in_kernel) {
		NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, UIO_SYSSPACE, vniop->vn_file, ctx);
	}
	else {
		NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, 
			   (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), 
			   vniop->vn_file, ctx);
	}
	/* vn_open gives both long- and short-term references */
	error = vn_open(&nd, flags, 0);
	if (error) {
		if (error != EACCES && error != EPERM && error != EROFS) {
			return (error);
		}
		flags &= ~FWRITE;
		if (in_kernel) {
			NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, UIO_SYSSPACE, 
			       vniop->vn_file, ctx);
		}
		else {
			NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW, 
				   (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32), 
			       vniop->vn_file, ctx);
		}
		error = vn_open(&nd, flags, 0);
		if (error) {
			return (error);
		}
	}
	if (nd.ni_vp->v_type != VREG) {
		error = EINVAL;
	}
	else {
		error = vnode_size(nd.ni_vp, &file_size, ctx);
	}
	if (error != 0) {
		(void) vn_close(nd.ni_vp, flags, ctx);
		vnode_put(nd.ni_vp);
		return (error);
	}
	cred = kauth_cred_proc_ref(p);
	nd.ni_vp->v_flag |= VNOCACHE_DATA;
	error = setcred(nd.ni_vp, cred);
	if (error) {
		(void)vn_close(nd.ni_vp, flags, ctx);
		vnode_put(nd.ni_vp);
		kauth_cred_unref(&cred);
		return(error);
	}
	vn->sc_secsize = DEV_BSIZE;
	vn->sc_fsize = file_size;
	vn->sc_size = file_size / vn->sc_secsize;
	vn->sc_vp = nd.ni_vp;
	vn->sc_vid = vnode_vid(nd.ni_vp);
	vn->sc_open_flags = flags;
	vn->sc_cred = cred;
	cdev = makedev(vndevice_cdev_major, minor(dev));
	vn->sc_cdev = devfs_make_node(cdev, DEVFS_CHAR,
				      UID_ROOT, GID_OPERATOR, 
				      0600, "rvn%d", 
				      minor(dev));
	vn->sc_flags |= VNF_INITED;
	if (flags == FREAD)
		vn->sc_flags |= VNF_READONLY;
	/* lose the short-term reference */
	vnode_put(nd.ni_vp);
	return(0);
}
Exemple #23
0
/*
 * XXX: this is borrowed from in6_pcbbind(). If possible, we should
 * share this function by all *bsd*...
 */
int
in6_pcbsetport(
	__unused struct in6_addr *laddr,
	struct inpcb *inp,
	struct proc *p,
	int locked)
{
	struct socket *so = inp->inp_socket;
	u_int16_t lport = 0, first, last, *lastport;
	int count, error = 0, wild = 0;
	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
	kauth_cred_t cred;
	if (!locked) { /* Make sure we don't run into a deadlock: 4052373 */
		if (!lck_rw_try_lock_exclusive(pcbinfo->mtx)) {
			socket_unlock(inp->inp_socket, 0);
			lck_rw_lock_exclusive(pcbinfo->mtx);
			socket_lock(inp->inp_socket, 0);
		}
	}

	/* XXX: this is redundant when called from in6_pcbbind */
	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
		wild = INPLOOKUP_WILDCARD;

	inp->inp_flags |= INP_ANONPORT;

	if (inp->inp_flags & INP_HIGHPORT) {
		first = ipport_hifirstauto;	/* sysctl */
		last  = ipport_hilastauto;
		lastport = &pcbinfo->lasthi;
	} else if (inp->inp_flags & INP_LOWPORT) {
		cred = kauth_cred_proc_ref(p);
		error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0);
		kauth_cred_unref(&cred);
		if (error != 0) {
			if (!locked)
				lck_rw_done(pcbinfo->mtx);
			return error;
		}
		first = ipport_lowfirstauto;	/* 1023 */
		last  = ipport_lowlastauto;	/* 600 */
		lastport = &pcbinfo->lastlow;
	} else {
		first = ipport_firstauto;	/* sysctl */
		last  = ipport_lastauto;
		lastport = &pcbinfo->lastport;
	}
	/*
	 * Simple check to ensure all ports are not used up causing
	 * a deadlock here.
	 *
	 * We split the two cases (up and down) so that the direction
	 * is not being tested on each round of the loop.
	 */
	if (first > last) {
		/*
		 * counting down
		 */
		count = first - last;

		do {
			if (count-- < 0) {	/* completely used? */
				/*
				 * Undo any address bind that may have
				 * occurred above.
				 */
				inp->in6p_laddr = in6addr_any;
				inp->in6p_last_outif = 0;
				if (!locked)
					lck_rw_done(pcbinfo->mtx);
				return (EAGAIN);
			}
			--*lastport;
			if (*lastport > first || *lastport < last)
				*lastport = first;
			lport = htons(*lastport);
		} while (in6_pcblookup_local(pcbinfo,
					     &inp->in6p_laddr, lport, wild));
	} else {
		/*
			 * counting up
			 */
		count = last - first;

		do {
			if (count-- < 0) {	/* completely used? */
				/*
				 * Undo any address bind that may have
				 * occurred above.
				 */
				inp->in6p_laddr = in6addr_any;
				inp->in6p_last_outif = 0;
				if (!locked)
					lck_rw_done(pcbinfo->mtx);
				return (EAGAIN);
			}
			++*lastport;
			if (*lastport < first || *lastport > last)
				*lastport = first;
			lport = htons(*lastport);
		} while (in6_pcblookup_local(pcbinfo,
					     &inp->in6p_laddr, lport, wild));
	}

	inp->inp_lport = lport;
	if (in_pcbinshash(inp, 1) != 0) {
		inp->in6p_laddr = in6addr_any;
		inp->inp_lport = 0;
		inp->in6p_last_outif = 0;
		if (!locked)
			lck_rw_done(pcbinfo->mtx);
		return (EAGAIN);
	}

	if (!locked)
		lck_rw_done(pcbinfo->mtx);
	return(0);
}
Exemple #24
0
void *
uthread_alloc(task_t task, thread_t thread, int noinherit)
{
	proc_t p;
	uthread_t uth;
	uthread_t uth_parent;
	void *ut;

	if (!uthread_zone_inited)
		uthread_zone_init();

	ut = (void *)zalloc(uthread_zone);
	bzero(ut, sizeof(struct uthread));

	p = (proc_t) get_bsdtask_info(task);
	uth = (uthread_t)ut;

	/*
	 * Thread inherits credential from the creating thread, if both
	 * are in the same task.
	 *
	 * If the creating thread has no credential or is from another
	 * task we can leave the new thread credential NULL.  If it needs
	 * one later, it will be lazily assigned from the task's process.
	 */
	uth_parent = (uthread_t)get_bsdthread_info(current_thread());
	if ((noinherit == 0) && task == current_task() && 
	    uth_parent != NULL &&
	    IS_VALID_CRED(uth_parent->uu_ucred)) {
		/*
		 * XXX The new thread is, in theory, being created in context
		 * XXX of parent thread, so a direct reference to the parent
		 * XXX is OK.
		 */
		kauth_cred_ref(uth_parent->uu_ucred);
		uth->uu_ucred = uth_parent->uu_ucred;
		/* the credential we just inherited is an assumed credential */
		if (uth_parent->uu_flag & UT_SETUID)
			uth->uu_flag |= UT_SETUID;
	} else {
		/* sometimes workqueue threads are created out task context */
		if ((task != kernel_task) && (p != PROC_NULL))
			uth->uu_ucred = kauth_cred_proc_ref(p);
		else
			uth->uu_ucred = NOCRED;
	}

	
	if ((task != kernel_task) && p) {
		
		proc_lock(p);
		if (noinherit != 0) {
			/* workq threads will not inherit masks */
			uth->uu_sigmask = ~workq_threadmask;
		} else if (uth_parent) {
			if (uth_parent->uu_flag & UT_SAS_OLDMASK)
				uth->uu_sigmask = uth_parent->uu_oldmask;
			else
				uth->uu_sigmask = uth_parent->uu_sigmask;
		}
		uth->uu_context.vc_thread = thread;
		TAILQ_INSERT_TAIL(&p->p_uthlist, uth, uu_list);
		proc_unlock(p);

#if CONFIG_DTRACE
		if (p->p_dtrace_ptss_pages != NULL) {
			uth->t_dtrace_scratch = dtrace_ptss_claim_entry(p);
		}
#endif
	}

	return (ut);
}
Exemple #25
0
int
in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct proc *p)
{
	struct socket *so = inp->inp_socket;
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
	u_short	lport = 0;
	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
	int error;
	kauth_cred_t cred;

	if (!in6_ifaddrs) /* XXX broken! */
		return (EADDRNOTAVAIL);
	if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
		return(EINVAL);
	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
		wild = 1;
	socket_unlock(so, 0); /* keep reference */
	lck_rw_lock_exclusive(pcbinfo->mtx);
	if (nam) {
		unsigned int outif = 0;

		sin6 = (struct sockaddr_in6 *)nam;
		if (nam->sa_len != sizeof(*sin6)) {
			lck_rw_done(pcbinfo->mtx);
			socket_lock(so, 0);
			return(EINVAL);
		}
		/*
		 * family check.
		 */
		if (nam->sa_family != AF_INET6) {
			lck_rw_done(pcbinfo->mtx);
			socket_lock(so, 0);
			return(EAFNOSUPPORT);
		}

		/* KAME hack: embed scopeid */
		if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL,
		    NULL) != 0) {
			lck_rw_done(pcbinfo->mtx);
			socket_lock(so, 0);
			return EINVAL;
		}
		/* this must be cleared for ifa_ifwithaddr() */
		sin6->sin6_scope_id = 0;

		lport = sin6->sin6_port;
		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
			/*
			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
			 * allow compepte duplication of binding if
			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
			 * and a multicast address is bound on both
			 * new and duplicated sockets.
			 */
			if (so->so_options & SO_REUSEADDR)
				reuseport = SO_REUSEADDR|SO_REUSEPORT;
		} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
			struct ifaddr *ifa;

			sin6->sin6_port = 0;		/* yech... */
			if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0) {
				lck_rw_done(pcbinfo->mtx);
				socket_lock(so, 0);
				return(EADDRNOTAVAIL);
			}

			/*
			 * XXX: bind to an anycast address might accidentally
			 * cause sending a packet with anycast source address.
			 * We should allow to bind to a deprecated address, since
			 * the application dare to use it.
			 */
			if (ifa != NULL) {
				IFA_LOCK_SPIN(ifa);
				if (((struct in6_ifaddr *)ifa)->ia6_flags &
				    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
					IFA_UNLOCK(ifa);
					IFA_REMREF(ifa);
					lck_rw_done(pcbinfo->mtx);
					socket_lock(so, 0);
					return(EADDRNOTAVAIL);
				}
				outif = ifa->ifa_ifp->if_index;
				IFA_UNLOCK(ifa);
				IFA_REMREF(ifa);
			}
		}
		if (lport) {
			struct inpcb *t;

			/* GROSS */
			if (ntohs(lport) < IPV6PORT_RESERVED) {
				cred = kauth_cred_proc_ref(p);
				error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0);
				kauth_cred_unref(&cred);
				if (error != 0) {
					lck_rw_done(pcbinfo->mtx);
					socket_lock(so, 0);
					return(EACCES);
				}
			}

			if (so->so_uid &&
			    !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
				t = in6_pcblookup_local_and_cleanup(pcbinfo,
				    &sin6->sin6_addr, lport,
				    INPLOOKUP_WILDCARD);
				if (t &&
				    (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
				     !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
				     (t->inp_socket->so_options &
				      SO_REUSEPORT) == 0) &&
				     (so->so_uid != t->inp_socket->so_uid) &&
				     ((t->inp_socket->so_flags & SOF_REUSESHAREUID) == 0)) {
					lck_rw_done(pcbinfo->mtx);
					socket_lock(so, 0);
					return (EADDRINUSE);
				}
				if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
				    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
					struct sockaddr_in sin;

					in6_sin6_2_sin(&sin, sin6);
					t = in_pcblookup_local_and_cleanup(pcbinfo,
						sin.sin_addr, lport,
						INPLOOKUP_WILDCARD);
					if (t && (t->inp_socket->so_options & SO_REUSEPORT) == 0 &&
					    (so->so_uid !=
					     t->inp_socket->so_uid) &&
					    (ntohl(t->inp_laddr.s_addr) !=
					     INADDR_ANY ||
					     INP_SOCKAF(so) ==
					     INP_SOCKAF(t->inp_socket))) {

						lck_rw_done(pcbinfo->mtx);
						socket_lock(so, 0);
						return (EADDRINUSE);
					}
				}
			}
			t = in6_pcblookup_local_and_cleanup(pcbinfo, &sin6->sin6_addr,
						lport, wild);
			if (t && (reuseport & t->inp_socket->so_options) == 0) {
				lck_rw_done(pcbinfo->mtx);
				socket_lock(so, 0);
				return(EADDRINUSE);
			}
			if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
			    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
				struct sockaddr_in sin;

				in6_sin6_2_sin(&sin, sin6);
				t = in_pcblookup_local_and_cleanup(pcbinfo, sin.sin_addr,
						       lport, wild);
				if (t &&
				    (reuseport & t->inp_socket->so_options)
				    == 0 &&
				    (ntohl(t->inp_laddr.s_addr)
				     != INADDR_ANY ||
				     INP_SOCKAF(so) ==
				     INP_SOCKAF(t->inp_socket))) {
					lck_rw_done(pcbinfo->mtx);
					socket_lock(so, 0);
					return (EADDRINUSE);
				}
			}
		}
		inp->in6p_laddr = sin6->sin6_addr;
		inp->in6p_last_outif = outif;
	}
	socket_lock(so, 0);
	if (lport == 0) {
		int e;
		if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, p, 1)) != 0) {
			lck_rw_done(pcbinfo->mtx);
			return(e);
		}
	}
	else {
		inp->inp_lport = lport;
		if (in_pcbinshash(inp, 1) != 0) {
			inp->in6p_laddr = in6addr_any;
			inp->inp_lport = 0;
			inp->in6p_last_outif = 0;
			lck_rw_done(pcbinfo->mtx);
			return (EAGAIN);
		}
	}
	lck_rw_done(pcbinfo->mtx);
	sflt_notify(so, sock_evt_bound, NULL);
	return(0);
}
Exemple #26
0
/**
 * Device open. Called on open /dev/vboxdrv
 *
 * @param   Dev         The device number.
 * @param   fFlags      ???.
 * @param   fDevType    ???.
 * @param   pProcess    The process issuing this request.
 */
static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
{
#ifdef DEBUG_DARWIN_GIP
    char szName[128];
    szName[0] = '\0';
    proc_name(proc_pid(pProcess), szName, sizeof(szName));
    Log(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
#endif

    /*
     * Only two minor devices numbers are allowed.
     */
    if (minor(Dev) != 0 && minor(Dev) != 1)
        return EACCES;

    /*
     * Find the session created by org_virtualbox_SupDrvClient, fail
     * if no such session, and mark it as opened. We set the uid & gid
     * here too, since that is more straight forward at this point.
     */
    const bool      fUnrestricted = minor(Dev) == 0;
    int             rc = VINF_SUCCESS;
    PSUPDRVSESSION  pSession = NULL;
    kauth_cred_t    pCred = kauth_cred_proc_ref(pProcess);
    if (pCred)
    {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
        RTUID           Uid = kauth_cred_getruid(pCred);
        RTGID           Gid = kauth_cred_getrgid(pCred);
#else
        RTUID           Uid = pCred->cr_ruid;
        RTGID           Gid = pCred->cr_rgid;
#endif
        RTPROCESS       Process = RTProcSelf();
        unsigned        iHash = SESSION_HASH(Process);
        RTSpinlockAcquire(g_Spinlock);

        pSession = g_apSessionHashTab[iHash];
        while (pSession && pSession->Process != Process)
            pSession = pSession->pNextHash;
        if (pSession)
        {
            if (!pSession->fOpened)
            {
                pSession->fOpened = true;
                pSession->fUnrestricted = fUnrestricted;
                pSession->Uid = Uid;
                pSession->Gid = Gid;
            }
            else
                rc = VERR_ALREADY_LOADED;
        }
        else
            rc = VERR_GENERAL_FAILURE;

        RTSpinlockReleaseNoInts(g_Spinlock);
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
        kauth_cred_unref(&pCred);
#else  /* 10.4 */
        /* The 10.4u SDK headers and 10.4.11 kernel source have inconsistent definitions
           of kauth_cred_unref(), so use the other (now deprecated) API for releasing it. */
        kauth_cred_rele(pCred);
#endif /* 10.4 */
    }
    else
        rc = VERR_INVALID_PARAMETER;

#ifdef DEBUG_DARWIN_GIP
    OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
#else
    Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
#endif
    return VBoxDrvDarwinErr2DarwinErr(rc);
}
Exemple #27
0
kern_return_t
task_name_for_pid(
	struct task_name_for_pid_args *args)
{
	mach_port_name_t	target_tport = args->target_tport;
	int			pid = args->pid;
	user_addr_t		task_addr = args->t;
	proc_t		p = PROC_NULL;
	task_t		t1;
	mach_port_name_t	tret;
	void * sright;
	int error = 0, refheld = 0;
	kauth_cred_t target_cred;

	AUDIT_MACH_SYSCALL_ENTER(AUE_TASKNAMEFORPID);
	AUDIT_ARG(pid, pid);
	AUDIT_ARG(mach_port1, target_tport);

	t1 = port_name_to_task(target_tport);
	if (t1 == TASK_NULL) {
		(void) copyout((char *)&t1, task_addr, sizeof(mach_port_name_t));
		AUDIT_MACH_SYSCALL_EXIT(KERN_FAILURE);
		return(KERN_FAILURE);
	} 

	p = proc_find(pid);
	if (p != PROC_NULL) {
		AUDIT_ARG(process, p);
		target_cred = kauth_cred_proc_ref(p);
		refheld = 1;

		if ((p->p_stat != SZOMB)
		    && ((current_proc() == p)
			|| kauth_cred_issuser(kauth_cred_get()) 
			|| ((kauth_cred_getuid(target_cred) == kauth_cred_getuid(kauth_cred_get())) && 
			    ((kauth_cred_getruid(target_cred) == kauth_getruid()))))) {

			if (p->task != TASK_NULL) {
				task_reference(p->task);
#if CONFIG_MACF
				error = mac_proc_check_get_task_name(kauth_cred_get(),  p);
				if (error) {
					task_deallocate(p->task);
					goto noperm;
				}
#endif
				sright = (void *)convert_task_name_to_port(p->task);
				tret = ipc_port_copyout_send(sright, 
						get_task_ipcspace(current_task()));
			} else
				tret  = MACH_PORT_NULL;

			AUDIT_ARG(mach_port2, tret);
			(void) copyout((char *)&tret, task_addr, sizeof(mach_port_name_t));
			task_deallocate(t1);
			error = KERN_SUCCESS;
			goto tnfpout;
		}
	}

#if CONFIG_MACF
noperm:
#endif
    task_deallocate(t1);
	tret = MACH_PORT_NULL;
	(void) copyout((char *) &tret, task_addr, sizeof(mach_port_name_t));
	error = KERN_FAILURE;
tnfpout:
	if (refheld != 0)
		kauth_cred_unref(&target_cred);
	if (p != PROC_NULL)
		proc_rele(p);
	AUDIT_MACH_SYSCALL_EXIT(error);
	return(error);
}
Exemple #28
0
/* ARGSUSED */
int
auditon(proc_t p, struct auditon_args *uap, __unused int32_t *retval)
{
	kauth_cred_t scred;
	int error = 0;
	union auditon_udata udata;
	proc_t tp = PROC_NULL;
	struct auditinfo_addr aia;

	AUDIT_ARG(cmd, uap->cmd);

#if CONFIG_MACF
	error = mac_system_check_auditon(kauth_cred_get(), uap->cmd);
	if (error)
		return (error);
#endif

	if ((uap->length <= 0) || (uap->length >
	    (int)sizeof(union auditon_udata)))
		return (EINVAL);

	memset((void *)&udata, 0, sizeof(udata));

	/*
	 * Some of the GET commands use the arguments too.
	 */
	switch (uap->cmd) {
	case A_SETPOLICY:
	case A_OLDSETPOLICY:
	case A_SETKMASK:
	case A_SETQCTRL:
	case A_OLDSETQCTRL:
	case A_SETSTAT:
	case A_SETUMASK:
	case A_SETSMASK:
	case A_SETCOND:
	case A_OLDSETCOND:
	case A_SETCLASS:
	case A_SETPMASK:
	case A_SETFSIZE:
	case A_SETKAUDIT:
	case A_GETCLASS:
	case A_GETPINFO:
	case A_GETPINFO_ADDR:
	case A_SENDTRIGGER:
	case A_GETSINFO_ADDR:
	case A_GETSFLAGS:
	case A_SETSFLAGS:
		error = copyin(uap->data, (void *)&udata, uap->length);
		if (error)
			return (error);
		AUDIT_ARG(auditon, &udata);
		AUDIT_ARG(len, uap->length);
		break;
	}

	/* Check appropriate privilege. */
	switch (uap->cmd) {
	/*
	 * A_GETSINFO doesn't require priviledge but only superuser  
	 * gets to see the audit masks. 
	 */
	case A_GETSINFO_ADDR:
		if ((sizeof(udata.au_kau_info) != uap->length) ||
	   		(audit_session_lookup(udata.au_kau_info.ai_asid,
					      &udata.au_kau_info) != 0))
			error = EINVAL;
		else if (!kauth_cred_issuser(kauth_cred_get())) {
			udata.au_kau_info.ai_mask.am_success = ~0;
			udata.au_kau_info.ai_mask.am_failure = ~0;
		}
		break;
	case A_GETSFLAGS:
	case A_SETSFLAGS:
		/* Getting one's own audit session flags requires no
		 * privilege.  Setting the flags is subject to access
		 * control implemented in audit_session_setaia().
		 */
		break;
	default:
		error = suser(kauth_cred_get(), &p->p_acflag);
		break;
	}
	if (error)
		return (error);

	/*
	 * XXX Need to implement these commands by accessing the global
	 * values associated with the commands.
	 */
	switch (uap->cmd) {
	case A_OLDGETPOLICY:
	case A_GETPOLICY:
		if (sizeof(udata.au_policy64) == uap->length) {
			mtx_lock(&audit_mtx);
			if (!audit_fail_stop)
				udata.au_policy64 |= AUDIT_CNT;
			if (audit_panic_on_write_fail)
				udata.au_policy64 |= AUDIT_AHLT;
			if (audit_argv)
				udata.au_policy64 |= AUDIT_ARGV;
			if (audit_arge)
				udata.au_policy64 |= AUDIT_ARGE;
			mtx_unlock(&audit_mtx);
			break;
		}
		if (sizeof(udata.au_policy) != uap->length)
			return (EINVAL);
		mtx_lock(&audit_mtx);
		if (!audit_fail_stop)
			udata.au_policy |= AUDIT_CNT;
		if (audit_panic_on_write_fail)
			udata.au_policy |= AUDIT_AHLT;
		if (audit_argv)
			udata.au_policy |= AUDIT_ARGV;
		if (audit_arge)
			udata.au_policy |= AUDIT_ARGE;
		mtx_unlock(&audit_mtx);
		break;

	case A_OLDSETPOLICY:
	case A_SETPOLICY:
		if (sizeof(udata.au_policy64) == uap->length) {
			if (udata.au_policy64 & ~(AUDIT_CNT|AUDIT_AHLT|
				AUDIT_ARGV|AUDIT_ARGE))
				return (EINVAL);
			mtx_lock(&audit_mtx);
			audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
			    0);
			audit_panic_on_write_fail = (udata.au_policy64 &
			    AUDIT_AHLT);
			audit_argv = (udata.au_policy64 & AUDIT_ARGV);
			audit_arge = (udata.au_policy64 & AUDIT_ARGE);
			mtx_unlock(&audit_mtx);
			break;
		}	
		if ((sizeof(udata.au_policy) != uap->length) ||
		    (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
					 AUDIT_ARGE)))
			return (EINVAL);
		/*
		 * XXX - Need to wake up waiters if the policy relaxes?
		 */
		mtx_lock(&audit_mtx);
		audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
		audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
		audit_argv = (udata.au_policy & AUDIT_ARGV);
		audit_arge = (udata.au_policy & AUDIT_ARGE);
		mtx_unlock(&audit_mtx);
		break;

	case A_GETKMASK:
		if (sizeof(udata.au_mask) != uap->length)
			return (EINVAL);
		mtx_lock(&audit_mtx);
		udata.au_mask = audit_nae_mask;
		mtx_unlock(&audit_mtx);
		break;

	case A_SETKMASK:
		if (sizeof(udata.au_mask) != uap->length)
			return (EINVAL);
		mtx_lock(&audit_mtx);
		audit_nae_mask = udata.au_mask;
		AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask);
		mtx_unlock(&audit_mtx);
		break;

	case A_OLDGETQCTRL:
	case A_GETQCTRL:
		if (sizeof(udata.au_qctrl64) == uap->length) {
			mtx_lock(&audit_mtx);
			udata.au_qctrl64.aq64_hiwater =
			    (u_int64_t)audit_qctrl.aq_hiwater;
			udata.au_qctrl64.aq64_lowater =
			    (u_int64_t)audit_qctrl.aq_lowater;
			udata.au_qctrl64.aq64_bufsz =
			    (u_int64_t)audit_qctrl.aq_bufsz;
			udata.au_qctrl64.aq64_delay =
			    (u_int64_t)audit_qctrl.aq_delay;
			udata.au_qctrl64.aq64_minfree = 
			    (int64_t)audit_qctrl.aq_minfree;
			mtx_unlock(&audit_mtx);
			break;
		} 
		if (sizeof(udata.au_qctrl) != uap->length)
			return (EINVAL);
		mtx_lock(&audit_mtx);
		udata.au_qctrl = audit_qctrl;
		mtx_unlock(&audit_mtx);
		break;

	case A_OLDSETQCTRL:
	case A_SETQCTRL:
		if (sizeof(udata.au_qctrl64) == uap->length) {
			 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) ||
			     (udata.au_qctrl64.aq64_lowater >= 
			      udata.au_qctrl64.aq64_hiwater) ||
			     (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
			     (udata.au_qctrl64.aq64_minfree < 0) ||
			     (udata.au_qctrl64.aq64_minfree > 100))
				return (EINVAL);
			mtx_lock(&audit_mtx);
			audit_qctrl.aq_hiwater =
			     (int)udata.au_qctrl64.aq64_hiwater;
			audit_qctrl.aq_lowater =
			     (int)udata.au_qctrl64.aq64_lowater;
			audit_qctrl.aq_bufsz =
			     (int)udata.au_qctrl64.aq64_bufsz;
			audit_qctrl.aq_minfree = 
			    (int)udata.au_qctrl64.aq64_minfree;
			audit_qctrl.aq_delay = -1;  /* Not used. */
			mtx_unlock(&audit_mtx);
			break;
		}
		if ((sizeof(udata.au_qctrl) != uap->length) ||
		    (udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
		    (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
		    (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
		    (udata.au_qctrl.aq_minfree < 0) ||
		    (udata.au_qctrl.aq_minfree > 100))
			return (EINVAL);

		mtx_lock(&audit_mtx);
		audit_qctrl = udata.au_qctrl;
		/* XXX The queue delay value isn't used with the kernel. */
		audit_qctrl.aq_delay = -1;
		mtx_unlock(&audit_mtx);
		break;

	case A_GETCWD:
		return (ENOSYS);

	case A_GETCAR:
		return (ENOSYS);

	case A_GETSTAT:
		return (ENOSYS);

	case A_SETSTAT:
		return (ENOSYS);

	case A_SETUMASK:
		return (ENOSYS);

	case A_SETSMASK:
		return (ENOSYS);

	case A_OLDGETCOND:
	case A_GETCOND:
		if (sizeof(udata.au_cond64) == uap->length) {
			mtx_lock(&audit_mtx);
			if (audit_enabled && !audit_suspended)
				udata.au_cond64 = AUC_AUDITING;
			else
				udata.au_cond64 = AUC_NOAUDIT;
			mtx_unlock(&audit_mtx);
			break;
		}
		if (sizeof(udata.au_cond) != uap->length)
			return (EINVAL);
		mtx_lock(&audit_mtx);
		if (audit_enabled && !audit_suspended)
			udata.au_cond = AUC_AUDITING;
		else
			udata.au_cond = AUC_NOAUDIT;
		mtx_unlock(&audit_mtx);
		break;

	case A_OLDSETCOND:
	case A_SETCOND:
		if (sizeof(udata.au_cond64) == uap->length) {
			mtx_lock(&audit_mtx);
			if (udata.au_cond64 == AUC_NOAUDIT)
				audit_suspended = 1;
			if (udata.au_cond64 == AUC_AUDITING)
				audit_suspended = 0;
			if (udata.au_cond64 == AUC_DISABLED) {
				audit_suspended = 1;
				mtx_unlock(&audit_mtx);
				audit_shutdown();
				break;
			}
			mtx_unlock(&audit_mtx);
			break;
		}
		if (sizeof(udata.au_cond) != uap->length) {
			return (EINVAL);
		}
		mtx_lock(&audit_mtx);
		if (udata.au_cond == AUC_NOAUDIT)
			audit_suspended = 1;
		if (udata.au_cond == AUC_AUDITING)
			audit_suspended = 0;
		if (udata.au_cond == AUC_DISABLED) {
			audit_suspended = 1;
			mtx_unlock(&audit_mtx);
			audit_shutdown();
			break;
		}
		mtx_unlock(&audit_mtx);
		break;

	case A_GETCLASS:
		if (sizeof(udata.au_evclass) != uap->length)
			return (EINVAL);
		udata.au_evclass.ec_class = au_event_class(
		    udata.au_evclass.ec_number);
		break;

	case A_SETCLASS:
		if (sizeof(udata.au_evclass) != uap->length)
			return (EINVAL);
		au_evclassmap_insert(udata.au_evclass.ec_number,
		    udata.au_evclass.ec_class);
		break;

	case A_GETPINFO:
		if ((sizeof(udata.au_aupinfo) != uap->length) ||
		    IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
			return (EINVAL);
		if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
			return (ESRCH);

		scred = kauth_cred_proc_ref(tp);
		if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) {
			kauth_cred_unref(&scred);
			proc_rele(tp);
			return (EINVAL);
		}
		
		udata.au_aupinfo.ap_auid =
		    scred->cr_audit.as_aia_p->ai_auid;
		udata.au_aupinfo.ap_mask.am_success =
		    scred->cr_audit.as_mask.am_success;
		udata.au_aupinfo.ap_mask.am_failure =
		    scred->cr_audit.as_mask.am_failure;
		udata.au_aupinfo.ap_termid.machine =
		    scred->cr_audit.as_aia_p->ai_termid.at_addr[0];
		udata.au_aupinfo.ap_termid.port =
		    scred->cr_audit.as_aia_p->ai_termid.at_port;
		udata.au_aupinfo.ap_asid =
		    scred->cr_audit.as_aia_p->ai_asid;
		kauth_cred_unref(&scred);
		proc_rele(tp);
		tp = PROC_NULL;
		break;

	case A_SETPMASK:
		if ((sizeof(udata.au_aupinfo) != uap->length) ||
		    IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid))
			return (EINVAL);
		if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
			return (ESRCH);
		scred = kauth_cred_proc_ref(tp);
		bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia));
		kauth_cred_unref(&scred);
		aia.ai_mask.am_success =
		    udata.au_aupinfo.ap_mask.am_success;
		aia.ai_mask.am_failure =
		    udata.au_aupinfo.ap_mask.am_failure;
		AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask);
		error = audit_session_setaia(tp, &aia);
		proc_rele(tp);
		tp = PROC_NULL;
		if (error)
			return (error);
		break;

	case A_SETFSIZE:
		if ((sizeof(udata.au_fstat) != uap->length) ||
		    ((udata.au_fstat.af_filesz != 0) &&
		     (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)))
			return (EINVAL);
		mtx_lock(&audit_mtx);
		audit_fstat.af_filesz = udata.au_fstat.af_filesz;
		mtx_unlock(&audit_mtx);
		break;

	case A_GETFSIZE:
		if (sizeof(udata.au_fstat) != uap->length)
			return (EINVAL);
		mtx_lock(&audit_mtx);
		udata.au_fstat.af_filesz = audit_fstat.af_filesz;
		udata.au_fstat.af_currsz = audit_fstat.af_currsz;
		mtx_unlock(&audit_mtx);
		break;

	case A_GETPINFO_ADDR:
		if ((sizeof(udata.au_aupinfo_addr) != uap->length) ||
		    IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid))
			return (EINVAL);
		if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL)
			return (ESRCH);
		WARN_IF_AINFO_ADDR_CHANGED(uap->length,
		    sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)",
		    "auditpinfo_addr_t");
		scred = kauth_cred_proc_ref(tp);
		udata.au_aupinfo_addr.ap_auid =
		    scred->cr_audit.as_aia_p->ai_auid;
		udata.au_aupinfo_addr.ap_asid =
		    scred->cr_audit.as_aia_p->ai_asid;
		udata.au_aupinfo_addr.ap_mask.am_success =
		    scred->cr_audit.as_mask.am_success;
		udata.au_aupinfo_addr.ap_mask.am_failure =
		    scred->cr_audit.as_mask.am_failure;
		bcopy(&scred->cr_audit.as_aia_p->ai_termid, 
		    &udata.au_aupinfo_addr.ap_termid,
		    sizeof(au_tid_addr_t));
		udata.au_aupinfo_addr.ap_flags =
		    scred->cr_audit.as_aia_p->ai_flags;
		kauth_cred_unref(&scred);
		proc_rele(tp);
		tp = PROC_NULL;
		break;

	case A_GETKAUDIT:
		if (sizeof(udata.au_kau_info) != uap->length) 
			return (EINVAL);
		audit_get_kinfo(&udata.au_kau_info);
		break;

	case A_SETKAUDIT:
		if ((sizeof(udata.au_kau_info) != uap->length) ||
		    (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
		    udata.au_kau_info.ai_termid.at_type != AU_IPv6))
			return (EINVAL);
		audit_set_kinfo(&udata.au_kau_info);
		break;

	case A_SENDTRIGGER:
		if ((sizeof(udata.au_trigger) != uap->length) || 
		    (udata.au_trigger < AUDIT_TRIGGER_MIN) ||
		    (udata.au_trigger > AUDIT_TRIGGER_MAX))
			return (EINVAL);
		return (audit_send_trigger(udata.au_trigger));

	case A_GETSINFO_ADDR:
		/* Handled above before switch(). */
		break;

	case A_GETSFLAGS:
		if (sizeof(udata.au_flags) != uap->length)
			return (EINVAL);
		bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags),
		    &udata.au_flags, sizeof(udata.au_flags));
		break;

	case A_SETSFLAGS:
		if (sizeof(udata.au_flags) != uap->length)
			return (EINVAL);
		bcopy(kauth_cred_get()->cr_audit.as_aia_p, &aia, sizeof(aia));
		aia.ai_flags = udata.au_flags;
		error = audit_session_setaia(p, &aia);
		if (error)
			return (error);
		break;

	default:
		return (EINVAL);
	}

	/*
	 * Copy data back to userspace for the GET comands.
	 */
	switch (uap->cmd) {
	case A_GETPOLICY:
	case A_OLDGETPOLICY:
	case A_GETKMASK:
	case A_GETQCTRL:
	case A_OLDGETQCTRL:
	case A_GETCWD:
	case A_GETCAR:
	case A_GETSTAT:
	case A_GETCOND:
	case A_OLDGETCOND:
	case A_GETCLASS:
	case A_GETPINFO:
	case A_GETFSIZE:
	case A_GETPINFO_ADDR:
	case A_GETKAUDIT:
	case A_GETSINFO_ADDR:
	case A_GETSFLAGS:
		error = copyout((void *)&udata, uap->data, uap->length);
		if (error)
			return (ENOSYS);
		break;
	}

	return (0);
}
Exemple #29
0
int
cttyopen(dev_t dev, int flag, __unused int mode, proc_t p)
{
	vnode_t ttyvp = cttyvp(p);
	struct vfs_context context;
	int error = 0;
	int cttyflag, doclose = 0;
	struct session *sessp;

	if (ttyvp == NULL)
		return (ENXIO);

	context.vc_thread = current_thread();
	context.vc_ucred = kauth_cred_proc_ref(p);

	sessp = proc_session(p);
	session_lock(sessp);
	cttyflag = sessp->s_flags & S_CTTYREF;	
	session_unlock(sessp);

	/*
	 * A little hack--this device, used by many processes,
	 * happens to do an open on another device, which can 
	 * cause unhappiness if the second-level open blocks indefinitely 
	 * (as could be the case if the master side has hung up).  Since
	 * we know that this driver doesn't care about the serializing
	 * opens and closes, we can drop the lock. To avoid opencount leak,
	 * open the vnode only for the first time. 
	 */
	if (cttyflag == 0) {
		devsw_unlock(dev, S_IFCHR);
		error = VNOP_OPEN(ttyvp, flag, &context);
		devsw_lock(dev, S_IFCHR);

		if (error) 
			goto out;
	
		/*
		 * If S_CTTYREF is set, some other thread did an open
		 * and was able to set the flag, now perform a close, else
		 * set the flag.
		 */
		session_lock(sessp);
		if (cttyflag == (sessp->s_flags & S_CTTYREF))
			sessp->s_flags |= S_CTTYREF;
		else
			doclose = 1;
		session_unlock(sessp);

		/*
		 * We have to take a reference here to make sure a close
		 * gets called during revoke. Note that once a controlling 
		 * tty gets opened by this driver, the only way close will
		 * get called is when the session leader , whose controlling
		 * tty is ttyvp, exits and vnode is revoked. We cannot 
		 * redirect close from this driver because underlying controlling
		 * terminal might change and close may get redirected to a 
		 * wrong vnode causing panic.
		 */
		if (doclose) {
			devsw_unlock(dev, S_IFCHR);
			VNOP_CLOSE(ttyvp, flag, &context);
			devsw_lock(dev, S_IFCHR);
		} else {
			error = vnode_ref(ttyvp);
		}
	}
out:
	session_rele(sessp);

	vnode_put(ttyvp);
	kauth_cred_unref(&context.vc_ucred);

	return (error);
}
Exemple #30
0
/*
 * audit_syscall_enter() is called on entry to each system call.  It is
 * responsible for deciding whether or not to audit the call (preselection),
 * and if so, allocating a per-thread audit record.  audit_new() will fill in
 * basic thread/credential properties.
 */
void
audit_syscall_enter(unsigned int code, proc_t proc, struct uthread *uthread)
{
	struct au_mask *aumask;
	au_class_t class;
	au_event_t event;
	au_id_t auid;
	kauth_cred_t cred;

	/*
	 * In FreeBSD, each ABI has its own system call table, and hence
	 * mapping of system call codes to audit events.  Convert the code to
	 * an audit event identifier using the process system call table
	 * reference.  In Darwin, there's only one, so we use the global
	 * symbol for the system call table.  No audit record is generated
	 * for bad system calls, as no operation has been performed.
	 *
	 * In Mac OS X, the audit events are stored in a table seperate from
	 * the syscall table(s).  This table is generated by makesyscalls.sh
	 * from syscalls.master and stored in audit_kevents.c.
	 */
	if (code > NUM_SYSENT)
		return;
	event = sys_au_event[code];
	if (event == AUE_NULL)
		return;

	KASSERT(uthread->uu_ar == NULL,
	    ("audit_syscall_enter: uthread->uu_ar != NULL"));

	/*
	 * Check which audit mask to use; either the kernel non-attributable
	 * event mask or the process audit mask.
	 */
	cred = kauth_cred_proc_ref(proc);
	auid = cred->cr_audit.as_aia_p->ai_auid;
	if (auid == AU_DEFAUDITID) 
		aumask = &audit_nae_mask;
	else
		aumask = &cred->cr_audit.as_mask;

	/*
	 * Allocate an audit record, if preselection allows it, and store in
	 * the thread for later use.
	 */
	class = au_event_class(event);
#if CONFIG_MACF
	/*
	 * Note: audit_mac_syscall_enter() may call audit_new() and allocate
	 * memory for the audit record (uu_ar).
	 */
	if (audit_mac_syscall_enter(code, proc, uthread, cred, event) == 0)
		goto out;
#endif
	if (au_preselect(event, class, aumask, AU_PRS_BOTH)) {
		/*
		 * If we're out of space and need to suspend unprivileged
		 * processes, do that here rather than trying to allocate
		 * another audit record.
		 *
		 * Note: we might wish to be able to continue here in the
		 * future, if the system recovers.  That should be possible
		 * by means of checking the condition in a loop around
		 * cv_wait().  It might be desirable to reevaluate whether an
		 * audit record is still required for this event by
		 * re-calling au_preselect().
		 */
		if (audit_in_failure &&
		    suser(cred, &proc->p_acflag) != 0) {
			cv_wait(&audit_fail_cv, &audit_mtx);
			panic("audit_failing_stop: thread continued");
		}
		if (uthread->uu_ar == NULL)
			uthread->uu_ar = audit_new(event, proc, uthread);
	} else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) {