Skip to content

Commit fe7a004

Browse files
nathanchanceAflaungos
authored andcommitted
Bluetooth: Fix type of len in {l2cap,sco}_sock_getsockopt_old()
commit 9bf4e919ccad613b3596eebf1ff37b05b6405307 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 9c2805c commit fe7a004

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
@@ -405,7 +405,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
405405
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
406406
struct l2cap_options opts;
407407
struct l2cap_conninfo cinfo;
408-
int len, err = 0;
408+
int err = 0;
409+
size_t len;
409410
u32 opt;
410411

411412
BT_DBG("sk %p", sk);
@@ -436,7 +437,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
436437
opts.max_tx = chan->max_tx;
437438
opts.txwin_size = chan->tx_win;
438439

439-
len = min_t(unsigned int, len, sizeof(opts));
440+
len = min(len, sizeof(opts));
440441
if (copy_to_user(optval, (char *) &opts, len))
441442
err = -EFAULT;
442443

@@ -486,7 +487,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
486487
cinfo.hci_handle = chan->conn->hcon->handle;
487488
memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
488489

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

net/bluetooth/sco.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,8 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
880880
struct sock *sk = sock->sk;
881881
struct sco_options opts;
882882
struct sco_conninfo cinfo;
883-
int len, err = 0;
883+
int err = 0;
884+
size_t len;
884885

885886
BT_DBG("sk %p", sk);
886887

@@ -902,7 +903,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
902903

903904
BT_DBG("mtu %d", opts.mtu);
904905

905-
len = min_t(unsigned int, len, sizeof(opts));
906+
len = min(len, sizeof(opts));
906907
if (copy_to_user(optval, (char *)&opts, len))
907908
err = -EFAULT;
908909

@@ -920,7 +921,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
920921
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
921922
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
922923

923-
len = min_t(unsigned int, len, sizeof(cinfo));
924+
len = min(len, sizeof(cinfo));
924925
if (copy_to_user(optval, (char *)&cinfo, len))
925926
err = -EFAULT;
926927

0 commit comments

Comments
 (0)