netlink: use slice allocator for "struct nl_msg"

This commit is contained in:
Thomas Haller 2018-02-16 17:48:20 +01:00
parent ff7f8b3a79
commit 5376aa2db7

View file

@ -304,7 +304,7 @@ nlmsg_alloc_size (size_t len)
if (len < sizeof (struct nlmsghdr)) if (len < sizeof (struct nlmsghdr))
len = sizeof (struct nlmsghdr); len = sizeof (struct nlmsghdr);
nm = g_new0 (struct nl_msg, 1); nm = g_slice_new0 (struct nl_msg);
nm->nm_refcnt = 1; nm->nm_refcnt = 1;
nm->nm_protocol = -1; nm->nm_protocol = -1;
@ -648,8 +648,8 @@ void nlmsg_free (struct nl_msg *msg)
msg->nm_refcnt--; msg->nm_refcnt--;
if (msg->nm_refcnt <= 0) { if (msg->nm_refcnt <= 0) {
free(msg->nm_nlh); g_free (msg->nm_nlh);
free(msg); g_slice_free (struct nl_msg, msg);
} }
} }
@ -1054,32 +1054,26 @@ int
nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb)
{ {
int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0; int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0;
unsigned char *buf = NULL; gs_free unsigned char *buf = NULL;
struct nlmsghdr *hdr; struct nlmsghdr *hdr;
struct sockaddr_nl nla = { 0 };
/* gs_free struct ucred *creds = NULL;
nla is passed on to not only to nl_recv() but may also be passed
to a function pointer provided by the caller which may or may not
initialize the variable. Thomas Graf.
*/
struct sockaddr_nl nla = {0};
struct nl_msg *msg = NULL;
struct ucred *creds = NULL;
continue_reading: continue_reading:
n = nl_recv(sk, &nla, &buf, &creds); n = nl_recv (sk, &nla, &buf, &creds);
if (n <= 0) if (n <= 0)
return n; return n;
hdr = (struct nlmsghdr *) buf; hdr = (struct nlmsghdr *) buf;
while (nlmsg_ok(hdr, n)) { while (nlmsg_ok (hdr, n)) {
nlmsg_free(msg); nm_auto_nlmsg struct nl_msg *msg = NULL;
msg = nlmsg_alloc_convert(hdr);
nlmsg_set_proto(msg, sk->s_proto); msg = nlmsg_alloc_convert (hdr);
nlmsg_set_src(msg, &nla);
nlmsg_set_proto (msg, sk->s_proto);
nlmsg_set_src (msg, &nla);
if (creds) if (creds)
nlmsg_set_creds(msg, creds); nlmsg_set_creds (msg, creds);
nrecv++; nrecv++;
@ -1178,31 +1172,22 @@ skip:
hdr = nlmsg_next(hdr, &n); hdr = nlmsg_next(hdr, &n);
} }
nlmsg_free(msg);
free(buf);
free(creds);
buf = NULL;
msg = NULL;
creds = NULL;
if (multipart) { if (multipart) {
/* Multipart message not yet complete, continue reading */ /* Multipart message not yet complete, continue reading */
nm_clear_g_free (&creds);
nm_clear_g_free (&buf);
goto continue_reading; goto continue_reading;
} }
stop: stop:
err = 0; err = 0;
out:
nlmsg_free(msg);
free(buf);
free(creds);
out:
if (interrupted) if (interrupted)
err = -NLE_DUMP_INTR; err = -NLE_DUMP_INTR;
if (!err) return err ?: nrecv;
err = nrecv;
return err;
} }
int int
@ -1313,14 +1298,16 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
.msg_iov = &iov, .msg_iov = &iov,
.msg_iovlen = 1, .msg_iovlen = 1,
}; };
struct ucred* tmpcreds = NULL; gs_free struct ucred* tmpcreds = NULL;
int retval = 0; int retval = 0;
if (!buf || !nla) nm_assert (nla);
g_return_val_if_reached (-NLE_BUG); nm_assert (buf && !*buf);
nm_assert (!creds || !*creds);
if ( (sk->s_flags & NL_MSG_PEEK) if ( (sk->s_flags & NL_MSG_PEEK)
|| (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0)) || ( !(sk->s_flags & NL_MSG_PEEK_EXPLICIT)
&& sk->s_bufsize == 0))
flags |= MSG_PEEK | MSG_TRUNC; flags |= MSG_PEEK | MSG_TRUNC;
if (page_size == 0) if (page_size == 0)
@ -1330,11 +1317,11 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
iov.iov_base = g_malloc (iov.iov_len); iov.iov_base = g_malloc (iov.iov_len);
if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) { if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); msg.msg_controllen = CMSG_SPACE (sizeof(struct ucred));
msg.msg_control = g_malloc (msg.msg_controllen); msg.msg_control = g_malloc (msg.msg_controllen);
} }
retry:
retry:
n = recvmsg(sk->s_fd, &msg, flags); n = recvmsg(sk->s_fd, &msg, flags);
if (!n) { if (!n) {
retval = 0; retval = 0;
@ -1349,22 +1336,17 @@ retry:
} }
if (msg.msg_flags & MSG_CTRUNC) { if (msg.msg_flags & MSG_CTRUNC) {
void *tmp;
if (msg.msg_controllen == 0) { if (msg.msg_controllen == 0) {
retval = -NLE_MSG_TRUNC; retval = -NLE_MSG_TRUNC;
goto abort; goto abort;
} }
msg.msg_controllen *= 2; msg.msg_controllen *= 2;
tmp = g_realloc (msg.msg_control, msg.msg_controllen); msg.msg_control = g_realloc (msg.msg_control, msg.msg_controllen);
msg.msg_control = tmp;
goto retry; goto retry;
} }
if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) { if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
void *tmp;
/* respond with error to an incomplete message */ /* respond with error to an incomplete message */
if (flags == 0) { if (flags == 0) {
retval = -NLE_MSG_TRUNC; retval = -NLE_MSG_TRUNC;
@ -1374,9 +1356,8 @@ retry:
/* Provided buffer is not long enough, enlarge it /* Provided buffer is not long enough, enlarge it
* to size of n (which should be total length of the message) * to size of n (which should be total length of the message)
* and try again. */ * and try again. */
iov.iov_base = g_realloc (iov.iov_base, n);
iov.iov_len = n; iov.iov_len = n;
tmp = g_realloc (iov.iov_base, iov.iov_len);
iov.iov_base = tmp;
flags = 0; flags = 0;
goto retry; goto retry;
} }
@ -1400,26 +1381,22 @@ retry:
continue; continue;
if (cmsg->cmsg_type != SCM_CREDENTIALS) if (cmsg->cmsg_type != SCM_CREDENTIALS)
continue; continue;
tmpcreds = g_malloc (sizeof(*tmpcreds)); tmpcreds = g_memdup (CMSG_DATA(cmsg), sizeof(*tmpcreds));
memcpy(tmpcreds, CMSG_DATA(cmsg), sizeof(*tmpcreds));
break; break;
} }
} }
retval = n; retval = n;
abort: abort:
free(msg.msg_control); g_free (msg.msg_control);
if (retval <= 0) { if (retval <= 0) {
free(iov.iov_base); g_free (iov.iov_base);
iov.iov_base = NULL; return retval;
free(tmpcreds); }
tmpcreds = NULL;
} else
*buf = iov.iov_base;
if (creds)
*creds = tmpcreds;
*buf = iov.iov_base;
NM_SET_OUT (creds, g_steal_pointer (&tmpcreds));
return retval; return retval;
} }