diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 1bad2d7488c..de68676a1c7 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -118,6 +118,9 @@ struct prison prison0 = { }; MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); +/* prison0 has all privileges. */ +static privset_t prison0_privset = PRIVSET_T_INITIALIZER(PRIVSET_FSET); + struct bool_flags { const char *name; const char *noname; @@ -141,6 +144,7 @@ static void prison_complete(void *context, int pending); static void prison_deref(struct prison *pr, int flags); static char *prison_path(struct prison *pr1, struct prison *pr2); static void prison_remove_one(struct prison *pr); +static int prison_privset_init(struct prison *pr, privset_t *privset); #ifdef RACCT static void prison_racct_attach(struct prison *pr); static void prison_racct_modify(struct prison *pr); @@ -226,6 +230,7 @@ prison0_init(void) uint8_t *file, *data; size_t size; + prison0.pr_privset = &prison0_privset; prison0.pr_cpuset = cpuset_ref(thread0.td_cpuset); prison0.pr_osreldate = osreldate; strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease)); @@ -498,6 +503,7 @@ int kern_jail_set(struct thread *td, struct uio *optuio, int flags) { struct nameidata nd; + privset_t iprivs, *privset; #ifdef INET struct in_addr *ip4; #endif @@ -618,6 +624,25 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) else gotrsnum = 1; + privset = NULL; + error = vfs_copyopt(opts, "privset", &iprivs, sizeof(iprivs)); + if (error != 0 && error != ENOENT) { + goto done_free; + } else if (error == 0) { + error = priv_check(td, PRIV_JAIL_SETPRIVS); + if (error != 0) { + vfs_opterror(opts, + "insufficient privileges to set privset"); + goto done_errmsg; + } + if (flags & JAIL_UPDATE) { + vfs_opterror(opts, + "privset cannot be changed after creation"); + goto done_errmsg; + } + privset = &iprivs; + } + pr_flags = ch_flags = 0; for (bf = pr_flag_bool; bf < pr_flag_bool + nitems(pr_flag_bool); @@ -1303,6 +1328,13 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) goto done_releroot; } + pr->pr_privset = malloc(sizeof(*pr->pr_privset), M_PRISON, + M_WAITOK); + error = prison_privset_init(pr, privset); + if (error) { + prison_deref(pr, PD_LIST_XLOCKED); + goto done_releroot; + } mtx_lock(&pr->pr_mtx); /* * New prisons do not yet have a reference, because we do not @@ -2053,6 +2085,10 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) sizeof(pr->pr_cpuset->cs_id)); if (error != 0 && error != ENOENT) goto done_deref; + error = vfs_setopt(opts, "privset", pr->pr_privset, + sizeof(pr->pr_privset)); + if (error != 0 && error != ENOENT) + goto done_deref; error = vfs_setopts(opts, "path", prison_path(mypr, pr)); if (error != 0 && error != ENOENT) goto done_deref; @@ -2663,6 +2699,7 @@ prison_deref(struct prison *pr, int flags) #endif if (pr->pr_cpuset != NULL) cpuset_rel(pr->pr_cpuset); + free(pr->pr_privset, M_PRISON); osd_jail_exit(pr); #ifdef RACCT if (racct_enable) @@ -3038,370 +3075,358 @@ prison_enforce_statfs(struct ucred *cred, struct mount *mp, struct statfs *sp) } } -/* - * Check with permission for a specific privilege is granted within jail. We - * have a specific list of accepted privileges; the rest are denied. - */ -int -prison_priv_check(struct ucred *cred, int priv) +static int +prison_privset_init(struct prison *pr, privset_t *privset) { + struct prison *ppr; - /* - * Some policies have custom handlers. This routine should not be - * called for them. See priv_check_cred(). - */ - switch (priv) { - case PRIV_VFS_LOOKUP: - case PRIV_VFS_GENERATION: - KASSERT(0, ("prison_priv_check instead of a custom handler " - "called for %d\n", priv)); - } + ppr = pr->pr_parent; + KASSERT(ppr != NULL, + ("Cannot init a privset on a jail without a parent")); - if (!jailed(cred)) + if (privset != NULL) { + /* + * We allow the parent jail to specify whatever privileges it + * would like to, as long as it's specifying some subset of its + * own privileges. + */ + if (!PRIV_SUBSET(ppr->pr_privset, privset)) + return (EPERM); + + PRIV_COPY(privset, pr->pr_privset); return (0); + } + + privset = pr->pr_privset; +#define PRISON_GRANT(p) PRIV_SET(p, privset) #ifdef VIMAGE - /* - * Privileges specific to prisons with a virtual network stack. - * There might be a duplicate entry here in case the privilege - * is only granted conditionally in the legacy jail case. - */ - switch (priv) { -#ifdef notyet + if (pr->pr_flags & PR_VNET) { /* - * NFS-specific privileges. + * Privileges specific to prisons with a virtual network stack. + * There might be a duplicate entry here in case the privilege + * is only granted conditionally in the legacy jail case. */ - case PRIV_NFS_DAEMON: - case PRIV_NFS_LOCKD: +#ifdef notyet + PRISON_GRANT(PRIV_NFS_DAEMON); + PRISON_GRANT(PRIV_NFS_LOCKD); #endif /* * Network stack privileges. */ - case PRIV_NET_BRIDGE: - case PRIV_NET_GRE: - case PRIV_NET_BPF: - case PRIV_NET_RAW: /* Dup, cond. in legacy jail case. */ - case PRIV_NET_ROUTE: - case PRIV_NET_TAP: - case PRIV_NET_SETIFMTU: - case PRIV_NET_SETIFFLAGS: - case PRIV_NET_SETIFCAP: - case PRIV_NET_SETIFDESCR: - case PRIV_NET_SETIFNAME : - case PRIV_NET_SETIFMETRIC: - case PRIV_NET_SETIFPHYS: - case PRIV_NET_SETIFMAC: - case PRIV_NET_SETLANPCP: - case PRIV_NET_ADDMULTI: - case PRIV_NET_DELMULTI: - case PRIV_NET_HWIOCTL: - case PRIV_NET_SETLLADDR: - case PRIV_NET_ADDIFGROUP: - case PRIV_NET_DELIFGROUP: - case PRIV_NET_IFCREATE: - case PRIV_NET_IFDESTROY: - case PRIV_NET_ADDIFADDR: - case PRIV_NET_DELIFADDR: - case PRIV_NET_LAGG: - case PRIV_NET_GIF: - case PRIV_NET_SETIFVNET: - case PRIV_NET_SETIFFIB: + PRISON_GRANT(PRIV_NET_BRIDGE); + PRISON_GRANT(PRIV_NET_GRE); + PRISON_GRANT(PRIV_NET_BPF); + PRISON_GRANT(PRIV_NET_RAW); /* Dup, cond. in legacy jail case. */ + PRISON_GRANT(PRIV_NET_ROUTE); + PRISON_GRANT(PRIV_NET_TAP); + PRISON_GRANT(PRIV_NET_SETIFMTU); + PRISON_GRANT(PRIV_NET_SETIFFLAGS); + PRISON_GRANT(PRIV_NET_SETIFCAP); + PRISON_GRANT(PRIV_NET_SETIFDESCR); + PRISON_GRANT(PRIV_NET_SETIFNAME ); + PRISON_GRANT(PRIV_NET_SETIFMETRIC); + PRISON_GRANT(PRIV_NET_SETIFPHYS); + PRISON_GRANT(PRIV_NET_SETIFMAC); + PRISON_GRANT(PRIV_NET_SETLANPCP); + PRISON_GRANT(PRIV_NET_ADDMULTI); + PRISON_GRANT(PRIV_NET_DELMULTI); + PRISON_GRANT(PRIV_NET_HWIOCTL); + PRISON_GRANT(PRIV_NET_SETLLADDR); + PRISON_GRANT(PRIV_NET_ADDIFGROUP); + PRISON_GRANT(PRIV_NET_DELIFGROUP); + PRISON_GRANT(PRIV_NET_IFCREATE); + PRISON_GRANT(PRIV_NET_IFDESTROY); + PRISON_GRANT(PRIV_NET_ADDIFADDR); + PRISON_GRANT(PRIV_NET_DELIFADDR); + PRISON_GRANT(PRIV_NET_LAGG); + PRISON_GRANT(PRIV_NET_GIF); + PRISON_GRANT(PRIV_NET_SETIFVNET); + PRISON_GRANT(PRIV_NET_SETIFFIB); /* * 802.11-related privileges. */ - case PRIV_NET80211_VAP_GETKEY: - case PRIV_NET80211_VAP_MANAGE: + PRISON_GRANT(PRIV_NET80211_VAP_GETKEY); + PRISON_GRANT(PRIV_NET80211_VAP_MANAGE); #ifdef notyet /* * ATM privileges. */ - case PRIV_NETATM_CFG: - case PRIV_NETATM_ADD: - case PRIV_NETATM_DEL: - case PRIV_NETATM_SET: + PRISON_GRANT(PRIV_NETATM_CFG); + PRISON_GRANT(PRIV_NETATM_ADD); + PRISON_GRANT(PRIV_NETATM_DEL); + PRISON_GRANT(PRIV_NETATM_SET); /* * Bluetooth privileges. */ - case PRIV_NETBLUETOOTH_RAW: + PRISON_GRANT(PRIV_NETBLUETOOTH_RAW); #endif /* * Netgraph and netgraph module privileges. */ - case PRIV_NETGRAPH_CONTROL: + PRISON_GRANT(PRIV_NETGRAPH_CONTROL); #ifdef notyet - case PRIV_NETGRAPH_TTY: + PRISON_GRANT(PRIV_NETGRAPH_TTY); #endif /* * IPv4 and IPv6 privileges. */ - case PRIV_NETINET_IPFW: - case PRIV_NETINET_DIVERT: - case PRIV_NETINET_PF: - case PRIV_NETINET_DUMMYNET: - case PRIV_NETINET_CARP: - case PRIV_NETINET_MROUTE: - case PRIV_NETINET_RAW: - case PRIV_NETINET_ADDRCTRL6: - case PRIV_NETINET_ND6: - case PRIV_NETINET_SCOPE6: - case PRIV_NETINET_ALIFETIME6: - case PRIV_NETINET_IPSEC: - case PRIV_NETINET_BINDANY: + PRISON_GRANT(PRIV_NETINET_IPFW); + PRISON_GRANT(PRIV_NETINET_DIVERT); + PRISON_GRANT(PRIV_NETINET_PF); + PRISON_GRANT(PRIV_NETINET_DUMMYNET); + PRISON_GRANT(PRIV_NETINET_CARP); + PRISON_GRANT(PRIV_NETINET_MROUTE); + PRISON_GRANT(PRIV_NETINET_RAW); + PRISON_GRANT(PRIV_NETINET_ADDRCTRL6); + PRISON_GRANT(PRIV_NETINET_ND6); + PRISON_GRANT(PRIV_NETINET_SCOPE6); + PRISON_GRANT(PRIV_NETINET_ALIFETIME6); + PRISON_GRANT(PRIV_NETINET_IPSEC); + PRISON_GRANT(PRIV_NETINET_BINDANY); #ifdef notyet - /* - * NCP privileges. - */ - case PRIV_NETNCP: + /* + * NCP privileges. + */ + PRISON_GRANT(PRIV_NETNCP); - /* - * SMB privileges. - */ - case PRIV_NETSMB: + /* + * SMB privileges. + */ + PRISON_GRANT(PRIV_NETSMB); #endif - - /* - * No default: or deny here. - * In case of no permit fall through to next switch(). - */ - if (cred->cr_prison->pr_flags & PR_VNET) - return (0); } #endif /* VIMAGE */ - switch (priv) { - /* - * Allow ktrace privileges for root in jail. - */ - case PRIV_KTRACE: + /* + * Allow ktrace privileges for root in jail. + */ + PRISON_GRANT(PRIV_KTRACE); #if 0 - /* - * Allow jailed processes to configure audit identity and - * submit audit records (login, etc). In the future we may - * want to further refine the relationship between audit and - * jail. - */ - case PRIV_AUDIT_GETAUDIT: - case PRIV_AUDIT_SETAUDIT: - case PRIV_AUDIT_SUBMIT: + /* + * Allow jailed processes to configure audit identity and + * submit audit records (login, etc). In the future we may + * want to further refine the relationship between audit and + * jail. + */ + PRISON_GRANT(PRIV_AUDIT_GETAUDIT); + PRISON_GRANT(PRIV_AUDIT_SETAUDIT); + PRISON_GRANT(PRIV_AUDIT_SUBMIT); #endif - /* - * Allow jailed processes to manipulate process UNIX - * credentials in any way they see fit. - */ - case PRIV_CRED_SETUID: - case PRIV_CRED_SETEUID: - case PRIV_CRED_SETGID: - case PRIV_CRED_SETEGID: - case PRIV_CRED_SETGROUPS: - case PRIV_CRED_SETREUID: - case PRIV_CRED_SETREGID: - case PRIV_CRED_SETRESUID: - case PRIV_CRED_SETRESGID: + /* + * Allow jailed processes to manipulate process UNIX + * credentials in any way they see fit. + */ + PRISON_GRANT(PRIV_CRED_SETUID); + PRISON_GRANT(PRIV_CRED_SETEUID); + PRISON_GRANT(PRIV_CRED_SETGID); + PRISON_GRANT(PRIV_CRED_SETEGID); + PRISON_GRANT(PRIV_CRED_SETGROUPS); + PRISON_GRANT(PRIV_CRED_SETREUID); + PRISON_GRANT(PRIV_CRED_SETREGID); + PRISON_GRANT(PRIV_CRED_SETRESUID); + PRISON_GRANT(PRIV_CRED_SETRESGID); - /* - * Jail implements visibility constraints already, so allow - * jailed root to override uid/gid-based constraints. - */ - case PRIV_SEEOTHERGIDS: - case PRIV_SEEOTHERUIDS: + /* + * Jail implements visibility constraints already, so allow + * jailed root to override uid/gid-based constraints. + */ + PRISON_GRANT(PRIV_SEEOTHERGIDS); + PRISON_GRANT(PRIV_SEEOTHERUIDS); - /* - * Jail implements inter-process debugging limits already, so - * allow jailed root various debugging privileges. - */ - case PRIV_DEBUG_DIFFCRED: - case PRIV_DEBUG_SUGID: - case PRIV_DEBUG_UNPRIV: + /* + * Jail implements inter-process debugging limits already, so + * allow jailed root various debugging privileges. + */ + PRISON_GRANT(PRIV_DEBUG_DIFFCRED); + PRISON_GRANT(PRIV_DEBUG_SUGID); + PRISON_GRANT(PRIV_DEBUG_UNPRIV); - /* - * Allow jail to set various resource limits and login - * properties, and for now, exceed process resource limits. - */ - case PRIV_PROC_LIMIT: - case PRIV_PROC_SETLOGIN: - case PRIV_PROC_SETRLIMIT: + /* + * Allow jail to set various resource limits and login + * properties, and for now, exceed process resource limits. + */ + PRISON_GRANT(PRIV_PROC_LIMIT); + PRISON_GRANT(PRIV_PROC_SETLOGIN); + PRISON_GRANT(PRIV_PROC_SETRLIMIT); - /* - * System V and POSIX IPC privileges are granted in jail. - */ - case PRIV_IPC_READ: - case PRIV_IPC_WRITE: - case PRIV_IPC_ADMIN: - case PRIV_IPC_MSGSIZE: - case PRIV_MQ_ADMIN: + /* + * System V and POSIX IPC privileges are granted in jail. + */ + PRISON_GRANT(PRIV_IPC_READ); + PRISON_GRANT(PRIV_IPC_WRITE); + PRISON_GRANT(PRIV_IPC_ADMIN); + PRISON_GRANT(PRIV_IPC_MSGSIZE); + PRISON_GRANT(PRIV_MQ_ADMIN); - /* - * Jail operations within a jail work on child jails. - */ - case PRIV_JAIL_ATTACH: - case PRIV_JAIL_SET: - case PRIV_JAIL_REMOVE: + /* + * Jail operations within a jail work on child jails. + */ + PRISON_GRANT(PRIV_JAIL_ATTACH); + PRISON_GRANT(PRIV_JAIL_SET); + PRISON_GRANT(PRIV_JAIL_REMOVE); + PRISON_GRANT(PRIV_JAIL_SETPRIVS); - /* - * Jail implements its own inter-process limits, so allow - * root processes in jail to change scheduling on other - * processes in the same jail. Likewise for signalling. - */ - case PRIV_SCHED_DIFFCRED: - case PRIV_SCHED_CPUSET: - case PRIV_SIGNAL_DIFFCRED: - case PRIV_SIGNAL_SUGID: + /* + * Jail implements its own inter-process limits, so allow + * root processes in jail to change scheduling on other + * processes in the same jail. Likewise for signalling. + */ + PRISON_GRANT(PRIV_SCHED_DIFFCRED); + PRISON_GRANT(PRIV_SCHED_CPUSET); + PRISON_GRANT(PRIV_SIGNAL_DIFFCRED); + PRISON_GRANT(PRIV_SIGNAL_SUGID); - /* - * Allow jailed processes to write to sysctls marked as jail - * writable. - */ - case PRIV_SYSCTL_WRITEJAIL: + /* + * Allow jailed processes to write to sysctls marked as jail + * writable. + */ + PRISON_GRANT(PRIV_SYSCTL_WRITEJAIL); - /* - * Allow root in jail to manage a variety of quota - * properties. These should likely be conditional on a - * configuration option. - */ - case PRIV_VFS_GETQUOTA: - case PRIV_VFS_SETQUOTA: + /* + * Allow root in jail to manage a variety of quota + * properties. These should likely be conditional on a + * configuration option. + */ + PRISON_GRANT(PRIV_VFS_GETQUOTA); + PRISON_GRANT(PRIV_VFS_SETQUOTA); - /* - * Since Jail relies on chroot() to implement file system - * protections, grant many VFS privileges to root in jail. - * Be careful to exclude mount-related and NFS-related - * privileges. - */ - case PRIV_VFS_READ: - case PRIV_VFS_WRITE: - case PRIV_VFS_ADMIN: - case PRIV_VFS_EXEC: - case PRIV_VFS_BLOCKRESERVE: /* XXXRW: Slightly surprising. */ - case PRIV_VFS_CHFLAGS_DEV: - case PRIV_VFS_CHOWN: - case PRIV_VFS_CHROOT: - case PRIV_VFS_RETAINSUGID: - case PRIV_VFS_FCHROOT: - case PRIV_VFS_LINK: - case PRIV_VFS_SETGID: - case PRIV_VFS_STAT: - case PRIV_VFS_STICKYFILE: + /* + * Since Jail relies on chroot() to implement file system + * protections, grant many VFS privileges to root in jail. + * Be careful to exclude mount-related and NFS-related + * privileges. + */ + PRISON_GRANT(PRIV_VFS_READ); + PRISON_GRANT(PRIV_VFS_WRITE); + PRISON_GRANT(PRIV_VFS_ADMIN); + PRISON_GRANT(PRIV_VFS_EXEC); + PRISON_GRANT(PRIV_VFS_BLOCKRESERVE); /* XXXRW: Slightly surprising. */ + PRISON_GRANT(PRIV_VFS_CHFLAGS_DEV); + PRISON_GRANT(PRIV_VFS_CHOWN); + PRISON_GRANT(PRIV_VFS_CHROOT); + PRISON_GRANT(PRIV_VFS_RETAINSUGID); + PRISON_GRANT(PRIV_VFS_FCHROOT); + PRISON_GRANT(PRIV_VFS_LINK); + PRISON_GRANT(PRIV_VFS_SETGID); + PRISON_GRANT(PRIV_VFS_STAT); + PRISON_GRANT(PRIV_VFS_STICKYFILE); - /* - * As in the non-jail case, non-root users are expected to be - * able to read kernel/phyiscal memory (provided /dev/[k]mem - * exists in the jail and they have permission to access it). - */ - case PRIV_KMEM_READ: - return (0); + /* + * As in the non-jail case, non-root users are expected to be + * able to read kernel/phyiscal memory (provided /dev/[k]mem + * exists in the jail and they have permission to access it). + */ + PRISON_GRANT(PRIV_KMEM_READ); - /* - * Depending on the global setting, allow privilege of - * setting system flags. - */ - case PRIV_VFS_SYSFLAGS: - if (cred->cr_prison->pr_allow & PR_ALLOW_CHFLAGS) - return (0); - else - return (EPERM); + /* + * Depending on the global setting, allow privilege of + * setting system flags. + */ + if ((pr->pr_allow & PR_ALLOW_CHFLAGS) != 0) + PRISON_GRANT(PRIV_VFS_SYSFLAGS); - /* - * Depending on the global setting, allow privilege of - * mounting/unmounting file systems. - */ - case PRIV_VFS_MOUNT: - case PRIV_VFS_UNMOUNT: - case PRIV_VFS_MOUNT_NONUSER: - case PRIV_VFS_MOUNT_OWNER: - if (cred->cr_prison->pr_allow & PR_ALLOW_MOUNT && - cred->cr_prison->pr_enforce_statfs < 2) - return (0); - else - return (EPERM); + /* + * Depending on the global setting, allow privilege of + * mounting/unmounting file systems. + */ + if ((pr->pr_allow & PR_ALLOW_MOUNT) != 0 && pr->pr_enforce_statfs < 2) { + PRISON_GRANT(PRIV_VFS_MOUNT); + PRISON_GRANT(PRIV_VFS_UNMOUNT); + PRISON_GRANT(PRIV_VFS_MOUNT_NONUSER); + PRISON_GRANT(PRIV_VFS_MOUNT_OWNER); + } - /* - * Jails should hold no disposition on the PRIV_VFS_READ_DIR - * policy. priv_check_cred will not specifically allow it, and - * we may want a MAC policy to allow it. - */ - case PRIV_VFS_READ_DIR: - return (0); + /* + * Jails should hold no disposition on the PRIV_VFS_READ_DIR + * policy. priv_check_cred will not specifically allow it, and + * we may want a MAC policy to allow it. + */ + PRISON_GRANT(PRIV_VFS_READ_DIR); - /* - * Conditionnaly allow locking (unlocking) physical pages - * in memory. - */ - case PRIV_VM_MLOCK: - case PRIV_VM_MUNLOCK: - if (cred->cr_prison->pr_allow & PR_ALLOW_MLOCK) - return (0); - else - return (EPERM); + /* Conditionally allow locking (unlocking) physical pages in memory. */ + if ((pr->pr_allow & PR_ALLOW_MLOCK) != 0) { + PRISON_GRANT(PRIV_VM_MLOCK); + PRISON_GRANT(PRIV_VM_MUNLOCK); + } - /* - * Conditionally allow jailed root to bind reserved ports. - */ - case PRIV_NETINET_RESERVEDPORT: - if (cred->cr_prison->pr_allow & PR_ALLOW_RESERVED_PORTS) - return (0); - else - return (EPERM); + /* + * Conditionally allow jailed root to bind reserved ports. + */ + if ((pr->pr_allow & PR_ALLOW_RESERVED_PORTS) != 0) + PRISON_GRANT(PRIV_NETINET_RESERVEDPORT); - /* - * Allow jailed root to reuse in-use ports. - */ - case PRIV_NETINET_REUSEPORT: - return (0); + /* + * Allow jailed root to reuse in-use ports. + */ + PRISON_GRANT(PRIV_NETINET_REUSEPORT); - /* - * Allow jailed root to set certain IPv4/6 (option) headers. - */ - case PRIV_NETINET_SETHDROPTS: - return (0); + /* + * Allow jailed root to set certain IPv4/6 (option) headers. + */ + PRISON_GRANT(PRIV_NETINET_SETHDROPTS); - /* - * Conditionally allow creating raw sockets in jail. - */ - case PRIV_NETINET_RAW: - if (cred->cr_prison->pr_allow & PR_ALLOW_RAW_SOCKETS) - return (0); - else - return (EPERM); + /* + * Conditionally allow creating raw sockets in jail. + */ + if ((pr->pr_allow & PR_ALLOW_RAW_SOCKETS) != 0) + PRISON_GRANT(PR_ALLOW_RAW_SOCKETS); - /* - * Since jail implements its own visibility limits on netstat - * sysctls, allow getcred. This allows identd to work in - * jail. - */ - case PRIV_NETINET_GETCRED: - return (0); + /* + * Since jail implements its own visibility limits on netstat + * sysctls, allow getcred. This allows identd to work in + * jail. + */ + PRISON_GRANT(PRIV_NETINET_GETCRED); - /* - * Allow jailed root to set loginclass. - */ - case PRIV_PROC_SETLOGINCLASS: - return (0); + /* + * Allow jailed root to set loginclass. + */ + PRISON_GRANT(PRIV_PROC_SETLOGINCLASS); - /* - * Do not allow a process inside a jail to read the kernel - * message buffer unless explicitly permitted. - */ - case PRIV_MSGBUF: - if (cred->cr_prison->pr_allow & PR_ALLOW_READ_MSGBUF) - return (0); - return (EPERM); + /* + * Do not allow a process inside a jail to read the kernel + * message buffer unless explicitly permitted. + */ + if ((pr->pr_allow & PR_ALLOW_READ_MSGBUF) != 0) + PRISON_GRANT(PRIV_MSGBUF); +#undef PRISON_GRANT + return (0); +} - default: - /* - * In all remaining cases, deny the privilege request. This - * includes almost all network privileges, many system - * configuration privileges. - */ - return (EPERM); +/* + * Check with permission for a specific privilege is granted within jail. We + * have a specific list of accepted privileges; the rest are denied. + */ +int +prison_priv_check(struct ucred *cred, int priv) +{ + + /* + * Some policies have custom handlers. This routine should not be + * called for them. See priv_check_cred(). + */ + switch (priv) { + case PRIV_VFS_LOOKUP: + case PRIV_VFS_GENERATION: + KASSERT(0, ("prison_priv_check instead of a custom handler " + "called for %d\n", priv)); } + + if (!jailed(cred)) + return (0); + + if (PRIV_ISSET(priv, cred->cr_prison->pr_privset)) + return (0); + return (EPERM); } /* diff --git a/sys/sys/jail.h b/sys/sys/jail.h index 2a6ee07ecc4..225bd827ed3 100644 --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -140,6 +140,7 @@ MALLOC_DECLARE(M_PRISON); #define HOSTUUIDLEN 64 #define OSRELEASELEN 32 +struct _privset; struct racct; struct prison_racct; @@ -156,6 +157,7 @@ struct prison_racct; */ struct prison { TAILQ_ENTRY(prison) pr_list; /* (a) all prisons */ + struct _privset *pr_privset; /* (c) prison privs */ int pr_id; /* (c) prison id */ int pr_ref; /* (p) refcount */ int pr_uref; /* (p) user (alive) refcount */ diff --git a/sys/sys/priv.h b/sys/sys/priv.h index 7ef54782a60..76d0c92091c 100644 --- a/sys/sys/priv.h +++ b/sys/sys/priv.h @@ -37,6 +37,9 @@ #ifndef _SYS_PRIV_H_ #define _SYS_PRIV_H_ +#include +#include + /* * Privilege list, sorted loosely by kernel subsystem. * @@ -134,6 +137,7 @@ #define PRIV_JAIL_ATTACH 110 /* Attach to a jail. */ #define PRIV_JAIL_SET 111 /* Set jail parameters. */ #define PRIV_JAIL_REMOVE 112 /* Remove a jail. */ +#define PRIV_JAIL_SETPRIVS 113 /* Set jail privileges. */ /* * Kernel environment privileges. @@ -524,6 +528,43 @@ */ #define PRIV_VALID(x) ((x) > _PRIV_LOWEST && (x) < _PRIV_HIGHEST) +#ifndef PRIV_SETSIZE +#define PRIV_SETSIZE (_PRIV_HIGHEST - 1) +#endif + +BITSET_DEFINE(_privset, PRIV_SETSIZE); +typedef struct _privset privset_t; + +#define _NPRIVBITS _BITSET_BITS +#define _NPRIVWORDS __bitset_words(PRIV_SETSIZE) + +#define PRIV_CLR(n, p) BIT_CLR(PRIV_SETSIZE, n, p) +#define PRIV_COPY(f, t) BIT_COPY(PRIV_SETSIZE, f, t) +#define PRIV_ISSET(n, p) BIT_ISSET(PRIV_SETSIZE, n, p) +#define PRIV_SET(n, p) BIT_SET(PRIV_SETSIZE, n, p) +#define PRIV_ZERO(p) BIT_ZERO(PRIV_SETSIZE, p) +#define PRIV_FILL(p) BIT_FILL(PRIV_SETSIZE, p) +#define PRIV_SETOF(n, p) BIT_SETOF(PRIV_SETSIZE, n, p) +#define PRIV_EMPTY(p) BIT_EMPTY(PRIV_SETSIZE, p) +#define PRIV_ISFULLSET(p) BIT_ISFULLSET(PRIV_SETSIZE, p) +#define PRIV_SUBSET(p, c) BIT_SUBSET(PRIV_SETSIZE, p, c) +#define PRIV_OVERLAP(p, c) BIT_OVERLAP(PRIV_SETSIZE, p, c) +#define PRIV_CMP(p, c) BIT_CMP(PRIV_SETSIZE, p, c) +#define PRIV_OR(d, s) BIT_OR(PRIV_SETSIZE, d, s) +#define PRIV_AND(d, s) BIT_AND(PRIV_SETSIZE, d, s) +#define PRIV_ANDNOT(d, s) BIT_ANDNOT(PRIV_SETSIZE, d, s) +#define PRIV_CLR_ATOMIC(n, p) BIT_CLR_ATOMIC(PRIV_SETSIZE, n, p) +#define PRIV_SET_ATOMIC(n, p) BIT_SET_ATOMIC(PRIV_SETSIZE, n, p) +#define PRIV_SET_ATOMIC_ACQ(n, p) BIT_SET_ATOMIC_ACQ(PRIV_SETSIZE, n, p) +#define PRIV_AND_ATOMIC(n, p) BIT_AND_ATOMIC(PRIV_SETSIZE, n, p) +#define PRIV_OR_ATOMIC(d, s) BIT_OR_ATOMIC(PRIV_SETSIZE, d, s) +#define PRIV_COPY_STORE_REL(f, t) BIT_COPY_STORE_REL(PRIV_SETSIZE, f, t) +#define PRIV_FFS(p) BIT_FFS(PRIV_SETSIZE, p) +#define PRIV_COUNT(p) ((int)BIT_COUNT(PRIV_SETSIZE, p)) + +#define PRIVSET_FSET BITSET_FSET(_NPRIVWORDS) +#define PRIVSET_T_INITIALIZER BITSET_T_INITIALIZER + #ifdef _KERNEL /* * Privilege check interfaces, modeled after historic suser() interfaces, but