Skip to content

Commit 9bf4e91

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 5b5f724 commit 9bf4e91

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
@@ -964,7 +964,8 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
964964
struct sock *sk = sock->sk;
965965
struct sco_options opts;
966966
struct sco_conninfo cinfo;
967-
int len, err = 0;
967+
int err = 0;
968+
size_t len;
968969

969970
BT_DBG("sk %p", sk);
970971

@@ -986,7 +987,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
986987

987988
BT_DBG("mtu %u", opts.mtu);
988989

989-
len = min_t(unsigned int, len, sizeof(opts));
990+
len = min(len, sizeof(opts));
990991
if (copy_to_user(optval, (char *)&opts, len))
991992
err = -EFAULT;
992993

@@ -1004,7 +1005,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
10041005
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
10051006
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
10061007

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

0 commit comments

Comments
 (0)