summaryrefslogtreecommitdiff
path: root/usr/src/uts
diff options
context:
space:
mode:
authorPatrick Mooney <patrick.f.mooney@gmail.com>2015-08-05 23:11:50 +0000
committerPatrick Mooney <patrick.f.mooney@gmail.com>2015-08-07 18:25:58 +0000
commit0fe0e0bba325e1e009fcdcead63d569e9c04947e (patch)
tree6427613facbe71091f650de5d3b546d37d5a7dc9 /usr/src/uts
parent2cddbb7deeb2b0a12e4245af332867caf26550f3 (diff)
downloadillumos-joyent-0fe0e0bba325e1e009fcdcead63d569e9c04947e.tar.gz
OS-4603 lxbrand netlink should support SO_RECVUCRED
OS-4538 lxbrand systemd Failed to configure loopback device Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Diffstat (limited to 'usr/src/uts')
-rw-r--r--usr/src/uts/common/brand/lx/io/lx_netlink.c147
1 files changed, 106 insertions, 41 deletions
diff --git a/usr/src/uts/common/brand/lx/io/lx_netlink.c b/usr/src/uts/common/brand/lx/io/lx_netlink.c
index 36b0cf9b2b..3ce70fee36 100644
--- a/usr/src/uts/common/brand/lx/io/lx_netlink.c
+++ b/usr/src/uts/common/brand/lx/io/lx_netlink.c
@@ -29,17 +29,17 @@
#include <sys/tihdr.h>
#include <sys/sockio.h>
#include <sys/brand.h>
+#include <sys/debug.h>
+#include <sys/ucred.h>
#include <inet/ip.h>
#include <inet/ip6.h>
#include <inet/ip_impl.h>
#include <inet/ip_ire.h>
#include <sys/lx_brand.h>
#include <sys/lx_misc.h>
+#include <sys/lx_socket.h>
#include <sys/ethernet.h>
#include <sys/dlpi.h>
-#include <sys/priv_const.h>
-#include <sys/priv_impl.h>
-#include <sys/priv.h>
#include <sys/policy.h>
/*
@@ -231,13 +231,6 @@
#define LX_NETLINK_IFA_F_NOPREFIXROUTE 0x200
/*
- * Linux address families.
- */
-#define LX_AF_INET 2
-#define LX_AF_INET6 10
-#define LX_AF_NETLINK 16
-
-/*
* Linux interface flags.
*/
#define LX_IFF_UP (1<<0)
@@ -306,6 +299,10 @@
#define LX_NETLINK_SO_RX_RING 6
#define LX_NETLINK_SO_TX_RING 7
+/* Internal socket flags */
+#define LXNLF_RECVUCRED 0x1
+
+/* nlmsg structure macros */
#define LXNLMSG_ALIGNTO 4
#define LXNLMSG_ALIGN(len) \
(((len) + LXNLMSG_ALIGNTO - 1) & ~(LXNLMSG_ALIGNTO - 1))
@@ -388,6 +385,7 @@ typedef struct lx_netlink_sock {
uint32_t lxns_port; /* port identifier */
uint32_t lxns_groups; /* group subscriptions */
uint32_t lxns_bufsize; /* buffer size */
+ uint32_t lxns_flags; /* socket flags */
} lx_netlink_sock_t;
typedef struct lx_netlink_reply {
@@ -438,7 +436,20 @@ static int
lx_netlink_setsockopt(sock_lower_handle_t handle, int level,
int option_name, const void *optval, socklen_t optlen, struct cred *cr)
{
- if (level == SOL_SOCKET) {
+ lx_netlink_sock_t *lxsock = (lx_netlink_sock_t *)handle;
+
+ if (level == SOL_SOCKET && option_name == SO_RECVUCRED) {
+ int *ival;
+ if (optlen != sizeof (int)) {
+ return (EINVAL);
+ }
+ ival = (int *)optval;
+ if (*ival == 0) {
+ lxsock->lxns_flags &= ~LXNLF_RECVUCRED;
+ } else {
+ lxsock->lxns_flags |= LXNLF_RECVUCRED;
+ }
+ } else if (level == SOL_SOCKET) {
return (0);
} else if (level != SOL_LX_NETLINK) {
return (EOPNOTSUPP);
@@ -531,10 +542,82 @@ lx_netlink_getsockname(sock_lower_handle_t handle, struct sockaddr *sa,
}
static mblk_t *
-lx_netlink_alloc_mp1()
+lx_netlink_alloc_mp1(lx_netlink_sock_t *lxsock)
{
- return (allocb(sizeof (struct T_unitdata_ind) +
- sizeof (lx_netlink_sockaddr_t), 0));
+ mblk_t *mp;
+ size_t size;
+ struct T_unitdata_ind *tunit;
+ lx_netlink_sockaddr_t *lxsa;
+ boolean_t send_ucred;
+
+ /*
+ * Certain netlink clients (such as systemd) will set SO_RECVUCRED
+ * (via the Linux SCM_CREDENTIALS) on the expectation that all replies
+ * will contain credentials passed via cmsg. They require this to
+ * authenticate those messages as having originated in the kernel by
+ * checking uc_pid == 0.
+ */
+ VERIFY(lxsock != NULL);
+ send_ucred = ((lxsock->lxns_flags & LXNLF_RECVUCRED) != 0);
+
+ /*
+ * Message structure:
+ * +----------------------------+
+ * | struct T_unit_data_ind |
+ * +----------------------------+
+ * | lx_netlink_sockaddr_t |
+ * +----------------------------+ -+
+ * | struct cmsghdr (SCM_UCRED) | |
+ * +----------------------------+ +-(optional)
+ * | struct ucred_s (cmsg data) | |
+ * +----------------------------+ -+
+ */
+ size = sizeof (*tunit) + sizeof (*lxsa);
+ if (send_ucred) {
+ size += sizeof (struct cmsghdr) +
+ ROUNDUP_cmsglen(sizeof (struct ucred_s));
+ }
+ mp = allocb(size, 0);
+ if (mp == NULL) {
+ return (NULL);
+ }
+
+ tunit = (struct T_unitdata_ind *)mp->b_rptr;
+ lxsa = (lx_netlink_sockaddr_t *)((caddr_t)tunit + sizeof (*tunit));
+ mp->b_wptr += size;
+
+ mp->b_datap->db_type = M_PROTO;
+ tunit->PRIM_type = T_UNITDATA_IND;
+ tunit->SRC_length = sizeof (*lxsa);
+ tunit->SRC_offset = (caddr_t)lxsa - (caddr_t)mp->b_rptr;
+
+ lxsa->lxnl_family = AF_LX_NETLINK;
+ lxsa->lxnl_port = 0;
+ lxsa->lxnl_groups = 0;
+ lxsa->lxnl_pad = 0;
+
+ if (send_ucred) {
+ struct cmsghdr *cmsg;
+ struct ucred_s *ucred;
+
+ cmsg = (struct cmsghdr *)((caddr_t)lxsa + sizeof (*lxsa));
+ ucred = (struct ucred_s *)CMSG_CONTENT(cmsg);
+ cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*ucred);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_UCRED;
+ bzero(ucred, sizeof (*ucred));
+ ucred->uc_size = sizeof (*ucred);
+ ucred->uc_zoneid = getzoneid();
+
+ tunit->OPT_length = sizeof (*cmsg) +
+ ROUNDUP_cmsglen(sizeof (*ucred));
+ tunit->OPT_offset = (caddr_t)cmsg - (caddr_t)mp->b_rptr;
+ } else {
+ tunit->OPT_length = 0;
+ tunit->OPT_offset = 0;
+ }
+
+ return (mp);
}
static lx_netlink_reply_t *
@@ -551,7 +634,7 @@ lx_netlink_reply(lx_netlink_sock_t *lxsock,
if ((err = allocb(sizeof (lx_netlink_err_t), 0)) == NULL)
return (NULL);
- if ((mp1 = lx_netlink_alloc_mp1()) == NULL) {
+ if ((mp1 = lx_netlink_alloc_mp1(lxsock)) == NULL) {
freeb(err);
return (NULL);
}
@@ -676,8 +759,6 @@ static void
lx_netlink_reply_sendup(lx_netlink_reply_t *reply, mblk_t *mp, mblk_t *mp1)
{
lx_netlink_sock_t *lxsock = reply->lxnr_sock;
- lx_netlink_sockaddr_t *lxsa;
- struct T_unitdata_ind *tunit;
int error;
/*
@@ -687,25 +768,8 @@ lx_netlink_reply_sendup(lx_netlink_reply_t *reply, mblk_t *mp, mblk_t *mp1)
*/
mp1->b_cont = mp;
- mp = mp1;
- mp->b_datap->db_type = M_PROTO;
-
- tunit = (struct T_unitdata_ind *)mp->b_rptr;
- tunit->PRIM_type = T_UNITDATA_IND;
- tunit->SRC_length = sizeof (lx_netlink_sockaddr_t);
- tunit->SRC_offset = sizeof (*tunit);
- tunit->OPT_length = 0;
-
- lxsa = (lx_netlink_sockaddr_t *)(mp->b_rptr + sizeof (*tunit));
- lxsa->lxnl_family = AF_LX_NETLINK;
- lxsa->lxnl_port = 0;
- lxsa->lxnl_groups = 0;
- lxsa->lxnl_pad = 0;
-
- mp->b_wptr += sizeof (*tunit) + sizeof (*lxsa);
-
- lxsock->lxns_upcalls->su_recv(lxsock->lxns_uphandle, mp,
- msgdsize(mp), 0, &error, NULL);
+ lxsock->lxns_upcalls->su_recv(lxsock->lxns_uphandle, mp1,
+ msgdsize(mp1), 0, &error, NULL);
if (error != 0)
lx_netlink_flowctrld++;
@@ -719,7 +783,7 @@ lx_netlink_reply_send(lx_netlink_reply_t *reply)
if (reply->lxnr_errno)
return;
- if ((mp1 = lx_netlink_alloc_mp1()) == NULL) {
+ if ((mp1 = lx_netlink_alloc_mp1(reply->lxnr_sock)) == NULL) {
reply->lxnr_errno = ENOMEM;
return;
}
@@ -752,18 +816,19 @@ lx_netlink_reply_done(lx_netlink_reply_t *reply)
}
mp = reply->lxnr_err;
+ VERIFY(mp != NULL);
+ reply->lxnr_err = NULL;
err = (lx_netlink_err_t *)mp->b_rptr;
hdr = &err->lxne_hdr;
+ mp->b_wptr += sizeof (lx_netlink_err_t);
+ err->lxne_failed = reply->lxnr_hdr;
+ err->lxne_errno = reply->lxnr_errno;
hdr->lxnh_type = LX_NETLINK_NLMSG_ERROR;
hdr->lxnh_seq = reply->lxnr_hdr.lxnh_seq;
hdr->lxnh_len = sizeof (lx_netlink_err_t);
hdr->lxnh_seq = reply->lxnr_hdr.lxnh_seq;
hdr->lxnh_pid = lxsock->lxns_port;
- err->lxne_failed = reply->lxnr_hdr;
- err->lxne_errno = reply->lxnr_errno;
- mp->b_wptr += sizeof (lx_netlink_err_t);
- reply->lxnr_err = NULL;
} else {
mp = reply->lxnr_mp;
VERIFY(mp != NULL);