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:
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user