Skip to content

Commit 2216e1e

Browse files
nathanchanceVudentz
authored andcommitted
Bluetooth: Fix type of len in {l2cap,sco}_sock_getsockopt_old()
After an innocuous optimization change in LLVM main (19.0.0), x86_64 allmodconfig (which enables CONFIG_KCSAN / -fsanitize=thread) fails to build due to the checks in check_copy_size(): In file included from net/bluetooth/sco.c:27: In file included from include/linux/module.h:13: In file included from include/linux/stat.h:19: In file included from include/linux/time.h:60: In file included from include/linux/time32.h:13: In file included from include/linux/timex.h:67: In file included from arch/x86/include/asm/timex.h:6: In file included from arch/x86/include/asm/tsc.h:10: In file included from arch/x86/include/asm/msr.h:15: In file included from include/linux/percpu.h:7: In file included from include/linux/smp.h:118: include/linux/thread_info.h:244:4: error: call to '__bad_copy_from' declared with 'error' attribute: copy source size is too small 244 | __bad_copy_from(); | ^ The same exact error occurs in l2cap_sock.c. The copy_to_user() statements that are failing come from l2cap_sock_getsockopt_old() and sco_sock_getsockopt_old(). This does not occur with GCC with or without KCSAN or Clang without KCSAN enabled. len is defined as an 'int' because it is assigned from '__user int *optlen'. However, it is clamped against the result of sizeof(), which has a type of 'size_t' ('unsigned long' for 64-bit platforms). This is done with min_t() because min() requires compatible types, which results in both len and the result of sizeof() being casted to 'unsigned int', meaning len changes signs and the result of sizeof() is truncated. From there, len is passed to copy_to_user(), which has a third parameter type of 'unsigned long', so it is widened and changes signs again. This excessive casting in combination with the KCSAN instrumentation causes LLVM to fail to eliminate the __bad_copy_from() call, failing the build. The official recommendation from LLVM developers is to consistently use long types for all size variables to avoid the unnecessary casting in the first place. Change the type of len to size_t in both l2cap_sock_getsockopt_old() and sco_sock_getsockopt_old(). This clears up the error while allowing min_t() to be replaced with min(), resulting in simpler code with no casts and fewer implicit conversions. While len is a different type than optlen now, it should result in no functional change because the result of sizeof() will clamp all values of optlen in the same manner as before. Cc: [email protected] Closes: ClangBuiltLinux/linux#2007 Link: llvm/llvm-project#85647 Signed-off-by: Nathan Chancellor <[email protected]> Reviewed-by: Justin Stitt <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent b7adccd commit 2216e1e

File tree

2 files changed

+8
-6
lines changed

2 files changed

+8
-6
lines changed

net/bluetooth/l2cap_sock.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
439439
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
440440
struct l2cap_options opts;
441441
struct l2cap_conninfo cinfo;
442-
int len, err = 0;
442+
int err = 0;
443+
size_t len;
443444
u32 opt;
444445

445446
BT_DBG("sk %p", sk);
@@ -486,7 +487,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
486487

487488
BT_DBG("mode 0x%2.2x", chan->mode);
488489

489-
len = min_t(unsigned int, len, sizeof(opts));
490+
len = min(len, sizeof(opts));
490491
if (copy_to_user(optval, (char *) &opts, len))
491492
err = -EFAULT;
492493

@@ -536,7 +537,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
536537
cinfo.hci_handle = chan->conn->hcon->handle;
537538
memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
538539

539-
len = min_t(unsigned int, len, sizeof(cinfo));
540+
len = min(len, sizeof(cinfo));
540541
if (copy_to_user(optval, (char *) &cinfo, len))
541542
err = -EFAULT;
542543

net/bluetooth/sco.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,8 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
982982
struct sock *sk = sock->sk;
983983
struct sco_options opts;
984984
struct sco_conninfo cinfo;
985-
int len, err = 0;
985+
int err = 0;
986+
size_t len;
986987

987988
BT_DBG("sk %p", sk);
988989

@@ -1004,7 +1005,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
10041005

10051006
BT_DBG("mtu %u", opts.mtu);
10061007

1007-
len = min_t(unsigned int, len, sizeof(opts));
1008+
len = min(len, sizeof(opts));
10081009
if (copy_to_user(optval, (char *)&opts, len))
10091010
err = -EFAULT;
10101011

@@ -1022,7 +1023,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
10221023
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
10231024
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
10241025

1025-
len = min_t(unsigned int, len, sizeof(cinfo));
1026+
len = min(len, sizeof(cinfo));
10261027
if (copy_to_user(optval, (char *)&cinfo, len))
10271028
err = -EFAULT;
10281029

0 commit comments

Comments
 (0)