The nlmsg_len() helper returned "int" from a u32 calculation that could possible go negative. WARN() if this calculation ever goes negative (instead returning 0), or if the result would be larger than INT_MAX (instead returning INT_MAX). Cc: "David S. Miller" <davem@xxxxxxxxxxxxx> Cc: Eric Dumazet <edumazet@xxxxxxxxxx> Cc: Jakub Kicinski <kuba@xxxxxxxxxx> Cc: Paolo Abeni <pabeni@xxxxxxxxxx> Cc: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> Cc: Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxx> Cc: Florian Westphal <fw@xxxxxxxxx> Cc: syzbot <syzkaller@xxxxxxxxxxxxxxxx> Cc: Yajun Deng <yajun.deng@xxxxxxxxx> Cc: netdev@xxxxxxxxxxxxxxx Cc: netfilter-devel@xxxxxxxxxxxxxxx Cc: coreteam@xxxxxxxxxxxxx Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx> --- include/net/netlink.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/net/netlink.h b/include/net/netlink.h index 7a2a9d3144ba..f8cb0543635e 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -576,7 +576,15 @@ static inline void *nlmsg_data(const struct nlmsghdr *nlh) */ static inline int nlmsg_len(const struct nlmsghdr *nlh) { - return nlh->nlmsg_len - NLMSG_HDRLEN; + u32 nlmsg_contents_len; + + if (WARN_ON_ONCE(check_sub_overflow(nlh->nlmsg_len, + (u32)NLMSG_HDRLEN, + &nlmsg_contents_len))) + return 0; + if (WARN_ON_ONCE(nlmsg_contents_len > INT_MAX)) + return INT_MAX; + return nlmsg_contents_len; } /** -- 2.34.1