do_ipv6_getsockopt() reads optlen into an int and never checks its sign. Most of what consumes len compares it as unsigned, so a negative optlen reads as a huge buffer, and the reply depends on the option. The int options clamp it to their own size: len = min_t(unsigned int, sizeof(int), len); so getsockopt(fd, SOL_IPV6, IPV6_TCLASS, buf, &len) with len set to -1 answers 4 bytes and reports 4, rather than failing. The other options see a huge buffer. The sticky options reply with their whole header, IPV6_2292PKTOPTIONS writes every pending control message without a limit, and IPV6_PATHMTU and IPV6_FLOWLABEL_MGR pass their length check. do_ip_getsockopt() rejects a negative optlen, but doing that here would turn a call that works today into an error for a caller that passes an uninitialized length. Answer it as 4, as the int options do, for every option this function handles itself. That leaves the int options as they are. The sticky headers are cut to 4 bytes, IPV6_2292PKTOPTIONS gets a 4 byte control buffer, and IPV6_PATHMTU and IPV6_FLOWLABEL_MGR fail with -EINVAL, as they do for any other undersized buffer. MRT6_* is dispatched earlier and keeps rejecting a negative optlen, and the netfilter fallback still sees the caller's value. This changes what callers that pass a negative length see. It is a behaviour change, not a fix, so there is no Fixes: tag. The conversion of this function to sockopt_t builds its buffers from optlen, which the standard helpers reject when negative, so the answer has to be settled before that. Suggested-by: David Laight Acked-by: Stanislav Fomichev Signed-off-by: Breno Leitao --- net/ipv6/ipv6_sockglue.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4b3536571c9804..700133e2fd11c2 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1002,6 +1002,11 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname, if (copy_from_sockptr(&len, optlen, sizeof(int))) return -EFAULT; + /* Historic bug compatibility: take a negative optlen as 4, as the + * int options always did. + */ + if (len < 0) + len = 4; switch (optname) { case MCAST_MSFILTER: if (in_compat_syscall()) -- 2.53.0-Meta