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 <[email protected]>
Acked-by: Stanislav Fomichev <[email protected]>
Signed-off-by: Breno Leitao <[email protected]>
---
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