From ff4aaa2d1db81fcb7c078deb667789f75a259284 Mon Sep 17 00:00:00 2001 From: Dudu Lu Date: Sun, 5 Apr 2026 23:47:41 +0800 Subject: [PATCH 1/7] Bluetooth: l2cap: Add missing chan lock in l2cap_ecred_reconf_rsp l2cap_ecred_reconf_rsp() calls l2cap_chan_del() without holding l2cap_chan_lock(). Every other l2cap_chan_del() caller in the file acquires the lock first. A remote BLE device can send a crafted L2CAP ECRED reconfiguration response to corrupt the channel list while another thread is iterating it. Add l2cap_chan_hold() and l2cap_chan_lock() before l2cap_chan_del(), and l2cap_chan_unlock() and l2cap_chan_put() after, matching the pattern used in l2cap_ecred_conn_rsp() and l2cap_conn_del(). Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add L2CAP_ECRED_RECONF support") Signed-off-by: Dudu Lu Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/l2cap_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5a4cd530ef33c..77dec104a9c36 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5473,7 +5473,13 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, if (chan->ident != cmd->ident) continue; + l2cap_chan_hold(chan); + l2cap_chan_lock(chan); + l2cap_chan_del(chan, ECONNRESET); + + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } return 0; From 66f6fb971a2e8f9782cb7928f9ca073bb97dce46 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Wed, 4 Nov 2020 21:09:48 -0800 Subject: [PATCH 2/7] workflow: Add workflow files for ci This patch adds workflow files for ci: [sync.yml] - The workflow file for scheduled work - Sync the repo with upstream repo and rebase the workflow branch - Review the patches in the patchwork and creates the PR if needed [ci.yml] - The workflow file for CI tasks - Run CI tests when PR is created Signed-off-by: Tedd Ho-Jeong An --- .github/workflows/ci.yml | 25 ++++++++++++++++++++++ .github/workflows/sync.yml | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/sync.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000000..3a2c45c37553c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: [pull_request] + +jobs: + ci: + runs-on: ubuntu-latest + name: CI for Pull Request + steps: + - name: Checkout the source code + uses: actions/checkout@v3 + with: + path: src/src + + - name: CI + uses: tedd-an/bzcafe@main + with: + task: ci + base_folder: src + space: kernel + github_token: ${{ secrets.GITHUB_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + patchwork_user: ${{ secrets.PATCHWORK_USER }} + diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml new file mode 100644 index 0000000000000..3883d55a23267 --- /dev/null +++ b/.github/workflows/sync.yml @@ -0,0 +1,43 @@ +name: Sync + +on: + schedule: + - cron: "*/30 * * * *" + +jobs: + sync_repo: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: master + + - name: Sync Repo + uses: tedd-an/bzcafe@main + with: + task: sync + upstream_repo: 'https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git' + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Cleanup PR + uses: tedd-an/bzcafe@main + with: + task: cleanup + github_token: ${{ secrets.ACTION_TOKEN }} + + sync_patchwork: + needs: sync_repo + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Sync Patchwork + uses: tedd-an/bzcafe@main + with: + task: patchwork + space: kernel + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + patchwork_user: ${{ secrets.PATCHWORK_USER }} + From 44792f549debd7b9e889b7b31b18b50af36fb967 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Apr 2026 18:03:13 +0200 Subject: [PATCH 3/7] uaccess: fix ignored_trailing logic in copy_struct_to_user() Currently all callers pass ignored_trailing=NULL, but I have code that will make use of. Now it actually behaves like documented: * If @usize < @ksize, then the kernel is trying to pass userspace a newer struct than it supports. Thus we only copy the interoperable portions (@usize) and ignore the rest (but @ignored_trailing is set to %true if any of the trailing (@ksize - @usize) bytes are non-zero). Fixes: 424a55a4a908 ("uaccess: add copy_struct_to_user helper") Cc: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Dmitry Safonov Cc: Francesco Ruggeri Cc: Salam Noureddine Cc: David Ahern Cc: David S. Miller Cc: Michal Luczaj Cc: David Wei Cc: Luiz Augusto von Dentz Cc: Luiz Augusto von Dentz Cc: Marcel Holtmann Cc: Xin Long Cc: Eric Dumazet Cc: Kuniyuki Iwashima Cc: Paolo Abeni Cc: Willem de Bruijn Cc: Neal Cardwell Cc: Jakub Kicinski Cc: Simon Horman Cc: Aleksa Sarai Cc: Christian Brauner CC: Kees Cook Cc: netdev@vger.kernel.org Cc: linux-bluetooth@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Stefan Metzmacher --- include/linux/uaccess.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 809e4f7dfdbd4..7e91442325a36 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -505,7 +505,7 @@ copy_struct_to_user(void __user *dst, size_t usize, const void *src, return -EFAULT; } if (ignored_trailing) - *ignored_trailing = ksize < usize && + *ignored_trailing = usize < ksize && memchr_inv(src + size, 0, rest) != NULL; /* Copy the interoperable parts of the struct. */ if (copy_to_user(dst, src, size)) From 17dc3407f78c4fbf3a2f3574ff9303aae09a06ad Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Apr 2026 18:03:14 +0200 Subject: [PATCH 4/7] sockptr: fix usize check in copy_struct_from_sockptr() for user pointers copy_struct_from_user will never hit the check_zeroed_user() call and will never return -E2BIG if new userspace passed new bits in a larger structure than the current kernel structure. As far as I can there are no critical/related uapi changes in - include/net/bluetooth/bluetooth.h and net/bluetooth/sco.c after the use of copy_struct_from_sockptr in v6.13-rc3 - include/uapi/linux/tcp.h and net/ipv4/tcp_ao.c after the use of copy_struct_from_sockptr in v6.6-rc1 So that new callers will get the correct behavior from the start. Fixes: 4954f17ddefc ("net/tcp: Introduce TCP_AO setsockopt()s") Fixes: ef84703a911f ("net/tcp: Add TCP-AO getsockopt()s") Fixes: faadfaba5e01 ("net/tcp: Add TCP_AO_REPAIR") Fixes: 3e643e4efa1e ("Bluetooth: Improve setsockopt() handling of malformed user input") Cc: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Dmitry Safonov Cc: Francesco Ruggeri Cc: Salam Noureddine Cc: David Ahern Cc: David S. Miller Cc: Michal Luczaj Cc: David Wei Cc: Luiz Augusto von Dentz Cc: Luiz Augusto von Dentz Cc: Marcel Holtmann Cc: Xin Long Cc: Eric Dumazet Cc: Kuniyuki Iwashima Cc: Paolo Abeni Cc: Willem de Bruijn Cc: Neal Cardwell Cc: Jakub Kicinski Cc: Simon Horman Cc: Aleksa Sarai Cc: Christian Brauner CC: Kees Cook Cc: netdev@vger.kernel.org Cc: linux-bluetooth@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Stefan Metzmacher --- include/linux/sockptr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h index 3e6c8e9d67aef..ba88f4d78c1b1 100644 --- a/include/linux/sockptr.h +++ b/include/linux/sockptr.h @@ -91,7 +91,7 @@ static inline int copy_struct_from_sockptr(void *dst, size_t ksize, size_t rest = max(ksize, usize) - size; if (!sockptr_is_kernel(src)) - return copy_struct_from_user(dst, ksize, src.user, size); + return copy_struct_from_user(dst, ksize, src.user, usize); if (usize < ksize) { memset(dst + size, 0, rest); From b56ff8c62dde326ef018c777be2cb3661602b948 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Apr 2026 18:03:15 +0200 Subject: [PATCH 5/7] uaccess: add copy_struct_{from,to}_bounce_buffer() helpers These are similar to copy_struct_{from,to}_user() but operate on kernel buffers instead of user buffers. They can be used when there is a temporary bounce buffer used, e.g. in msg_control or similar places. It allows us to have the same logic to handle old vs. current and current vs. new structures in the same compatible way. copy_struct_from_sockptr() will also be able to use copy_struct_from_bounce_buffer() for the kernel case as follow us patch. I'll use this in my IPPROTO_SMBDIRECT work, but maybe it will also be useful for others... IPPROTO_QUIC will likely also use it. Cc: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Dmitry Safonov Cc: Francesco Ruggeri Cc: Salam Noureddine Cc: David Ahern Cc: David S. Miller Cc: Michal Luczaj Cc: David Wei Cc: Luiz Augusto von Dentz Cc: Luiz Augusto von Dentz Cc: Marcel Holtmann Cc: Xin Long Cc: Eric Dumazet Cc: Kuniyuki Iwashima Cc: Paolo Abeni Cc: Willem de Bruijn Cc: Neal Cardwell Cc: Jakub Kicinski Cc: Simon Horman Cc: Aleksa Sarai Cc: Christian Brauner CC: Kees Cook Cc: netdev@vger.kernel.org Cc: linux-bluetooth@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Stefan Metzmacher --- include/linux/uaccess.h | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index 7e91442325a36..0f3c9455976ec 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -513,6 +513,69 @@ copy_struct_to_user(void __user *dst, size_t usize, const void *src, return 0; } +static __always_inline void +__copy_struct_generic_bounce_buffer(void *dst, size_t dstsize, + const void *src, size_t srcsize, + bool *ignored_trailing) +{ + size_t size = min(dstsize, srcsize); + size_t rest = max(dstsize, srcsize) - size; + + /* Deal with trailing bytes. */ + if (dstsize > srcsize) + memset(dst + size, 0, rest); + if (ignored_trailing) + *ignored_trailing = dstsize < srcsize && + memchr_inv(src + size, 0, rest) != NULL; + /* Copy the interoperable parts of the struct. */ + memcpy(dst, src, size); +} + +/** + * This is like copy_struct_from_user(), but the + * src buffer was already copied into a kernel + * bounce buffer, so it will never return -EFAULT. + */ +static __always_inline __must_check int +copy_struct_from_bounce_buffer(void *dst, size_t dstsize, + const void *src, size_t srcsize) +{ + bool ignored_trailing; + + /* Double check if ksize is larger than a known object size. */ + if (WARN_ON_ONCE(dstsize > __builtin_object_size(dst, 1))) + return -E2BIG; + + __copy_struct_generic_bounce_buffer(dst, dstsize, + src, srcsize, + &ignored_trailing); + if (unlikely(ignored_trailing)) + return -E2BIG; + + return 0; +} + +/** + * This is like copy_struct_to_user(), but the + * dst buffer is a kernel bounce buffer instead + * of a direct userspace buffer, so it will never return -EFAULT. + */ +static __always_inline __must_check int +copy_struct_to_bounce_buffer(void *dst, size_t dstsize, + const void *src, + size_t srcsize, + bool *ignored_trailing) +{ + /* Double check if srcsize is larger than a known object size. */ + if (WARN_ON_ONCE(srcsize > __builtin_object_size(src, 1))) + return -E2BIG; + + __copy_struct_generic_bounce_buffer(dst, dstsize, + src, srcsize, + ignored_trailing); + return 0; +} + bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size); long copy_from_kernel_nofault(void *dst, const void *src, size_t size); From d887da3a51992e4e69fe0c99136d46d961673ff7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Apr 2026 18:03:16 +0200 Subject: [PATCH 6/7] sockptr: let copy_struct_from_sockptr() use copy_struct_from_bounce_buffer() The world would be better without sockptr_t, but this at least simplifies copy_struct_from_sockptr() to be just a dispatcher for copy_struct_from_user() or copy_struct_from_bounce_buffer() without any special logic on its own. Cc: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Dmitry Safonov Cc: Francesco Ruggeri Cc: Salam Noureddine Cc: David Ahern Cc: David S. Miller Cc: Michal Luczaj Cc: David Wei Cc: Luiz Augusto von Dentz Cc: Luiz Augusto von Dentz Cc: Marcel Holtmann Cc: Xin Long Cc: Eric Dumazet Cc: Kuniyuki Iwashima Cc: Paolo Abeni Cc: Willem de Bruijn Cc: Neal Cardwell Cc: Jakub Kicinski Cc: Simon Horman Cc: Aleksa Sarai Cc: Christian Brauner CC: Kees Cook Cc: netdev@vger.kernel.org Cc: linux-bluetooth@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Stefan Metzmacher --- include/linux/sockptr.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h index ba88f4d78c1b1..706a8526cf3c6 100644 --- a/include/linux/sockptr.h +++ b/include/linux/sockptr.h @@ -87,24 +87,10 @@ static inline int copy_safe_from_sockptr(void *dst, size_t ksize, static inline int copy_struct_from_sockptr(void *dst, size_t ksize, sockptr_t src, size_t usize) { - size_t size = min(ksize, usize); - size_t rest = max(ksize, usize) - size; - if (!sockptr_is_kernel(src)) return copy_struct_from_user(dst, ksize, src.user, usize); - if (usize < ksize) { - memset(dst + size, 0, rest); - } else if (usize > ksize) { - char *p = src.kernel; - - while (rest--) { - if (*p++) - return -E2BIG; - } - } - memcpy(dst, src.kernel, size); - return 0; + return copy_struct_from_bounce_buffer(dst, ksize, src.kernel, usize); } static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset, From bdfa4936475cf7dd0beeb71750a6d08bf8f51558 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Apr 2026 18:03:17 +0200 Subject: [PATCH 7/7] sockptr: introduce copy_struct_to_sockptr() We already have copy_struct_from_sockptr() as wrapper to copy_struct_from_user() or copy_struct_from_bounce_buffer(), so it's good to have copy_struct_to_sockptr() as well matching the behavior of copy_struct_to_user() or copy_struct_to_bounce_buffer(). The world would be better without sockptr_t, but having copy_struct_to_sockptr() is better than open code it in various places. I'll use this in my IPPROTO_SMBDIRECT work, but maybe it will also be useful for others... IPPROTO_QUIC will likely also use it. Cc: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Dmitry Safonov Cc: Francesco Ruggeri Cc: Salam Noureddine Cc: David Ahern Cc: David S. Miller Cc: Michal Luczaj Cc: David Wei Cc: Luiz Augusto von Dentz Cc: Luiz Augusto von Dentz Cc: Marcel Holtmann Cc: Xin Long Cc: Eric Dumazet Cc: Kuniyuki Iwashima Cc: Paolo Abeni Cc: Willem de Bruijn Cc: Neal Cardwell Cc: Jakub Kicinski Cc: Simon Horman Cc: Aleksa Sarai Cc: Christian Brauner CC: Kees Cook Cc: netdev@vger.kernel.org Cc: linux-bluetooth@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Stefan Metzmacher --- include/linux/sockptr.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h index 706a8526cf3c6..9c2429c1a570a 100644 --- a/include/linux/sockptr.h +++ b/include/linux/sockptr.h @@ -107,6 +107,16 @@ static inline int copy_to_sockptr(sockptr_t dst, const void *src, size_t size) return copy_to_sockptr_offset(dst, 0, src, size); } +static inline int +copy_struct_to_sockptr(sockptr_t dst, size_t usize, const void *src, + size_t ksize, bool *ignored_trailing) +{ + if (!sockptr_is_kernel(dst)) + return copy_struct_to_user(dst.user, usize, src, ksize, ignored_trailing); + + return copy_struct_to_bounce_buffer(dst.kernel, usize, src, ksize, ignored_trailing); +} + static inline void *memdup_sockptr_noprof(sockptr_t src, size_t len) { void *p = kmalloc_track_caller_noprof(len, GFP_USER | __GFP_NOWARN);