diff mbox series

[v1,net] tcp: Fix shift-out-of-bounds in dctcp_update_alpha().

Message ID 20240517091626.32772-1-kuniyu@amazon.com (mailing list archive)
State Accepted
Commit 3ebc46ca8675de6378e3f8f40768e180bb8afa66
Delegated to: Netdev Maintainers
Headers show
Series [v1,net] tcp: Fix shift-out-of-bounds in dctcp_update_alpha(). | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 920 this patch: 920
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers fail 1 blamed authors not CCed: stephen@networkplumber.org; 1 maintainers not CCed: stephen@networkplumber.org
netdev/build_clang success Errors and warnings before: 925 this patch: 925
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api warning Found: 'module_param' was: 1 now: 1
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 925 this patch: 925
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 19 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-05-19--03-00 (tests: 1039)

Commit Message

Kuniyuki Iwashima May 17, 2024, 9:16 a.m. UTC
In dctcp_update_alpha(), we use a module parameter dctcp_shift_g
as follows:

  alpha -= min_not_zero(alpha, alpha >> dctcp_shift_g);
  ...
  delivered_ce <<= (10 - dctcp_shift_g);

It seems syzkaller started fuzzing module parameters and triggered
shift-out-of-bounds [0] by setting 100 to dctcp_shift_g:

  memcpy((void*)0x20000080,
         "/sys/module/tcp_dctcp/parameters/dctcp_shift_g\000", 47);
  res = syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x20000080ul,
                /*flags=*/2ul, /*mode=*/0ul);
  memcpy((void*)0x20000000, "100\000", 4);
  syscall(__NR_write, /*fd=*/r[0], /*val=*/0x20000000ul, /*len=*/4ul);

Let's limit the max value of dctcp_shift_g by param_set_uint_minmax().

With this patch:

  # echo 10 > /sys/module/tcp_dctcp/parameters/dctcp_shift_g
  # cat /sys/module/tcp_dctcp/parameters/dctcp_shift_g
  10
  # echo 11 > /sys/module/tcp_dctcp/parameters/dctcp_shift_g
  -bash: echo: write error: Invalid argument

[0]:
UBSAN: shift-out-of-bounds in net/ipv4/tcp_dctcp.c:143:12
shift exponent 100 is too large for 32-bit type 'u32' (aka 'unsigned int')
CPU: 0 PID: 8083 Comm: syz-executor345 Not tainted 6.9.0-05151-g1b294a1f3561 #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:88 [inline]
 dump_stack_lvl+0x201/0x300 lib/dump_stack.c:114
 ubsan_epilogue lib/ubsan.c:231 [inline]
 __ubsan_handle_shift_out_of_bounds+0x346/0x3a0 lib/ubsan.c:468
 dctcp_update_alpha+0x540/0x570 net/ipv4/tcp_dctcp.c:143
 tcp_in_ack_event net/ipv4/tcp_input.c:3802 [inline]
 tcp_ack+0x17b1/0x3bc0 net/ipv4/tcp_input.c:3948
 tcp_rcv_state_process+0x57a/0x2290 net/ipv4/tcp_input.c:6711
 tcp_v4_do_rcv+0x764/0xc40 net/ipv4/tcp_ipv4.c:1937
 sk_backlog_rcv include/net/sock.h:1106 [inline]
 __release_sock+0x20f/0x350 net/core/sock.c:2983
 release_sock+0x61/0x1f0 net/core/sock.c:3549
 mptcp_subflow_shutdown+0x3d0/0x620 net/mptcp/protocol.c:2907
 mptcp_check_send_data_fin+0x225/0x410 net/mptcp/protocol.c:2976
 __mptcp_close+0x238/0xad0 net/mptcp/protocol.c:3072
 mptcp_close+0x2a/0x1a0 net/mptcp/protocol.c:3127
 inet_release+0x190/0x1f0 net/ipv4/af_inet.c:437
 __sock_release net/socket.c:659 [inline]
 sock_close+0xc0/0x240 net/socket.c:1421
 __fput+0x41b/0x890 fs/file_table.c:422
 task_work_run+0x23b/0x300 kernel/task_work.c:180
 exit_task_work include/linux/task_work.h:38 [inline]
 do_exit+0x9c8/0x2540 kernel/exit.c:878
 do_group_exit+0x201/0x2b0 kernel/exit.c:1027
 __do_sys_exit_group kernel/exit.c:1038 [inline]
 __se_sys_exit_group kernel/exit.c:1036 [inline]
 __x64_sys_exit_group+0x3f/0x40 kernel/exit.c:1036
 do_syscall_x64 arch/x86/entry/common.c:52 [inline]
 do_syscall_64+0xe4/0x240 arch/x86/entry/common.c:83
 entry_SYSCALL_64_after_hwframe+0x67/0x6f
RIP: 0033:0x7f6c2b5005b6
Code: Unable to access opcode bytes at 0x7f6c2b50058c.
RSP: 002b:00007ffe883eb948 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7
RAX: ffffffffffffffda RBX: 00007f6c2b5862f0 RCX: 00007f6c2b5005b6
RDX: 0000000000000001 RSI: 000000000000003c RDI: 0000000000000001
RBP: 0000000000000001 R08: 00000000000000e7 R09: ffffffffffffffc0
R10: 0000000000000006 R11: 0000000000000246 R12: 00007f6c2b5862f0
R13: 0000000000000001 R14: 0000000000000000 R15: 0000000000000001
 </TASK>

Reported-by: syzkaller <syzkaller@googlegroups.com>
Reported-by: Yue Sun <samsun1006219@gmail.com>
Reported-by: xingwei lee <xrivendell7@gmail.com>
Closes: https://lore.kernel.org/netdev/CAEkJfYNJM=cw-8x7_Vmj1J6uYVCWMbbvD=EFmDPVBGpTsqOxEA@mail.gmail.com/
Fixes: e3118e8359bb ("net: tcp: add DCTCP congestion control algorithm")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/ipv4/tcp_dctcp.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

Comments

Simon Horman May 17, 2024, 8:28 p.m. UTC | #1
On Fri, May 17, 2024 at 06:16:26PM +0900, Kuniyuki Iwashima wrote:
> In dctcp_update_alpha(), we use a module parameter dctcp_shift_g
> as follows:
> 
>   alpha -= min_not_zero(alpha, alpha >> dctcp_shift_g);
>   ...
>   delivered_ce <<= (10 - dctcp_shift_g);
> 
> It seems syzkaller started fuzzing module parameters and triggered
> shift-out-of-bounds [0] by setting 100 to dctcp_shift_g:
> 
>   memcpy((void*)0x20000080,
>          "/sys/module/tcp_dctcp/parameters/dctcp_shift_g\000", 47);
>   res = syscall(__NR_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x20000080ul,
>                 /*flags=*/2ul, /*mode=*/0ul);
>   memcpy((void*)0x20000000, "100\000", 4);
>   syscall(__NR_write, /*fd=*/r[0], /*val=*/0x20000000ul, /*len=*/4ul);
> 
> Let's limit the max value of dctcp_shift_g by param_set_uint_minmax().
> 
> With this patch:
> 
>   # echo 10 > /sys/module/tcp_dctcp/parameters/dctcp_shift_g
>   # cat /sys/module/tcp_dctcp/parameters/dctcp_shift_g
>   10
>   # echo 11 > /sys/module/tcp_dctcp/parameters/dctcp_shift_g
>   -bash: echo: write error: Invalid argument
> 
> [0]:
> UBSAN: shift-out-of-bounds in net/ipv4/tcp_dctcp.c:143:12
> shift exponent 100 is too large for 32-bit type 'u32' (aka 'unsigned int')
> CPU: 0 PID: 8083 Comm: syz-executor345 Not tainted 6.9.0-05151-g1b294a1f3561 #2
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
> 1.13.0-1ubuntu1.1 04/01/2014
> Call Trace:
>  <TASK>
>  __dump_stack lib/dump_stack.c:88 [inline]
>  dump_stack_lvl+0x201/0x300 lib/dump_stack.c:114
>  ubsan_epilogue lib/ubsan.c:231 [inline]
>  __ubsan_handle_shift_out_of_bounds+0x346/0x3a0 lib/ubsan.c:468
>  dctcp_update_alpha+0x540/0x570 net/ipv4/tcp_dctcp.c:143
>  tcp_in_ack_event net/ipv4/tcp_input.c:3802 [inline]
>  tcp_ack+0x17b1/0x3bc0 net/ipv4/tcp_input.c:3948
>  tcp_rcv_state_process+0x57a/0x2290 net/ipv4/tcp_input.c:6711
>  tcp_v4_do_rcv+0x764/0xc40 net/ipv4/tcp_ipv4.c:1937
>  sk_backlog_rcv include/net/sock.h:1106 [inline]
>  __release_sock+0x20f/0x350 net/core/sock.c:2983
>  release_sock+0x61/0x1f0 net/core/sock.c:3549
>  mptcp_subflow_shutdown+0x3d0/0x620 net/mptcp/protocol.c:2907
>  mptcp_check_send_data_fin+0x225/0x410 net/mptcp/protocol.c:2976
>  __mptcp_close+0x238/0xad0 net/mptcp/protocol.c:3072
>  mptcp_close+0x2a/0x1a0 net/mptcp/protocol.c:3127
>  inet_release+0x190/0x1f0 net/ipv4/af_inet.c:437
>  __sock_release net/socket.c:659 [inline]
>  sock_close+0xc0/0x240 net/socket.c:1421
>  __fput+0x41b/0x890 fs/file_table.c:422
>  task_work_run+0x23b/0x300 kernel/task_work.c:180
>  exit_task_work include/linux/task_work.h:38 [inline]
>  do_exit+0x9c8/0x2540 kernel/exit.c:878
>  do_group_exit+0x201/0x2b0 kernel/exit.c:1027
>  __do_sys_exit_group kernel/exit.c:1038 [inline]
>  __se_sys_exit_group kernel/exit.c:1036 [inline]
>  __x64_sys_exit_group+0x3f/0x40 kernel/exit.c:1036
>  do_syscall_x64 arch/x86/entry/common.c:52 [inline]
>  do_syscall_64+0xe4/0x240 arch/x86/entry/common.c:83
>  entry_SYSCALL_64_after_hwframe+0x67/0x6f
> RIP: 0033:0x7f6c2b5005b6
> Code: Unable to access opcode bytes at 0x7f6c2b50058c.
> RSP: 002b:00007ffe883eb948 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7
> RAX: ffffffffffffffda RBX: 00007f6c2b5862f0 RCX: 00007f6c2b5005b6
> RDX: 0000000000000001 RSI: 000000000000003c RDI: 0000000000000001
> RBP: 0000000000000001 R08: 00000000000000e7 R09: ffffffffffffffc0
> R10: 0000000000000006 R11: 0000000000000246 R12: 00007f6c2b5862f0
> R13: 0000000000000001 R14: 0000000000000000 R15: 0000000000000001
>  </TASK>
> 
> Reported-by: syzkaller <syzkaller@googlegroups.com>
> Reported-by: Yue Sun <samsun1006219@gmail.com>
> Reported-by: xingwei lee <xrivendell7@gmail.com>
> Closes: https://lore.kernel.org/netdev/CAEkJfYNJM=cw-8x7_Vmj1J6uYVCWMbbvD=EFmDPVBGpTsqOxEA@mail.gmail.com/
> Fixes: e3118e8359bb ("net: tcp: add DCTCP congestion control algorithm")
> Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>

Reviewed-by: Simon Horman <horms@kernel.org>
patchwork-bot+netdevbpf@kernel.org May 21, 2024, 11:40 a.m. UTC | #2
Hello:

This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:

On Fri, 17 May 2024 18:16:26 +0900 you wrote:
> In dctcp_update_alpha(), we use a module parameter dctcp_shift_g
> as follows:
> 
>   alpha -= min_not_zero(alpha, alpha >> dctcp_shift_g);
>   ...
>   delivered_ce <<= (10 - dctcp_shift_g);
> 
> [...]

Here is the summary with links:
  - [v1,net] tcp: Fix shift-out-of-bounds in dctcp_update_alpha().
    https://git.kernel.org/netdev/net/c/3ebc46ca8675

You are awesome, thank you!
diff mbox series

Patch

diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c
index 6b712a33d49f..8a45a4aea933 100644
--- a/net/ipv4/tcp_dctcp.c
+++ b/net/ipv4/tcp_dctcp.c
@@ -58,7 +58,18 @@  struct dctcp {
 };
 
 static unsigned int dctcp_shift_g __read_mostly = 4; /* g = 1/2^4 */
-module_param(dctcp_shift_g, uint, 0644);
+
+static int dctcp_shift_g_set(const char *val, const struct kernel_param *kp)
+{
+	return param_set_uint_minmax(val, kp, 0, 10);
+}
+
+static const struct kernel_param_ops dctcp_shift_g_ops = {
+	.set = dctcp_shift_g_set,
+	.get = param_get_uint,
+};
+
+module_param_cb(dctcp_shift_g, &dctcp_shift_g_ops, &dctcp_shift_g, 0644);
 MODULE_PARM_DESC(dctcp_shift_g, "parameter g for updating dctcp_alpha");
 
 static unsigned int dctcp_alpha_on_init __read_mostly = DCTCP_MAX_ALPHA;