NetBSD/sys/secmodel/bsd44/secmodel_bsd44_suser.c
2009-05-08 11:09:43 +00:00

1160 lines
23 KiB
C

/* $NetBSD: secmodel_bsd44_suser.c,v 1.67 2009/05/08 11:09:43 elad Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file contains kauth(9) listeners needed to implement the traditional
* NetBSD superuser access restrictions.
*
* There are two main resources a request can be issued to: user-owned and
* system owned. For the first, traditional Unix access checks are done, as
* well as superuser checks. If needed, the request context is examined before
* a decision is made. For the latter, usually only superuser checks are done
* as normal users are not allowed to access system resources.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: secmodel_bsd44_suser.c,v 1.67 2009/05/08 11:09:43 elad Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/kauth.h>
#include <sys/acct.h>
#include <sys/mutex.h>
#include <sys/ktrace.h>
#include <sys/mount.h>
#include <sys/pset.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/tty.h>
#include <net/route.h>
#include <sys/ptrace.h>
#include <sys/vnode.h>
#include <sys/proc.h>
#include <sys/uidinfo.h>
#include <miscfs/procfs/procfs.h>
#include <secmodel/bsd44/suser.h>
extern int dovfsusermount;
static kauth_listener_t l_generic, l_system, l_process, l_network, l_machdep,
l_device;
void
secmodel_bsd44_suser_start(void)
{
l_generic = kauth_listen_scope(KAUTH_SCOPE_GENERIC,
secmodel_bsd44_suser_generic_cb, NULL);
l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
secmodel_bsd44_suser_system_cb, NULL);
l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
secmodel_bsd44_suser_process_cb, NULL);
l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
secmodel_bsd44_suser_network_cb, NULL);
l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
secmodel_bsd44_suser_machdep_cb, NULL);
l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
secmodel_bsd44_suser_device_cb, NULL);
}
#if defined(_LKM)
void
secmodel_bsd44_suser_stop(void)
{
kauth_unlisten_scope(l_generic);
kauth_unlisten_scope(l_system);
kauth_unlisten_scope(l_process);
kauth_unlisten_scope(l_network);
kauth_unlisten_scope(l_machdep);
kauth_unlisten_scope(l_device);
}
#endif /* _LKM */
/*
* kauth(9) listener
*
* Security model: Traditional NetBSD
* Scope: Generic
* Responsibility: Superuser access
*/
int
secmodel_bsd44_suser_generic_cb(kauth_cred_t cred, kauth_action_t action,
void *cookie, void *arg0, void *arg1,
void *arg2, void *arg3)
{
bool isroot;
int result;
isroot = (kauth_cred_geteuid(cred) == 0);
result = KAUTH_RESULT_DEFER;
switch (action) {
case KAUTH_GENERIC_ISSUSER:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_GENERIC_CANSEE:
if (!secmodel_bsd44_curtain)
result = KAUTH_RESULT_ALLOW;
else if (isroot || kauth_cred_uidmatch(cred, arg0))
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
return (result);
}
/*
* kauth(9) listener
*
* Security model: Traditional NetBSD
* Scope: System
* Responsibility: Superuser access
*/
int
secmodel_bsd44_suser_system_cb(kauth_cred_t cred, kauth_action_t action,
void *cookie, void *arg0, void *arg1,
void *arg2, void *arg3)
{
bool isroot;
int result;
enum kauth_system_req req;
isroot = (kauth_cred_geteuid(cred) == 0);
result = KAUTH_RESULT_DEFER;
req = (enum kauth_system_req)arg0;
switch (action) {
case KAUTH_SYSTEM_CPU:
switch (req) {
case KAUTH_REQ_SYSTEM_CPU_SETSTATE:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_SYSTEM_FS_QUOTA:
switch (req) {
case KAUTH_REQ_SYSTEM_FS_QUOTA_GET:
case KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF:
case KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE:
case KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_SYSTEM_FS_RESERVEDSPACE:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_SYSTEM_MOUNT:
switch (req) {
case KAUTH_REQ_SYSTEM_MOUNT_GET:
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_SYSTEM_MOUNT_NEW:
if (isroot)
result = KAUTH_RESULT_ALLOW;
else if (dovfsusermount) {
struct vnode *vp = arg1;
u_long flags = (u_long)arg2;
if (!(flags & MNT_NODEV) ||
!(flags & MNT_NOSUID))
break;
if ((vp->v_mount->mnt_flag & MNT_NOEXEC) &&
!(flags & MNT_NOEXEC))
break;
result = KAUTH_RESULT_ALLOW;
}
break;
case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT:
if (isroot)
result = KAUTH_RESULT_ALLOW;
else {
struct mount *mp = arg1;
if (mp->mnt_stat.f_owner ==
kauth_cred_geteuid(cred))
result = KAUTH_RESULT_ALLOW;
}
break;
case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
if (isroot)
result = KAUTH_RESULT_ALLOW;
else if (dovfsusermount) {
struct mount *mp = arg1;
u_long flags = (u_long)arg2;
/* No exporting for non-root. */
if (flags & MNT_EXPORTED)
break;
if (!(flags & MNT_NODEV) ||
!(flags & MNT_NOSUID))
break;
/*
* Only super-user, or user that did the mount,
* can update.
*/
if (mp->mnt_stat.f_owner !=
kauth_cred_geteuid(cred))
break;
/* Retain 'noexec'. */
if ((mp->mnt_flag & MNT_NOEXEC) &&
!(flags & MNT_NOEXEC))
break;
result = KAUTH_RESULT_ALLOW;
}
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
break;
case KAUTH_SYSTEM_PSET: {
psetid_t id;
id = (psetid_t)(unsigned long)arg1;
switch (req) {
case KAUTH_REQ_SYSTEM_PSET_ASSIGN:
case KAUTH_REQ_SYSTEM_PSET_BIND:
if (isroot || id == PS_QUERY)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_SYSTEM_PSET_CREATE:
case KAUTH_REQ_SYSTEM_PSET_DESTROY:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
}
case KAUTH_SYSTEM_TIME:
switch (req) {
case KAUTH_REQ_SYSTEM_TIME_ADJTIME:
case KAUTH_REQ_SYSTEM_TIME_NTPADJTIME:
case KAUTH_REQ_SYSTEM_TIME_TIMECOUNTERS:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
bool device_context = (bool)arg3;
if (device_context || isroot)
result = KAUTH_RESULT_ALLOW;
break;
}
case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
break;
case KAUTH_SYSTEM_SYSCTL:
switch (req) {
case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
case KAUTH_REQ_SYSTEM_SYSCTL_MODIFY:
case KAUTH_REQ_SYSTEM_SYSCTL_PRVT:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_SYSTEM_SWAPCTL:
case KAUTH_SYSTEM_ACCOUNTING:
case KAUTH_SYSTEM_REBOOT:
case KAUTH_SYSTEM_CHROOT:
case KAUTH_SYSTEM_FILEHANDLE:
case KAUTH_SYSTEM_MKNOD:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_SYSTEM_DEBUG:
switch (req) {
case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
default:
/* Decisions are root-agnostic. */
result = KAUTH_RESULT_ALLOW;
break;
}
break;
case KAUTH_SYSTEM_CHSYSFLAGS:
/*
* Needs to be checked in conjunction with the immutable and
* append-only flags (usually). Should be handled differently.
* Infects ufs, ext2fs, tmpfs, and rump.
*/
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_SYSTEM_SETIDCORE:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_SYSTEM_MODULE:
if (isroot)
result = KAUTH_RESULT_ALLOW;
if ((uintptr_t)arg2 != 0) /* autoload */
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
return (result);
}
/*
* common code for corename, rlimit, and stopflag.
*/
static int
proc_uidmatch(kauth_cred_t cred, kauth_cred_t target)
{
int r = 0;
if (kauth_cred_getuid(cred) != kauth_cred_getuid(target) ||
kauth_cred_getuid(cred) != kauth_cred_getsvuid(target)) {
/*
* suid proc of ours or proc not ours
*/
r = EPERM;
} else if (kauth_cred_getgid(target) != kauth_cred_getsvgid(target)) {
/*
* sgid proc has sgid back to us temporarily
*/
r = EPERM;
} else {
/*
* our rgid must be in target's group list (ie,
* sub-processes started by a sgid process)
*/
int ismember = 0;
if (kauth_cred_ismember_gid(cred,
kauth_cred_getgid(target), &ismember) != 0 ||
!ismember)
r = EPERM;
}
return (r);
}
/*
* kauth(9) listener
*
* Security model: Traditional NetBSD
* Scope: Process
* Responsibility: Superuser access
*/
int
secmodel_bsd44_suser_process_cb(kauth_cred_t cred, kauth_action_t action,
void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
{
struct proc *p;
bool isroot;
int result;
isroot = (kauth_cred_geteuid(cred) == 0);
result = KAUTH_RESULT_DEFER;
p = arg0;
switch (action) {
case KAUTH_PROCESS_SIGNAL: {
int signum;
signum = (int)(unsigned long)arg1;
if (isroot || kauth_cred_uidmatch(cred, p->p_cred) ||
(signum == SIGCONT && (curproc->p_session == p->p_session)))
result = KAUTH_RESULT_ALLOW;
break;
}
case KAUTH_PROCESS_CANSEE: {
unsigned long req;
req = (unsigned long)arg1;
switch (req) {
case KAUTH_REQ_PROCESS_CANSEE_ARGS:
case KAUTH_REQ_PROCESS_CANSEE_ENTRY:
case KAUTH_REQ_PROCESS_CANSEE_OPENFILES:
if (!secmodel_bsd44_curtain)
result = KAUTH_RESULT_ALLOW;
else if (isroot || kauth_cred_uidmatch(cred, p->p_cred))
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_PROCESS_CANSEE_ENV:
if (!isroot &&
(kauth_cred_getuid(cred) !=
kauth_cred_getuid(p->p_cred) ||
kauth_cred_getuid(cred) !=
kauth_cred_getsvuid(p->p_cred)))
break;
else
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
}
case KAUTH_PROCESS_KTRACE: {
enum kauth_process_req req;
req = (enum kauth_process_req)(unsigned long)arg1;
if (isroot) {
result = KAUTH_RESULT_ALLOW;
break;
} else if (req == KAUTH_REQ_PROCESS_KTRACE_PERSISTENT) {
break;
}
if ((p->p_traceflag & KTRFAC_PERSISTENT) ||
(p->p_flag & PK_SUGID)) {
break;
}
if (kauth_cred_geteuid(cred) == kauth_cred_getuid(p->p_cred) &&
kauth_cred_getuid(cred) == kauth_cred_getsvuid(p->p_cred) &&
kauth_cred_getgid(cred) == kauth_cred_getgid(p->p_cred) &&
kauth_cred_getgid(cred) == kauth_cred_getsvgid(p->p_cred)) {
result = KAUTH_RESULT_ALLOW;
break;
}
break;
}
case KAUTH_PROCESS_PROCFS: {
enum kauth_process_req req = (enum kauth_process_req)arg2;
struct pfsnode *pfs = arg1;
if (isroot) {
result = KAUTH_RESULT_ALLOW;
break;
}
if (req == KAUTH_REQ_PROCESS_PROCFS_CTL) {
break;
}
switch (pfs->pfs_type) {
case PFSregs:
case PFSfpregs:
case PFSmem:
if (kauth_cred_getuid(cred) !=
kauth_cred_getuid(p->p_cred) ||
ISSET(p->p_flag, PK_SUGID)) {
break;
}
/*FALLTHROUGH*/
default:
result = KAUTH_RESULT_ALLOW;
break;
}
break;
}
case KAUTH_PROCESS_PTRACE: {
switch ((u_long)arg1) {
case PT_TRACE_ME:
case PT_ATTACH:
case PT_WRITE_I:
case PT_WRITE_D:
case PT_READ_I:
case PT_READ_D:
case PT_IO:
#ifdef PT_GETREGS
case PT_GETREGS:
#endif
#ifdef PT_SETREGS
case PT_SETREGS:
#endif
#ifdef PT_GETFPREGS
case PT_GETFPREGS:
#endif
#ifdef PT_SETFPREGS
case PT_SETFPREGS:
#endif
#ifdef __HAVE_PTRACE_MACHDEP
PTRACE_MACHDEP_REQUEST_CASES
#endif
if (isroot) {
result = KAUTH_RESULT_ALLOW;
break;
}
if (kauth_cred_getuid(cred) !=
kauth_cred_getuid(p->p_cred) ||
ISSET(p->p_flag, PK_SUGID)) {
break;
}
result = KAUTH_RESULT_ALLOW;
break;
#ifdef PT_STEP
case PT_STEP:
#endif
case PT_CONTINUE:
case PT_KILL:
case PT_DETACH:
case PT_LWPINFO:
case PT_SYSCALL:
case PT_DUMPCORE:
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
break;
}
case KAUTH_PROCESS_CORENAME:
if (isroot || proc_uidmatch(cred, p->p_cred) == 0)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_PROCESS_FORK: {
int lnprocs = (int)(unsigned long)arg2;
/*
* Don't allow a nonprivileged user to use the last few
* processes. The variable lnprocs is the current number of
* processes, maxproc is the limit.
*/
if (__predict_false((lnprocs >= maxproc - 5) && !isroot))
break;
else
result = KAUTH_RESULT_ALLOW;
break;
}
case KAUTH_PROCESS_KEVENT_FILTER:
if ((kauth_cred_getuid(p->p_cred) !=
kauth_cred_getuid(cred) ||
ISSET(p->p_flag, PK_SUGID)) &&
!isroot)
break;
else
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_PROCESS_NICE:
if (isroot) {
result = KAUTH_RESULT_ALLOW;
break;
}
if (kauth_cred_geteuid(cred) !=
kauth_cred_geteuid(p->p_cred) &&
kauth_cred_getuid(cred) !=
kauth_cred_geteuid(p->p_cred)) {
break;
}
if ((u_long)arg1 >= p->p_nice)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_PROCESS_RLIMIT: {
unsigned long req;
req = (unsigned long)arg1;
switch (req) {
case KAUTH_REQ_PROCESS_RLIMIT_SET: {
struct rlimit *new_rlimit;
u_long which;
if (isroot) {
result = KAUTH_RESULT_ALLOW;
break;
}
if ((p != curlwp->l_proc) &&
(proc_uidmatch(cred, p->p_cred) != 0)) {
break;
}
new_rlimit = arg2;
which = (u_long)arg3;
if (new_rlimit->rlim_max <=
p->p_rlimit[which].rlim_max)
result = KAUTH_RESULT_ALLOW;
break;
}
case KAUTH_REQ_PROCESS_RLIMIT_GET:
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
}
case KAUTH_PROCESS_SCHEDULER_GETPARAM:
if (isroot || kauth_cred_uidmatch(cred, p->p_cred))
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_PROCESS_SCHEDULER_SETPARAM:
if (isroot)
result = KAUTH_RESULT_ALLOW;
else if (kauth_cred_uidmatch(cred, p->p_cred)) {
struct lwp *l;
int policy;
pri_t priority;
l = arg1;
policy = (int)(unsigned long)arg2;
priority = (pri_t)(unsigned long)arg3;
if ((policy == l->l_class ||
(policy != SCHED_FIFO && policy != SCHED_RR)) &&
priority <= l->l_priority)
result = KAUTH_RESULT_ALLOW;
}
break;
case KAUTH_PROCESS_SCHEDULER_GETAFFINITY:
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_PROCESS_SCHEDULER_SETAFFINITY:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_PROCESS_SETID:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_PROCESS_STOPFLAG:
if (isroot || proc_uidmatch(cred, p->p_cred) == 0) {
result = KAUTH_RESULT_ALLOW;
break;
}
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
return (result);
}
/*
* kauth(9) listener
*
* Security model: Traditional NetBSD
* Scope: Network
* Responsibility: Superuser access
*/
int
secmodel_bsd44_suser_network_cb(kauth_cred_t cred, kauth_action_t action,
void *cookie, void *arg0, void *arg1, void *arg2,
void *arg3)
{
bool isroot;
int result;
enum kauth_network_req req;
isroot = (kauth_cred_geteuid(cred) == 0);
result = KAUTH_RESULT_DEFER;
req = (enum kauth_network_req)arg0;
switch (action) {
case KAUTH_NETWORK_ALTQ:
switch (req) {
case KAUTH_REQ_NETWORK_ALTQ_AFMAP:
case KAUTH_REQ_NETWORK_ALTQ_BLUE:
case KAUTH_REQ_NETWORK_ALTQ_CBQ:
case KAUTH_REQ_NETWORK_ALTQ_CDNR:
case KAUTH_REQ_NETWORK_ALTQ_CONF:
case KAUTH_REQ_NETWORK_ALTQ_FIFOQ:
case KAUTH_REQ_NETWORK_ALTQ_HFSC:
case KAUTH_REQ_NETWORK_ALTQ_JOBS:
case KAUTH_REQ_NETWORK_ALTQ_PRIQ:
case KAUTH_REQ_NETWORK_ALTQ_RED:
case KAUTH_REQ_NETWORK_ALTQ_RIO:
case KAUTH_REQ_NETWORK_ALTQ_WFQ:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
break;
case KAUTH_NETWORK_BIND:
switch (req) {
case KAUTH_REQ_NETWORK_BIND_PORT:
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_NETWORK_BIND_PRIVPORT:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_NETWORK_FIREWALL:
switch (req) {
case KAUTH_REQ_NETWORK_FIREWALL_FW:
case KAUTH_REQ_NETWORK_FIREWALL_NAT:
/*
* Decisions are root-agnostic.
*
* Both requests are issued from the context of a
* device with permission bits acting as access
* control.
*/
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_NETWORK_FORWSRCRT:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_NETWORK_INTERFACE:
switch (req) {
case KAUTH_REQ_NETWORK_INTERFACE_GET:
case KAUTH_REQ_NETWORK_INTERFACE_SET:
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_NETWORK_INTERFACE_GETPRIV:
case KAUTH_REQ_NETWORK_INTERFACE_SETPRIV:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
break;
case KAUTH_NETWORK_INTERFACE_PPP:
switch (req) {
case KAUTH_REQ_NETWORK_INTERFACE_PPP_ADD:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_NETWORK_INTERFACE_SLIP:
switch (req) {
case KAUTH_REQ_NETWORK_INTERFACE_SLIP_ADD:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_NETWORK_INTERFACE_STRIP:
switch (req) {
case KAUTH_REQ_NETWORK_INTERFACE_STRIP_ADD:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_NETWORK_INTERFACE_TUN:
switch (req) {
case KAUTH_REQ_NETWORK_INTERFACE_TUN_ADD:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
case KAUTH_NETWORK_NFS:
switch (req) {
case KAUTH_REQ_NETWORK_NFS_EXPORT:
case KAUTH_REQ_NETWORK_NFS_SVC:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
break;
case KAUTH_NETWORK_ROUTE:
switch (((struct rt_msghdr *)arg1)->rtm_type) {
case RTM_GET:
result = KAUTH_RESULT_ALLOW;
break;
default:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
}
break;
case KAUTH_NETWORK_SOCKET:
switch (req) {
case KAUTH_REQ_NETWORK_SOCKET_DROP:
/*
* The superuser can drop any connection. Normal users
* can only drop their own connections.
*/
if (isroot)
result = KAUTH_RESULT_ALLOW;
else {
struct socket *so = (struct socket *)arg1;
uid_t sockuid = so->so_uidinfo->ui_uid;
if (sockuid == kauth_cred_getuid(cred) ||
sockuid == kauth_cred_geteuid(cred))
result = KAUTH_RESULT_ALLOW;
}
break;
case KAUTH_REQ_NETWORK_SOCKET_OPEN:
if ((u_long)arg1 == PF_ROUTE || (u_long)arg1 == PF_BLUETOOTH)
result = KAUTH_RESULT_ALLOW;
else if ((u_long)arg2 == SOCK_RAW) {
if (isroot)
result = KAUTH_RESULT_ALLOW;
} else
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_NETWORK_SOCKET_RAWSOCK:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_NETWORK_SOCKET_CANSEE:
if (secmodel_bsd44_curtain) {
uid_t so_uid;
so_uid =
((struct socket *)arg1)->so_uidinfo->ui_uid;
if (isroot ||
kauth_cred_geteuid(cred) == so_uid)
result = KAUTH_RESULT_ALLOW;
} else
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_REQ_NETWORK_SOCKET_SETPRIV:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
return (result);
}
/*
* kauth(9) listener
*
* Security model: Traditional NetBSD
* Scope: Machdep
* Responsibility: Superuser access
*/
int
secmodel_bsd44_suser_machdep_cb(kauth_cred_t cred, kauth_action_t action,
void *cookie, void *arg0, void *arg1, void *arg2,
void *arg3)
{
bool isroot;
int result;
isroot = (kauth_cred_geteuid(cred) == 0);
result = KAUTH_RESULT_DEFER;
switch (action) {
case KAUTH_MACHDEP_IOPERM_GET:
case KAUTH_MACHDEP_LDT_GET:
case KAUTH_MACHDEP_LDT_SET:
case KAUTH_MACHDEP_MTRR_GET:
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_MACHDEP_CACHEFLUSH:
case KAUTH_MACHDEP_IOPERM_SET:
case KAUTH_MACHDEP_IOPL:
case KAUTH_MACHDEP_MTRR_SET:
case KAUTH_MACHDEP_NVRAM:
case KAUTH_MACHDEP_UNMANAGEDMEM:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
return (result);
}
/*
* kauth(9) listener
*
* Security model: Traditional NetBSD
* Scope: Device
* Responsibility: Superuser access
*/
int
secmodel_bsd44_suser_device_cb(kauth_cred_t cred, kauth_action_t action,
void *cookie, void *arg0, void *arg1, void *arg2,
void *arg3)
{
struct tty *tty;
bool isroot;
int result;
isroot = (kauth_cred_geteuid(cred) == 0);
result = KAUTH_RESULT_DEFER;
switch (action) {
case KAUTH_DEVICE_BLUETOOTH_SETPRIV:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_DEVICE_BLUETOOTH_BCSP:
case KAUTH_DEVICE_BLUETOOTH_BTUART: {
enum kauth_device_req req;
req = (enum kauth_device_req)arg0;
switch (req) {
case KAUTH_REQ_DEVICE_BLUETOOTH_BCSP_ADD:
case KAUTH_REQ_DEVICE_BLUETOOTH_BTUART_ADD:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
break;
}
break;
}
case KAUTH_DEVICE_RAWIO_SPEC:
case KAUTH_DEVICE_RAWIO_PASSTHRU:
/*
* Decision is root-agnostic.
*
* Both requests can be issued on devices subject to their
* permission bits.
*/
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_DEVICE_TTY_OPEN:
tty = arg0;
if (!(tty->t_state & TS_ISOPEN))
result = KAUTH_RESULT_ALLOW;
else if (tty->t_state & TS_XCLUDE) {
if (isroot)
result = KAUTH_RESULT_ALLOW;
} else
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_DEVICE_TTY_PRIVSET:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_DEVICE_TTY_STI:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
case KAUTH_DEVICE_RND_ADDDATA:
case KAUTH_DEVICE_RND_GETPRIV:
case KAUTH_DEVICE_RND_SETPRIV:
if (isroot)
result = KAUTH_RESULT_ALLOW;
break;
default:
result = KAUTH_RESULT_DEFER;
break;
}
return (result);
}