From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Waldemar Kozaczuk <jwkozac...@gmail.com>
Branch: master

netlink: return stashed pid

There are three types of pid used in netlink interface:
- the nl_pid on the source (app) side (part of sockaddr_nl) set before
  bind(); could be 0 to request kernel generating new one
- the nl_pid on the destination (kernel) size set into dst_addr that
  always needs to be 0 if we communicate with kernel
- the nlmsg_pid (sender port ID) that is part of the netlink message
  header sent to and received from kernel

Some relevant information from Linux docs:

"      nlmsg_seq and nlmsg_pid are used to track messages.  nlmsg_pid
       shows the origin of the message.  Note that there isn't a 1:1
       relationship between nlmsg_pid and the PID of the process if the
       message originated from a netlink socket.  See the ADDRESS
       FORMATS section for further information.

       Both nlmsg_seq and nlmsg_pid are opaque to netlink core."

and:

"      nl_pid is the unicast address of netlink socket.  It's always 0
       if the destination is in the kernel.  For a user-space process,
       nl_pid is usually the PID of the process owning the destination
       socket.  However, nl_pid identifies a netlink socket, not a
       process.  If a process owns several netlink sockets, then nl_pid
       can be equal to the process ID only for at most one socket.
       There are two ways to assign nl_pid to a netlink socket.  If the
       application sets nl_pid before calling bind(2), then it is up to
       the application to make sure that nl_pid is unique.  If the
       application sets it to 0, the kernel takes care of assigning it.
       The kernel assigns the process ID to the first netlink socket the
       process opens and assigns a unique nl_pid to every netlink socket
       that the process subsequently creates."

The 1st one needs to be stashed or generated (if 0) and then set on nlmsg_pid
for each response so that the application receving it can distinguish it
if necessary. Golang runtime actually calls sockname() and verifies that
the nlmsg_pid in the replies matches the nl_pid on the source socket.

The patch modifies relevant code that builds netlink responses
to put the nl_pid stashed during socket attach process to set it as
value of inlmsg_pid. It also re-implements the netlink_sockaddr()
to make it return information including the source PID.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>

---
diff --git a/bsd/sys/compat/linux/linux_netlink.cc 
b/bsd/sys/compat/linux/linux_netlink.cc
--- a/bsd/sys/compat/linux/linux_netlink.cc
+++ b/bsd/sys/compat/linux/linux_netlink.cc
@@ -436,10 +436,27 @@ netlink_shutdown(struct socket *so)
        return (raw_usrreqs.pru_shutdown(so));
 }
 
+static pid_t
+get_socket_pid(struct socket *so)
+{
+       struct rawcb *rp = sotorawcb(so);
+       struct netlinkcb *ncb = (netlinkcb *)rp;
+       return ncb->nl_pid;
+}
+
 static int
 netlink_sockaddr(struct socket *so, struct bsd_sockaddr **nam)
 {
-       return (raw_usrreqs.pru_sockaddr(so, nam));
+       struct bsd_sockaddr_nl *sin;
+
+       sin = (bsd_sockaddr_nl*)malloc(sizeof *sin);
+       bzero(sin, sizeof *sin);
+       sin->nl_family = AF_NETLINK;
+       sin->nl_len = sizeof(*sin);
+       sin->nl_pid = get_socket_pid(so);
+
+       *nam = (bsd_sockaddr*)sin;
+       return 0;
 }
 
 static struct pr_usrreqs netlink_usrreqs = initialize_with([] (pr_usrreqs& x) {
@@ -474,7 +491,7 @@ netlink_senderr(struct socket *so, struct nlmsghdr *nlm, 
int error)
        }
 
        if ((hdr = (struct nlmsghdr *)nlmsg_put(m,
-                                               nlm ? nlm->nlmsg_pid : 0,
+                                               get_socket_pid(so),
                                                nlm ? nlm->nlmsg_seq : 0,
                                                NLMSG_ERROR, sizeof(*err),
                                                nlm ? nlm->nlmsg_flags : 0)) == 
NULL) {
@@ -513,7 +530,7 @@ netlink_process_getlink_msg(struct socket *so, struct 
nlmsghdr *nlm)
        TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
                IF_ADDR_RLOCK(ifp);
 
-               nlh = nlmsg_begin(m, nlm->nlmsg_pid, nlm->nlmsg_seq, 
LINUX_RTM_NEWLINK, sizeof(*ifm), nlm->nlmsg_flags);
+               nlh = nlmsg_begin(m, get_socket_pid(so), nlm->nlmsg_seq, 
LINUX_RTM_NEWLINK, sizeof(*ifm), nlm->nlmsg_flags);
                if (!nlh) {
                        error = ENOBUFS;
                        goto done;
@@ -547,7 +564,7 @@ netlink_process_getlink_msg(struct socket *so, struct 
nlmsghdr *nlm)
                IF_ADDR_RUNLOCK(ifp);
                nlmsg_end(m, nlh);
        }
-       nlh = nlmsg_put(m, nlm->nlmsg_pid, nlm->nlmsg_seq, NLMSG_DONE, 0, 
nlm->nlmsg_flags);
+       nlh = nlmsg_put(m, get_socket_pid(so), nlm->nlmsg_seq, NLMSG_DONE, 0, 
nlm->nlmsg_flags);
 
 done:
        if (ifp != NULL)
@@ -605,7 +622,7 @@ netlink_process_getaddr_msg(struct socket *so, struct 
nlmsghdr *nlm)
                        if (!ifa->ifa_addr)
                                continue;
 
-                       nlh = nlmsg_begin(m, nlm->nlmsg_pid, nlm->nlmsg_seq, 
LINUX_RTM_NEWADDR, sizeof(*ifm), nlm->nlmsg_flags);
+                       nlh = nlmsg_begin(m, get_socket_pid(so), 
nlm->nlmsg_seq, LINUX_RTM_NEWADDR, sizeof(*ifm), nlm->nlmsg_flags);
                        if (!nlh) {
                                error = ENOBUFS;
                                goto done;
@@ -663,7 +680,7 @@ netlink_process_getaddr_msg(struct socket *so, struct 
nlmsghdr *nlm)
 
                IF_ADDR_RUNLOCK(ifp);
        }
-       nlh = nlmsg_put(m, nlm->nlmsg_pid, nlm->nlmsg_seq, NLMSG_DONE, 0, 
nlm->nlmsg_flags);
+       nlh = nlmsg_put(m, get_socket_pid(so), nlm->nlmsg_seq, NLMSG_DONE, 0, 
nlm->nlmsg_flags);
 done:
        if (ifp != NULL)
                IF_ADDR_RUNLOCK(ifp);
@@ -728,7 +745,7 @@ struct netlink_getneigh_lle_cbdata {
 };
 
 static int
-netlink_getneigh_lle_cb(struct lltable *llt, struct llentry *lle, void *data)
+netlink_getneigh_lle_cb(struct socket *so, struct lltable *llt, struct llentry 
*lle, void *data)
 {
        struct netlink_getneigh_lle_cbdata *cbdata = (struct 
netlink_getneigh_lle_cbdata *) data;
        int ndm_family = netlink_bsd_to_linux_family(llt->llt_af);
@@ -743,7 +760,7 @@ netlink_getneigh_lle_cb(struct lltable *llt, struct llentry 
*lle, void *data)
        struct nlmsghdr *nlm = cbdata->nlm;
        struct mbuf *m = cbdata->m;
        struct ndmsg *ndm;
-       struct nlmsghdr *nlh = nlmsg_begin(m, nlm->nlmsg_pid, nlm->nlmsg_seq, 
LINUX_RTM_NEWNEIGH, sizeof(*ndm), nlm->nlmsg_flags);
+       struct nlmsghdr *nlh = nlmsg_begin(m, get_socket_pid(so), 
nlm->nlmsg_seq, LINUX_RTM_NEWNEIGH, sizeof(*ndm), nlm->nlmsg_flags);
 
        if (!nlh) {
                return ENOBUFS;
@@ -788,7 +805,7 @@ netlink_getneigh_lle_cb(struct lltable *llt, struct llentry 
*lle, void *data)
 
 
 static int
-netlink_getneigh_lltable_cb(struct lltable *llt, void *cbdata)
+netlink_getneigh_lltable_cb(struct socket *so, struct lltable *llt, void 
*cbdata)
 {
        struct netlink_getneigh_lle_cbdata *data = (struct 
netlink_getneigh_lle_cbdata *) cbdata;
        int error = 0;
@@ -799,7 +816,7 @@ netlink_getneigh_lltable_cb(struct lltable *llt, void 
*cbdata)
                return 0;
 
        IF_AFDATA_RLOCK(llt->llt_ifp);
-       error = lltable_foreach_lle(llt, netlink_getneigh_lle_cb, data);
+       error = lltable_foreach_lle(so, llt, netlink_getneigh_lle_cb, data);
        IF_AFDATA_RUNLOCK(llt->llt_ifp);
 
        return error;
@@ -829,10 +846,10 @@ netlink_process_getneigh_msg(struct socket *so, struct 
nlmsghdr *nlm)
        cbdata.family = ndm->ndm_family;
        cbdata.state = ndm->ndm_state;
 
-       error = lltable_foreach(netlink_getneigh_lltable_cb, &cbdata);
+       error = lltable_foreach(so, netlink_getneigh_lltable_cb, &cbdata);
 
        if (!error) {
-               nlh = nlmsg_put(m, nlm->nlmsg_pid, nlm->nlmsg_seq, NLMSG_DONE, 
0, nlm->nlmsg_flags);
+               nlh = nlmsg_put(m, get_socket_pid(so), nlm->nlmsg_seq, 
NLMSG_DONE, 0, nlm->nlmsg_flags);
                netlink_dispatch(so, m);
        } else {
                m_free(m);
diff --git a/bsd/sys/net/if_llatbl.cc b/bsd/sys/net/if_llatbl.cc
--- a/bsd/sys/net/if_llatbl.cc
+++ b/bsd/sys/net/if_llatbl.cc
@@ -501,14 +501,14 @@ DB_SHOW_ALL_COMMAND(lltables, db_show_all_lltables)
 /*
  * Iterate over all lltables
  */
-int lltable_foreach(int (*func)(struct lltable *llt, void *cbdata), void 
*cbdata)
+int lltable_foreach(struct socket *so, int (*func)(struct socket *so, struct 
lltable *llt, void *cbdata), void *cbdata)
 {
        struct lltable *llt;
        int error = 0;
 
        LLTABLE_RLOCK();
        SLIST_FOREACH(llt, &V_lltables, llt_link) {
-               if ((error = func(llt, cbdata)) != 0)
+               if ((error = func(so, llt, cbdata)) != 0)
                        break;
        }
        LLTABLE_RUNLOCK();
@@ -519,7 +519,7 @@ int lltable_foreach(int (*func)(struct lltable *llt, void 
*cbdata), void *cbdata
 /*
  * Iterate over all llentries in the lltable
  */
-int lltable_foreach_lle(struct lltable *llt, int (*func)(struct lltable *llt, 
struct llentry *lle, void *cbdata), void *cbdata)
+int lltable_foreach_lle(struct socket *so, struct lltable *llt, int 
(*func)(struct socket *so, struct lltable *llt, struct llentry *lle, void 
*cbdata), void *cbdata)
 {
        struct llentry *lle;
        int i;
@@ -530,7 +530,7 @@ int lltable_foreach_lle(struct lltable *llt, int 
(*func)(struct lltable *llt, st
                        /* skip deleted entries */
                        if ((lle->la_flags & LLE_DELETED) == LLE_DELETED)
                                continue;
-                       if ((error = func(llt, lle, cbdata)) != 0)
+                       if ((error = func(so, llt, lle, cbdata)) != 0)
                                break;
                }
        }
diff --git a/bsd/sys/net/if_llatbl.h b/bsd/sys/net/if_llatbl.h
--- a/bsd/sys/net/if_llatbl.h
+++ b/bsd/sys/net/if_llatbl.h
@@ -201,12 +201,12 @@ struct llentry  *llentry_alloc(struct ifnet *, struct 
lltable *,
 /*
  * Iterate over all lltables
  */
-int lltable_foreach(int (*func)(struct lltable *llt, void *cbdata), void 
*cbdata);
+int lltable_foreach(struct socket *so, int (*func)(struct socket *so, struct 
lltable *llt, void *cbdata), void *cbdata);
 
 /*
  * Iterate over all llentries in the lltable
  */
-int lltable_foreach_lle(struct lltable *llt, int (*func)(struct lltable *llt, 
struct llentry *lle, void *cbdata), void *cbdata);
+int lltable_foreach_lle(struct socket *so, struct lltable *llt, int 
(*func)(struct socket *so, struct lltable *llt, struct llentry *lle, void 
*cbdata), void *cbdata);
 
 __END_DECLS
 

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000fdb53005e155972c%40google.com.

Reply via email to