keysock: do not use raw socket code

This makes key socket implementation self contained and removes one
of the last dependencies on the raw socket code and pr_output method.

There are very subtle API visible changes:
- now key socket would return EOPNOTSUPP instead of EINVAL on
  syscalls that are not supposed to be called on a key socket.
- key socket buffer sizes are now controlled by net.key sysctls instead
  of net.raw.  The latter were not documented anywhere, and even Internet
  search doesn't find any references or discussions related to them.

Reviewed by:		melifaro
Differential revision:	https://reviews.freebsd.org/D36123
This commit is contained in:
Gleb Smirnoff 2022-08-11 09:19:36 -07:00
parent 36b10ac2cd
commit ea7be1293b
3 changed files with 64 additions and 170 deletions

View File

@ -66,7 +66,6 @@
#include <net/if.h>
#include <net/if_var.h>
#include <net/vnet.h>
#include <net/raw_cb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@ -468,7 +467,6 @@ SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug,
"Enable IPsec debugging output when set.");
#endif
SYSCTL_DECL(_net_key);
SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(key_debug_level), 0, "");
@ -516,8 +514,7 @@ SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin,
SYSCTL_INT(_net_key, KEYCTL_PREFERED_OLDSA, preferred_oldsa,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(key_preferred_oldsa), 0, "");
static SYSCTL_NODE(_net_key, OID_AUTO, spdcache,
CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
SYSCTL_NODE(_net_key, OID_AUTO, spdcache, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"SPD cache");
SYSCTL_UINT(_net_key_spdcache, OID_AUTO, maxentries,
@ -7157,7 +7154,7 @@ key_register(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
}
newreg->so = so;
((struct keycb *)sotorawcb(so))->kp_registered++;
((struct keycb *)(so->so_pcb))->kp_registered++;
/* add regnode to regtree. */
LIST_INSERT_HEAD(&V_regtree[mhp->msg->sadb_msg_satype], newreg, chain);
@ -7717,7 +7714,7 @@ key_promisc(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp)
/* enable/disable promisc mode */
struct keycb *kp;
if ((kp = (struct keycb *)sotorawcb(so)) == NULL)
if ((kp = so->so_pcb) == NULL)
return key_senderror(so, m, EINVAL);
mhp->msg->sadb_msg_errno = 0;
switch (mhp->msg->sadb_msg_satype) {

View File

@ -55,7 +55,6 @@
#include <net/if.h>
#include <net/vnet.h>
#include <net/raw_cb.h>
#include <netinet/in.h>
@ -67,16 +66,18 @@
#include <machine/stdarg.h>
struct key_cb {
int key_count;
int any_count;
};
VNET_DEFINE_STATIC(struct key_cb, key_cb) = {};
#define V_key_cb VNET(key_cb)
static struct mtx keysock_mtx;
MTX_SYSINIT(keysock, &keysock_mtx, "key socket pcb list", MTX_DEF);
#define KEYSOCK_LOCK() mtx_lock(&keysock_mtx)
#define KEYSOCK_UNLOCK() mtx_unlock(&keysock_mtx)
VNET_DEFINE_STATIC(LIST_HEAD(, keycb), keycb_list);
#define V_keycb_list VNET(keycb_list)
static struct sockaddr key_src = { 2, PF_KEY, };
static int key_sendup0(struct rawcb *, struct mbuf *, int);
static int key_sendup0(struct keycb *, struct mbuf *, int);
VNET_PCPUSTAT_DEFINE(struct pfkeystat, pfkeystat);
VNET_PCPUSTAT_SYSINIT(pfkeystat);
@ -85,17 +86,19 @@ VNET_PCPUSTAT_SYSINIT(pfkeystat);
VNET_PCPUSTAT_SYSUNINIT(pfkeystat);
#endif /* VIMAGE */
/*
* key_output()
*/
int
key_output(struct mbuf *m, struct socket *so, ...)
static int
key_send(struct socket *so, int flags, struct mbuf *m,
struct sockaddr *nam, struct mbuf *control, struct thread *td)
{
struct sadb_msg *msg;
int len, error = 0;
if (m == NULL)
panic("%s: NULL pointer was passed.\n", __func__);
if ((flags & PRUS_OOB) || control != NULL) {
m_freem(m);
if (control != NULL)
m_freem(control);
return (EOPNOTSUPP);
}
PFKEYSTAT_INC(out_total);
PFKEYSTAT_ADD(out_bytes, m->m_pkthdr.len);
@ -139,7 +142,7 @@ end:
* send message to the socket.
*/
static int
key_sendup0(struct rawcb *rp, struct mbuf *m, int promisc)
key_sendup0(struct keycb *kp, struct mbuf *m, int promisc)
{
if (promisc) {
@ -160,15 +163,14 @@ key_sendup0(struct rawcb *rp, struct mbuf *m, int promisc)
PFKEYSTAT_INC(in_msgtype[pmsg->sadb_msg_type]);
}
if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src,
m, NULL)) {
if (!sbappendaddr(&kp->kp_socket->so_rcv, &key_src, m, NULL)) {
PFKEYSTAT_INC(in_nomem);
m_freem(m);
soroverflow(rp->rcb_socket);
soroverflow(kp->kp_socket);
return ENOBUFS;
}
sorwakeup(rp->rcb_socket);
sorwakeup(kp->kp_socket);
return 0;
}
@ -178,7 +180,6 @@ key_sendup_mbuf(struct socket *so, struct mbuf *m, int target)
{
struct mbuf *n;
struct keycb *kp;
struct rawcb *rp;
int error = 0;
KASSERT(m != NULL, ("NULL mbuf pointer was passed."));
@ -201,37 +202,23 @@ key_sendup_mbuf(struct socket *so, struct mbuf *m, int target)
msg = mtod(m, struct sadb_msg *);
PFKEYSTAT_INC(in_msgtype[msg->sadb_msg_type]);
}
mtx_lock(&rawcb_mtx);
if (V_key_cb.any_count == 0) {
mtx_unlock(&rawcb_mtx);
m_freem(m);
return (0);
}
LIST_FOREACH(rp, &V_rawcb_list, list)
{
if (rp->rcb_proto.sp_family != PF_KEY)
continue;
if (rp->rcb_proto.sp_protocol
&& rp->rcb_proto.sp_protocol != PF_KEY_V2) {
continue;
}
KEYSOCK_LOCK();
LIST_FOREACH(kp, &V_keycb_list, kp_next) {
/*
* If you are in promiscuous mode, and when you get broadcasted
* reply, you'll get two PF_KEY messages.
* (based on pf_key@inner.net message on 14 Oct 1998)
*/
kp = (struct keycb *)rp;
if (kp->kp_promisc) {
n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
if (n != NULL)
key_sendup0(rp, n, 1);
key_sendup0(kp, n, 1);
else
PFKEYSTAT_INC(in_nomem);
}
/* the exact target will be processed later */
if (so && sotorawcb(so) == rp)
if (so != NULL && so->so_pcb == kp)
continue;
if (target == KEY_SENDUP_ONE || (
@ -246,36 +233,29 @@ key_sendup_mbuf(struct socket *so, struct mbuf *m, int target)
continue;
}
if (key_sendup0(rp, n, 0) == 0)
if (key_sendup0(kp, n, 0) == 0)
PFKEYSTAT_INC(in_msgtarget[target]);
}
if (so) { /* KEY_SENDUP_ONE */
error = key_sendup0(sotorawcb(so), m, 0);
error = key_sendup0(so->so_pcb, m, 0);
if (error == 0)
PFKEYSTAT_INC(in_msgtarget[KEY_SENDUP_ONE]);
} else {
error = 0;
m_freem(m);
}
mtx_unlock(&rawcb_mtx);
KEYSOCK_UNLOCK();
return (error);
}
/*
* key_abort()
* derived from net/rtsock.c:rts_abort()
*/
static void
key_abort(struct socket *so)
{
raw_usrreqs.pru_abort(so);
}
static u_long key_sendspace = 8192;
SYSCTL_ULONG(_net_key, OID_AUTO, sendspace, CTLFLAG_RW, &key_sendspace, 0,
"Default key socket send space");
static u_long key_recvspace = 8192;
SYSCTL_ULONG(_net_key, OID_AUTO, recvspace, CTLFLAG_RW, &key_recvspace, 0,
"Default key socket receive space");
/*
* key_attach()
* derived from net/rtsock.c:rts_attach()
*/
static int
key_attach(struct socket *so, int proto, struct thread *td)
{
@ -290,143 +270,59 @@ key_attach(struct socket *so, int proto, struct thread *td)
return error;
}
/* XXX */
kp = malloc(sizeof *kp, M_PCB, M_WAITOK | M_ZERO);
if (kp == NULL)
return ENOBUFS;
so->so_pcb = (caddr_t)kp;
error = raw_attach(so, proto);
kp = (struct keycb *)sotorawcb(so);
if (error) {
free(kp, M_PCB);
so->so_pcb = (caddr_t) 0;
return error;
}
error = soreserve(so, key_sendspace, key_recvspace);
if (error)
return (error);
kp = malloc(sizeof(*kp), M_PCB, M_WAITOK);
kp->kp_socket = so;
kp->kp_promisc = kp->kp_registered = 0;
if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */
V_key_cb.key_count++;
V_key_cb.any_count++;
soisconnected(so);
so->so_pcb = kp;
so->so_options |= SO_USELOOPBACK;
return 0;
KEYSOCK_LOCK();
LIST_INSERT_HEAD(&V_keycb_list, kp, kp_next);
KEYSOCK_UNLOCK();
soisconnected(so);
return (0);
}
/*
* key_bind()
* derived from net/rtsock.c:rts_bind()
*/
static int
key_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
return EINVAL;
}
/*
* key_close()
* derived from net/rtsock.c:rts_close().
*/
static void
key_close(struct socket *so)
{
raw_usrreqs.pru_close(so);
soisdisconnected(so);
}
/*
* key_connect()
* derived from net/rtsock.c:rts_connect()
*/
static int
key_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
return EINVAL;
}
/*
* key_detach()
* derived from net/rtsock.c:rts_detach()
*/
static void
key_detach(struct socket *so)
{
struct keycb *kp = (struct keycb *)sotorawcb(so);
KASSERT(kp != NULL, ("key_detach: kp == NULL"));
if (kp->kp_raw.rcb_proto.sp_protocol
== PF_KEY) /* XXX: AF_KEY */
V_key_cb.key_count--;
V_key_cb.any_count--;
struct keycb *kp = so->so_pcb;
key_freereg(so);
raw_usrreqs.pru_detach(so);
KEYSOCK_LOCK();
LIST_REMOVE(kp, kp_next);
KEYSOCK_UNLOCK();
free(kp, M_PCB);
so->so_pcb = NULL;
}
/*
* key_disconnect()
* derived from net/rtsock.c:key_disconnect()
*/
static int
key_disconnect(struct socket *so)
{
return(raw_usrreqs.pru_disconnect(so));
}
/*
* key_peeraddr()
* derived from net/rtsock.c:rts_peeraddr()
*/
static int
key_peeraddr(struct socket *so, struct sockaddr **nam)
{
return(raw_usrreqs.pru_peeraddr(so, nam));
}
/*
* key_send()
* derived from net/rtsock.c:rts_send()
*/
static int
key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
struct mbuf *control, struct thread *td)
{
return(raw_usrreqs.pru_send(so, flags, m, nam, control, td));
}
/*
* key_shutdown()
* derived from net/rtsock.c:rts_shutdown()
*/
static int
key_shutdown(struct socket *so)
{
return(raw_usrreqs.pru_shutdown(so));
}
/*
* key_sockaddr()
* derived from net/rtsock.c:rts_sockaddr()
*/
static int
key_sockaddr(struct socket *so, struct sockaddr **nam)
{
return(raw_usrreqs.pru_sockaddr(so, nam));
socantsendmore(so);
return (0);
}
struct pr_usrreqs key_usrreqs = {
.pru_abort = key_abort,
.pru_abort = key_close,
.pru_attach = key_attach,
.pru_bind = key_bind,
.pru_connect = key_connect,
.pru_detach = key_detach,
.pru_disconnect = key_disconnect,
.pru_peeraddr = key_peeraddr,
.pru_send = key_send,
.pru_shutdown = key_shutdown,
.pru_sockaddr = key_sockaddr,
.pru_close = key_close,
};
@ -446,8 +342,6 @@ struct protosw keysw[] = {
.pr_domain = &keydomain,
.pr_protocol = PF_KEY_V2,
.pr_flags = PR_ATOMIC|PR_ADDR,
.pr_output = key_output,
.pr_ctlinput = raw_ctlinput,
.pr_usrreqs = &key_usrreqs
}
};

View File

@ -67,8 +67,11 @@ struct pfkeystat {
#ifdef _KERNEL
#include <sys/counter.h>
SYSCTL_DECL(_net_key);
struct keycb {
struct rawcb kp_raw; /* rawcb */
LIST_ENTRY(keycb) kp_next;
struct socket *kp_socket;
int kp_promisc; /* promiscuous mode */
int kp_registered; /* registered socket */
};