From: Eric Dumazet edumazet@google.com
mainline inclusion from mainline-v6.9 commit 6309863b31dd80317cd7d6824820b44e254e2a9c category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9U9YN CVE: CVE-2024-36915
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
copy_from_sockptr() helper is unsafe, unless callers did the prior check against user provided optlen.
Too many callers get this wrong, lets add a helper to fix them and avoid future copy/paste bugs.
Instead of :
if (optlen < sizeof(opt)) { err = -EINVAL; break; } if (copy_from_sockptr(&opt, optval, sizeof(opt)) { err = -EFAULT; break; }
Use :
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen); if (err) break;
Conflicts: include/linux/sockptr.h [There are only context conficts, no code logic conflicts] Signed-off-by: Eric Dumazet edumazet@google.com Link: https://lore.kernel.org/r/20240408082845.3957374-2-edumazet@google.com Signed-off-by: Jakub Kicinski kuba@kernel.org Signed-off-by: Wang Wensheng wangwensheng4@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- include/linux/sockptr.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/include/linux/sockptr.h b/include/linux/sockptr.h index 38862819e77a..a74ce1deab8e 100644 --- a/include/linux/sockptr.h +++ b/include/linux/sockptr.h @@ -50,11 +50,36 @@ static inline int copy_from_sockptr_offset(void *dst, sockptr_t src, return 0; }
+/* Deprecated. + * This is unsafe, unless caller checked user provided optlen. + * Prefer copy_safe_from_sockptr() instead. + */ static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size) { return copy_from_sockptr_offset(dst, src, 0, size); }
+/** + * copy_safe_from_sockptr: copy a struct from sockptr + * @dst: Destination address, in kernel space. This buffer must be @ksize + * bytes long. + * @ksize: Size of @dst struct. + * @optval: Source address. (in user or kernel space) + * @optlen: Size of @optval data. + * + * Returns: + * * -EINVAL: @optlen < @ksize + * * -EFAULT: access to userspace failed. + * * 0 : @ksize bytes were copied + */ +static inline int copy_safe_from_sockptr(void *dst, size_t ksize, + sockptr_t optval, unsigned int optlen) +{ + if (optlen < ksize) + return -EINVAL; + return copy_from_sockptr(dst, optval, ksize); +} + static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset, const void *src, size_t size) {