Add internal 'mac_policy_count' counter to the MAC Framework, which is a

count of the number of registered policies.

Rather than unconditionally locking sockets before passing them into MAC,
lock them in the MAC entry points only if mac_policy_count is non-zero.

This avoids locking overhead for a number of socket system calls when no
policies are registered, eliminating measurable overhead for the MAC
Framework for the socket subsystem when there are no active policies.

Possibly socket locks should be acquired by policies if they are required
for socket labels, which would further avoid locking overhead when there
are policies but they don't require labeling of sockets, or possibly
don't even implement socket controls.

Obtained from:	TrustedBSD Project
This commit is contained in:
Robert Watson 2009-06-02 18:26:17 +00:00
parent fd02a3b5c9
commit f93bfb23dc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=193332
13 changed files with 83 additions and 85 deletions

View File

@ -1690,9 +1690,7 @@ cr_canseesocket(struct ucred *cred, struct socket *so)
if (error)
return (ENOENT);
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_visible(cred, so);
SOCK_UNLOCK(so);
if (error)
return (error);
#endif

View File

@ -78,9 +78,7 @@ soo_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
int error;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_receive(active_cred, so);
SOCK_UNLOCK(so);
if (error)
return (error);
#endif
@ -99,9 +97,7 @@ soo_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
int error;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_send(active_cred, so);
SOCK_UNLOCK(so);
if (error)
return (error);
#endif
@ -222,9 +218,7 @@ soo_poll(struct file *fp, int events, struct ucred *active_cred,
#ifdef MAC
int error;
SOCK_LOCK(so);
error = mac_socket_check_poll(active_cred, so);
SOCK_UNLOCK(so);
if (error)
return (error);
#endif
@ -243,9 +237,7 @@ soo_stat(struct file *fp, struct stat *ub, struct ucred *active_cred,
bzero((caddr_t)ub, sizeof (*ub));
ub->st_mode = S_IFSOCK;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_stat(active_cred, so);
SOCK_UNLOCK(so);
if (error)
return (error);
#endif

View File

@ -444,9 +444,7 @@ sonewconn(struct socket *head, int connstatus)
so->so_proto = head->so_proto;
so->so_cred = crhold(head->so_cred);
#ifdef MAC
SOCK_LOCK(head);
mac_socket_newconn(head, so);
SOCK_UNLOCK(head);
#endif
knlist_init(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv),
NULL, NULL, NULL);

View File

@ -221,16 +221,10 @@ kern_bind(td, fd, sa)
ktrsockaddr(sa);
#endif
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_bind(td->td_ucred, so, sa);
SOCK_UNLOCK(so);
if (error)
goto done;
#endif
error = sobind(so, sa, td);
#ifdef MAC
done:
if (error == 0)
#endif
error = sobind(so, sa, td);
fdrop(fp, td);
return (error);
}
@ -252,17 +246,14 @@ listen(td, uap)
if (error == 0) {
so = fp->f_data;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_listen(td->td_ucred, so);
SOCK_UNLOCK(so);
if (error)
goto done;
if (error == 0) {
#endif
CURVNET_SET(so->so_vnet);
error = solisten(so, uap->backlog, td);
CURVNET_RESTORE();
CURVNET_SET(so->so_vnet);
error = solisten(so, uap->backlog, td);
CURVNET_RESTORE();
#ifdef MAC
done:
}
#endif
fdrop(fp, td);
}
@ -354,9 +345,7 @@ kern_accept(struct thread *td, int s, struct sockaddr **name,
goto done;
}
#ifdef MAC
SOCK_LOCK(head);
error = mac_socket_check_accept(td->td_ucred, head);
SOCK_UNLOCK(head);
if (error != 0)
goto done;
#endif
@ -549,9 +538,7 @@ kern_connect(td, fd, sa)
ktrsockaddr(sa);
#endif
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_connect(td->td_ucred, so, sa);
SOCK_UNLOCK(so);
if (error)
goto bad;
#endif
@ -603,7 +590,6 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol,
if (error)
return (error);
#endif
error = socreate(domain, &so1, type, protocol, td->td_ucred, td);
if (error)
return (error);
@ -752,13 +738,13 @@ kern_sendit(td, s, mp, flags, control, segflg)
so = (struct socket *)fp->f_data;
#ifdef MAC
SOCK_LOCK(so);
if (mp->msg_name != NULL)
if (mp->msg_name != NULL) {
error = mac_socket_check_connect(td->td_ucred, so,
mp->msg_name);
if (error == 0)
error = mac_socket_check_send(td->td_ucred, so);
SOCK_UNLOCK(so);
if (error)
goto bad;
}
error = mac_socket_check_send(td->td_ucred, so);
if (error)
goto bad;
#endif
@ -951,9 +937,7 @@ kern_recvit(td, s, mp, fromseg, controlp)
so = fp->f_data;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_receive(td->td_ucred, so);
SOCK_UNLOCK(so);
if (error) {
fdrop(fp, td);
return (error);
@ -1887,9 +1871,7 @@ kern_sendfile(struct thread *td, struct sendfile_args *uap,
}
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_send(td->td_ucred, so);
SOCK_UNLOCK(so);
if (error)
goto out;
#endif
@ -2417,9 +2399,7 @@ sctp_generic_sendmsg (td, uap)
so = (struct socket *)fp->f_data;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_send(td->td_ucred, so);
SOCK_UNLOCK(so);
if (error)
goto sctp_bad;
#endif /* MAC */
@ -2521,9 +2501,7 @@ sctp_generic_sendmsg_iov(td, uap)
so = (struct socket *)fp->f_data;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_send(td->td_ucred, so);
SOCK_UNLOCK(so);
if (error)
goto sctp_bad;
#endif /* MAC */
@ -2618,9 +2596,7 @@ sctp_generic_recvmsg(td, uap)
so = fp->f_data;
#ifdef MAC
SOCK_LOCK(so);
error = mac_socket_check_receive(td->td_ucred, so);
SOCK_UNLOCK(so);
if (error) {
goto out;
return (error);

View File

@ -1246,10 +1246,8 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
UNP_PCB_UNLOCK(unp2);
UNP_PCB_UNLOCK(unp);
#ifdef MAC
SOCK_LOCK(so);
mac_socketpeer_set_from_socket(so, so3);
mac_socketpeer_set_from_socket(so3, so);
SOCK_UNLOCK(so);
#endif
so2 = so3;

View File

@ -410,12 +410,8 @@ ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase)
goto out;
#ifdef MAC
SOCK_LOCK(ddp->ddp_socket);
if (mac_socket_check_deliver(ddp->ddp_socket, m) != 0) {
SOCK_UNLOCK(ddp->ddp_socket);
if (mac_socket_check_deliver(ddp->ddp_socket, m) != 0)
goto out;
}
SOCK_UNLOCK(ddp->ddp_socket);
#endif
/*

View File

@ -467,9 +467,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
m->m_pkthdr.rcvif = ifa->ifa_ifp;
}
#ifdef MAC
SOCK_LOCK(so);
mac_socket_create_mbuf(so, m);
SOCK_UNLOCK(so);
#endif
/* Send packet to input processing via netisr */
netisr_queue_src(NETISR_IP, (uintptr_t)so, m);

View File

@ -1562,9 +1562,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
TCPSTAT_INC(tcps_connects);
soisconnected(so);
#ifdef MAC
SOCK_LOCK(so);
mac_socketpeer_set_from_mbuf(m, so);
SOCK_UNLOCK(so);
#endif
/* Do window scaling on this connection? */
if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==

View File

@ -635,9 +635,7 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m)
goto abort2;
}
#ifdef MAC
SOCK_LOCK(so);
mac_socketpeer_set_from_mbuf(m, so);
SOCK_UNLOCK(so);
#endif
inp = sotoinpcb(so);

View File

@ -271,9 +271,7 @@ svc_vc_accept(struct socket *head, struct socket **sop)
goto done;
}
#ifdef MAC
SOCK_LOCK(head);
error = mac_socket_check_accept(td->td_ucred, head);
SOCK_UNLOCK(head);
if (error != 0)
goto done;
#endif

View File

@ -179,6 +179,7 @@ static struct sx mac_policy_sx; /* Sleeping entry points. */
struct mac_policy_list_head mac_policy_list;
struct mac_policy_list_head mac_static_policy_list;
u_int mac_policy_count; /* Registered policy count. */
static void mac_policy_xlock(void);
static void mac_policy_xlock_assert(void);
@ -351,17 +352,22 @@ mac_policy_getlabeled(struct mac_policy_conf *mpc)
* requiring labels across all policies.
*/
static void
mac_policy_updateflags(void)
mac_policy_update(void)
{
struct mac_policy_conf *mpc;
mac_policy_xlock_assert();
mac_labeled = 0;
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list)
mac_policy_count = 0;
LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
mac_labeled |= mac_policy_getlabeled(mpc);
LIST_FOREACH(mpc, &mac_policy_list, mpc_list)
mac_policy_count++;
}
LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
mac_labeled |= mac_policy_getlabeled(mpc);
mac_policy_count++;
}
}
static int
@ -434,7 +440,7 @@ mac_policy_register(struct mac_policy_conf *mpc)
*/
if (mpc->mpc_ops->mpo_init != NULL)
(*(mpc->mpc_ops->mpo_init))(mpc);
mac_policy_updateflags();
mac_policy_update();
SDT_PROBE(mac, kernel, policy, register, mpc, 0, 0, 0, 0);
printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
@ -480,7 +486,7 @@ mac_policy_unregister(struct mac_policy_conf *mpc)
LIST_REMOVE(mpc, mpc_list);
mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
mac_policy_updateflags();
mac_policy_update();
mac_policy_xunlock();
SDT_PROBE(mac, kernel, policy, unregister, mpc, 0, 0, 0, 0);

View File

@ -189,6 +189,7 @@ struct label {
*/
extern struct mac_policy_list_head mac_policy_list;
extern struct mac_policy_list_head mac_static_policy_list;
extern u_int mac_policy_count;
extern uint64_t mac_labeled;
extern struct mtx mac_ifnet_mtx;

View File

@ -234,10 +234,13 @@ void
mac_socket_newconn(struct socket *oldso, struct socket *newso)
{
SOCK_LOCK_ASSERT(oldso);
if (mac_policy_count == 0)
return;
SOCK_LOCK(oldso);
MAC_POLICY_PERFORM_NOSLEEP(socket_newconn, oldso, oldso->so_label,
newso, newso->so_label);
SOCK_UNLOCK(oldso);
}
static void
@ -256,25 +259,30 @@ mac_socketpeer_set_from_mbuf(struct mbuf *m, struct socket *so)
{
struct label *label;
SOCK_LOCK_ASSERT(so);
label = mac_mbuf_to_label(m);
SOCK_LOCK(so);
MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_mbuf, m, label, so,
so->so_peerlabel);
SOCK_UNLOCK(so);
}
void
mac_socketpeer_set_from_socket(struct socket *oldso, struct socket *newso)
{
if (mac_policy_count == 0)
return;
/*
* XXXRW: only hold the socket lock on one at a time, as one socket
* is the original, and one is the new. However, it's called in both
* directions, so we can't assert the lock here currently.
* XXXRW: We want to hold locks on both sockets, but can't currently
* due to lock order -- opt to lock the socket where we're accessing
* so_label as it's more likely to change.
*/
SOCK_LOCK(oldso);
MAC_POLICY_PERFORM_NOSLEEP(socketpeer_set_from_socket, oldso,
oldso->so_label, newso, newso->so_peerlabel);
SOCK_UNLOCK(oldso);
}
void
@ -282,12 +290,15 @@ mac_socket_create_mbuf(struct socket *so, struct mbuf *m)
{
struct label *label;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return;
label = mac_mbuf_to_label(m);
SOCK_LOCK(so);
MAC_POLICY_PERFORM_NOSLEEP(socket_create_mbuf, so, so->so_label, m,
label);
SOCK_UNLOCK(so);
}
MAC_CHECK_PROBE_DEFINE2(socket_check_accept, "struct ucred *",
@ -298,11 +309,14 @@ mac_socket_check_accept(struct ucred *cred, struct socket *so)
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_accept, cred, so,
so->so_label);
MAC_CHECK_PROBE2(socket_check_accept, error, cred, so);
SOCK_UNLOCK(so);
return (error);
}
@ -316,11 +330,14 @@ mac_socket_check_bind(struct ucred *cred, struct socket *so,
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_bind, cred, so, so->so_label,
sa);
MAC_CHECK_PROBE3(socket_check_bind, error, cred, so, sa);
SOCK_UNLOCK(so);
return (error);
}
@ -334,11 +351,14 @@ mac_socket_check_connect(struct ucred *cred, struct socket *so,
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_connect, cred, so,
so->so_label, sa);
MAC_CHECK_PROBE3(socket_check_connect, error, cred, so, sa);
SOCK_UNLOCK(so);
return (error);
}
@ -368,13 +388,16 @@ mac_socket_check_deliver(struct socket *so, struct mbuf *m)
struct label *label;
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
label = mac_mbuf_to_label(m);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_deliver, so, so->so_label, m,
label);
MAC_CHECK_PROBE2(socket_check_deliver, error, so, m);
SOCK_UNLOCK(so);
return (error);
}
@ -387,11 +410,14 @@ mac_socket_check_listen(struct ucred *cred, struct socket *so)
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_listen, cred, so,
so->so_label);
MAC_CHECK_PROBE2(socket_check_listen, error, cred, so);
SOCK_UNLOCK(so);
return (error);
}
@ -404,10 +430,13 @@ mac_socket_check_poll(struct ucred *cred, struct socket *so)
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_poll, cred, so, so->so_label);
MAC_CHECK_PROBE2(socket_check_poll, error, cred, so);
SOCK_UNLOCK(so);
return (error);
}
@ -420,11 +449,14 @@ mac_socket_check_receive(struct ucred *cred, struct socket *so)
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_receive, cred, so,
so->so_label);
MAC_CHECK_PROBE2(socket_check_receive, error, cred, so);
SOCK_UNLOCK(so);
return (error);
}
@ -455,10 +487,13 @@ mac_socket_check_send(struct ucred *cred, struct socket *so)
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_send, cred, so, so->so_label);
MAC_CHECK_PROBE2(socket_check_send, error, cred, so);
SOCK_UNLOCK(so);
return (error);
}
@ -471,10 +506,13 @@ mac_socket_check_stat(struct ucred *cred, struct socket *so)
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_stat, cred, so, so->so_label);
MAC_CHECK_PROBE2(socket_check_stat, error, cred, so);
SOCK_UNLOCK(so);
return (error);
}
@ -487,11 +525,14 @@ mac_socket_check_visible(struct ucred *cred, struct socket *so)
{
int error;
SOCK_LOCK_ASSERT(so);
if (mac_policy_count == 0)
return (0);
SOCK_LOCK(so);
MAC_POLICY_CHECK_NOSLEEP(socket_check_visible, cred, so,
so->so_label);
MAC_CHECK_PROBE2(socket_check_visible, error, cred, so);
SOCK_UNLOCK(so);
return (error);
}