Socket MAC labels so_label and so_peerlabel are now protected by
SOCK_LOCK(so): - Hold socket lock over calls to MAC entry points reading or manipulating socket labels. - Assert socket lock in MAC entry point implementations. - When externalizing the socket label, first make a thread-local copy while holding the socket lock, then release the socket lock to externalize to userspace.
This commit is contained in:
parent
c73b7c1f99
commit
0f9a4a0ff3
@ -171,7 +171,9 @@ svr4_sendit(td, s, mp, flags)
|
||||
return (error);
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_send(td->td_ucred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
goto done1;
|
||||
#endif
|
||||
@ -275,7 +277,9 @@ svr4_recvit(td, s, mp, namelenp)
|
||||
return (error);
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_receive(td->td_ucred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
goto done1;
|
||||
#endif
|
||||
|
@ -1685,7 +1685,9 @@ cr_canseesocket(struct ucred *cred, struct socket *so)
|
||||
if (error)
|
||||
return (ENOENT);
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_visible(cred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
return (error);
|
||||
#endif
|
||||
|
@ -77,7 +77,9 @@ soo_read(fp, uio, active_cred, flags, td)
|
||||
|
||||
NET_LOCK_GIANT();
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_receive(active_cred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error) {
|
||||
NET_UNLOCK_GIANT();
|
||||
return (error);
|
||||
@ -102,7 +104,9 @@ soo_write(fp, uio, active_cred, flags, td)
|
||||
|
||||
NET_LOCK_GIANT();
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_send(active_cred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error) {
|
||||
NET_UNLOCK_GIANT();
|
||||
return (error);
|
||||
|
@ -209,7 +209,9 @@ sonewconn(head, connstatus)
|
||||
so->so_timeo = head->so_timeo;
|
||||
so->so_cred = crhold(head->so_cred);
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(head);
|
||||
mac_create_socket_from_socket(head, so);
|
||||
SOCK_UNLOCK(head);
|
||||
#endif
|
||||
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) ||
|
||||
(*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
|
||||
|
@ -209,7 +209,9 @@ sonewconn(head, connstatus)
|
||||
so->so_timeo = head->so_timeo;
|
||||
so->so_cred = crhold(head->so_cred);
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(head);
|
||||
mac_create_socket_from_socket(head, so);
|
||||
SOCK_UNLOCK(head);
|
||||
#endif
|
||||
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) ||
|
||||
(*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
|
||||
|
@ -190,7 +190,9 @@ kern_bind(td, fd, sa)
|
||||
if ((error = fgetsock(td, fd, &so, NULL)) != 0)
|
||||
goto done2;
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_bind(td->td_ucred, so, sa);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
goto done1;
|
||||
#endif
|
||||
@ -223,7 +225,9 @@ listen(td, uap)
|
||||
NET_LOCK_GIANT();
|
||||
if ((error = fgetsock(td, uap->s, &so, NULL)) == 0) {
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_listen(td->td_ucred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
goto done;
|
||||
#endif
|
||||
@ -482,7 +486,9 @@ kern_connect(td, fd, sa)
|
||||
goto done1;
|
||||
}
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_connect(td->td_ucred, so, sa);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
goto bad;
|
||||
#endif
|
||||
@ -701,7 +707,9 @@ kern_sendit(td, s, mp, flags, control)
|
||||
goto bad2;
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_send(td->td_ucred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
goto bad;
|
||||
#endif
|
||||
@ -944,7 +952,9 @@ recvit(td, s, mp, namelenp)
|
||||
}
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_receive(td->td_ucred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error) {
|
||||
fputsock(so);
|
||||
NET_UNLOCK_GIANT();
|
||||
@ -1750,7 +1760,9 @@ do_sendfile(struct thread *td, struct sendfile_args *uap, int compat)
|
||||
}
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_send(td->td_ucred, so);
|
||||
SOCK_UNLOCK(so);
|
||||
if (error)
|
||||
goto done;
|
||||
#endif
|
||||
|
@ -846,8 +846,10 @@ unp_connect(so, nam, td)
|
||||
sizeof(unp->unp_peercred));
|
||||
unp->unp_flags |= UNP_HAVEPC;
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
mac_set_socket_peer_from_socket(so, so3);
|
||||
mac_set_socket_peer_from_socket(so3, so);
|
||||
SOCK_UNLOCK(so);
|
||||
#endif
|
||||
|
||||
so2 = so3;
|
||||
|
@ -366,10 +366,13 @@ ddp_input(m, ifp, elh, phase)
|
||||
}
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(ddp->ddp_socket);
|
||||
if (mac_check_socket_deliver(ddp->ddp_socket, m) != 0) {
|
||||
SOCK_UNLOCK(ddp->ddp_socket);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
SOCK_UNLOCK(ddp->ddp_socket);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -52,7 +52,9 @@ ddp_output(struct mbuf *m, struct socket *so)
|
||||
struct ddpcb *ddp = sotoddpcb(so);
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
mac_create_mbuf_from_socket(so, m);
|
||||
SOCK_UNLOCK(so);
|
||||
#endif
|
||||
|
||||
M_PREPEND(m, sizeof(struct ddpehdr), M_TRYWAIT);
|
||||
|
@ -176,7 +176,9 @@ in_pcballoc(so, pcbinfo, type)
|
||||
error = mac_init_inpcb(inp, M_NOWAIT);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
SOCK_LOCK(so);
|
||||
mac_create_inpcb_from_socket(so, inp);
|
||||
SOCK_UNLOCK(so);
|
||||
#endif
|
||||
#if defined(IPSEC) || defined(FAST_IPSEC)
|
||||
#ifdef FAST_IPSEC
|
||||
@ -1175,10 +1177,11 @@ in_pcbsosetlabel(so)
|
||||
#ifdef MAC
|
||||
struct inpcb *inp;
|
||||
|
||||
/* XXX: Will assert socket lock when we have them. */
|
||||
inp = (struct inpcb *)so->so_pcb;
|
||||
INP_LOCK(inp);
|
||||
SOCK_LOCK(so);
|
||||
mac_inpcb_sosetlabel(so, inp);
|
||||
SOCK_UNLOCK(so);
|
||||
INP_UNLOCK(inp);
|
||||
#endif
|
||||
}
|
||||
|
@ -263,7 +263,9 @@ div_output(struct socket *so, struct mbuf *m,
|
||||
KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
|
||||
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
mac_create_mbuf_from_socket(so, m);
|
||||
SOCK_UNLOCK(so);
|
||||
#endif
|
||||
|
||||
if (control)
|
||||
|
@ -1352,7 +1352,9 @@ tcp_input(m, off0)
|
||||
tcpstat.tcps_connects++;
|
||||
soisconnected(so);
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
mac_set_socket_peer_from_mbuf(m, so);
|
||||
SOCK_UNLOCK(so);
|
||||
#endif
|
||||
/* Do window scaling on this connection? */
|
||||
if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
|
||||
|
@ -1352,7 +1352,9 @@ tcp_input(m, off0)
|
||||
tcpstat.tcps_connects++;
|
||||
soisconnected(so);
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
mac_set_socket_peer_from_mbuf(m, so);
|
||||
SOCK_UNLOCK(so);
|
||||
#endif
|
||||
/* Do window scaling on this connection? */
|
||||
if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
|
||||
|
@ -559,7 +559,9 @@ syncache_socket(sc, lso, m)
|
||||
goto abort2;
|
||||
}
|
||||
#ifdef MAC
|
||||
SOCK_LOCK(so);
|
||||
mac_set_socket_peer_from_mbuf(m, so);
|
||||
SOCK_UNLOCK(so);
|
||||
#endif
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
|
@ -218,6 +218,7 @@ mac_create_socket_from_socket(struct socket *oldsocket,
|
||||
struct socket *newsocket)
|
||||
{
|
||||
|
||||
SOCK_LOCK_ASSERT(oldsocket);
|
||||
MAC_PERFORM(create_socket_from_socket, oldsocket, oldsocket->so_label,
|
||||
newsocket, newsocket->so_label);
|
||||
}
|
||||
@ -227,6 +228,7 @@ mac_relabel_socket(struct ucred *cred, struct socket *socket,
|
||||
struct label *newlabel)
|
||||
{
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
MAC_PERFORM(relabel_socket, cred, socket, socket->so_label, newlabel);
|
||||
}
|
||||
|
||||
@ -235,6 +237,8 @@ mac_set_socket_peer_from_mbuf(struct mbuf *mbuf, struct socket *socket)
|
||||
{
|
||||
struct label *label;
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
|
||||
label = mac_mbuf_to_label(mbuf);
|
||||
|
||||
MAC_PERFORM(set_socket_peer_from_mbuf, mbuf, label, socket,
|
||||
@ -246,6 +250,12 @@ mac_set_socket_peer_from_socket(struct socket *oldsocket,
|
||||
struct socket *newsocket)
|
||||
{
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
MAC_PERFORM(set_socket_peer_from_socket, oldsocket,
|
||||
oldsocket->so_label, newsocket, newsocket->so_peerlabel);
|
||||
}
|
||||
@ -257,6 +267,7 @@ mac_create_mbuf_from_socket(struct socket *socket, struct mbuf *mbuf)
|
||||
|
||||
label = mac_mbuf_to_label(mbuf);
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
MAC_PERFORM(create_mbuf_from_socket, socket, socket->so_label, mbuf,
|
||||
label);
|
||||
}
|
||||
@ -267,6 +278,8 @@ mac_check_socket_bind(struct ucred *ucred, struct socket *socket,
|
||||
{
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
|
||||
if (!mac_enforce_socket)
|
||||
return (0);
|
||||
|
||||
@ -282,6 +295,8 @@ mac_check_socket_connect(struct ucred *cred, struct socket *socket,
|
||||
{
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
|
||||
if (!mac_enforce_socket)
|
||||
return (0);
|
||||
|
||||
@ -297,6 +312,8 @@ mac_check_socket_deliver(struct socket *socket, struct mbuf *mbuf)
|
||||
struct label *label;
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
|
||||
if (!mac_enforce_socket)
|
||||
return (0);
|
||||
|
||||
@ -313,6 +330,8 @@ mac_check_socket_listen(struct ucred *cred, struct socket *socket)
|
||||
{
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
|
||||
if (!mac_enforce_socket)
|
||||
return (0);
|
||||
|
||||
@ -325,6 +344,8 @@ mac_check_socket_receive(struct ucred *cred, struct socket *so)
|
||||
{
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(so);
|
||||
|
||||
if (!mac_enforce_socket)
|
||||
return (0);
|
||||
|
||||
@ -339,6 +360,8 @@ mac_check_socket_relabel(struct ucred *cred, struct socket *socket,
|
||||
{
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
|
||||
MAC_CHECK(check_socket_relabel, cred, socket, socket->so_label,
|
||||
newlabel);
|
||||
|
||||
@ -350,6 +373,8 @@ mac_check_socket_send(struct ucred *cred, struct socket *so)
|
||||
{
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(so);
|
||||
|
||||
if (!mac_enforce_socket)
|
||||
return (0);
|
||||
|
||||
@ -363,6 +388,8 @@ mac_check_socket_visible(struct ucred *cred, struct socket *socket)
|
||||
{
|
||||
int error;
|
||||
|
||||
SOCK_LOCK_ASSERT(socket);
|
||||
|
||||
if (!mac_enforce_socket)
|
||||
return (0);
|
||||
|
||||
@ -377,12 +404,24 @@ mac_socket_label_set(struct ucred *cred, struct socket *so,
|
||||
{
|
||||
int error;
|
||||
|
||||
/*
|
||||
* We acquire the socket lock when we perform the test and set,
|
||||
* but have to release it as the pcb code needs to acquire the
|
||||
* pcb lock, which will precede the socket lock in the lock
|
||||
* order. However, this is fine, as any race will simply
|
||||
* result in the inpcb being refreshed twice, but still
|
||||
* consistently, as the inpcb code will acquire the socket lock
|
||||
* before refreshing, holding both locks.
|
||||
*/
|
||||
SOCK_LOCK(so);
|
||||
error = mac_check_socket_relabel(cred, so, label);
|
||||
if (error)
|
||||
if (error) {
|
||||
SOCK_UNLOCK(so);
|
||||
return (error);
|
||||
}
|
||||
|
||||
mac_relabel_socket(cred, so, label);
|
||||
|
||||
SOCK_UNLOCK(so);
|
||||
/*
|
||||
* If the protocol has expressed interest in socket layer changes,
|
||||
* such as if it needs to propagate changes to a cached pcb
|
||||
@ -419,9 +458,7 @@ mac_setsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* XXX: Socket lock here. */
|
||||
error = mac_socket_label_set(cred, so, intlabel);
|
||||
/* XXX: Socket unlock here. */
|
||||
out:
|
||||
mac_socket_label_free(intlabel);
|
||||
return (error);
|
||||
@ -431,6 +468,7 @@ int
|
||||
mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
|
||||
{
|
||||
char *buffer, *elements;
|
||||
struct label *intlabel;
|
||||
int error;
|
||||
|
||||
error = mac_check_structmac_consistent(mac);
|
||||
@ -445,8 +483,13 @@ mac_getsockopt_label(struct ucred *cred, struct socket *so, struct mac *mac)
|
||||
}
|
||||
|
||||
buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
|
||||
error = mac_externalize_socket_label(so->so_label, elements,
|
||||
buffer, mac->m_buflen);
|
||||
intlabel = mac_socket_label_alloc(M_WAITOK);
|
||||
SOCK_LOCK(so);
|
||||
mac_copy_socket_label(so->so_label, intlabel);
|
||||
SOCK_UNLOCK(so);
|
||||
error = mac_externalize_socket_label(intlabel, elements, buffer,
|
||||
mac->m_buflen);
|
||||
mac_socket_label_free(intlabel);
|
||||
if (error == 0)
|
||||
error = copyout(buffer, mac->m_string, strlen(buffer)+1);
|
||||
|
||||
@ -461,6 +504,7 @@ mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
|
||||
struct mac *mac)
|
||||
{
|
||||
char *elements, *buffer;
|
||||
struct label *intlabel;
|
||||
int error;
|
||||
|
||||
error = mac_check_structmac_consistent(mac);
|
||||
@ -475,8 +519,13 @@ mac_getsockopt_peerlabel(struct ucred *cred, struct socket *so,
|
||||
}
|
||||
|
||||
buffer = malloc(mac->m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
|
||||
error = mac_externalize_socket_peer_label(so->so_peerlabel,
|
||||
elements, buffer, mac->m_buflen);
|
||||
intlabel = mac_socket_label_alloc(M_WAITOK);
|
||||
SOCK_LOCK(so);
|
||||
mac_copy_socket_label(so->so_peerlabel, intlabel);
|
||||
SOCK_UNLOCK(so);
|
||||
error = mac_externalize_socket_peer_label(intlabel, elements, buffer,
|
||||
mac->m_buflen);
|
||||
mac_socket_label_free(intlabel);
|
||||
if (error == 0)
|
||||
error = copyout(buffer, mac->m_string, strlen(buffer)+1);
|
||||
|
||||
|
@ -124,8 +124,8 @@ struct socket {
|
||||
void (*so_upcall)(struct socket *, void *, int);
|
||||
void *so_upcallarg;
|
||||
struct ucred *so_cred; /* user credentials */
|
||||
struct label *so_label; /* MAC label for socket */
|
||||
struct label *so_peerlabel; /* cached MAC label for socket peer */
|
||||
struct label *so_label; /* (b) MAC label for socket */
|
||||
struct label *so_peerlabel; /* (b) cached MAC label for peer */
|
||||
/* NB: generation count must not be first; easiest to make it last. */
|
||||
so_gen_t so_gencnt; /* generation count */
|
||||
void *so_emuldata; /* private data for emulators */
|
||||
|
Loading…
Reference in New Issue
Block a user