netlink: do not pass writer to the Linux translation layer

Another flaw in the KPI between Netlink and Linuxulator is that we pass
the on-stack writer structure.  This structure belongs to someone, that we
can't even identify inside nl_send() and we shall not tamper it.  The
Linux translation layer needs a writer, because it actually composes a new
message.  Instead of reusing someone's writer and trying to repair it in
all possible cases where translation process tampers the writer, just let
Linuxulator use its own writer.  See also b977dd1ea5.

PR:			288892
Reviewed by:		melifaro
Differential Revision:	https://reviews.freebsd.org/D51928
This commit is contained in:
Gleb Smirnoff
2025-08-22 09:23:38 -07:00
parent 554907bac3
commit 0d9ef08e09
3 changed files with 21 additions and 31 deletions
+13 -24
View File
@@ -550,22 +550,15 @@ nlmsg_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw)
}
}
static bool
nlmsgs_to_linux(struct nl_writer *nw, struct nlpcb *nlp)
static struct nl_buf *
nlmsgs_to_linux(struct nl_buf *orig, struct nlpcb *nlp)
{
struct nl_buf *nb, *orig;
u_int offset, msglen, orig_messages;
struct nl_writer nw;
u_int offset, msglen;
RT_LOG(LOG_DEBUG3, "%p: in %u bytes %u messages", __func__,
nw->buf->datalen, nw->num_messages);
orig = nw->buf;
nb = nl_buf_alloc(orig->datalen + SCRATCH_BUFFER_SIZE, M_NOWAIT);
if (__predict_false(nb == NULL))
return (false);
nw->buf = nb;
orig_messages = nw->num_messages;
nw->num_messages = 0;
if (__predict_false(!nl_writer_unicast(&nw,
orig->datalen + SCRATCH_BUFFER_SIZE, nlp, false)))
return (NULL);
/* Assume correct headers. Buffer IS mutable */
for (offset = 0;
@@ -574,22 +567,18 @@ nlmsgs_to_linux(struct nl_writer *nw, struct nlpcb *nlp)
struct nlmsghdr *hdr = (struct nlmsghdr *)&orig->data[offset];
msglen = NLMSG_ALIGN(hdr->nlmsg_len);
if (!nlmsg_to_linux(hdr, nlp, nw)) {
if (!nlmsg_to_linux(hdr, nlp, &nw)) {
RT_LOG(LOG_DEBUG, "failed to process msg type %d",
hdr->nlmsg_type);
nl_buf_free(nb);
nw->buf = orig;
nw->num_messages = orig_messages;
return (false);
nl_buf_free(nw.buf);
return (NULL);
}
}
MPASS(nw->num_messages == orig_messages);
MPASS(nw->buf == nb);
nl_buf_free(orig);
RT_LOG(LOG_DEBUG3, "%p: out %u bytes", __func__, offset);
RT_LOG(LOG_DEBUG3, "%p: in %u bytes %u messages", __func__,
nw.buf->datalen, nw.num_messages);
return (true);
return (nw.buf);
}
static struct linux_netlink_provider linux_netlink_v1 = {
+7 -6
View File
@@ -216,16 +216,17 @@ nl_send(struct nl_writer *nw, struct nlpcb *nlp)
hdr->nlmsg_len);
}
if (nlp->nl_linux && linux_netlink_p != NULL &&
__predict_false(!linux_netlink_p->msgs_to_linux(nw, nlp))) {
if (nlp->nl_linux && linux_netlink_p != NULL) {
nb = linux_netlink_p->msgs_to_linux(nw->buf, nlp);
nl_buf_free(nw->buf);
nw->buf = NULL;
return (false);
if (nb == NULL)
return (false);
} else {
nb = nw->buf;
nw->buf = NULL;
}
nb = nw->buf;
nw->buf = NULL;
SOCK_RECVBUF_LOCK(so);
if (!nw->ignore_limit && __predict_false(sb->sb_hiwat <= sb->sb_ccc)) {
SOCK_RECVBUF_UNLOCK(so);
+1 -1
View File
@@ -37,7 +37,7 @@ struct nlpcb;
struct nl_pstate;
struct nl_writer;
typedef bool msgs_to_linux_cb_t(struct nl_writer *nw, struct nlpcb *nlp);
typedef struct nl_buf * msgs_to_linux_cb_t(struct nl_buf *, struct nlpcb *);
typedef int msg_from_linux_cb_t(int netlink_family, struct nlmsghdr **hdr,
struct nl_pstate *npt);