Skip to content

Commit fad4bee

Browse files
nathanchanceSasha Levin
authored and
Sasha Levin
committed
Bluetooth: Fix type of len in {l2cap,sco}_sock_getsockopt_old()
commit 9bf4e91 upstream. 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]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent c4ca9ba commit fad4bee

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
@@ -438,7 +438,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
438438
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
439439
struct l2cap_options opts;
440440
struct l2cap_conninfo cinfo;
441-
int len, err = 0;
441+
int err = 0;
442+
size_t len;
442443
u32 opt;
443444

444445
BT_DBG("sk %p", sk);
@@ -485,7 +486,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
485486

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

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

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

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

net/bluetooth/sco.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -963,7 +963,8 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
963963
struct sock *sk = sock->sk;
964964
struct sco_options opts;
965965
struct sco_conninfo cinfo;
966-
int len, err = 0;
966+
int err = 0;
967+
size_t len;
967968

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

@@ -985,7 +986,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
985986

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

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

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

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

0 commit comments

Comments
 (0)