| From 567efd3b001b1d7a6a8d9d0388cfa750d8d59aae Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sat, 17 Jul 2021 17:19:19 -0400 |
| Subject: sctp: trim optlen when it's a huge value in sctp_setsockopt |
| |
| From: Xin Long <lucien.xin@gmail.com> |
| |
| [ Upstream commit 2f3fdd8d4805015fa964807e1c7f3d88f31bd389 ] |
| |
| After commit ca84bd058dae ("sctp: copy the optval from user space in |
| sctp_setsockopt"), it does memory allocation in sctp_setsockopt with |
| the optlen, and it would fail the allocation and return error if the |
| optlen from user space is a huge value. |
| |
| This breaks some sockopts, like SCTP_HMAC_IDENT, SCTP_RESET_STREAMS and |
| SCTP_AUTH_KEY, as when processing these sockopts before, optlen would |
| be trimmed to a biggest value it needs when optlen is a huge value, |
| instead of failing the allocation and returning error. |
| |
| This patch is to fix the allocation failure when it's a huge optlen from |
| user space by trimming it to the biggest size sctp sockopt may need when |
| necessary, and this biggest size is from sctp_setsockopt_reset_streams() |
| for SCTP_RESET_STREAMS, which is bigger than those for SCTP_HMAC_IDENT |
| and SCTP_AUTH_KEY. |
| |
| Fixes: ca84bd058dae ("sctp: copy the optval from user space in sctp_setsockopt") |
| Signed-off-by: Xin Long <lucien.xin@gmail.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/sctp/socket.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| diff --git a/net/sctp/socket.c b/net/sctp/socket.c |
| index a79d193ff872..dbd074f4d450 100644 |
| --- a/net/sctp/socket.c |
| +++ b/net/sctp/socket.c |
| @@ -4521,6 +4521,10 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, |
| } |
| |
| if (optlen > 0) { |
| + /* Trim it to the biggest size sctp sockopt may need if necessary */ |
| + optlen = min_t(unsigned int, optlen, |
| + PAGE_ALIGN(USHRT_MAX + |
| + sizeof(__u16) * sizeof(struct sctp_reset_streams))); |
| kopt = memdup_sockptr(optval, optlen); |
| if (IS_ERR(kopt)) |
| return PTR_ERR(kopt); |
| -- |
| 2.30.2 |
| |