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:
parent
51929c017a
commit
1be0e27b0b
1
NEWS
1
NEWS
@ -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
|
||||
|
54
netlink.c
54
netlink.c
@ -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("}");
|
||||
|
@ -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");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user