diff options
author | Dmitry V. Levin <ldv@strace.io> | 2021-05-02 08:00:00 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2021-05-02 08:00:00 +0000 |
commit | bd93379586c4a117eb1e8dea88c64f39da4e2944 (patch) | |
tree | 47b5396a3fa1a949b720c71c183b19f81864eff6 | |
parent | f7c07acc1bef1b0682f0fc542bde44572f659a27 (diff) | |
download | strace-bd93379586c4a117eb1e8dea88c64f39da4e2944.tar.gz |
netlink: validate struct nlmsgerr.msg.nlmsg_len
* src/netlink.c (decode_nlmsgerr): Use sizeof(struct nlmsgerr.msg)
instead of struct nlmsgerr.msg.nlmsg_len if the latter is invalid.
* tests/netlink_protocol.c (test_nlmsgerr): Check it.
-rw-r--r-- | src/netlink.c | 18 | ||||
-rw-r--r-- | tests/netlink_protocol.c | 26 |
2 files changed, 40 insertions, 4 deletions
diff --git a/src/netlink.c b/src/netlink.c index f5487fbad..cf7eee83d 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -533,10 +533,20 @@ decode_nlmsgerr(struct tcb *const tcp, tprint_struct_next(); tprints_field_name("msg"); if (fetch_nlmsghdr(tcp, &err.msg, addr, len, false)) { - unsigned int payload = - capped ? sizeof(err.msg) : err.msg.nlmsg_len; - if (payload > len) - payload = len; + /* + * If err.msg.nlmsg_len < sizeof(err.msg), then it is + * invalid and sizeof(err.msg) would be used instead. + */ + const unsigned int nlmsg_len = + MAX(sizeof(err.msg), err.msg.nlmsg_len); + /* + * Despite of fetch_nlmsghdr guarantee that + * len >= sizeof(err.msg) + * a valid nlmsg_len can exceed sizeof(err.msg) + * and an invalid nlmsg_len can exceed len. + */ + const unsigned int payload = + MIN(len, capped ? sizeof(err.msg) : nlmsg_len); decode_nlmsghdr_with_payload(tcp, fd, family, &err.msg, addr, payload); diff --git a/tests/netlink_protocol.c b/tests/netlink_protocol.c index bb368cb19..9cc9535c8 100644 --- a/tests/netlink_protocol.c +++ b/tests/netlink_protocol.c @@ -285,6 +285,32 @@ test_nlmsgerr(const int fd) err->msg.nlmsg_seq, err->msg.nlmsg_pid, nlh->nlmsg_len, sprintrc(rc)); + /* err->msg.nlmsg_len < sizeof(err->msg) */ + err->msg.nlmsg_len = sizeof(err->msg.nlmsg_len); + + rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); + printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR" + ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}" + ", {error=-EACCES, msg={nlmsg_len=%u, nlmsg_type=NLMSG_NOOP" + ", nlmsg_flags=NLM_F_REQUEST|0x%x, nlmsg_seq=%u, nlmsg_pid=%d}}]" + ", %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)); + + /* nlh->nlmsg_len < NLMSG_HDRLEN + err->msg.nlmsg_len */ + err->msg.nlmsg_len = NLMSG_HDRLEN + 4; + + rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); + printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR" + ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}" + ", {error=-EACCES, msg={nlmsg_len=%u, nlmsg_type=NLMSG_NOOP" + ", nlmsg_flags=NLM_F_REQUEST|0x%x, nlmsg_seq=%u, nlmsg_pid=%d}}]" + ", %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; |