Skip to content

Commit f3b1e36

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 86aa587 commit f3b1e36

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
@@ -456,7 +456,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
456456
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
457457
struct l2cap_options opts;
458458
struct l2cap_conninfo cinfo;
459-
int len, err = 0;
459+
int err = 0;
460+
size_t len;
460461
u32 opt;
461462

462463
BT_DBG("sk %p", sk);
@@ -503,7 +504,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
503504

504505
BT_DBG("mode 0x%2.2x", chan->mode);
505506

506-
len = min_t(unsigned int, len, sizeof(opts));
507+
len = min(len, sizeof(opts));
507508
if (copy_to_user(optval, (char *) &opts, len))
508509
err = -EFAULT;
509510

@@ -553,7 +554,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
553554
cinfo.hci_handle = chan->conn->hcon->handle;
554555
memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3);
555556

556-
len = min_t(unsigned int, len, sizeof(cinfo));
557+
len = min(len, sizeof(cinfo));
557558
if (copy_to_user(optval, (char *) &cinfo, len))
558559
err = -EFAULT;
559560

net/bluetooth/sco.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,8 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
901901
struct sock *sk = sock->sk;
902902
struct sco_options opts;
903903
struct sco_conninfo cinfo;
904-
int len, err = 0;
904+
int err = 0;
905+
size_t len;
905906

906907
BT_DBG("sk %p", sk);
907908

@@ -923,7 +924,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
923924

924925
BT_DBG("mtu %d", opts.mtu);
925926

926-
len = min_t(unsigned int, len, sizeof(opts));
927+
len = min(len, sizeof(opts));
927928
if (copy_to_user(optval, (char *)&opts, len))
928929
err = -EFAULT;
929930

@@ -941,7 +942,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname,
941942
cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
942943
memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
943944

944-
len = min_t(unsigned int, len, sizeof(cinfo));
945+
len = min(len, sizeof(cinfo));
945946
if (copy_to_user(optval, (char *)&cinfo, len))
946947
err = -EFAULT;
947948

0 commit comments

Comments
 (0)