From bbae86d3d2997a853ca0365e8eb7a3ca7489ee09 Mon Sep 17 00:00:00 2001 From: Sebastien Bacher Date: Fri, 25 Jan 2019 11:24:41 +0100 Subject: New upstream version 1.15.2 --- src/platform/nm-netlink.c | 262 ++++++++++++++++++++-------------------------- 1 file changed, 111 insertions(+), 151 deletions(-) (limited to 'src/platform/nm-netlink.c') diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 3e2ad911..6abc1c3a 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -25,6 +25,8 @@ #include #include +#include "nm-utils/nm-errno.h" + /*****************************************************************************/ #ifndef SOL_NETLINK @@ -42,16 +44,14 @@ #define NETLINK_EXT_ACK 11 #endif -#define NL_MSG_CRED_PRESENT 1 - struct nl_msg { int nm_protocol; - int nm_flags; struct sockaddr_nl nm_src; struct sockaddr_nl nm_dst; struct ucred nm_creds; struct nlmsghdr * nm_nlh; size_t nm_size; + bool nm_creds_has:1; }; struct nl_sock { @@ -67,38 +67,6 @@ struct nl_sock { /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_ITEM (NLE_UNSPEC, "NLE_UNSPEC"), - NM_UTILS_LOOKUP_ITEM (NLE_BUG, "NLE_BUG"), - NM_UTILS_LOOKUP_ITEM (NLE_NATIVE_ERRNO, "NLE_NATIVE_ERRNO"), - - NM_UTILS_LOOKUP_ITEM (NLE_ATTRSIZE, "NLE_ATTRSIZE"), - NM_UTILS_LOOKUP_ITEM (NLE_BAD_SOCK, "NLE_BAD_SOCK"), - NM_UTILS_LOOKUP_ITEM (NLE_DUMP_INTR, "NLE_DUMP_INTR"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_OVERFLOW, "NLE_MSG_OVERFLOW"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TOOSHORT, "NLE_MSG_TOOSHORT"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TRUNC, "NLE_MSG_TRUNC"), - NM_UTILS_LOOKUP_ITEM (NLE_SEQ_MISMATCH, "NLE_SEQ_MISMATCH"), -) - -const char * -nl_geterror (int nlerr) -{ - const char *s; - - nlerr = nl_errno (nlerr); - - if (nlerr >= _NLE_BASE) { - s = _geterror (nlerr); - if (s) - return s; - } - return g_strerror (nlerr); -} - -/*****************************************************************************/ - NM_UTILS_ENUM2STR_DEFINE (nl_nlmsgtype2str, int, NM_UTILS_ENUM2STR (NLMSG_NOOP, "NOOP"), NM_UTILS_ENUM2STR (NLMSG_ERROR, "ERROR"), @@ -285,20 +253,6 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) /*****************************************************************************/ -static int -get_default_page_size (void) -{ - static int val = 0; - int v; - - if (G_UNLIKELY (val == 0)) { - v = getpagesize (); - g_assert (v > 0); - val = v; - } - return val; -} - struct nl_msg * nlmsg_alloc_size (size_t len) { @@ -328,7 +282,7 @@ nlmsg_alloc_size (size_t len) struct nl_msg * nlmsg_alloc (void) { - return nlmsg_alloc_size (get_default_page_size ()); + return nlmsg_alloc_size (nm_utils_getpagesize ()); } struct nl_msg * @@ -385,7 +339,7 @@ nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { if (!nlmsg_valid_hdr (nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; + return -NME_NL_MSG_TOOSHORT; return nla_parse (tb, maxtype, nlmsg_attrdata (nlh, hdrlen), nlmsg_attrlen (nlh, hdrlen), policy); @@ -465,7 +419,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data) nla = nla_reserve (msg, attrtype, datalen); if (!nla) { if (datalen < 0) - g_return_val_if_reached (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); return -ENOMEM; } @@ -531,7 +485,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) nla_nest_cancel (msg, start); /* Return error only if nlattr size was exceeded */ - return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE; + return (len == NLA_HDRLEN) ? 0 : -NME_NL_ATTRSIZE; } start->nla_len = len; @@ -539,13 +493,13 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) pad = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; if (pad > 0) { /* - * Data inside attribute does not end at a alignment boundry. + * Data inside attribute does not end at a alignment boundary. * Pad accordingly and accoun for the additional space in * the message. nlmsg_reserve() may never fail in this situation, * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. */ if (!nlmsg_reserve (msg, pad, 0)) - g_return_val_if_reached (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); } return 0; @@ -580,7 +534,7 @@ validate_nla (const struct nlattr *nla, int maxtype, pt = &policy[type]; if (pt->type > NLA_TYPE_MAX) - g_return_val_if_reached (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); if (pt->minlen) minlen = pt->minlen; @@ -588,15 +542,15 @@ validate_nla (const struct nlattr *nla, int maxtype, minlen = nla_attr_minlen[pt->type]; if (nla_len (nla) < minlen) - return -NLE_UNSPEC; + return -NME_UNSPEC; if (pt->maxlen && nla_len (nla) > pt->maxlen) - return -NLE_UNSPEC; + return -NME_UNSPEC; if (pt->type == NLA_STRING) { const char *data = nla_data (nla); if (data[nla_len (nla) - 1] != '\0') - return -NLE_UNSPEC; + return -NME_UNSPEC; } return 0; @@ -607,7 +561,7 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, const struct nla_policy *policy) { struct nlattr *nla; - int rem, nlerr; + int rem, nmerr; memset (tb, 0, sizeof (struct nlattr *) * (maxtype + 1)); @@ -618,17 +572,17 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, continue; if (policy) { - nlerr = validate_nla (nla, maxtype, policy); - if (nlerr < 0) + nmerr = validate_nla (nla, maxtype, policy); + if (nmerr < 0) goto errout; } tb[type] = nla; } - nlerr = 0; + nmerr = 0; errout: - return nlerr; + return nmerr; } /*****************************************************************************/ @@ -654,7 +608,7 @@ nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr) struct ucred * nlmsg_get_creds (struct nl_msg *msg) { - if (msg->nm_flags & NL_MSG_CRED_PRESENT) + if (msg->nm_creds_has) return &msg->nm_creds; return NULL; } @@ -662,8 +616,11 @@ nlmsg_get_creds (struct nl_msg *msg) void nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds) { - memcpy (&msg->nm_creds, creds, sizeof (*creds)); - msg->nm_flags |= NL_MSG_CRED_PRESENT; + if (creds) { + memcpy (&msg->nm_creds, creds, sizeof (*creds)); + msg->nm_creds_has = TRUE; + } else + msg->nm_creds_has = FALSE; } /*****************************************************************************/ @@ -754,7 +711,7 @@ genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], struct genlmsghdr *ghdr; if (!genlmsg_valid_hdr (nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; + return -NME_NL_MSG_TOOSHORT; ghdr = nlmsg_data (nlh); return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), @@ -791,7 +748,7 @@ int genl_ctrl_resolve (struct nl_sock *sk, const char *name) { nm_auto_nlmsg struct nl_msg *msg = NULL; - int nlerr; + int nmerr; gint32 response_data = -1; const struct nl_cb cb = { .valid_cb = _genl_parse_getfamily, @@ -804,25 +761,25 @@ genl_ctrl_resolve (struct nl_sock *sk, const char *name) 0, 0, CTRL_CMD_GETFAMILY, 1)) return -ENOMEM; - nlerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name); - if (nlerr < 0) - return nlerr; + nmerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name); + if (nmerr < 0) + return nmerr; - nlerr = nl_send_auto (sk, msg); - if (nlerr < 0) - return nlerr; + nmerr = nl_send_auto (sk, msg); + if (nmerr < 0) + return nmerr; - nlerr = nl_recvmsgs (sk, &cb); - if (nlerr < 0) - return nlerr; + nmerr = nl_recvmsgs (sk, &cb); + if (nmerr < 0) + return nmerr; /* If search was successful, request may be ACKed after data */ - nlerr = nl_wait_for_ack (sk, NULL); - if (nlerr < 0) - return nlerr; + nmerr = nl_wait_for_ack (sk, NULL); + if (nmerr < 0) + return nmerr; if (response_data < 0) - return -NLE_UNSPEC; + return -NME_UNSPEC; return response_data; } @@ -879,12 +836,12 @@ nl_socket_set_passcred (struct nl_sock *sk, int state) int err; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; err = setsockopt (sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof (state)); if (err < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); if (state) sk->s_flags |= NL_SOCK_PASSCRED; @@ -912,10 +869,10 @@ int nl_socket_set_nonblocking (const struct nl_sock *sk) { if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; if (fcntl (sk->s_fd, F_SETFL, O_NONBLOCK) < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); return 0; } @@ -932,18 +889,18 @@ nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf) txbuf = 32768; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; err = setsockopt (sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof (txbuf)); if (err < 0) { - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); } err = setsockopt (sk->s_fd, SOL_SOCKET, SO_RCVBUF, &rxbuf, sizeof (rxbuf)); if (err < 0) { - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); } return 0; @@ -956,14 +913,14 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...) va_list ap; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; va_start (ap, group); while (group != 0) { if (group < 0) { va_end (ap); - g_return_val_if_reached (-NLE_BUG); + g_return_val_if_reached (-NME_BUG); } err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, @@ -972,7 +929,7 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...) int errsv = errno; va_end (ap); - return -nl_syserr2nlerr (errsv); + return -nm_errno_from_native (errsv); } group = va_arg (ap, int); @@ -989,12 +946,12 @@ nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable) int err, val; if (sk->s_fd == -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; val = !!enable; err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof (val)); if (err < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); return 0; } @@ -1008,21 +965,21 @@ void nl_socket_disable_msg_peek (struct nl_sock *sk) int nl_connect (struct nl_sock *sk, int protocol) { - int err, nlerr; + int err, nmerr; socklen_t addrlen; struct sockaddr_nl local = { 0 }; if (sk->s_fd != -1) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); if (sk->s_fd < 0) { - nlerr = -nl_syserr2nlerr (errno); + nmerr = -nm_errno_from_native (errno); goto errout; } - nlerr = nl_socket_set_buffer_size (sk, 0, 0); - if (nlerr < 0) + nmerr = nl_socket_set_buffer_size (sk, 0, 0); + if (nmerr < 0) goto errout; nm_assert (sk->s_local.nl_pid == 0); @@ -1030,7 +987,7 @@ nl_connect (struct nl_sock *sk, int protocol) err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local, sizeof (sk->s_local)); if (err != 0) { - nlerr = -nl_syserr2nlerr (errno); + nmerr = -nm_errno_from_native (errno); goto errout; } @@ -1038,17 +995,17 @@ nl_connect (struct nl_sock *sk, int protocol) err = getsockname (sk->s_fd, (struct sockaddr *) &local, &addrlen); if (err < 0) { - nlerr = -nl_syserr2nlerr (errno); + nmerr = -nm_errno_from_native (errno); goto errout; } if (addrlen != sizeof (local)) { - nlerr = -NLE_UNSPEC; + nmerr = -NME_UNSPEC; goto errout; } if (local.nl_family != AF_NETLINK) { - nlerr = -NLE_UNSPEC; + nmerr = -NME_UNSPEC; goto errout; } @@ -1062,7 +1019,7 @@ errout: close (sk->s_fd); sk->s_fd = -1; } - return nlerr; + return nmerr; } /*****************************************************************************/ @@ -1098,22 +1055,22 @@ nl_wait_for_ack (struct nl_sock *sk, do { \ const struct nl_cb *_cb = (cb); \ \ - if (_cb->type##_cb) { \ + if (_cb && _cb->type##_cb) { \ /* the returned value here must be either a negative * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \ - nlerr = _cb->type##_cb ((msg), _cb->type##_arg); \ - switch (nlerr) { \ + nmerr = _cb->type##_cb ((msg), _cb->type##_arg); \ + switch (nmerr) { \ case NL_OK: \ - nlerr = 0; \ + nmerr = 0; \ break; \ case NL_SKIP: \ goto skip; \ case NL_STOP: \ goto stop; \ default: \ - if (nlerr >= 0) { \ + if (nmerr >= 0) { \ nm_assert_not_reached (); \ - nlerr = -NLE_BUG; \ + nmerr = -NME_BUG; \ } \ goto out; \ } \ @@ -1123,14 +1080,15 @@ do { \ int nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) { - int n, nlerr = 0, multipart = 0, interrupted = 0, nrecv = 0; + int n, nmerr = 0, multipart = 0, interrupted = 0, nrecv = 0; gs_free unsigned char *buf = NULL; struct nlmsghdr *hdr; struct sockaddr_nl nla = { 0 }; - gs_free struct ucred *creds = NULL; + struct ucred creds; + gboolean creds_has; continue_reading: - n = nl_recv (sk, &nla, &buf, &creds); + n = nl_recv (sk, &nla, &buf, &creds, &creds_has); if (n <= 0) return n; @@ -1142,15 +1100,14 @@ continue_reading: nlmsg_set_proto (msg, sk->s_proto); nlmsg_set_src (msg, &nla); - if (creds) - nlmsg_set_creds (msg, creds); + nlmsg_set_creds (msg, creds_has ? &creds : NULL); nrecv++; /* Only do sequence checking if auto-ack mode is enabled */ if (! (sk->s_flags & NL_NO_AUTO_ACK)) { if (hdr->nlmsg_seq != sk->s_seq_expect) { - nlerr = -NLE_SEQ_MISMATCH; + nmerr = -NME_NL_SEQ_MISMATCH; goto out; } } @@ -1196,7 +1153,7 @@ continue_reading: * quit parsing. The user may overrule this action by retuning * NL_SKIP or NL_PROCEED (dangerous) */ else if (hdr->nlmsg_type == NLMSG_OVERRUN) { - nlerr = -NLE_MSG_OVERFLOW; + nmerr = -NME_NL_MSG_OVERFLOW; goto out; } @@ -1209,27 +1166,27 @@ continue_reading: * is to stop parsing. The user may overrule * this action by returning NL_SKIP or * NL_PROCEED (dangerous) */ - nlerr = -NLE_MSG_TRUNC; + nmerr = -NME_NL_MSG_TRUNC; goto out; } if (e->error) { /* Error message reported back from kernel. */ - if (cb->err_cb) { + if (cb && cb->err_cb) { /* the returned value here must be either a negative * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ - nlerr = cb->err_cb (&nla, e, + nmerr = cb->err_cb (&nla, e, cb->err_arg); - if (nlerr < 0) + if (nmerr < 0) goto out; - else if (nlerr == NL_SKIP) + else if (nmerr == NL_SKIP) goto skip; - else if (nlerr == NL_STOP) { - nlerr = -nl_syserr2nlerr (e->error); + else if (nmerr == NL_STOP) { + nmerr = -nm_errno_from_native (e->error); goto out; } - nm_assert (nlerr == NL_OK); + nm_assert (nmerr == NL_OK); } else { - nlerr = -nl_syserr2nlerr (e->error); + nmerr = -nm_errno_from_native (e->error); goto out; } } else @@ -1241,27 +1198,26 @@ continue_reading: NL_CB_CALL (cb, valid, msg); } skip: - nlerr = 0; + nmerr = 0; hdr = nlmsg_next (hdr, &n); } if (multipart) { /* Multipart message not yet complete, continue reading */ - nm_clear_g_free (&creds); nm_clear_g_free (&buf); goto continue_reading; } stop: - nlerr = 0; + nmerr = 0; out: if (interrupted) - nlerr = -NLE_DUMP_INTR; + nmerr = -NME_NL_DUMP_INTR; - nm_assert (nlerr <= 0); - return nlerr ?: nrecv; + nm_assert (nmerr <= 0); + return nmerr ?: nrecv; } int @@ -1270,13 +1226,13 @@ nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) int ret; if (sk->s_fd < 0) - return -NLE_BAD_SOCK; + return -NME_NL_BAD_SOCK; nlmsg_set_src (msg, &sk->s_local); ret = sendmsg (sk->s_fd, hdr, 0); if (ret < 0) - return -nl_syserr2nlerr (errno); + return -nm_errno_from_native (errno); return ret; } @@ -1359,12 +1315,14 @@ int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg) } int -nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds) +nl_recv (struct nl_sock *sk, + struct sockaddr_nl *nla, + unsigned char **buf, + struct ucred *out_creds, + gboolean *out_creds_has) { ssize_t n; int flags = 0; - static int page_size = 0; struct iovec iov; struct msghdr msg = { .msg_name = (void *) nla, @@ -1372,25 +1330,24 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, .msg_iov = &iov, .msg_iovlen = 1, }; - gs_free struct ucred* tmpcreds = NULL; + struct ucred tmpcreds; + gboolean tmpcreds_has = FALSE; int retval; nm_assert (nla); nm_assert (buf && !*buf); - nm_assert (!creds || !*creds); + nm_assert (!out_creds_has == !out_creds); if ( (sk->s_flags & NL_MSG_PEEK) || ( !(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0)) flags |= MSG_PEEK | MSG_TRUNC; - if (page_size == 0) - page_size = getpagesize () * 4; - - iov.iov_len = sk->s_bufsize ?: page_size; + iov.iov_len = sk->s_bufsize + ?: (((size_t) nm_utils_getpagesize ()) * 4u); iov.iov_base = g_malloc (iov.iov_len); - if ( creds + if ( out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { msg.msg_controllen = CMSG_SPACE (sizeof (struct ucred)); msg.msg_control = g_malloc (msg.msg_controllen); @@ -1407,13 +1364,13 @@ retry: if (errno == EINTR) goto retry; - retval = -nl_syserr2nlerr (errno); + retval = -nm_errno_from_native (errno); goto abort; } if (msg.msg_flags & MSG_CTRUNC) { if (msg.msg_controllen == 0) { - retval = -NLE_MSG_TRUNC; + retval = -NME_NL_MSG_TRUNC; goto abort; } @@ -1426,7 +1383,7 @@ retry: || (msg.msg_flags & MSG_TRUNC)) { /* respond with error to an incomplete message */ if (flags == 0) { - retval = -NLE_MSG_TRUNC; + retval = -NME_NL_MSG_TRUNC; goto abort; } @@ -1446,11 +1403,11 @@ retry: } if (msg.msg_namelen != sizeof (struct sockaddr_nl)) { - retval = -NLE_UNSPEC; + retval = -NME_UNSPEC; goto abort; } - if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) { + if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { @@ -1458,7 +1415,8 @@ retry: continue; if (cmsg->cmsg_type != SCM_CREDENTIALS) continue; - tmpcreds = nm_memdup (CMSG_DATA (cmsg), sizeof (*tmpcreds)); + memcpy (&tmpcreds, CMSG_DATA (cmsg), sizeof (tmpcreds)); + tmpcreds_has = TRUE; break; } } @@ -1474,6 +1432,8 @@ abort: } *buf = iov.iov_base; - NM_SET_OUT (creds, g_steal_pointer (&tmpcreds)); + if (out_creds && tmpcreds_has) + *out_creds = tmpcreds; + NM_SET_OUT (out_creds_has, tmpcreds_has); return retval; } -- cgit 1.3.0-6-gf8a5