netlink: decode NLMSG_ERROR messages

* netlink.c (decode_nlmsgerr, decode_payload): New functions.
(decode_nlmsghdr_with_payload): Use decode_payload.
* tests/netlink_protocol.c (send_query): Check decoding
of NLMSG_ERROR messages.
* NEWS: Mention this change.
This commit is contained in:
Дмитрий Левин 2017-04-17 04:37:41 +00:00
parent 51929c017a
commit 1be0e27b0b
3 changed files with 172 additions and 4 deletions

1
NEWS
View File

@ -20,6 +20,7 @@ Noteworthy changes in release ?.?? (????-??-??)
* Implemented decoding of statx syscall.
* Implemented decoding of NS_* ioctl commands.
* Implemented decoding of the remaining V4L2_BUF_TYPE_* types.
* Implemented decoding of NLMSG_ERROR netlink messages.
* Updated lists of ioctl commands from Linux 4.11.
* Bug fixes

View File

@ -69,6 +69,55 @@ print_nlmsghdr(struct tcb *tcp, const struct nlmsghdr *const nlmsghdr)
nlmsghdr->nlmsg_pid);
}
static void
decode_nlmsghdr_with_payload(struct tcb *const tcp,
const struct nlmsghdr *const nlmsghdr,
const kernel_ulong_t addr,
const kernel_ulong_t len);
static void
decode_nlmsgerr(struct tcb *const tcp,
kernel_ulong_t addr,
kernel_ulong_t len)
{
struct nlmsgerr err;
if (umove_or_printaddr(tcp, addr, &err.error))
return;
tprints("{error=");
if (err.error < 0 && (unsigned) -err.error < nerrnos) {
tprintf("-%s", errnoent[-err.error]);
} else {
tprintf("%d", err.error);
}
addr += offsetof(struct nlmsgerr, msg);
len -= offsetof(struct nlmsgerr, msg);
if (len) {
tprints(", msg=");
if (fetch_nlmsghdr(tcp, &err.msg, addr, len)) {
decode_nlmsghdr_with_payload(tcp, &err.msg, addr, len);
}
}
tprints("}");
}
static void
decode_payload(struct tcb *const tcp,
const struct nlmsghdr *const nlmsghdr,
const kernel_ulong_t addr,
const kernel_ulong_t len)
{
if (nlmsghdr->nlmsg_type == NLMSG_ERROR && len >= sizeof(int)) {
decode_nlmsgerr(tcp, addr, len);
} else {
printstrn(tcp, addr, len);
}
}
static void
decode_nlmsghdr_with_payload(struct tcb *const tcp,
const struct nlmsghdr *const nlmsghdr,
@ -83,9 +132,8 @@ decode_nlmsghdr_with_payload(struct tcb *const tcp,
nlmsghdr->nlmsg_len > len ? len : nlmsghdr->nlmsg_len;
if (nlmsg_len > NLMSG_HDRLEN) {
tprints(", ");
printstrn(tcp, addr + NLMSG_HDRLEN,
nlmsg_len - NLMSG_HDRLEN);
decode_payload(tcp, nlmsghdr, addr + NLMSG_HDRLEN,
nlmsg_len - NLMSG_HDRLEN);
}
tprints("}");

View File

@ -1,7 +1,7 @@
/*
* Check decoding of netlink protocol.
*
* Copyright (c) 2014-2016 Dmitry V. Levin <ldv@altlinux.org>
* Copyright (c) 2014-2017 Dmitry V. Levin <ldv@altlinux.org>
* Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
* All rights reserved.
*
@ -199,6 +199,124 @@ send_query(const int fd)
printf(", ...], %u, MSG_DONTWAIT, NULL, 0) = %s\n", msg_len, errstr);
}
static void
test_nlmsgerr(const int fd)
{
struct nlmsgerr *err;
struct nlmsghdr *nlh;
void *const nlh0 = tail_alloc(NLMSG_HDRLEN);
long rc;
/* error message without enough room for the error code */
nlh = nlh0;
nlh->nlmsg_len = NLMSG_HDRLEN + 4;
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_flags = NLM_F_REQUEST;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = 0;
rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
", seq=0, pid=0}, %p}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN,
nlh->nlmsg_len, sprintrc(rc));
nlh = nlh0 - 2;
nlh->nlmsg_len = NLMSG_HDRLEN + 2;
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_flags = NLM_F_REQUEST;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = 0;
memcpy(NLMSG_DATA(nlh), "42", 2);
rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
", seq=0, pid=0}, \"42\"}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc));
/* error message with room for the error code only */
nlh = nlh0 - sizeof(err->error);
nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(err->error);
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_flags = NLM_F_REQUEST;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = 0;
err = NLMSG_DATA(nlh);
err->error = 42;
rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
", seq=0, pid=0}, {error=42}}, %u, MSG_DONTWAIT, NULL, 0)"
" = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc));
err->error = -1;
rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
", seq=0, pid=0}, {error=-EPERM}}, %u, MSG_DONTWAIT, NULL, 0)"
" = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc));
err->error = -32767;
nlh->nlmsg_len += sizeof(err->msg.nlmsg_len);
rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
", seq=0, pid=0}, {error=-32767, msg=%p}}"
", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN,
nlh->nlmsg_len, sprintrc(rc));
/* error message with room for the error code and a header */
nlh = nlh0 - sizeof(*err);
nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err);
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_flags = NLM_F_REQUEST;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = 0;
err = NLMSG_DATA(nlh);
err->error = -13;
err->msg.nlmsg_len = NLMSG_HDRLEN;
err->msg.nlmsg_type = NLMSG_NOOP;
err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
err->msg.nlmsg_seq = 42;
err->msg.nlmsg_pid = 1234;
rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
", seq=0, pid=0}, {error=-EACCES"
", msg={{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
", seq=%u, pid=%u}}}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
err->msg.nlmsg_seq, err->msg.nlmsg_pid,
nlh->nlmsg_len, sprintrc(rc));
/* error message with room for the error code, a header, and some data */
nlh = nlh0 - sizeof(*err) - 4;
nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err) + 4;
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_flags = NLM_F_REQUEST;
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = 0;
err = NLMSG_DATA(nlh);
err->error = -13;
err->msg.nlmsg_len = NLMSG_HDRLEN + 4;
err->msg.nlmsg_type = NLMSG_NOOP;
err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
err->msg.nlmsg_seq = 421;
err->msg.nlmsg_pid = 12345;
memcpy(NLMSG_DATA(&err->msg), "abcd", 4);
rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST"
", seq=0, pid=0}, {error=-EACCES"
", msg={{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
", seq=%u, pid=%u}, \"abcd\"}}}, %u, MSG_DONTWAIT, NULL, 0)"
" = %s\n",
fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
err->msg.nlmsg_seq, err->msg.nlmsg_pid,
nlh->nlmsg_len, sprintrc(rc));
}
int main(void)
{
struct sockaddr_nl addr;
@ -227,6 +345,7 @@ int main(void)
free(path);
send_query(fd);
test_nlmsgerr(fd);
printf("+++ exited with 0 +++\n");