Hi,
In our continuing effort to eliminate root causes of flaws in the kernel,
this series is the start to providing a way to have sensible coverage
for catching unexpected arithmetic wrap-around.
A quick word on language: while discussing[1] the finer details of
the C standard's view on arithmetic, I was disabused of using the term
"overflow" when what I really mean is "wrap-around". When describing
security vulnerabilities, "overflow" is the common term and often used
interchangeably with "wrap-around". Strictly speaking, though, "overflow"
applies only to signed[2] and pointer[3] types, and "wrap-around" is for
unsigned[4]. An arithmetic "overflow" is considered undefined behavior,
which has caused our builds pain in the past, since "impossible"
conditions might get elided by the compiler. As a result, we build
with -fno-strict-overflow which coverts all "overflow" conditions into
"wrap-around" (i.e. 2s complement), regardless of type.
All this is to say I am discussing arithmetic wrap-around, which is
the condition where the value exceeds a type's maximum value (or goes
below its minimum value) and wraps around. I'm not interested in the
narrow definition of "undefined behavior" -- we need to stamp out the
_unexpected_ behavior, where the kernel operates on a pathological value
that wrapped around without the code author's intent.
As always, this is about being able disambiguate the intent of arithmetic
in the kernel. We intentionally use wrapping arithmetic in all kinds of
places, but we need to be able to annotate it as such going forward so
the compiler can distinguish when it needs to perform instrumentation
(when such instrumentation is enabled).
Getting back to my earlier mention of -fno-strict-overflow, the bulk of
the series is refactoring for a common code pattern in the kernel where
to test for potentially overflowing addition, the addition is performed,
and wrap-around is tested for. This is what originally[5] caused us to
enable -fno-strict-overflow:
var + offset < var
For these cases we can use either check_add_overflow() or
add_would_overflow(). These helpers will not trip the wrap-around
instrumentation, and do not depend on the whims of the compiler options.
(Note that I have no intention of removing -fno-strict-overflow any
time soon, if ever. As with all these kinds of changes, we need to
evolve our support for it, and we can't introduce undefined behavior
into the kernel.)
This series is mainly 3 parts:
- documentation, a coccinelle script, and new/improved helpers
- (re)introduction of the overflow sanitizers
- refactoring the "please wrap around to see if I wrapped around" tests
While this work is underway in the kernel, there will be complementary
work happening in GCC and Clang to expand the existing sanitizers
to behave correctly with -fno-strict-overflow. In the meantime, the
sanitizers are excluded from CONFIG_COMPILE_TEST.
-Kees
[1] https://gcc.gnu.org/pipermail/gcc-patches/2023-September/630578.html
[2] https://github.com/KSPP/linux/issues/26
[3] https://github.com/KSPP/linux/issues/344
[4] https://github.com/KSPP/linux/issues/27
[5] https://bugzilla.kernel.org/show_bug.cgi?id=12597
Kees Cook (82):
overflow: Expand check_add_overflow() for pointer addition
overflow: Introduce add_would_overflow()
overflow: Introduce add_wrap()
docs: deprecated.rst: deprecate open-coded arithmetic wrap-around
cocci: Refactor open-coded arithmetic wrap-around
overflow: Reintroduce signed and unsigned overflow sanitizers
overflow: Introduce CONFIG_UBSAN_POINTER_WRAP
iov_iter: Avoid wrap-around instrumentation in
copy_compat_iovec_from_user
select: Avoid wrap-around instrumentation in do_sys_poll()
locking/atomic/x86: Silence intentional wrapping addition
arm64: atomics: lse: Silence intentional wrapping addition
ipv4: Silence intentional wrapping addition
btrfs: Refactor intentional wrap-around calculation
smb: client: Refactor intentional wrap-around calculation
dma-buf: Refactor intentional wrap-around calculation
drm/nouveau/mmu: Refactor intentional wrap-around calculation
drm/vc4: Refactor intentional wrap-around calculation
ext4: Refactor intentional wrap-around calculation
fs: Refactor intentional wrap-around calculation
fpga: dfl: Refactor intentional wrap-around calculation
drivers/fsi: Refactor intentional wrap-around calculation
x86/sgx: Refactor intentional wrap-around calculation
KVM: Refactor intentional wrap-around calculation
KVM: arm64: vgic: Refactor intentional wrap-around calculation
KVM: SVM: Refactor intentional wrap-around calculation
buildid: Refactor intentional wrap-around calculation
m68k: Refactor intentional wrap-around calculation
niu: Refactor intentional wrap-around calculation
rds: Refactor intentional wrap-around calculation
s390/kexec_file: Refactor intentional wrap-around calculation
ARC: dw2 unwind: Refactor intentional wrap-around calculation
vringh: Refactor intentional wrap-around calculation
mm/vmalloc: Refactor intentional wrap-around calculation
ipc: Refactor intentional wrap-around calculation
ACPI: custom_method: Refactor intentional wrap-around test
agp: Refactor intentional wrap-around test
aio: Refactor intentional wrap-around test
arm: 3117/1: Refactor intentional wrap-around test
crypto: Refactor intentional wrap-around test
arm64: stacktrace: Refactor intentional wrap-around test
wil6210: Refactor intentional wrap-around test
bcachefs: Refactor intentional wrap-around test
bpf: Refactor intentional wrap-around test
btrfs: Refactor intentional wrap-around test
cifs: Refactor intentional wrap-around test
crypto: Refactor intentional wrap-around test
dm verity: Refactor intentional wrap-around test
drm/nouveau/mmu: Refactor intentional wrap-around test
drm/i915: Refactor intentional wrap-around test
drm/vc4: Refactor intentional wrap-around test
ext4: Refactor intentional wrap-around test
f2fs: Refactor intentional wrap-around test
fs: Refactor intentional wrap-around test
hpfs: Refactor intentional wrap-around test
kasan: Refactor intentional wrap-around test
usercopy: Refactor intentional wrap-around test
KVM: arm64: vgic-v3: Refactor intentional wrap-around test
s390/mm: Refactor intentional wrap-around test
lib/scatterlist: Refactor intentional wrap-around test
powerpc: Refactor intentional wrap-around test
scsi: mpt3sas: Refactor intentional wrap-around test
mwifiex: pcie: Refactor intentional wrap-around test
mm: Refactor intentional wrap-around test
netfilter: Refactor intentional wrap-around test
nios2: Refactor intentional wrap-around test
fs/ntfs3: Refactor intentional wrap-around test
ocfs2: Refactor intentional wrap-around test
PCI: Refactor intentional wrap-around test
perf tools: Refactor intentional wrap-around test
remoteproc: Refactor intentional wrap-around test
s390/mm: Refactor intentional wrap-around test
scsi: sd_zbc: Refactor intentional wrap-around test
sh: Refactor intentional wrap-around test
ARC: dw2 unwind: Refactor intentional wrap-around test
timekeeping: Refactor intentional wrap-around test
udf: Refactor intentional wrap-around test
virtio: Refactor intentional wrap-around test
mm/vmalloc: Refactor intentional wrap-around test
staging: vme_user: Refactor intentional wrap-around test
xen-netback: Refactor intentional wrap-around test
lib: zstd: Refactor intentional wrap-around test
mqueue: Refactor intentional wrap-around test
Documentation/process/deprecated.rst | 36 ++++++++
arch/arc/kernel/unwind.c | 7 +-
arch/arm/nwfpe/softfloat.c | 2 +-
arch/arm64/include/asm/atomic_lse.h | 8 +-
arch/arm64/include/asm/stacktrace/common.h | 2 +-
arch/arm64/kvm/vgic/vgic-kvm-device.c | 6 +-
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +-
arch/arm64/kvm/vgic/vgic-v2.c | 10 ++-
arch/m68k/kernel/sys_m68k.c | 5 +-
arch/nios2/kernel/sys_nios2.c | 2 +-
arch/powerpc/platforms/powernv/opal-prd.c | 2 +-
arch/powerpc/xmon/xmon.c | 2 +-
arch/s390/include/asm/stacktrace.h | 6 +-
arch/s390/kernel/machine_kexec_file.c | 5 +-
arch/s390/mm/gmap.c | 4 +-
arch/s390/mm/vmem.c | 2 +-
arch/sh/kernel/sys_sh.c | 2 +-
arch/x86/include/asm/atomic.h | 2 +-
arch/x86/kernel/cpu/sgx/ioctl.c | 6 +-
arch/x86/kvm/svm/sev.c | 5 +-
crypto/adiantum.c | 2 +-
drivers/acpi/custom_method.c | 2 +-
drivers/char/agp/generic.c | 2 +-
drivers/crypto/amcc/crypto4xx_alg.c | 2 +-
drivers/crypto/axis/artpec6_crypto.c | 2 +-
drivers/dma-buf/dma-buf.c | 7 +-
drivers/fpga/dfl.c | 5 +-
drivers/fsi/fsi-core.c | 6 +-
drivers/gpu/drm/i915/i915_vma.c | 2 +-
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c | 8 +-
drivers/gpu/drm/vc4/vc4_validate.c | 7 +-
drivers/md/dm-switch.c | 2 +-
drivers/md/dm-verity-target.c | 2 +-
drivers/md/dm-writecache.c | 2 +-
drivers/net/ethernet/sun/niu.c | 5 +-
drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
drivers/net/wireless/marvell/mwifiex/pcie.c | 6 +-
drivers/net/xen-netback/hash.c | 2 +-
drivers/pci/pci.c | 2 +-
drivers/remoteproc/pru_rproc.c | 2 +-
drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
drivers/remoteproc/remoteproc_virtio.c | 4 +-
drivers/scsi/mpt3sas/mpt3sas_ctl.c | 2 +-
drivers/scsi/sd_zbc.c | 2 +-
drivers/staging/vme_user/vme.c | 2 +-
drivers/vhost/vringh.c | 8 +-
drivers/virtio/virtio_pci_modern_dev.c | 4 +-
fs/aio.c | 2 +-
fs/bcachefs/bkey.c | 4 +-
fs/bcachefs/fs.c | 2 +-
fs/bcachefs/quota.c | 2 +-
fs/bcachefs/util.c | 2 +-
fs/btrfs/extent_map.c | 6 +-
fs/btrfs/extent_map.h | 6 +-
fs/btrfs/ordered-data.c | 2 +-
fs/ext4/block_validity.c | 2 +-
fs/ext4/extents.c | 5 +-
fs/ext4/resize.c | 2 +-
fs/f2fs/file.c | 2 +-
fs/f2fs/verity.c | 2 +-
fs/hpfs/alloc.c | 2 +-
fs/ntfs3/record.c | 4 +-
fs/ocfs2/resize.c | 2 +-
fs/read_write.c | 8 +-
fs/remap_range.c | 2 +-
fs/select.c | 13 +--
fs/smb/client/readdir.c | 5 +-
fs/smb/client/smb2pdu.c | 4 +-
fs/udf/balloc.c | 4 +-
include/linux/compiler_types.h | 29 +++++-
include/linux/overflow.h | 76 +++++++++++++++-
ipc/mqueue.c | 2 +-
ipc/shm.c | 6 +-
kernel/bpf/verifier.c | 12 +--
kernel/time/timekeeping.c | 2 +-
lib/Kconfig.ubsan | 27 ++++++
lib/buildid.c | 6 +-
lib/iov_iter.c | 5 +-
lib/overflow_kunit.c | 77 ++++++++++++++--
lib/scatterlist.c | 2 +-
lib/test_ubsan.c | 82 +++++++++++++++++
lib/ubsan.c | 89 +++++++++++++++++++
lib/ubsan.h | 5 ++
lib/zstd/decompress/zstd_decompress.c | 4 +-
mm/kasan/generic.c | 2 +-
mm/kasan/sw_tags.c | 2 +-
mm/memory.c | 4 +-
mm/mmap.c | 2 +-
mm/mremap.c | 2 +-
mm/nommu.c | 4 +-
mm/usercopy.c | 2 +-
mm/util.c | 2 +-
mm/vmalloc.c | 7 +-
net/ipv4/route.c | 8 +-
net/netfilter/xt_u32.c | 4 +-
net/rds/info.c | 6 +-
scripts/Makefile.ubsan | 3 +
.../coccinelle/misc/add_would_overflow.cocci | 70 +++++++++++++++
tools/perf/util/dso.c | 2 +-
tools/perf/util/unwind-libdw.c | 2 +-
tools/perf/util/unwind-libunwind-local.c | 2 +-
virt/kvm/coalesced_mmio.c | 6 +-
102 files changed, 680 insertions(+), 167 deletions(-)
create mode 100644 scripts/coccinelle/misc/add_would_overflow.cocci
--
2.34.1
In pursuit of gaining full kernel instrumentation for signed[1],
unsigned[2], and pointer[3] arithmetic overflow, we need to replace
the handful of instances in the kernel where we intentionally depend on
arithmetic wrap-around. Document this goal and provide an example for
the most common code pattern, checking for simple overflow:
if (VAR + OFFSET < VAR) ...
Link: https://github.com/KSPP/linux/issues/26 [1]
Link: https://github.com/KSPP/linux/issues/27 [2]
Link: https://github.com/KSPP/linux/issues/344 [3]
Cc: Jonathan Corbet <[email protected]>
Cc: "Gustavo A. R. Silva" <[email protected]>
Cc: Justin Stitt <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
Documentation/process/deprecated.rst | 32 ++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst
index 1f7f3e6c9cda..270f3af13b86 100644
--- a/Documentation/process/deprecated.rst
+++ b/Documentation/process/deprecated.rst
@@ -109,6 +109,38 @@ For more details, also see array3_size() and flex_array_size(),
as well as the related check_mul_overflow(), check_add_overflow(),
check_sub_overflow(), and check_shl_overflow() family of functions.
+open-coded intentional arithmetic wrap-around
+---------------------------------------------
+Depending on arithmetic wrap-around without annotations means the
+kernel cannot distinguish between intentional wrap-around and accidental
+wrap-around (when using things like the overflow sanitizers).
+
+For example, where an addition is intended to wrap around::
+
+ magic = counter + rotation;
+
+please use the add_wrap() helper::
+
+ magic = add_wrap(counter, rotation);
+
+Another common code pattern in the kernel open coded testing for overflow
+by performing an overflow and looking for wrap-around::
+
+ if (var + offset < var) ...
+
+Instead, use either check_add_overflow() (when you want to use the
+resulting sum when it doesn't overflow) or add_would_overflow()::
+
+ if (add_would_overflow(var, offset)) ...
+
+In rare cases where helpers aren't available (e.g. in early boot code,
+etc) but overflow instrumentation still needs to be avoided, it can be
+replaced with a type max subtraction test instead::
+
+ int var;
+ ...
+ if (INT_MAX - var < offset) ...
+
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
----------------------------------------------------------------------
The simple_strtol(), simple_strtoll(),
--
2.34.1
The overflow sanitizer quickly noticed what appears to have been an old
sore spot involving intended wrap around:
[ 22.192362] ------------[ cut here ]------------
[ 22.193329] UBSAN: signed-integer-overflow in ../arch/x86/include/asm/atomic.h:85:11
[ 22.194844] 1469769800 + 1671667352 cannot be represented in type 'int'
[ 22.195975] CPU: 2 PID: 2260 Comm: nmbd Not tainted 6.7.0 #1
[ 22.196927] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 0.0.0 02/06/2015
[ 22.198231] Call Trace:
[ 22.198641] <TASK>
[ 22.198641] dump_stack_lvl+0x64/0x80
[ 22.199533] handle_overflow+0x152/0x1a0
[ 22.200382] __ip_select_ident+0xe3/0x100
Explicitly perform a wrapping addition to solve for the needed
-fno-strict-overflow behavior but still allow the sanitizers to operate
correctly.
To see the (unchanged) assembly results more clearly, see:
https://godbolt.org/z/EhYhz6zTT
Cc: Jakub Kicinski <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Paolo Abeni <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
net/ipv4/route.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 16615d107cf0..c52e85b06fe7 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -473,11 +473,11 @@ static u32 ip_idents_reserve(u32 hash, int segs)
if (old != now && cmpxchg(p_tstamp, old, now) == old)
delta = get_random_u32_below(now - old);
- /* If UBSAN reports an error there, please make sure your compiler
- * supports -fno-strict-overflow before reporting it that was a bug
- * in UBSAN, and it has been fixed in GCC-8.
+ /* If UBSAN reports an error there, please make sure your arch's
+ * atomic_add_return() implementation has been annotated with
+ * __signed_wrap.
*/
- return atomic_add_return(segs + delta, p_id) - segs;
+ return atomic_add_return(add_wrap(segs, delta), p_id) - segs;
}
void __ip_select_ident(struct net *net, struct iphdr *iph, int segs)
--
2.34.1
Gain coverage for pointer wrap-around checking. Adds support for
-fsanitize=pointer-overflow, and introduces the __pointer_wrap function
attribute to match the signed and unsigned attributes. Also like the
others, it is currently disabled under CONFIG_COMPILE_TEST.
Cc: Andrew Morton <[email protected]>
Cc: Masahiro Yamada <[email protected]>
Cc: Nathan Chancellor <[email protected]>
Cc: Nicolas Schier <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
Documentation/process/deprecated.rst | 2 +-
include/linux/compiler_types.h | 7 +++++-
lib/Kconfig.ubsan | 8 +++++++
lib/test_ubsan.c | 33 ++++++++++++++++++++++++++++
lib/ubsan.c | 21 ++++++++++++++++++
lib/ubsan.h | 1 +
scripts/Makefile.ubsan | 1 +
7 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst
index aebd7c6cd2fc..15e77cbd4259 100644
--- a/Documentation/process/deprecated.rst
+++ b/Documentation/process/deprecated.rst
@@ -143,7 +143,7 @@ replaced with a type max subtraction test instead::
For inline helpers that are performing wrapping arithmetic, the entire
function can be annotated as intentionally wrapping by adding the
-`__signed_wrap` or `__unsigned_wrap` function attribute.
+`__signed_wrap`, `__unsigned_wrap`, or `__pointer_wrap` function attribute.
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
----------------------------------------------------------------------
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index d24f43fc79c6..84cfd9d55453 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -293,12 +293,17 @@ struct ftrace_likely_data {
#else
# define __unsigned_wrap
#endif
+#ifdef CONFIG_UBSAN_POINTER_WRAP
+# define __pointer_wrap __attribute__((no_sanitize("pointer-overflow")))
+#else
+# define __pointer_wrap
+#endif
/* Section for code which can't be instrumented at all */
#define __noinstr_section(section) \
noinline notrace __attribute((__section__(section))) \
__no_kcsan __no_sanitize_address __no_profile __no_sanitize_coverage \
- __no_sanitize_memory __signed_wrap __unsigned_wrap
+ __no_sanitize_memory __signed_wrap __unsigned_wrap __pointer_wrap
#define noinstr __noinstr_section(".noinstr.text")
diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
index a7003e5bd2a1..04222a6d7fd9 100644
--- a/lib/Kconfig.ubsan
+++ b/lib/Kconfig.ubsan
@@ -135,6 +135,14 @@ config UBSAN_UNSIGNED_WRAP
for wrap-around of any arithmetic operations with unsigned integers. This
currently causes x86 to fail to boot.
+config UBSAN_POINTER_WRAP
+ bool "Perform checking for pointer arithmetic wrap-around"
+ depends on !COMPILE_TEST
+ depends on $(cc-option,-fsanitize=pointer-overflow)
+ help
+ This option enables -fsanitize=pointer-overflow which checks
+ for wrap-around of any arithmetic operations with pointers.
+
config UBSAN_BOOL
bool "Perform checking for non-boolean values used as boolean"
default UBSAN
diff --git a/lib/test_ubsan.c b/lib/test_ubsan.c
index 84d8092d6c32..1cc049b3ef34 100644
--- a/lib/test_ubsan.c
+++ b/lib/test_ubsan.c
@@ -56,6 +56,36 @@ static void test_ubsan_negate_overflow(void)
val = -val;
}
+static void test_ubsan_pointer_overflow_add(void)
+{
+ volatile void *top = (void *)ULONG_MAX;
+
+ UBSAN_TEST(CONFIG_UBSAN_POINTER_WRAP);
+ top += 2;
+}
+
+static void test_ubsan_pointer_overflow_sub(void)
+{
+ volatile void *bottom = (void *)1;
+
+ UBSAN_TEST(CONFIG_UBSAN_POINTER_WRAP);
+ bottom -= 3;
+}
+
+struct ptr_wrap {
+ int a;
+ int b;
+};
+
+static void test_ubsan_pointer_overflow_mul(void)
+{
+ volatile struct ptr_wrap *half = (void *)(ULONG_MAX - 128);
+ volatile int bump = 128;
+
+ UBSAN_TEST(CONFIG_UBSAN_POINTER_WRAP);
+ half += bump;
+}
+
static void test_ubsan_divrem_overflow(void)
{
volatile int val = 16;
@@ -139,6 +169,9 @@ static const test_ubsan_fp test_ubsan_array[] = {
test_ubsan_sub_overflow,
test_ubsan_mul_overflow,
test_ubsan_negate_overflow,
+ test_ubsan_pointer_overflow_add,
+ test_ubsan_pointer_overflow_sub,
+ test_ubsan_pointer_overflow_mul,
test_ubsan_shift_out_of_bounds,
test_ubsan_out_of_bounds,
test_ubsan_load_invalid_value,
diff --git a/lib/ubsan.c b/lib/ubsan.c
index 5fc107f61934..d49580ff6aea 100644
--- a/lib/ubsan.c
+++ b/lib/ubsan.c
@@ -289,6 +289,27 @@ void __ubsan_handle_negate_overflow(void *_data, void *old_val)
}
EXPORT_SYMBOL(__ubsan_handle_negate_overflow);
+void __ubsan_handle_pointer_overflow(void *_data, void *lhs, void *rhs)
+{
+ struct overflow_data *data = _data;
+ unsigned long before = (unsigned long)lhs;
+ unsigned long after = (unsigned long)rhs;
+
+ if (suppress_report(&data->location))
+ return;
+
+ ubsan_prologue(&data->location, "pointer-overflow");
+
+ if (after == 0)
+ pr_err("overflow wrapped to NULL\n");
+ else if (after < before)
+ pr_err("overflow wrap-around\n");
+ else
+ pr_err("underflow wrap-around\n");
+
+ ubsan_epilogue();
+}
+EXPORT_SYMBOL(__ubsan_handle_pointer_overflow);
void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs)
{
diff --git a/lib/ubsan.h b/lib/ubsan.h
index 0abbbac8700d..5dd27923b78b 100644
--- a/lib/ubsan.h
+++ b/lib/ubsan.h
@@ -128,6 +128,7 @@ void __ubsan_handle_add_overflow(void *data, void *lhs, void *rhs);
void __ubsan_handle_sub_overflow(void *data, void *lhs, void *rhs);
void __ubsan_handle_mul_overflow(void *data, void *lhs, void *rhs);
void __ubsan_handle_negate_overflow(void *_data, void *old_val);
+void __ubsan_handle_pointer_overflow(void *_data, void *lhs, void *rhs);
void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs);
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr);
void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr);
diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
index de4fc0ae448a..37e8c31dc655 100644
--- a/scripts/Makefile.ubsan
+++ b/scripts/Makefile.ubsan
@@ -10,6 +10,7 @@ ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero
ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable
ubsan-cflags-$(CONFIG_UBSAN_SIGNED_WRAP) += -fsanitize=signed-integer-overflow
ubsan-cflags-$(CONFIG_UBSAN_UNSIGNED_WRAP) += -fsanitize=unsigned-integer-overflow
+ubsan-cflags-$(CONFIG_UBSAN_POINTER_WRAP) += -fsanitize=pointer-overflow
ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool
ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum
ubsan-cflags-$(CONFIG_UBSAN_TRAP) += -fsanitize-undefined-trap-on-error
--
2.34.1
Effectively revert commit 6aaa31aeb9cf ("ubsan: remove overflow
checks"), to allow the kernel to be built with the "*-overflow"
sanitizers again. This gives developers a chance to experiment[1][2][3]
with the instrumentation again, while dealing with the impact of
-fno-strict-oveflow.
Notably, the naming of the options is adjusted to use the name "WRAP"
instead of "OVERFLOW". In the strictest sense, arithmetic "overflow"
happens when a result exceeds the storage of the type, and is considered
by the C standard and compilers to be undefined behavior for signed
and pointer types (without -fno-strict-overflow). Unsigned arithmetic
overflow is defined as always wrapping around.
Because the kernel is built with -fno-strict-overflow, signed and pointer
arithmetic is defined to always wrap around instead of "overflowing"
(which would either be elided due to being undefined behavior or would
wrap around, which led to very weird bugs in the kernel).
So, the config options are added back as CONFIG_UBSAN_SIGNED_WRAP and
CONFIG_UBSAN_UNSIGNED_WRAP. Since the kernel has several places that
explicitly depend on wrap-around behavior (e.g. counters, atomics, etc),
also introduce the __signed_wrap and __unsigned_wrap function attributes
for annotating functions where wrapping is expected and should not
be caught. This will allow us to distinguish in the kernel between
intentional and unintentional cases of arithmetic wrap-around.
Additionally keep these disabled under CONFIG_COMPILE_TEST for now.
Link: https://github.com/KSPP/linux/issues/26 [1]
Link: https://github.com/KSPP/linux/issues/27 [2]
Link: https://github.com/KSPP/linux/issues/344 [3]
Cc: Justin Stitt <[email protected]>
Cc: Miguel Ojeda <[email protected]>
Cc: Nathan Chancellor <[email protected]>
Cc: Nick Desaulniers <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Hao Luo <[email protected]>
Cc: Przemek Kitszel <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
Documentation/process/deprecated.rst | 4 ++
include/linux/compiler_types.h | 14 +++++-
lib/Kconfig.ubsan | 19 ++++++++
lib/test_ubsan.c | 49 ++++++++++++++++++++
lib/ubsan.c | 68 ++++++++++++++++++++++++++++
lib/ubsan.h | 4 ++
scripts/Makefile.ubsan | 2 +
7 files changed, 159 insertions(+), 1 deletion(-)
diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst
index 270f3af13b86..aebd7c6cd2fc 100644
--- a/Documentation/process/deprecated.rst
+++ b/Documentation/process/deprecated.rst
@@ -141,6 +141,10 @@ replaced with a type max subtraction test instead::
...
if (INT_MAX - var < offset) ...
+For inline helpers that are performing wrapping arithmetic, the entire
+function can be annotated as intentionally wrapping by adding the
+`__signed_wrap` or `__unsigned_wrap` function attribute.
+
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
----------------------------------------------------------------------
The simple_strtol(), simple_strtoll(),
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index d27b58fddfaa..d24f43fc79c6 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -282,11 +282,23 @@ struct ftrace_likely_data {
#define __no_sanitize_or_inline __always_inline
#endif
+/* Allow wrapping arithmetic within an annotated function. */
+#ifdef CONFIG_UBSAN_SIGNED_WRAP
+# define __signed_wrap __attribute__((no_sanitize("signed-integer-overflow")))
+#else
+# define __signed_wrap
+#endif
+#ifdef CONFIG_UBSAN_UNSIGNED_WRAP
+# define __unsigned_wrap __attribute__((no_sanitize("unsigned-integer-overflow")))
+#else
+# define __unsigned_wrap
+#endif
+
/* Section for code which can't be instrumented at all */
#define __noinstr_section(section) \
noinline notrace __attribute((__section__(section))) \
__no_kcsan __no_sanitize_address __no_profile __no_sanitize_coverage \
- __no_sanitize_memory
+ __no_sanitize_memory __signed_wrap __unsigned_wrap
#define noinstr __noinstr_section(".noinstr.text")
diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan
index 59e21bfec188..a7003e5bd2a1 100644
--- a/lib/Kconfig.ubsan
+++ b/lib/Kconfig.ubsan
@@ -116,6 +116,25 @@ config UBSAN_UNREACHABLE
This option enables -fsanitize=unreachable which checks for control
flow reaching an expected-to-be-unreachable position.
+config UBSAN_SIGNED_WRAP
+ bool "Perform checking for signed arithmetic wrap-around"
+ default UBSAN
+ depends on !COMPILE_TEST
+ depends on $(cc-option,-fsanitize=signed-integer-overflow)
+ help
+ This option enables -fsanitize=signed-integer-overflow which checks
+ for wrap-around of any arithmetic operations with signed integers.
+
+config UBSAN_UNSIGNED_WRAP
+ bool "Perform checking for unsigned arithmetic wrap-around"
+ depends on $(cc-option,-fsanitize=unsigned-integer-overflow)
+ depends on !X86_32 # avoid excessive stack usage on x86-32/clang
+ depends on !COMPILE_TEST
+ help
+ This option enables -fsanitize=unsigned-integer-overflow which checks
+ for wrap-around of any arithmetic operations with unsigned integers. This
+ currently causes x86 to fail to boot.
+
config UBSAN_BOOL
bool "Perform checking for non-boolean values used as boolean"
default UBSAN
diff --git a/lib/test_ubsan.c b/lib/test_ubsan.c
index 2062be1f2e80..84d8092d6c32 100644
--- a/lib/test_ubsan.c
+++ b/lib/test_ubsan.c
@@ -11,6 +11,51 @@ typedef void(*test_ubsan_fp)(void);
#config, IS_ENABLED(config) ? "y" : "n"); \
} while (0)
+static void test_ubsan_add_overflow(void)
+{
+ volatile int val = INT_MAX;
+ volatile unsigned int uval = UINT_MAX;
+
+ UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP);
+ val += 2;
+
+ UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_WRAP);
+ uval += 2;
+}
+
+static void test_ubsan_sub_overflow(void)
+{
+ volatile int val = INT_MIN;
+ volatile unsigned int uval = 0;
+ volatile int val2 = 2;
+
+ UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP);
+ val -= val2;
+
+ UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_WRAP);
+ uval -= val2;
+}
+
+static void test_ubsan_mul_overflow(void)
+{
+ volatile int val = INT_MAX / 2;
+ volatile unsigned int uval = UINT_MAX / 2;
+
+ UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP);
+ val *= 3;
+
+ UBSAN_TEST(CONFIG_UBSAN_UNSIGNED_WRAP);
+ uval *= 3;
+}
+
+static void test_ubsan_negate_overflow(void)
+{
+ volatile int val = INT_MIN;
+
+ UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP);
+ val = -val;
+}
+
static void test_ubsan_divrem_overflow(void)
{
volatile int val = 16;
@@ -90,6 +135,10 @@ static void test_ubsan_misaligned_access(void)
}
static const test_ubsan_fp test_ubsan_array[] = {
+ test_ubsan_add_overflow,
+ test_ubsan_sub_overflow,
+ test_ubsan_mul_overflow,
+ test_ubsan_negate_overflow,
test_ubsan_shift_out_of_bounds,
test_ubsan_out_of_bounds,
test_ubsan_load_invalid_value,
diff --git a/lib/ubsan.c b/lib/ubsan.c
index df4f8d1354bb..5fc107f61934 100644
--- a/lib/ubsan.c
+++ b/lib/ubsan.c
@@ -222,6 +222,74 @@ static void ubsan_epilogue(void)
check_panic_on_warn("UBSAN");
}
+static void handle_overflow(struct overflow_data *data, void *lhs,
+ void *rhs, char op)
+{
+
+ struct type_descriptor *type = data->type;
+ char lhs_val_str[VALUE_LENGTH];
+ char rhs_val_str[VALUE_LENGTH];
+
+ if (suppress_report(&data->location))
+ return;
+
+ ubsan_prologue(&data->location, type_is_signed(type) ?
+ "signed-integer-overflow" :
+ "unsigned-integer-overflow");
+
+ val_to_string(lhs_val_str, sizeof(lhs_val_str), type, lhs);
+ val_to_string(rhs_val_str, sizeof(rhs_val_str), type, rhs);
+ pr_err("%s %c %s cannot be represented in type %s\n",
+ lhs_val_str,
+ op,
+ rhs_val_str,
+ type->type_name);
+
+ ubsan_epilogue();
+}
+
+void __ubsan_handle_add_overflow(void *data,
+ void *lhs, void *rhs)
+{
+
+ handle_overflow(data, lhs, rhs, '+');
+}
+EXPORT_SYMBOL(__ubsan_handle_add_overflow);
+
+void __ubsan_handle_sub_overflow(void *data,
+ void *lhs, void *rhs)
+{
+ handle_overflow(data, lhs, rhs, '-');
+}
+EXPORT_SYMBOL(__ubsan_handle_sub_overflow);
+
+void __ubsan_handle_mul_overflow(void *data,
+ void *lhs, void *rhs)
+{
+ handle_overflow(data, lhs, rhs, '*');
+}
+EXPORT_SYMBOL(__ubsan_handle_mul_overflow);
+
+void __ubsan_handle_negate_overflow(void *_data, void *old_val)
+{
+ struct overflow_data *data = _data;
+ char old_val_str[VALUE_LENGTH];
+
+ if (suppress_report(&data->location))
+ return;
+
+ ubsan_prologue(&data->location, "negation-overflow");
+
+ val_to_string(old_val_str, sizeof(old_val_str), data->type, old_val);
+
+ pr_err("negation of %s cannot be represented in type %s:\n",
+ old_val_str, data->type->type_name);
+
+ ubsan_epilogue();
+}
+EXPORT_SYMBOL(__ubsan_handle_negate_overflow);
+
+
void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs)
{
struct overflow_data *data = _data;
diff --git a/lib/ubsan.h b/lib/ubsan.h
index 5d99ab81913b..0abbbac8700d 100644
--- a/lib/ubsan.h
+++ b/lib/ubsan.h
@@ -124,6 +124,10 @@ typedef s64 s_max;
typedef u64 u_max;
#endif
+void __ubsan_handle_add_overflow(void *data, void *lhs, void *rhs);
+void __ubsan_handle_sub_overflow(void *data, void *lhs, void *rhs);
+void __ubsan_handle_mul_overflow(void *data, void *lhs, void *rhs);
+void __ubsan_handle_negate_overflow(void *_data, void *old_val);
void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs);
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr);
void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr);
diff --git a/scripts/Makefile.ubsan b/scripts/Makefile.ubsan
index 4749865c1b2c..de4fc0ae448a 100644
--- a/scripts/Makefile.ubsan
+++ b/scripts/Makefile.ubsan
@@ -8,6 +8,8 @@ ubsan-cflags-$(CONFIG_UBSAN_LOCAL_BOUNDS) += -fsanitize=local-bounds
ubsan-cflags-$(CONFIG_UBSAN_SHIFT) += -fsanitize=shift
ubsan-cflags-$(CONFIG_UBSAN_DIV_ZERO) += -fsanitize=integer-divide-by-zero
ubsan-cflags-$(CONFIG_UBSAN_UNREACHABLE) += -fsanitize=unreachable
+ubsan-cflags-$(CONFIG_UBSAN_SIGNED_WRAP) += -fsanitize=signed-integer-overflow
+ubsan-cflags-$(CONFIG_UBSAN_UNSIGNED_WRAP) += -fsanitize=unsigned-integer-overflow
ubsan-cflags-$(CONFIG_UBSAN_BOOL) += -fsanitize=bool
ubsan-cflags-$(CONFIG_UBSAN_ENUM) += -fsanitize=enum
ubsan-cflags-$(CONFIG_UBSAN_TRAP) += -fsanitize-undefined-trap-on-error
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Alexander Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Cc: Jan Kara <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/read_write.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/fs/read_write.c b/fs/read_write.c
index d4c036e82b6c..e24b94a8937d 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1417,6 +1417,7 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
struct inode *inode_out = file_inode(file_out);
uint64_t count = *req_count;
loff_t size_in;
+ loff_t sum_in, sum_out;
int ret;
ret = generic_file_rw_checks(file_in, file_out);
@@ -1451,7 +1452,8 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
return -ETXTBSY;
/* Ensure offsets don't wrap. */
- if (pos_in + count < pos_in || pos_out + count < pos_out)
+ if (check_add_overflow(pos_in, count, &sum_in) ||
+ check_add_overflow(pos_out, count, &sum_out))
return -EOVERFLOW;
/* Shorten the copy to EOF */
@@ -1467,8 +1469,8 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
/* Don't allow overlapped copying within the same file. */
if (inode_in == inode_out &&
- pos_out + count > pos_in &&
- pos_out < pos_in + count)
+ sum_out > pos_in &&
+ pos_out < sum_in)
return -EINVAL;
*req_count = count;
--
2.34.1
The loop counter "i" in copy_compat_iovec_from_user() is an int, but
because the nr_segs argument is unsigned long, the signed overflow
sanitizer got worried "i" could wrap around. Instead of making "i" an
unsigned long (which may enlarge the type size), switch both nr_segs
and i to u32. There is no truncation with nr_segs since its is never
larger than UIO_MAXIOV anyway. This keeps sanitizer instrumentation[1]
out of a UACCESS path:
vmlinux.o: warning: objtool: copy_compat_iovec_from_user+0xa9: call to __ubsan_handle_add_overflow() with UACCESS enabled
Link: https://github.com/KSPP/linux/issues/26 [1]
Cc: Alexander Viro <[email protected]>
Cc: Andrew Morton <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
lib/iov_iter.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index e0aa6b440ca5..d797a43dca91 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -1166,11 +1166,12 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
EXPORT_SYMBOL(dup_iter);
static __noclone int copy_compat_iovec_from_user(struct iovec *iov,
- const struct iovec __user *uvec, unsigned long nr_segs)
+ const struct iovec __user *uvec, u32 nr_segs)
{
const struct compat_iovec __user *uiov =
(const struct compat_iovec __user *)uvec;
- int ret = -EFAULT, i;
+ int ret = -EFAULT;
+ u32 i;
if (!user_access_begin(uiov, nr_segs * sizeof(*uiov)))
return -EFAULT;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Maxime Ripard <[email protected]>
Cc: Maarten Lankhorst <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/gpu/drm/vc4/vc4_validate.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
index 7dff3ca5af6b..9affba9c58b3 100644
--- a/drivers/gpu/drm/vc4/vc4_validate.c
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -305,6 +305,7 @@ validate_gl_array_primitive(VALIDATE_ARGS)
uint32_t length = *(uint32_t *)(untrusted + 1);
uint32_t base_index = *(uint32_t *)(untrusted + 5);
uint32_t max_index;
+ uint32_t sum;
struct vc4_shader_state *shader_state;
/* Check overflow condition */
@@ -314,11 +315,11 @@ validate_gl_array_primitive(VALIDATE_ARGS)
}
shader_state = &exec->shader_state[exec->shader_state_count - 1];
- if (length + base_index < length) {
+ if (check_add_overflow(length, base_index, &sum)) {
DRM_DEBUG("primitive vertex count overflow\n");
return -EINVAL;
}
- max_index = length + base_index - 1;
+ max_index = sum - 1;
if (max_index > shader_state->max_index)
shader_state->max_index = max_index;
--
2.34.1
For instances where only the overflow needs to be checked (and the sum
isn't used), provide the new helper add_would_overflow(), which is
a wrapper for check_add_overflow().
Cc: "Gustavo A. R. Silva" <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
include/linux/overflow.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/include/linux/overflow.h b/include/linux/overflow.h
index 099f2e559aa8..ac088f73e0fd 100644
--- a/include/linux/overflow.h
+++ b/include/linux/overflow.h
@@ -108,6 +108,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
__builtin_add_overflow(__filter_integral(a), b, \
__filter_ptrint(d))))
+/**
+ * add_would_overflow() - Check if an addition would overflow
+ * @a: first addend
+ * @b: second addend
+ *
+ * Returns true if the sum would overflow.
+ *
+ * To keep a copy of the sum when the addition doesn't overflow, use
+ * check_add_overflow() instead.
+ */
+#define add_would_overflow(a, b) \
+ __must_check_overflow(({ \
+ size_t __result; \
+ check_add_overflow(a, b, &__result);\
+ }))
+
/**
* check_sub_overflow() - Calculate subtraction with overflow checking
* @a: minuend; value to subtract from
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Mikulas Patocka <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
fs/hpfs/alloc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c
index 66617b1557c6..e9c7cc6033b5 100644
--- a/fs/hpfs/alloc.c
+++ b/fs/hpfs/alloc.c
@@ -99,7 +99,7 @@ static int chk_if_allocated(struct super_block *s, secno sec, char *msg)
int hpfs_chk_sectors(struct super_block *s, secno start, int len, char *msg)
{
- if (start + len < start || start < 0x12 ||
+ if (add_would_overflow(start, len) || start < 0x12 ||
start + len > hpfs_sb(s)->sb_fs_size) {
hpfs_error(s, "sector(s) '%s' badly placed at %08x", msg, start);
return 1;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Kalle Valo <[email protected]>
Cc: Johannes Berg <[email protected]>
Cc: Max Chen <[email protected]>
Cc: Yang Shen <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 6fdb77d4c59e..3b3c991f77e9 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -286,7 +286,7 @@ void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
off = HOSTADDR(ptr);
if (off > wil->bar_size - 4)
return NULL;
- if (size && ((off + size > wil->bar_size) || (off + size < off)))
+ if (size && ((off + size > wil->bar_size) || (add_would_overflow(off, size))))
return NULL;
return wil->csr + off;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Pablo Neira Ayuso <[email protected]>
Cc: Jozsef Kadlecsik <[email protected]>
Cc: Florian Westphal <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jakub Kicinski <[email protected]>
Cc: Paolo Abeni <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
net/netfilter/xt_u32.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c
index 117d4615d668..8623fe2d97e9 100644
--- a/net/netfilter/xt_u32.c
+++ b/net/netfilter/xt_u32.c
@@ -58,11 +58,11 @@ static bool u32_match_it(const struct xt_u32 *data,
val >>= number;
break;
case XT_U32_AT:
- if (at + val < at)
+ if (add_would_overflow(at, val))
return false;
at += val;
pos = number;
- if (at + 4 < at || skb->len < at + 4 ||
+ if (add_would_overflow(at, 4) || skb->len < at + 4 ||
pos > skb->len - at - 4)
return false;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Christian Borntraeger <[email protected]>
Cc: Janosch Frank <[email protected]>
Cc: Claudio Imbrenda <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Alexander Gordeev <[email protected]>
Cc: Gerald Schaefer <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Vasily Gorbik <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/s390/mm/gmap.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 6f96b5a71c63..977b61ab59f2 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -411,7 +411,7 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len)
BUG_ON(gmap_is_shadow(gmap));
if ((to | len) & (PMD_SIZE - 1))
return -EINVAL;
- if (len == 0 || to + len < to)
+ if (len == 0 || add_would_overflow(to, len))
return -EINVAL;
flush = 0;
@@ -443,7 +443,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
BUG_ON(gmap_is_shadow(gmap));
if ((from | to | len) & (PMD_SIZE - 1))
return -EINVAL;
- if (len == 0 || from + len < from || to + len < to ||
+ if (len == 0 || add_would_overflow(from, len) || add_would_overflow(to, len) ||
from + len - 1 > TASK_SIZE_MAX || to + len - 1 > gmap->asce_end)
return -EINVAL;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Andrey Ryabinin <[email protected]>
Cc: Alexander Potapenko <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Vincenzo Frascino <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
mm/kasan/generic.c | 2 +-
mm/kasan/sw_tags.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index df6627f62402..f9bc29ae09bd 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -171,7 +171,7 @@ static __always_inline bool check_region_inline(const void *addr,
if (unlikely(size == 0))
return true;
- if (unlikely(addr + size < addr))
+ if (unlikely(add_would_overflow(addr, size)))
return !kasan_report(addr, size, write, ret_ip);
if (unlikely(!addr_has_metadata(addr)))
diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
index 220b5d4c6876..79a3bbd66c32 100644
--- a/mm/kasan/sw_tags.c
+++ b/mm/kasan/sw_tags.c
@@ -80,7 +80,7 @@ bool kasan_check_range(const void *addr, size_t size, bool write,
if (unlikely(size == 0))
return true;
- if (unlikely(addr + size < addr))
+ if (unlikely(add_would_overflow(addr, size)))
return !kasan_report(addr, size, write, ret_ip);
tag = get_tag((const void *)addr);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Bjorn Andersson <[email protected]>
Cc: Mathieu Poirier <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/remoteproc/pru_rproc.c | 2 +-
drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
drivers/remoteproc/remoteproc_virtio.c | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 327f0c7ee3d6..834249ee3dd3 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -893,7 +893,7 @@ pru_rproc_find_interrupt_map(struct device *dev, const struct firmware *fw)
continue;
/* make sure we have the entire irq map */
- if (offset + size > fw->size || offset + size < size) {
+ if (offset + size > fw->size || add_would_overflow(size, offset)) {
dev_err(dev, ".pru_irq_map section truncated\n");
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 94177e416047..b9231cf46d68 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -278,7 +278,7 @@ find_table(struct device *dev, const struct firmware *fw)
table = (struct resource_table *)(elf_data + offset);
/* make sure we have the entire table */
- if (offset + size > fw_size || offset + size < size) {
+ if (offset + size > fw_size || add_would_overflow(size, offset)) {
dev_err(dev, "resource table truncated\n");
return NULL;
}
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index 83d76915a6ad..58742c666e35 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -298,7 +298,7 @@ static void rproc_virtio_get(struct virtio_device *vdev, unsigned int offset,
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
cfg = &rsc->vring[rsc->num_of_vrings];
- if (offset + len > rsc->config_len || offset + len < len) {
+ if (offset + len > rsc->config_len || add_would_overflow(len, offset)) {
dev_err(&vdev->dev, "rproc_virtio_get: access out of bounds\n");
return;
}
@@ -316,7 +316,7 @@ static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset,
rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
cfg = &rsc->vring[rsc->num_of_vrings];
- if (offset + len > rsc->config_len || offset + len < len) {
+ if (offset + len > rsc->config_len || add_would_overflow(len, offset)) {
dev_err(&vdev->dev, "rproc_virtio_set: access out of bounds\n");
return;
}
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Jarkko Sakkinen <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: [email protected]
Cc: "H. Peter Anvin" <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/x86/kernel/cpu/sgx/ioctl.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
index b65ab214bdf5..4b8f6c9f8ef5 100644
--- a/arch/x86/kernel/cpu/sgx/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/ioctl.c
@@ -350,16 +350,18 @@ static int sgx_validate_offset_length(struct sgx_encl *encl,
unsigned long offset,
unsigned long length)
{
+ unsigned long sum;
+
if (!IS_ALIGNED(offset, PAGE_SIZE))
return -EINVAL;
if (!length || !IS_ALIGNED(length, PAGE_SIZE))
return -EINVAL;
- if (offset + length < offset)
+ if (check_add_overflow(offset, length, &sum))
return -EINVAL;
- if (offset + length - PAGE_SIZE >= encl->size)
+ if (sum - PAGE_SIZE >= encl->size)
return -EINVAL;
return 0;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Geert Uytterhoeven <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Liam Howlett <[email protected]>
Cc: "Matthew Wilcox (Oracle)" <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/m68k/kernel/sys_m68k.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 1af5e6082467..b2b9248f2566 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -391,10 +391,11 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
mmap_read_lock(current->mm);
} else {
+ unsigned long sum;
struct vm_area_struct *vma;
/* Check for overflow. */
- if (addr + len < addr)
+ if (check_add_overflow(addr, len, &sum))
goto out;
/*
@@ -403,7 +404,7 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
*/
mmap_read_lock(current->mm);
vma = vma_lookup(current->mm, addr);
- if (!vma || addr + len > vma->vm_end)
+ if (!vma || sum > vma->vm_end)
goto out_unlock;
}
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded pointer wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Andrew Morton <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
lib/buildid.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/buildid.c b/lib/buildid.c
index e3a7acdeef0e..d0a310cb9b57 100644
--- a/lib/buildid.c
+++ b/lib/buildid.c
@@ -54,12 +54,14 @@ static inline int parse_build_id(const void *page_addr,
const void *note_start,
Elf32_Word note_size)
{
+ const void *sum;
+
/* check for overflow */
- if (note_start < page_addr || note_start + note_size < note_start)
+ if (note_start < page_addr || check_add_overflow(note_start, note_size, &sum))
return -EINVAL;
/* only supports note that fits in the first page */
- if (note_start + note_size > page_addr + PAGE_SIZE)
+ if (sum > page_addr + PAGE_SIZE)
return -EINVAL;
return parse_build_id_buf(build_id, size, note_start, note_size);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Kalesh Singh <[email protected]>
Cc: Fuad Tabba <[email protected]>
Cc: Mark Brown <[email protected]>
Cc: "Madhavan T. Venkataraman" <[email protected]>
Cc: Marc Zyngier <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/arm64/include/asm/stacktrace/common.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h
index f63dc654e545..6e0cb84961f8 100644
--- a/arch/arm64/include/asm/stacktrace/common.h
+++ b/arch/arm64/include/asm/stacktrace/common.h
@@ -49,7 +49,7 @@ static inline bool stackinfo_on_stack(const struct stack_info *info,
if (!info->low)
return false;
- if (sp < info->low || sp + size < sp || sp + size > info->high)
+ if (sp < info->low || add_would_overflow(sp, size) || sp + size > info->high)
return false;
return true;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Sathya Prakash <[email protected]>
Cc: Sreekanth Reddy <[email protected]>
Cc: Suganath Prabu Subramani <[email protected]>
Cc: "James E.J. Bottomley" <[email protected]>
Cc: "Martin K. Petersen" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/scsi/mpt3sas/mpt3sas_ctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 147cb7088d55..b36a9188720f 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -2382,7 +2382,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
karg.bytes_to_read));
/* Truncate data on requests that are too large */
- if ((diag_data + karg.bytes_to_read < diag_data) ||
+ if ((add_would_overflow(diag_data, karg.bytes_to_read)) ||
(diag_data + karg.bytes_to_read > request_data + request_size))
copy_size = request_size - karg.starting_offset;
else
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: "Michael S. Tsirkin" <[email protected]>
Cc: Jason Wang <[email protected]>
Cc: Xuan Zhuo <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/virtio/virtio_pci_modern_dev.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/virtio/virtio_pci_modern_dev.c b/drivers/virtio/virtio_pci_modern_dev.c
index 0d3dbfaf4b23..710d3bd45b4f 100644
--- a/drivers/virtio/virtio_pci_modern_dev.c
+++ b/drivers/virtio/virtio_pci_modern_dev.c
@@ -59,7 +59,7 @@ vp_modern_map_capability(struct virtio_pci_modern_device *mdev, int off,
length -= start;
- if (start + offset < offset) {
+ if (add_would_overflow(offset, start)) {
dev_err(&dev->dev,
"virtio_pci: map wrap-around %u+%u\n",
start, offset);
@@ -81,7 +81,7 @@ vp_modern_map_capability(struct virtio_pci_modern_device *mdev, int off,
if (len)
*len = length;
- if (minlen + offset < minlen ||
+ if (add_would_overflow(minlen, offset) ||
minlen + offset > pci_resource_len(dev, bar)) {
dev_err(&dev->dev,
"virtio_pci: map virtio %zu@%u "
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Bjorn Helgaas <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/pci/pci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d8f11a078924..ebf6d9064a59 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4251,7 +4251,7 @@ int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr,
#ifdef PCI_IOBASE
struct logic_pio_hwaddr *range;
- if (!size || addr + size < addr)
+ if (!size || add_would_overflow(addr, size))
return -EINVAL;
range = kzalloc(sizeof(*range), GFP_ATOMIC);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Kees Cook <[email protected]>
Cc: "Gustavo A. R. Silva" <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: Gustavo A. R. Silva <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
mm/usercopy.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mm/usercopy.c b/mm/usercopy.c
index 83c164aba6e0..5141c4402903 100644
--- a/mm/usercopy.c
+++ b/mm/usercopy.c
@@ -151,7 +151,7 @@ static inline void check_bogus_address(const unsigned long ptr, unsigned long n,
bool to_user)
{
/* Reject if object wraps past end of memory. */
- if (ptr + (n - 1) < ptr)
+ if (add_would_overflow(ptr, (n - 1)))
usercopy_abort("wrapped address", NULL, to_user, 0, ptr + n);
/* Reject if NULL or ZERO-allocation. */
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: John Stultz <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Stephen Boyd <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
kernel/time/timekeeping.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 266d02809dbb..2fc7cf16584c 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1984,7 +1984,7 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
* Which simplifies to:
* xtime_nsec -= offset
*/
- if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) {
+ if ((mult_adj > 0) && (add_would_overflow(mult_adj, tk->tkr_mono.mult))) {
/* NTP adjustment caused clocksource mult overflow */
WARN_ON_ONCE(1);
return;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Andrew Morton <[email protected]>
Cc: Shuah Khan <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
mm/memory.c | 4 ++--
mm/mmap.c | 2 +-
mm/mremap.c | 2 +-
mm/nommu.c | 4 ++--
mm/util.c | 2 +-
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/mm/memory.c b/mm/memory.c
index 7e1f4849463a..d47acdff7af3 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2559,7 +2559,7 @@ int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long
unsigned long vm_len, pfn, pages;
/* Check that the physical memory area passed in looks valid */
- if (start + len < start)
+ if (add_would_overflow(start, len))
return -EINVAL;
/*
* You *really* shouldn't map things that aren't page-aligned,
@@ -2569,7 +2569,7 @@ int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long
len += start & ~PAGE_MASK;
pfn = start >> PAGE_SHIFT;
pages = (len + ~PAGE_MASK) >> PAGE_SHIFT;
- if (pfn + pages < pfn)
+ if (add_would_overflow(pfn, pages))
return -EINVAL;
/* We start the mapping 'vm_pgoff' pages into the area */
diff --git a/mm/mmap.c b/mm/mmap.c
index b78e83d351d2..16501fcaf511 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -3023,7 +3023,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
return ret;
/* Does pgoff wrap? */
- if (pgoff + (size >> PAGE_SHIFT) < pgoff)
+ if (add_would_overflow(pgoff, (size >> PAGE_SHIFT)))
return ret;
if (mmap_write_lock_killable(mm))
diff --git a/mm/mremap.c b/mm/mremap.c
index 38d98465f3d8..efa27019a05d 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -848,7 +848,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr,
/* Need to be careful about a growing mapping */
pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
pgoff += vma->vm_pgoff;
- if (pgoff + (new_len >> PAGE_SHIFT) < pgoff)
+ if (add_would_overflow(pgoff, (new_len >> PAGE_SHIFT)))
return ERR_PTR(-EINVAL);
if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
diff --git a/mm/nommu.c b/mm/nommu.c
index b6dc558d3144..299bcfe19eed 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -202,7 +202,7 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
long vread_iter(struct iov_iter *iter, const char *addr, size_t count)
{
/* Don't allow overflow */
- if ((unsigned long) addr + count < count)
+ if (add_would_overflow(count, (unsigned long)addr))
count = -(unsigned long) addr;
return copy_to_iter(addr, count, iter);
@@ -1705,7 +1705,7 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
{
struct mm_struct *mm;
- if (addr + len < addr)
+ if (add_would_overflow(addr, len))
return 0;
mm = get_task_mm(tsk);
diff --git a/mm/util.c b/mm/util.c
index 5a6a9802583b..e6beeb23b48b 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -567,7 +567,7 @@ unsigned long vm_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long offset)
{
- if (unlikely(offset + PAGE_ALIGN(len) < offset))
+ if (unlikely(add_would_overflow(offset, PAGE_ALIGN(len))))
return -EINVAL;
if (unlikely(offset_in_page(offset)))
return -EINVAL;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Maxime Ripard <[email protected]>
Cc: Maarten Lankhorst <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/gpu/drm/vc4/vc4_validate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
index 9affba9c58b3..677d9975f888 100644
--- a/drivers/gpu/drm/vc4/vc4_validate.c
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -206,7 +206,7 @@ vc4_check_tex_size(struct vc4_exec_info *exec, struct drm_gem_dma_object *fbo,
stride = aligned_width * cpp;
size = stride * aligned_height;
- if (size + offset < size ||
+ if (add_would_overflow(size, offset) ||
size + offset > fbo->base.size) {
DRM_DEBUG("Overflow in %dx%d (%dx%d) fbo size (%d + %d > %zd)\n",
width, height,
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Dinh Nguyen <[email protected]>
Cc: Jann Horn <[email protected]>
Cc: Ley Foon Tan <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
arch/nios2/kernel/sys_nios2.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/nios2/kernel/sys_nios2.c b/arch/nios2/kernel/sys_nios2.c
index b1ca85699952..df53efdc96e3 100644
--- a/arch/nios2/kernel/sys_nios2.c
+++ b/arch/nios2/kernel/sys_nios2.c
@@ -32,7 +32,7 @@ asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len,
return -EINVAL;
/* Check for overflow */
- if (addr + len < addr)
+ if (add_would_overflow(addr, len))
return -EFAULT;
if (mmap_read_lock_killable(mm))
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Sumit Semwal <[email protected]>
Cc: Christian König <[email protected]>
Cc: "Christian König" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/dma-buf/dma-buf.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 8fe5aa67b167..3743c63a9b59 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1458,6 +1458,8 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_end_cpu_access, DMA_BUF);
int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
unsigned long pgoff)
{
+ unsigned long sum;
+
if (WARN_ON(!dmabuf || !vma))
return -EINVAL;
@@ -1466,12 +1468,11 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma,
return -EINVAL;
/* check for offset overflow */
- if (pgoff + vma_pages(vma) < pgoff)
+ if (check_add_overflow(pgoff, vma_pages(vma), &sum))
return -EOVERFLOW;
/* check for overflowing the buffer's size */
- if (pgoff + vma_pages(vma) >
- dmabuf->size >> PAGE_SHIFT)
+ if (sum > dmabuf->size >> PAGE_SHIFT)
return -EINVAL;
/* readjust the vma */
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Konstantin Komarov <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/ntfs3/record.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c
index 53629b1f65e9..8cd738c1dbe6 100644
--- a/fs/ntfs3/record.c
+++ b/fs/ntfs3/record.c
@@ -235,7 +235,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
}
/* Overflow check. */
- if (off + asize < off)
+ if (add_would_overflow(off, asize))
return NULL;
prev_type = le32_to_cpu(attr->type);
@@ -266,7 +266,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
return NULL;
/* Check overflow and boundary. */
- if (off + asize < off || off + asize > used)
+ if (add_would_overflow(off, asize) || off + asize > used)
return NULL;
/* Check size of attribute. */
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Alexander Shishkin <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Ian Rogers <[email protected]>
Cc: Adrian Hunter <[email protected]>
Cc: John Garry <[email protected]>
Cc: Fangrui Song <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
tools/perf/util/dso.c | 2 +-
tools/perf/util/unwind-libdw.c | 2 +-
tools/perf/util/unwind-libunwind-local.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 22fd5fa806ed..470a86f1cdfd 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1122,7 +1122,7 @@ static ssize_t data_read_write_offset(struct dso *dso, struct machine *machine,
if (offset > dso->data.file_size)
return -1;
- if (offset + size < offset)
+ if (add_would_overflow(offset, size))
return -1;
return cached_io(dso, machine, offset, data, size, out);
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 6013335a8dae..45a89cbb2c8d 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -198,7 +198,7 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
end = start + stack->size;
/* Check overflow. */
- if (addr + sizeof(Dwarf_Word) < addr)
+ if (add_would_overflow(addr, sizeof(Dwarf_Word)))
return false;
if (addr < start || addr + sizeof(Dwarf_Word) > end) {
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index dac536e28360..ac71cc7f53b9 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -587,7 +587,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
end = start + stack->size;
/* Check overflow. */
- if (addr + sizeof(unw_word_t) < addr)
+ if (add_would_overflow(addr, sizeof(unw_word_t)))
return -EINVAL;
if (addr < start || addr + sizeof(unw_word_t) >= end) {
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Alasdair Kergon <[email protected]>
Cc: Mike Snitzer <[email protected]>
Cc: Mikulas Patocka <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/md/dm-switch.c | 2 +-
drivers/md/dm-verity-target.c | 2 +-
drivers/md/dm-writecache.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c
index dfd9fb52a6f3..9053d7e65603 100644
--- a/drivers/md/dm-switch.c
+++ b/drivers/md/dm-switch.c
@@ -410,7 +410,7 @@ static int process_set_region_mappings(struct switch_ctx *sctx,
cycle_length - 1, region_index);
return -EINVAL;
}
- if (unlikely(region_index + num_write < region_index) ||
+ if (unlikely(add_would_overflow(region_index, num_write)) ||
unlikely(region_index + num_write >= sctx->nr_regions)) {
DMWARN("invalid set_region_mappings region number: %lu + %lu >= %lu",
region_index, num_write, sctx->nr_regions);
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 14e58ae70521..f2676c8c83c0 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -1392,7 +1392,7 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
v->hash_level_block[i] = hash_position;
s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
>> ((i + 1) * v->hash_per_block_bits);
- if (hash_position + s < hash_position) {
+ if (add_would_overflow(hash_position, s)) {
ti->error = "Hash device offset overflow";
r = -E2BIG;
goto bad;
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
index 074cb785eafc..45e54edd24aa 100644
--- a/drivers/md/dm-writecache.c
+++ b/drivers/md/dm-writecache.c
@@ -2631,7 +2631,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned int argc, char **argv)
offset = (offset + wc->block_size - 1) & ~(size_t)(wc->block_size - 1);
data_size = wc->n_blocks * (size_t)wc->block_size;
if (!offset || (data_size / wc->block_size != wc->n_blocks) ||
- (offset + data_size < offset))
+ (add_would_overflow(offset, data_size)))
goto overflow;
if (offset + data_size > wc->memory_map_size) {
ti->error = "Memory area is too small";
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Andrew Morton <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
lib/scatterlist.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 68b45c82c37a..121905119bbc 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -624,7 +624,7 @@ struct scatterlist *sgl_alloc_order(unsigned long long length,
nalloc = nent;
if (chainable) {
/* Check for integer overflow */
- if (nalloc + 1 < nalloc)
+ if (add_would_overflow(nalloc, 1))
return NULL;
nalloc++;
}
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Michael Ellerman <[email protected]>
Cc: Nicholas Piggin <[email protected]>
Cc: Christophe Leroy <[email protected]>
Cc: "Aneesh Kumar K.V" <[email protected]>
Cc: "Naveen N. Rao" <[email protected]>
Cc: Mahesh Salgaonkar <[email protected]>
Cc: Vasant Hegde <[email protected]>
Cc: dingsenjie <[email protected]>
Cc: [email protected]
Cc: Aneesh Kumar K.V <[email protected]>
Cc: Naveen N. Rao <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
arch/powerpc/platforms/powernv/opal-prd.c | 2 +-
arch/powerpc/xmon/xmon.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/powernv/opal-prd.c b/arch/powerpc/platforms/powernv/opal-prd.c
index b66b06efcef1..eaf95dc82925 100644
--- a/arch/powerpc/platforms/powernv/opal-prd.c
+++ b/arch/powerpc/platforms/powernv/opal-prd.c
@@ -51,7 +51,7 @@ static bool opal_prd_range_is_valid(uint64_t addr, uint64_t size)
struct device_node *parent, *node;
bool found;
- if (addr + size < addr)
+ if (add_would_overflow(addr, size))
return false;
parent = of_find_node_by_path("/reserved-memory");
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index b3b94cd37713..b91fdda49434 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -3252,7 +3252,7 @@ memzcan(void)
} else if (!ok && ook)
printf("%.8lx\n", a - mskip);
ook = ok;
- if (a + mskip < a)
+ if (add_would_overflow(a, mskip))
break;
}
if (ook)
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: "James E.J. Bottomley" <[email protected]>
Cc: "Martin K. Petersen" <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/scsi/sd_zbc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 26af5ab7d7c1..2c377e4cdb2b 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -295,7 +295,7 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
(lba < start_lba ||
lba >= start_lba + zone_length)) ||
(zone_idx > 0 && start_lba != lba) ||
- start_lba + zone_length < start_lba) {
+ add_would_overflow(start_lba, zone_length)) {
sd_printk(KERN_ERR, sdkp,
"Zone %d at LBA %llu is invalid: %llu + %llu\n",
zone_idx, lba, start_lba, zone_length);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Martyn Welch <[email protected]>
Cc: Manohar Vanga <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Soumya Negi <[email protected]>
Cc: Alexon Oliveira <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/staging/vme_user/vme.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/vme_user/vme.c b/drivers/staging/vme_user/vme.c
index e9461a7a7ab8..a0acf2a295cd 100644
--- a/drivers/staging/vme_user/vme.c
+++ b/drivers/staging/vme_user/vme.c
@@ -165,7 +165,7 @@ int vme_check_window(struct vme_bridge *bridge, u32 aspace,
{
int retval = 0;
- if (vme_base + size < size)
+ if (add_would_overflow(size, vme_base))
return -EINVAL;
switch (aspace) {
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Kent Overstreet <[email protected]>
Cc: Brian Foster <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/bcachefs/bkey.c | 4 ++--
fs/bcachefs/fs.c | 2 +-
fs/bcachefs/quota.c | 2 +-
fs/bcachefs/util.c | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/fs/bcachefs/bkey.c b/fs/bcachefs/bkey.c
index 76e79a15ba08..c68f1cfd579e 100644
--- a/fs/bcachefs/bkey.c
+++ b/fs/bcachefs/bkey.c
@@ -448,7 +448,7 @@ static bool bkey_format_has_too_big_fields(const struct bkey_format *f)
: 0;
u64 field_offset = le64_to_cpu(f->field_offset[i]);
- if (packed_max + field_offset < packed_max ||
+ if (add_would_overflow(packed_max, field_offset) ||
packed_max + field_offset > unpacked_max)
return true;
}
@@ -664,7 +664,7 @@ int bch2_bkey_format_invalid(struct bch_fs *c,
: 0;
u64 field_offset = le64_to_cpu(f->field_offset[i]);
- if (packed_max + field_offset < packed_max ||
+ if (add_would_overflow(packed_max, field_offset) ||
packed_max + field_offset > unpacked_max) {
prt_printf(err, "field %u too large: %llu + %llu > %llu",
i, packed_max, field_offset, unpacked_max);
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index ec419b8e2c43..00a606171656 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -901,7 +901,7 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
if (ret)
return ret;
- if (start + len < start)
+ if (add_would_overflow(start, len))
return -EINVAL;
start >>= 9;
diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c
index e68b34eab90a..1738b1fc1c75 100644
--- a/fs/bcachefs/quota.c
+++ b/fs/bcachefs/quota.c
@@ -392,7 +392,7 @@ static void __bch2_quota_transfer(struct bch_memquota *src_q,
enum quota_counters counter, s64 v)
{
BUG_ON(v > src_q->c[counter].v);
- BUG_ON(v + dst_q->c[counter].v < v);
+ BUG_ON(add_would_overflow(v, dst_q->c[counter].v));
src_q->c[counter].v -= v;
dst_q->c[counter].v += v;
diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c
index a135136adeee..2200c81edbd2 100644
--- a/fs/bcachefs/util.c
+++ b/fs/bcachefs/util.c
@@ -148,7 +148,7 @@ static int __bch2_strtou64_h(const char *cp, u64 *res)
return -ERANGE;
f_n = div_u64(f_n * b, f_d);
- if (v + f_n < v)
+ if (add_would_overflow(v, f_n))
return -ERANGE;
v += f_n;
--
2.34.1
In pursuit of gaining full kernel instrumentation for signed[1],
unsigned[2], and pointer[3] arithmetic overflow, we need to replace
the handful of instances in the kernel where we intentionally depend on
arithmetic wrap-around. Introduce Coccinelle script for finding these
and replacing them with the new add_would_overflow() helper, for this
common code pattern:
if (VAR + OFFSET < VAR) ...
Link: https://github.com/KSPP/linux/issues/26 [1]
Link: https://github.com/KSPP/linux/issues/27 [2]
Link: https://github.com/KSPP/linux/issues/344 [3]
Cc: Julia Lawall <[email protected]>
Cc: Nicolas Palix <[email protected]>
Cc: "Gustavo A. R. Silva" <[email protected]>
Cc: Justin Stitt <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
.../coccinelle/misc/add_would_overflow.cocci | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 scripts/coccinelle/misc/add_would_overflow.cocci
diff --git a/scripts/coccinelle/misc/add_would_overflow.cocci b/scripts/coccinelle/misc/add_would_overflow.cocci
new file mode 100644
index 000000000000..b9b67c9c3714
--- /dev/null
+++ b/scripts/coccinelle/misc/add_would_overflow.cocci
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0-only
+///
+/// Replace intentional wrap-around addition with calls to
+/// check_add_overflow() and add_would_overflow(), see
+/// Documentation/process/deprecated.rst
+///
+//
+// Confidence: High
+// Comments:
+// Options: --no-includes --include-headers
+
+virtual context
+virtual report
+virtual org
+virtual patch
+
+@report_wrap_sum depends on !patch@
+type RESULT;
+RESULT VAR;
+expression OFFSET;
+@@
+
+ {
+ RESULT sum;
+ ...
+ (
+* VAR + OFFSET < VAR
+ )
+ ...
+ (
+ VAR + OFFSET
+ )
+ ...
+ }
+
+@wrap_sum depends on patch@
+type RESULT;
+RESULT VAR;
+expression OFFSET;
+@@
+
+ {
++ RESULT sum;
+ ...
+ (
+- VAR + OFFSET < VAR
++ check_add_overflow(VAR, OFFSET, &sum)
+ )
+ ...
+ (
+- VAR + OFFSET
++ sum
+ )
+ ...
+ }
+
+@report_wrap depends on !patch && !report_wrap_sum@
+identifier PTR;
+expression OFFSET;
+@@
+
+* PTR + OFFSET < PTR
+
+@patch_wrap depends on patch && !wrap_sum@
+identifier PTR;
+expression OFFSET;
+@@
+
+- PTR + OFFSET < PTR
++ add_would_overflow(PTR, OFFSET)
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Vineet Gupta <[email protected]>
Cc: Luis Chamberlain <[email protected]>
Cc: "dean.yang_cp" <[email protected]>
Cc: Song Liu <[email protected]>
Cc: Yihao Han <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/arc/kernel/unwind.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 8924fa2a8f29..649b56204580 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -1278,7 +1278,7 @@ int arc_unwind(struct unwind_frame_info *frame)
if ((state.regs[i].value * state.dataAlign)
% sizeof(unsigned long)
|| addr < startLoc
- || addr + sizeof(unsigned long) < addr
+ || add_would_overflow(addr, sizeof(unsigned long))
|| addr + sizeof(unsigned long) > endLoc)
return -EIO;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded pointer wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which
removes the redundant open-coded addition). This paves the way to enabling
the unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Vineet Gupta <[email protected]>
Cc: Luis Chamberlain <[email protected]>
Cc: Song Liu <[email protected]>
Cc: Yihao Han <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: "dean.yang_cp" <[email protected]>
Cc: Jinchao Wang <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/arc/kernel/unwind.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 9270d0a713c3..8924fa2a8f29 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -612,6 +612,7 @@ static signed fde_pointer_type(const u32 *cie)
const char *aug;
const u8 *end = (const u8 *)(cie + 1) + *cie;
uleb128_t len;
+ const u8 *sum;
/* check if augmentation size is first (and thus present) */
if (*ptr != 'z')
@@ -630,10 +631,10 @@ static signed fde_pointer_type(const u32 *cie)
version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
len = get_uleb128(&ptr, end); /* augmentation length */
- if (ptr + len < ptr || ptr + len > end)
+ if (check_add_overflow(ptr, len, &sum) || sum > end)
return -1;
- end = ptr + len;
+ end = sum;
while (*++aug) {
if (ptr >= end)
return -1;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Yoshinori Sato <[email protected]>
Cc: Rich Felker <[email protected]>
Cc: John Paul Adrian Glaubitz <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/sh/kernel/sys_sh.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index a5a7b33ed81a..e390caeb8c00 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -66,7 +66,7 @@ asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op)
* Verify that the specified address region actually belongs
* to this process.
*/
- if (addr + len < addr)
+ if (add_would_overflow(addr, len))
return -EFAULT;
mmap_read_lock(current->mm);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Russell King <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/arm/nwfpe/softfloat.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c
index ffa6b438786b..0635b1eda1d3 100644
--- a/arch/arm/nwfpe/softfloat.c
+++ b/arch/arm/nwfpe/softfloat.c
@@ -603,7 +603,7 @@ static floatx80
roundBits = zSig0 & roundMask;
if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
if ( ( 0x7FFE < zExp )
- || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
+ || ( ( zExp == 0x7FFE ) && (add_would_overflow(zSig0, roundIncrement)) )
) {
goto overflow;
}
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Mark Fasheh <[email protected]>
Cc: Joel Becker <[email protected]>
Cc: Joseph Qi <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/ocfs2/resize.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
index d65d43c61857..5cc83e1d54a7 100644
--- a/fs/ocfs2/resize.c
+++ b/fs/ocfs2/resize.c
@@ -423,7 +423,7 @@ static int ocfs2_verify_group_and_input(struct inode *inode,
else if (next_free != cl_count && next_free != input->chain)
mlog(ML_ERROR,
"the add group should be in chain %u\n", next_free);
- else if (total_clusters + input->clusters < total_clusters)
+ else if (add_would_overflow(total_clusters, input->clusters))
mlog(ML_ERROR, "add group's clusters overflow.\n");
else if (input->clusters > cl_cpg)
mlog(ML_ERROR, "the cluster exceeds the maximum of a group\n");
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Maarten Lankhorst <[email protected]>
Cc: Maxime Ripard <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Jani Nikula <[email protected]>
Cc: Joonas Lahtinen <[email protected]>
Cc: Rodrigo Vivi <[email protected]>
Cc: Tvrtko Ursulin <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/gpu/drm/i915/i915_vma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index d09aad34ba37..1a4f048a5df9 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -1535,7 +1535,7 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww,
goto err_remove;
/* There should only be at most 2 active bindings (user, global) */
- GEM_BUG_ON(bound + I915_VMA_PAGES_ACTIVE < bound);
+ GEM_BUG_ON(add_would_overflow(bound, I915_VMA_PAGES_ACTIVE));
atomic_add(I915_VMA_PAGES_ACTIVE, &vma->pages_count);
list_move_tail(&vma->vm_link, &vma->vm->bound_list);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: "Michael S. Tsirkin" <[email protected]>
Cc: Jason Wang <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/vhost/vringh.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
index 7b8fd977f71c..07442f0a52bd 100644
--- a/drivers/vhost/vringh.c
+++ b/drivers/vhost/vringh.c
@@ -145,6 +145,8 @@ static inline bool range_check(struct vringh *vrh, u64 addr, size_t *len,
bool (*getrange)(struct vringh *,
u64, struct vringh_range *))
{
+ u64 sum;
+
if (addr < range->start || addr > range->end_incl) {
if (!getrange(vrh, addr, range))
return false;
@@ -152,20 +154,20 @@ static inline bool range_check(struct vringh *vrh, u64 addr, size_t *len,
BUG_ON(addr < range->start || addr > range->end_incl);
/* To end of memory? */
- if (unlikely(addr + *len == 0)) {
+ if (unlikely(U64_MAX - addr == *len)) {
if (range->end_incl == -1ULL)
return true;
goto truncate;
}
/* Otherwise, don't wrap. */
- if (addr + *len < addr) {
+ if (check_add_overflow(addr, *len, &sum)) {
vringh_bad("Wrapping descriptor %zu@0x%llx",
*len, (unsigned long long)addr);
return false;
}
- if (unlikely(addr + *len - 1 > range->end_incl))
+ if (unlikely(sum - 1 > range->end_incl))
goto truncate;
return true;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Jeremy Kerr <[email protected]>
Cc: Joel Stanley <[email protected]>
Cc: Alistar Popple <[email protected]>
Cc: Eddie James <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/fsi/fsi-core.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 097d5a780264..46b24d0aadc6 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -381,10 +381,12 @@ EXPORT_SYMBOL_GPL(fsi_slave_write);
int fsi_slave_claim_range(struct fsi_slave *slave,
uint32_t addr, uint32_t size)
{
- if (addr + size < addr)
+ uint32_t sum;
+
+ if (check_add_overflow(addr, size, &sum))
return -EINVAL;
- if (addr + size > slave->size)
+ if (sum > slave->size)
return -EINVAL;
/* todo: check for overlapping claims */
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Alexander Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Cc: Jan Kara <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/remap_range.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/remap_range.c b/fs/remap_range.c
index f8c1120b8311..15e91bf2c5e3 100644
--- a/fs/remap_range.c
+++ b/fs/remap_range.c
@@ -45,7 +45,7 @@ static int generic_remap_checks(struct file *file_in, loff_t pos_in,
return -EINVAL;
/* Ensure offsets don't wrap. */
- if (pos_in + count < pos_in || pos_out + count < pos_out)
+ if (add_would_overflow(pos_in, count) || add_would_overflow(pos_out, count))
return -EINVAL;
size_in = i_size_read(inode_in);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Wu Hao <[email protected]>
Cc: Tom Rix <[email protected]>
Cc: Moritz Fischer <[email protected]>
Cc: Xu Yilun <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/fpga/dfl.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index e6d12fbab653..7d10780e3a98 100644
--- a/drivers/fpga/dfl.c
+++ b/drivers/fpga/dfl.c
@@ -1939,15 +1939,16 @@ static int do_set_irq_trigger(struct dfl_feature *feature, unsigned int idx,
int dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start,
unsigned int count, int32_t *fds)
{
+ unsigned int sum;
unsigned int i;
int ret = 0;
/* overflow */
- if (unlikely(start + count < start))
+ if (unlikely(check_add_overflow(start, count, &sum)))
return -EINVAL;
/* exceeds nr_irqs */
- if (start + count > feature->nr_irqs)
+ if (sum > feature->nr_irqs)
return -EINVAL;
for (i = 0; i < count; i++) {
--
2.34.1
Provide a helper that will perform wrapping addition without tripping
the arithmetic wrap-around sanitizers.
Cc: "Gustavo A. R. Silva" <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
include/linux/overflow.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/include/linux/overflow.h b/include/linux/overflow.h
index ac088f73e0fd..30779905a77a 100644
--- a/include/linux/overflow.h
+++ b/include/linux/overflow.h
@@ -124,6 +124,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
check_add_overflow(a, b, &__result);\
}))
+/**
+ * add_wrap() - Intentionally perform a wrapping addition
+ * @a: first addend
+ * @b: second addend
+ *
+ * Return the potentially wrapped-around addition without
+ * tripping any overflow sanitizers that may be enabled.
+ */
+#define add_wrap(a, b) \
+ ({ \
+ typeof(a) __sum; \
+ if (check_add_overflow(a, b, &__sum)) \
+ /* do nothing */; \
+ __sum; \
+ })
+
/**
* check_sub_overflow() - Calculate subtraction with overflow checking
* @a: minuend; value to subtract from
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Marc Zyngier <[email protected]>
Cc: Oliver Upton <[email protected]>
Cc: James Morse <[email protected]>
Cc: Suzuki K Poulose <[email protected]>
Cc: Zenghui Yu <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Reiji Watanabe <[email protected]>
Cc: Eric Auger <[email protected]>
Cc: Ricardo Koller <[email protected]>
Cc: Raghavendra Rao Ananta <[email protected]>
Cc: Quentin Perret <[email protected]>
Cc: Jean-Philippe Brucker <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/arm64/kvm/vgic/vgic-kvm-device.c | 6 ++++--
arch/arm64/kvm/vgic/vgic-v2.c | 10 ++++++----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index f48b8dab8b3d..0eec5344d203 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -18,17 +18,19 @@ int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,
phys_addr_t addr, phys_addr_t alignment,
phys_addr_t size)
{
+ phys_addr_t sum;
+
if (!IS_VGIC_ADDR_UNDEF(ioaddr))
return -EEXIST;
if (!IS_ALIGNED(addr, alignment) || !IS_ALIGNED(size, alignment))
return -EINVAL;
- if (addr + size < addr)
+ if (check_add_overflow(addr, size, &sum))
return -EINVAL;
if (addr & ~kvm_phys_mask(&kvm->arch.mmu) ||
- (addr + size) > kvm_phys_size(&kvm->arch.mmu))
+ sum > kvm_phys_size(&kvm->arch.mmu))
return -E2BIG;
return 0;
diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c
index 7e9cdb78f7ce..c8d1e965d3b7 100644
--- a/arch/arm64/kvm/vgic/vgic-v2.c
+++ b/arch/arm64/kvm/vgic/vgic-v2.c
@@ -273,14 +273,16 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
/* check for overlapping regions and for regions crossing the end of memory */
static bool vgic_v2_check_base(gpa_t dist_base, gpa_t cpu_base)
{
- if (dist_base + KVM_VGIC_V2_DIST_SIZE < dist_base)
+ gpa_t dist_sum, cpu_sum;
+
+ if (check_add_overflow(dist_base, KVM_VGIC_V2_DIST_SIZE, &dist_sum))
return false;
- if (cpu_base + KVM_VGIC_V2_CPU_SIZE < cpu_base)
+ if (check_add_overflow(cpu_base, KVM_VGIC_V2_CPU_SIZE, &cpu_sum))
return false;
- if (dist_base + KVM_VGIC_V2_DIST_SIZE <= cpu_base)
+ if (dist_sum <= cpu_base)
return true;
- if (cpu_base + KVM_VGIC_V2_CPU_SIZE <= dist_base)
+ if (cpu_sum <= dist_base)
return true;
return false;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Jaegeuk Kim <[email protected]>
Cc: Chao Yu <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/f2fs/file.c | 2 +-
fs/f2fs/verity.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index b58ab1157b7e..6360efb98f64 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2819,7 +2819,7 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
}
ret = -EINVAL;
- if (pos_in + len > src->i_size || pos_in + len < pos_in)
+ if (pos_in + len > src->i_size || add_would_overflow(pos_in, len))
goto out_unlock;
if (len == 0)
olen = len = src->i_size - pos_in;
diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c
index 4fc95f353a7a..b641cb8d75e8 100644
--- a/fs/f2fs/verity.c
+++ b/fs/f2fs/verity.c
@@ -237,7 +237,7 @@ static int f2fs_get_verity_descriptor(struct inode *inode, void *buf,
pos = le64_to_cpu(dloc.pos);
/* Get the descriptor */
- if (pos + size < pos || pos + size > inode->i_sb->s_maxbytes ||
+ if (add_would_overflow(pos, size) || pos + size > inode->i_sb->s_maxbytes ||
pos < f2fs_verity_metadata_pos(inode) || size > INT_MAX) {
f2fs_warn(F2FS_I_SB(inode), "invalid verity xattr");
f2fs_handle_error(F2FS_I_SB(inode),
--
2.34.1
The mix of int, unsigned int, and unsigned long used by struct
poll_list::len, todo, len, and j meant that the signed overflow
sanitizer got worried it needed to instrument several places where
arithmetic happens between these variables. Since all of the variables
are always positive and bounded by unsigned int, use a single type in
all places. Additionally expand the zero-test into an explicit range
check before updating "todo".
This keeps sanitizer instrumentation[1] out of a UACCESS path:
vmlinux.o: warning: objtool: do_sys_poll+0x285: call to __ubsan_handle_sub_overflow() with UACCESS enabled
Cc: Alexander Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Cc: Jan Kara <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/select.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/fs/select.c b/fs/select.c
index 0ee55af1a55c..11a3b1312abe 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -839,7 +839,7 @@ SYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg)
struct poll_list {
struct poll_list *next;
- int len;
+ unsigned int len;
struct pollfd entries[];
};
@@ -975,14 +975,15 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
struct timespec64 *end_time)
{
struct poll_wqueues table;
- int err = -EFAULT, fdcount, len;
+ int err = -EFAULT, fdcount;
/* Allocate small arguments on the stack to save memory and be
faster - use long to make sure the buffer is aligned properly
on 64 bit archs to avoid unaligned access */
long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
struct poll_list *const head = (struct poll_list *)stack_pps;
struct poll_list *walk = head;
- unsigned long todo = nfds;
+ unsigned int todo = nfds;
+ unsigned int len;
if (nfds > rlimit(RLIMIT_NOFILE))
return -EINVAL;
@@ -998,9 +999,9 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
sizeof(struct pollfd) * walk->len))
goto out_fds;
- todo -= walk->len;
- if (!todo)
+ if (walk->len >= todo)
break;
+ todo -= walk->len;
len = min(todo, POLLFD_PER_PAGE);
walk = walk->next = kmalloc(struct_size(walk, entries, len),
@@ -1020,7 +1021,7 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
for (walk = head; walk; walk = walk->next) {
struct pollfd *fds = walk->entries;
- int j;
+ unsigned int j;
for (j = walk->len; j; fds++, ufds++, j--)
unsafe_put_user(fds->revents, &ufds->revents, Efault);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Santosh Shilimkar <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jakub Kicinski <[email protected]>
Cc: Paolo Abeni <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
net/rds/info.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/rds/info.c b/net/rds/info.c
index b6b46a8214a0..87b35d07ce04 100644
--- a/net/rds/info.c
+++ b/net/rds/info.c
@@ -163,6 +163,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
unsigned long nr_pages = 0;
unsigned long start;
rds_info_func func;
+ unsigned long sum;
struct page **pages = NULL;
int ret;
int len;
@@ -175,7 +176,8 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
/* check for all kinds of wrapping and the like */
start = (unsigned long)optval;
- if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 || start + len < start) {
+ if (len < 0 || len > INT_MAX - PAGE_SIZE + 1 ||
+ check_add_overflow(start, len, &sum)) {
ret = -EINVAL;
goto out;
}
@@ -184,7 +186,7 @@ int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
if (len == 0)
goto call_func;
- nr_pages = (PAGE_ALIGN(start + len) - (start & PAGE_MASK))
+ nr_pages = (PAGE_ALIGN(sum) - (start & PAGE_MASK))
>> PAGE_SHIFT;
pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded pointer wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizer in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Steve French <[email protected]>
Cc: Paulo Alcantara <[email protected]>
Cc: Ronnie Sahlberg <[email protected]>
Cc: Shyam Prasad N <[email protected]>
Cc: Tom Talpey <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/smb/client/readdir.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index 94255401b38d..7715297359ab 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -467,12 +467,13 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
pfData->FileNameLength;
} else {
u32 next_offset = le32_to_cpu(pDirInfo->NextEntryOffset);
+ char *sum;
- if (old_entry + next_offset < old_entry) {
+ if (check_add_overflow(old_entry, next_offset, &sum)) {
cifs_dbg(VFS, "Invalid offset %u\n", next_offset);
return NULL;
}
- new_entry = old_entry + next_offset;
+ new_entry = sum;
}
cifs_dbg(FYI, "new entry %p old entry %p\n", new_entry, old_entry);
/* validate that new_entry is not past end of SMB */
--
2.34.1
Annotate atomic_add_return() and atomic_sub_return() to avoid signed
overflow instrumentation. They are expected to wrap around.
Cc: Will Deacon <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Boqun Feng <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/arm64/include/asm/atomic_lse.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h
index 87f568a94e55..30572458d702 100644
--- a/arch/arm64/include/asm/atomic_lse.h
+++ b/arch/arm64/include/asm/atomic_lse.h
@@ -79,13 +79,13 @@ ATOMIC_FETCH_OP_SUB( )
#undef ATOMIC_FETCH_OP_SUB
#define ATOMIC_OP_ADD_SUB_RETURN(name) \
-static __always_inline int \
+static __always_inline __signed_wrap int \
__lse_atomic_add_return##name(int i, atomic_t *v) \
{ \
return __lse_atomic_fetch_add##name(i, v) + i; \
} \
\
-static __always_inline int \
+static __always_inline __signed_wrap int \
__lse_atomic_sub_return##name(int i, atomic_t *v) \
{ \
return __lse_atomic_fetch_sub(i, v) - i; \
@@ -186,13 +186,13 @@ ATOMIC64_FETCH_OP_SUB( )
#undef ATOMIC64_FETCH_OP_SUB
#define ATOMIC64_OP_ADD_SUB_RETURN(name) \
-static __always_inline long \
+static __always_inline __signed_wrap long \
__lse_atomic64_add_return##name(s64 i, atomic64_t *v) \
{ \
return __lse_atomic64_fetch_add##name(i, v) + i; \
} \
\
-static __always_inline long \
+static __always_inline __signed_wrap long \
__lse_atomic64_sub_return##name(s64 i, atomic64_t *v) \
{ \
return __lse_atomic64_fetch_sub##name(i, v) - i; \
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Christian Brauner <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
Cc: Dave Chinner <[email protected]>
Cc: Alexey Gladkov <[email protected]>
Cc: Jeff Layton <[email protected]>
Cc: Waiman Long <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
ipc/mqueue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 5eea4dc0509e..7ef9d325183a 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -366,7 +366,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
sizeof(struct posix_msg_tree_node);
mq_bytes = info->attr.mq_maxmsg * info->attr.mq_msgsize;
- if (mq_bytes + mq_treesize < mq_bytes)
+ if (add_would_overflow(mq_bytes, mq_treesize))
goto out_inode;
mq_bytes += mq_treesize;
info->ucounts = get_ucounts(current_ucounts());
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Karol Herbst <[email protected]>
Cc: Lyude Paul <[email protected]>
Cc: Danilo Krummrich <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Dave Airlie <[email protected]>
Cc: Ben Skeggs <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
index 6ca1a82ccbc1..87c0903be9a7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
@@ -1291,7 +1291,7 @@ nvkm_vmm_pfn_map(struct nvkm_vmm *vmm, u8 shift, u64 addr, u64 size, u64 *pfn)
if (!page->shift || !IS_ALIGNED(addr, 1ULL << shift) ||
!IS_ALIGNED(size, 1ULL << shift) ||
- addr + size < addr || addr + size > vmm->limit) {
+ add_would_overflow(addr, size) || addr + size > vmm->limit) {
VMM_DEBUG(vmm, "paged map %d %d %016llx %016llx\n",
shift, page->shift, addr, size);
return -EINVAL;
--
2.34.1
Annotate atomic_add_return() to avoid signed overflow instrumentation.
It is expected to wrap around.
Cc: Will Deacon <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Boqun Feng <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: [email protected]
Cc: "H. Peter Anvin" <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
arch/x86/include/asm/atomic.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
index 55a55ec04350..4120cdd87da8 100644
--- a/arch/x86/include/asm/atomic.h
+++ b/arch/x86/include/asm/atomic.h
@@ -80,7 +80,7 @@ static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v)
}
#define arch_atomic_add_negative arch_atomic_add_negative
-static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
+static __always_inline __signed_wrap int arch_atomic_add_return(int i, atomic_t *v)
{
return i + xadd(&v->counter, i);
}
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Steve French <[email protected]>
Cc: Paulo Alcantara <[email protected]>
Cc: Ronnie Sahlberg <[email protected]>
Cc: Shyam Prasad N <[email protected]>
Cc: Tom Talpey <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/smb/client/smb2pdu.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 288199f0b987..85399525f0a7 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -5007,7 +5007,7 @@ num_entries(int infotype, char *bufstart, char *end_of_buf, char **lastentry,
entryptr = bufstart;
while (1) {
- if (entryptr + next_offset < entryptr ||
+ if (add_would_overflow(entryptr, next_offset) ||
entryptr + next_offset > end_of_buf ||
entryptr + next_offset + size > end_of_buf) {
cifs_dbg(VFS, "malformed search entry would overflow\n");
@@ -5023,7 +5023,7 @@ num_entries(int infotype, char *bufstart, char *end_of_buf, char **lastentry,
len = le32_to_cpu(dir_info->FileNameLength);
if (len < 0 ||
- entryptr + len < entryptr ||
+ add_would_overflow(entryptr, len) ||
entryptr + len > end_of_buf ||
entryptr + len + size > end_of_buf) {
cifs_dbg(VFS, "directory entry name would overflow frame end of buf %p\n",
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Jan Kara <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
fs/udf/balloc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index ab3ffc355949..5c88300c3de7 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -139,7 +139,7 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
mutex_lock(&sbi->s_alloc_mutex);
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
- if (bloc->logicalBlockNum + count < count ||
+ if (add_would_overflow(count, bloc->logicalBlockNum) ||
(bloc->logicalBlockNum + count) > partmap->s_partition_len) {
udf_debug("%u < %d || %u + %u > %u\n",
bloc->logicalBlockNum, 0,
@@ -390,7 +390,7 @@ static void udf_table_free_blocks(struct super_block *sb,
mutex_lock(&sbi->s_alloc_mutex);
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
- if (bloc->logicalBlockNum + count < count ||
+ if (add_would_overflow(count, bloc->logicalBlockNum) ||
(bloc->logicalBlockNum + count) > partmap->s_partition_len) {
udf_debug("%u < %d || %u + %u > %u\n",
bloc->logicalBlockNum, 0,
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Karol Herbst <[email protected]>
Cc: Lyude Paul <[email protected]>
Cc: Danilo Krummrich <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Ben Skeggs <[email protected]>
Cc: Dave Airlie <[email protected]>
Cc: Julia Lawall <[email protected]>
Cc: Jiang Jian <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
index 9c97800fe037..6ca1a82ccbc1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
@@ -1149,13 +1149,15 @@ nvkm_vmm_ctor(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
vmm->root = RB_ROOT;
if (managed) {
+ u64 sum;
+
/* Address-space will be managed by the client for the most
* part, except for a specified area where NVKM allocations
* are allowed to be placed.
*/
vmm->start = 0;
vmm->limit = 1ULL << bits;
- if (addr + size < addr || addr + size > vmm->limit)
+ if (check_add_overflow(addr, size, &sum) || sum > vmm->limit)
return -EINVAL;
/* Client-managed area before the NVKM-managed area. */
@@ -1174,7 +1176,7 @@ nvkm_vmm_ctor(const struct nvkm_vmm_func *func, struct nvkm_mmu *mmu,
}
/* Client-managed area after the NVKM-managed area. */
- addr = addr + size;
+ addr = sum;
size = vmm->limit - addr;
if (size && (ret = nvkm_vmm_ctor_managed(vmm, addr, size)))
return ret;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Switch to a more regular type for a 64-bit value and refactor the
open-coded wrap-around addition test to use subtraction from the type max
(since add_would_overflow() may not be defined in early boot code). This
paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Nick Terrell <[email protected]>
Cc: Paul Jones <[email protected]>
Cc: Sedat Dilek <[email protected]>
Cc: Oleksandr Natalenko <[email protected]>
Cc: Xin Gao <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
lib/zstd/decompress/zstd_decompress.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/zstd/decompress/zstd_decompress.c b/lib/zstd/decompress/zstd_decompress.c
index 6b3177c94711..2c87cf702ad6 100644
--- a/lib/zstd/decompress/zstd_decompress.c
+++ b/lib/zstd/decompress/zstd_decompress.c
@@ -585,7 +585,7 @@ ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsign
* @return : decompressed size of the frames contained */
unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
{
- unsigned long long totalDstSize = 0;
+ U64 totalDstSize = 0;
while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {
U32 const magicNumber = MEM_readLE32(src);
@@ -606,7 +606,7 @@ unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
/* check for overflow */
- if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
+ if (U64_MAX - totalDstSize < ret) return ZSTD_CONTENTSIZE_ERROR;
totalDstSize += ret;
}
{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Andrew Morton <[email protected]>
Cc: Uladzislau Rezki <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
mm/vmalloc.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index d12a17fc0c17..7932ac99e9d3 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1223,6 +1223,7 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
unsigned long align, unsigned long vstart)
{
unsigned long nva_start_addr;
+ unsigned long sum;
if (va->va_start > vstart)
nva_start_addr = ALIGN(va->va_start, align);
@@ -1230,11 +1231,11 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
nva_start_addr = ALIGN(vstart, align);
/* Can be overflowed due to big size or alignment. */
- if (nva_start_addr + size < nva_start_addr ||
+ if (check_add_overflow(nva_start_addr, size, &sum) ||
nva_start_addr < vstart)
return false;
- return (nva_start_addr + size <= va->va_end);
+ return (sum <= va->va_end);
}
/*
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Heiko Carstens <[email protected]>
Cc: Vasily Gorbik <[email protected]>
Cc: Alexander Gordeev <[email protected]>
Cc: Christian Borntraeger <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: Nico Boehr <[email protected]>
Cc: Philipp Rudo <[email protected]>
Cc: Baoquan He <[email protected]>
Cc: Tao Liu <[email protected]>
Cc: Alexander Egorenkov <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/s390/include/asm/stacktrace.h | 6 ++++--
arch/s390/kernel/machine_kexec_file.c | 5 +++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h
index 31ec4f545e03..3ce08d32a8ad 100644
--- a/arch/s390/include/asm/stacktrace.h
+++ b/arch/s390/include/asm/stacktrace.h
@@ -34,11 +34,13 @@ int get_stack_info(unsigned long sp, struct task_struct *task,
static inline bool on_stack(struct stack_info *info,
unsigned long addr, size_t len)
{
+ unsigned long sum;
+
if (info->type == STACK_TYPE_UNKNOWN)
return false;
- if (addr + len < addr)
+ if (check_add_overflow(addr, len, &sum))
return false;
- return addr >= info->begin && addr + len <= info->end;
+ return addr >= info->begin && sum <= info->end;
}
/*
diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c
index 8d207b82d9fe..e5e925423061 100644
--- a/arch/s390/kernel/machine_kexec_file.c
+++ b/arch/s390/kernel/machine_kexec_file.c
@@ -238,6 +238,7 @@ void *kexec_file_add_components(struct kimage *image,
unsigned long max_command_line_size = LEGACY_COMMAND_LINE_SIZE;
struct s390_load_data data = {0};
unsigned long minsize;
+ unsigned long sum;
int ret;
data.report = ipl_report_init(&ipl_block);
@@ -256,10 +257,10 @@ void *kexec_file_add_components(struct kimage *image,
if (data.parm->max_command_line_size)
max_command_line_size = data.parm->max_command_line_size;
- if (minsize + max_command_line_size < minsize)
+ if (check_add_overflow(minsize, max_command_line_size, &sum))
goto out;
- if (image->kernel_buf_len < minsize + max_command_line_size)
+ if (image->kernel_buf_len < sum)
goto out;
if (image->cmdline_buf_len >= max_command_line_size)
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizer in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Chris Mason <[email protected]>
Cc: Josef Bacik <[email protected]>
Cc: David Sterba <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/btrfs/extent_map.c | 6 ++++--
fs/btrfs/extent_map.h | 6 ++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index b61099bf97a8..29a649507857 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -73,9 +73,11 @@ void free_extent_map(struct extent_map *em)
/* Do the math around the end of an extent, handling wrapping. */
static u64 range_end(u64 start, u64 len)
{
- if (start + len < start)
+ u64 sum;
+
+ if (check_add_overflow(start, len, &sum))
return (u64)-1;
- return start + len;
+ return sum;
}
static int tree_insert(struct rb_root_cached *root, struct extent_map *em)
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index e380fc08bbe4..3c4a6b977662 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -108,9 +108,11 @@ static inline int extent_map_in_tree(const struct extent_map *em)
static inline u64 extent_map_end(const struct extent_map *em)
{
- if (em->start + em->len < em->start)
+ u64 sum;
+
+ if (check_add_overflow(em->start, em->len, &sum))
return (u64)-1;
- return em->start + em->len;
+ return sum;
}
void extent_map_tree_init(struct extent_map_tree *tree);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Sean Christopherson <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: [email protected]
Cc: "H. Peter Anvin" <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/x86/kvm/svm/sev.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index f760106c31f8..12a6a2b1ac81 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -400,16 +400,17 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
unsigned long locked, lock_limit;
struct page **pages;
unsigned long first, last;
+ unsigned long sum;
int ret;
lockdep_assert_held(&kvm->lock);
- if (ulen == 0 || uaddr + ulen < uaddr)
+ if (ulen == 0 || check_add_overflow(uaddr, ulen, &sum))
return ERR_PTR(-EINVAL);
/* Calculate number of pages. */
first = (uaddr & PAGE_MASK) >> PAGE_SHIFT;
- last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT;
+ last = ((sum - 1) & PAGE_MASK) >> PAGE_SHIFT;
npages = (last - first + 1);
locked = sev->pages_locked + npages;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Chris Mason <[email protected]>
Cc: Josef Bacik <[email protected]>
Cc: David Sterba <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/btrfs/ordered-data.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 59850dc17b22..2e0865693cee 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -813,7 +813,7 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
u64 orig_end;
struct btrfs_ordered_extent *ordered;
- if (start + len < start) {
+ if (add_would_overflow(start, len)) {
orig_end = OFFSET_MAX;
} else {
orig_end = start + len - 1;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Alexei Starovoitov <[email protected]>
Cc: Daniel Borkmann <[email protected]>
Cc: John Fastabend <[email protected]>
Cc: Andrii Nakryiko <[email protected]>
Cc: Martin KaFai Lau <[email protected]>
Cc: Song Liu <[email protected]>
Cc: Yonghong Song <[email protected]>
Cc: KP Singh <[email protected]>
Cc: Stanislav Fomichev <[email protected]>
Cc: Hao Luo <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
kernel/bpf/verifier.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 65f598694d55..21e3f30c8757 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -12901,8 +12901,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
dst_reg->smin_value = smin_ptr + smin_val;
dst_reg->smax_value = smax_ptr + smax_val;
}
- if (umin_ptr + umin_val < umin_ptr ||
- umax_ptr + umax_val < umax_ptr) {
+ if (add_would_overflow(umin_ptr, umin_val) ||
+ add_would_overflow(umax_ptr, umax_val)) {
dst_reg->umin_value = 0;
dst_reg->umax_value = U64_MAX;
} else {
@@ -13023,8 +13023,8 @@ static void scalar32_min_max_add(struct bpf_reg_state *dst_reg,
dst_reg->s32_min_value += smin_val;
dst_reg->s32_max_value += smax_val;
}
- if (dst_reg->u32_min_value + umin_val < umin_val ||
- dst_reg->u32_max_value + umax_val < umax_val) {
+ if (add_would_overflow(umin_val, dst_reg->u32_min_value) ||
+ add_would_overflow(umax_val, dst_reg->u32_max_value)) {
dst_reg->u32_min_value = 0;
dst_reg->u32_max_value = U32_MAX;
} else {
@@ -13049,8 +13049,8 @@ static void scalar_min_max_add(struct bpf_reg_state *dst_reg,
dst_reg->smin_value += smin_val;
dst_reg->smax_value += smax_val;
}
- if (dst_reg->umin_value + umin_val < umin_val ||
- dst_reg->umax_value + umax_val < umax_val) {
+ if (add_would_overflow(umin_val, dst_reg->umin_value) ||
+ add_would_overflow(umax_val, dst_reg->umax_value)) {
dst_reg->umin_value = 0;
dst_reg->umax_value = U64_MAX;
} else {
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Alexander Gordeev <[email protected]>
Cc: Gerald Schaefer <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Vasily Gorbik <[email protected]>
Cc: Christian Borntraeger <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/s390/mm/vmem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 186a020857cf..98a7f08141f0 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -538,7 +538,7 @@ int vmem_add_mapping(unsigned long start, unsigned long size)
if (start < range.start ||
start + size > range.end + 1 ||
- start + size < start)
+ add_would_overflow(start, size))
return -ERANGE;
mutex_lock(&vmem_mutex);
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Marc Zyngier <[email protected]>
Cc: Oliver Upton <[email protected]>
Cc: James Morse <[email protected]>
Cc: Suzuki K Poulose <[email protected]>
Cc: Zenghui Yu <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Eric Auger <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index c15ee1df036a..860b774c0c13 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -863,7 +863,7 @@ static int vgic_v3_alloc_redist_region(struct kvm *kvm, uint32_t index,
int ret;
/* cross the end of memory ? */
- if (base + size < base)
+ if (add_would_overflow(base, size))
return -EINVAL;
if (list_empty(rd_regions)) {
--
2.34.1
On Mon, Jan 22, 2024 at 4:36 PM Kees Cook <[email protected]> wrote:
>
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: John Stultz <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Stephen Boyd <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
> ---
> kernel/time/timekeeping.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> index 266d02809dbb..2fc7cf16584c 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -1984,7 +1984,7 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
> * Which simplifies to:
> * xtime_nsec -= offset
> */
> - if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) {
> + if ((mult_adj > 0) && (add_would_overflow(mult_adj, tk->tkr_mono.mult))) {
> /* NTP adjustment caused clocksource mult overflow */
> WARN_ON_ONCE(1);
> return;
Acked-by: John Stultz <[email protected]>
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notable, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed, unsigned, or
pointer types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/27 [2]
Cc: Paolo Bonzini <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
virt/kvm/coalesced_mmio.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
index 1b90acb6e3fe..0a3b706fbf4c 100644
--- a/virt/kvm/coalesced_mmio.c
+++ b/virt/kvm/coalesced_mmio.c
@@ -25,17 +25,19 @@ static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev)
static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev,
gpa_t addr, int len)
{
+ gpa_t sum;
+
/* is it in a batchable area ?
* (addr,len) is fully included in
* (zone->addr, zone->size)
*/
if (len < 0)
return 0;
- if (addr + len < addr)
+ if (check_add_overflow(addr, len, &sum))
return 0;
if (addr < dev->zone.addr)
return 0;
- if (addr + len > dev->zone.addr + dev->zone.size)
+ if (sum > dev->zone.addr + dev->zone.size)
return 0;
return 1;
}
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Wei Liu <[email protected]>
Cc: Paul Durrant <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jakub Kicinski <[email protected]>
Cc: Paolo Abeni <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/net/xen-netback/hash.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c
index ff96f22648ef..69b03b4feba9 100644
--- a/drivers/net/xen-netback/hash.c
+++ b/drivers/net/xen-netback/hash.c
@@ -345,7 +345,7 @@ u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len,
.flags = GNTCOPY_source_gref
}};
- if ((off + len < off) || (off + len > vif->hash.size) ||
+ if ((add_would_overflow(off, len)) || (off + len > vif->hash.size) ||
len > XEN_PAGE_SIZE / sizeof(*mapping))
return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Greg Kroah-Hartman <[email protected]>
Cc: David Airlie <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/char/agp/generic.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3ffbb1c80c5c..fc2d07654154 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -228,7 +228,7 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
cur_memory = atomic_read(&bridge->current_memory_agp);
if ((cur_memory + page_count > bridge->max_memory_agp) ||
- (cur_memory + page_count < page_count))
+ (add_would_overflow(page_count, cur_memory)))
return NULL;
if (type >= AGP_USER_TYPES) {
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Herbert Xu <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Aditya Srivastava <[email protected]>
Cc: Randy Dunlap <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
crypto/adiantum.c | 2 +-
drivers/crypto/amcc/crypto4xx_alg.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/crypto/adiantum.c b/crypto/adiantum.c
index 60f3883b736a..c2f62ca455af 100644
--- a/crypto/adiantum.c
+++ b/crypto/adiantum.c
@@ -190,7 +190,7 @@ static inline void le128_add(le128 *r, const le128 *v1, const le128 *v2)
r->b = cpu_to_le64(x + y);
r->a = cpu_to_le64(le64_to_cpu(v1->a) + le64_to_cpu(v2->a) +
- (x + y < x));
+ (add_would_overflow(x, y)));
}
/* Subtraction in Z/(2^{128}Z) */
diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
index e0af611a95d8..33f73234ddd9 100644
--- a/drivers/crypto/amcc/crypto4xx_alg.c
+++ b/drivers/crypto/amcc/crypto4xx_alg.c
@@ -251,7 +251,7 @@ crypto4xx_ctr_crypt(struct skcipher_request *req, bool encrypt)
* the whole IV is a counter. So fallback if the counter is going to
* overlow.
*/
- if (counter + nblks < counter) {
+ if (add_would_overflow(counter, nblks)) {
SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->sw_cipher.cipher);
int ret;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: "David S. Miller" <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jakub Kicinski <[email protected]>
Cc: Paolo Abeni <[email protected]>
Cc: Simon Horman <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/net/ethernet/sun/niu.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index 21431f43e4c2..a4de07c6e618 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -6877,15 +6877,16 @@ static int niu_get_eeprom(struct net_device *dev,
{
struct niu *np = netdev_priv(dev);
u32 offset, len, val;
+ u32 sum;
offset = eeprom->offset;
len = eeprom->len;
- if (offset + len < offset)
+ if (check_add_overflow(offset, len, &sum))
return -EINVAL;
if (offset >= np->eeprom_len)
return -EINVAL;
- if (offset + len > np->eeprom_len)
+ if (sum > np->eeprom_len)
len = eeprom->len = np->eeprom_len - offset;
if (offset & 3) {
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded unsigned wrap-around addition test to use
check_add_overflow(), retaining the result for later usage (which removes
the redundant open-coded addition). This paves the way to enabling the
unsigned wrap-around sanitizer[2] in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Linus Torvalds <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: "Liam R. Howlett" <[email protected]>
Cc: Mark Brown <[email protected]>
Cc: Mike Kravetz <[email protected]>
Cc: Vasily Averin <[email protected]>
Cc: Alexander Mikhalitsyn <[email protected]>
Signed-off-by: Kees Cook <[email protected]>
---
ipc/shm.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/ipc/shm.c b/ipc/shm.c
index a89f001a8bf0..227a1610628a 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1650,11 +1650,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg,
}
if (addr && !(shmflg & SHM_REMAP)) {
+ unsigned long sum;
+
err = -EINVAL;
- if (addr + size < addr)
+ if (check_add_overflow(addr, size, &sum))
goto invalid;
- if (find_vma_intersection(current->mm, addr, addr + size))
+ if (find_vma_intersection(current->mm, addr, sum))
goto invalid;
}
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Andrew Morton <[email protected]>
Cc: Uladzislau Rezki <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
mm/vmalloc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 7932ac99e9d3..3d73f2ac6957 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -3750,7 +3750,7 @@ long vread_iter(struct iov_iter *iter, const char *addr, size_t count)
addr = kasan_reset_tag(addr);
/* Don't allow overflow */
- if ((unsigned long) addr + count < count)
+ if (add_would_overflow(count, (unsigned long)addr))
count = -(unsigned long) addr;
remains = count;
--
2.34.1
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: Benjamin LaHaise <[email protected]>
Cc: Alexander Viro <[email protected]>
Cc: Christian Brauner <[email protected]>
Cc: Jan Kara <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
fs/aio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/aio.c b/fs/aio.c
index bb2ff48991f3..edd19be3f4b1 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -796,7 +796,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
/* limit the number of system wide aios */
spin_lock(&aio_nr_lock);
if (aio_nr + ctx->max_reqs > aio_max_nr ||
- aio_nr + ctx->max_reqs < aio_nr) {
+ add_would_overflow(aio_nr, ctx->max_reqs)) {
spin_unlock(&aio_nr_lock);
err = -EAGAIN;
goto err_ctx;
--
2.34.1
On Mon, Jan 22, 2024 at 05:07:40PM -0800, Linus Torvalds wrote:
> First off, none of this has anything to do with -fno-strict-overflow.
> We do that, because without it gcc ends up doing various odd and
> surprising things, the same way it does with strict-aliasing.
>
> IOW, you should think of -fno-strict-overflow as a hardening thing.
> Any optimization that depends on "this can overflow, so I can do
> anything I want" is just a dangerous optimization for the kernel.
>
> It matches -fno-strict-aliasing and -fno-delete-null-pointer-checks,
> in other words.
>
> And I do not understand why you mention it in the first place, since
> this code USES UNSIGNED INTEGER ARITHMETIC, and thus has absolutely
> nothing to do with that no-strict-overflow flag.
I've tried to find the right balance between not enough details and too
much. I guess I got it wrong. I go into more detail in the cover letter:
https://lore.kernel.org/linux-hardening/[email protected]/
Basically, this isn't about -fno-strict-overflow -- that's just a wrinkle
on the compiler side. I completely agree: we have to keep the "undefined
behavior" junk as far away from the kernel as possible.
This is about disambiguating the intent of C arithmetic so we can be in
the position to instrument the kernel to catch unexpected wrap-arounds.
We can't use C++ tricks with operator overloading and the introduction
of wrapping vs trapping types, so we have to annotate things directly.
And we have sanitizers for signed, unsigned, and pointers. Hence, the
need to adjust these open-coded wrap tests. It's not about removing UB:
-fno-strict-overflow already does that. This is about let us trap
unexpected wrap-around, regardless of type.
> Stop making the world a worse place.
Rude. I'll leave that to ice storms.
--
Kees Cook
In an effort to separate intentional arithmetic wrap-around from
unexpected wrap-around, we need to refactor places that depend on this
kind of math. One of the most common code patterns of this is:
VAR + value < VAR
Notably, this is considered "undefined behavior" for signed and pointer
types, which the kernel works around by using the -fno-strict-overflow
option in the build[1] (which used to just be -fwrapv). Regardless, we
want to get the kernel source to the position where we can meaningfully
instrument arithmetic wrap-around conditions and catch them when they
are unexpected, regardless of whether they are signed[2], unsigned[3],
or pointer[4] types.
Refactor open-coded wrap-around addition test to use add_would_overflow().
This paves the way to enabling the wrap-around sanitizers in the future.
Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
Link: https://github.com/KSPP/linux/issues/26 [2]
Link: https://github.com/KSPP/linux/issues/27 [3]
Link: https://github.com/KSPP/linux/issues/344 [4]
Cc: "Rafael J. Wysocki" <[email protected]>
Cc: Len Brown <[email protected]>
Cc: [email protected]
Signed-off-by: Kees Cook <[email protected]>
---
drivers/acpi/custom_method.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
index d39a9b474727..0789317f4a1a 100644
--- a/drivers/acpi/custom_method.c
+++ b/drivers/acpi/custom_method.c
@@ -54,7 +54,7 @@ static ssize_t cm_write(struct file *file, const char __user *user_buf,
if ((*ppos > max_size) ||
(*ppos + count > max_size) ||
- (*ppos + count < count) ||
+ (add_would_overflow(count, *ppos)) ||
(count > uncopied_bytes)) {
kfree(buf);
buf = NULL;
--
2.34.1
On Mon, 22 Jan 2024 at 16:46, Kees Cook <[email protected]> wrote:
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(),
NAK.
First off, none of this has anything to do with -fno-strict-overflow.
We do that, because without it gcc ends up doing various odd and
surprising things, the same way it does with strict-aliasing.
IOW, you should think of -fno-strict-overflow as a hardening thing.
Any optimization that depends on "this can overflow, so I can do
anything I want" is just a dangerous optimization for the kernel.
It matches -fno-strict-aliasing and -fno-delete-null-pointer-checks,
in other words.
And I do not understand why you mention it in the first place, since
this code USES UNSIGNED INTEGER ARITHMETIC, and thus has absolutely
nothing to do with that no-strict-overflow flag.
So the commit message is actively misleading and broken. Unsigned
arithmetic has very well-defined behavior, and the code uses that with
a very traditional and valid test.
The comment about "redundant open-coded addition" is also PURE
GARBAGE, since the compiler will trivially do the CSE - and on the
source code level your modified code is actively bigger and uglier.
So your patch improves neither code generation or source code.
And if there's some unsigned wrap-around checker that doesn't
understand this traditional way of doing overflow checking, that piece
of crap needs fixing.
I don't want to see mindless conversion patches that work around some
broken tooling.
I want to see them even less when pretty much EVERY SINGLE WORD in the
commit message seems to be actively misleading and irrelevant garbage.
Stop making the world a worse place.
Linus
On Mon, Jan 22, 2024 at 04:26:35PM -0800, Kees Cook wrote:
> Hi,
>
> In our continuing effort to eliminate root causes of flaws in the kernel,
> this series is the start to providing a way to have sensible coverage
> for catching unexpected arithmetic wrap-around.
>
> A quick word on language: while discussing[1] the finer details of
> the C standard's view on arithmetic, I was disabused of using the term
> "overflow" when what I really mean is "wrap-around". When describing
> security vulnerabilities, "overflow" is the common term and often used
> interchangeably with "wrap-around". Strictly speaking, though, "overflow"
> applies only to signed[2] and pointer[3] types, and "wrap-around" is for
> unsigned[4]. An arithmetic "overflow" is considered undefined behavior,
> which has caused our builds pain in the past, since "impossible"
> conditions might get elided by the compiler. As a result, we build
> with -fno-strict-overflow which coverts all "overflow" conditions into
> "wrap-around" (i.e. 2s complement), regardless of type.
>
> All this is to say I am discussing arithmetic wrap-around, which is
> the condition where the value exceeds a type's maximum value (or goes
> below its minimum value) and wraps around. I'm not interested in the
> narrow definition of "undefined behavior" -- we need to stamp out the
> _unexpected_ behavior, where the kernel operates on a pathological value
> that wrapped around without the code author's intent.
>
> As always, this is about being able disambiguate the intent of arithmetic
> in the kernel. We intentionally use wrapping arithmetic in all kinds of
> places, but we need to be able to annotate it as such going forward so
> the compiler can distinguish when it needs to perform instrumentation
> (when such instrumentation is enabled).
>
> Getting back to my earlier mention of -fno-strict-overflow, the bulk of
> the series is refactoring for a common code pattern in the kernel where
> to test for potentially overflowing addition, the addition is performed,
> and wrap-around is tested for. This is what originally[5] caused us to
> enable -fno-strict-overflow:
>
> var + offset < var
>
> For these cases we can use either check_add_overflow() or
> add_would_overflow(). These helpers will not trip the wrap-around
> instrumentation, and do not depend on the whims of the compiler options.
> (Note that I have no intention of removing -fno-strict-overflow any
> time soon, if ever. As with all these kinds of changes, we need to
> evolve our support for it, and we can't introduce undefined behavior
> into the kernel.)
>
> This series is mainly 3 parts:
This all seems fine, but... Rust already has this at the type system
level....
I know you're not one of the people bringing bickering into the Rust
threads, so I'm wondering if perhaps your secret plan is to annoy the
die hard "I want everything to be fast with razor blades everywhere" C
programmers enough to finally get onboard the "let's just switch to a
language with less razor wire" train.
On Tue, Jan 23, 2024 at 1:28 AM Kees Cook <[email protected]> wrote:
>
> Because the kernel is built with -fno-strict-overflow, signed and pointer
> arithmetic is defined to always wrap around instead of "overflowing"
> (which would either be elided due to being undefined behavior or would
> wrap around, which led to very weird bugs in the kernel).
By elided I guess you also mean assumed to not happen and thus the
usual chain-of-logic magic?
> So, the config options are added back as CONFIG_UBSAN_SIGNED_WRAP and
> CONFIG_UBSAN_UNSIGNED_WRAP. Since the kernel has several places that
> explicitly depend on wrap-around behavior (e.g. counters, atomics, etc),
> also introduce the __signed_wrap and __unsigned_wrap function attributes
> for annotating functions where wrapping is expected and should not
> be caught. This will allow us to distinguish in the kernel between
> intentional and unintentional cases of arithmetic wrap-around.
Sounds good -- it seems to go in the direction of Rust, i.e. to have a
way to mark expected wrap-arounds so that we can start catching the
unintended ones.
> + depends on !COMPILE_TEST
> + depends on $(cc-option,-fsanitize=signed-integer-overflow)
Maybe this line goes above the other, to be consistent with the
unsigned case? (or the other way around)
> + depends on !X86_32 # avoid excessive stack usage on x86-32/clang
> + depends on !COMPILE_TEST
> + help
> + This option enables -fsanitize=unsigned-integer-overflow which checks
> + for wrap-around of any arithmetic operations with unsigned integers. This
> + currently causes x86 to fail to boot.
Is it related to the excessive stack usage? In that case, users would
not reach the point to see this description, right? If so, I guess it
could be removed from the `help` and moved into the comment above or
similar.
> +static void test_ubsan_sub_overflow(void)
> +{
> + volatile int val = INT_MIN;
> + volatile unsigned int uval = 0;
> + volatile int val2 = 2;
In the other tests you use a constant instead of `val2`, I am curious
if there is a reason for it?
Thanks!
Cheers,
Miguel
On Mon, Jan 22, 2024 at 04:26:48PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> wrap-around sanitizer in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Chris Mason <[email protected]>
> Cc: Josef Bacik <[email protected]>
> Cc: David Sterba <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Acked-by: David Sterba <[email protected]>
On January 22, 2024 6:22:13 PM PST, Kent Overstreet <[email protected]> wrote:
>On Mon, Jan 22, 2024 at 04:26:35PM -0800, Kees Cook wrote:
>> In our continuing effort to eliminate root causes of flaws in the kernel,
>> this series is the start to providing a way to have sensible coverage
>> for catching unexpected arithmetic wrap-around.
>>
>This all seems fine, but... Rust already has this at the type system
>level....
>
>I know you're not one of the people bringing bickering into the Rust
>threads, so I'm wondering if perhaps your secret plan is to annoy the
>die hard "I want everything to be fast with razor blades everywhere" C
>programmers enough to finally get onboard the "let's just switch to a
>language with less razor wire" train.
I don't want to annoy anyone, but yeah, in the process of getting rid of dangerous stuff we do end up asking people to make changes they're not used to. I hope to make it as easy as possible, though.
I'm a big fan of Rust, but I know it's not going to happen over night; there is a LOT of C code in Linux. :) I look at making the kernel safer by removing as many C foot-guns as possible. As we remove the ambiguities in C that lead to vulnerabilities, we'll eventually meet halfway with the new Rust code.
-Kees
--
Kees Cook
* Kees Cook <[email protected]> [240122 19:36]:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> unsigned wrap-around sanitizer[2] in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Andrew Morton <[email protected]>
> Cc: Arnd Bergmann <[email protected]>
> Cc: Liam Howlett <[email protected]>
> Cc: "Matthew Wilcox (Oracle)" <[email protected]>
> Cc: Hugh Dickins <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/m68k/kernel/sys_m68k.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
> index 1af5e6082467..b2b9248f2566 100644
> --- a/arch/m68k/kernel/sys_m68k.c
> +++ b/arch/m68k/kernel/sys_m68k.c
> @@ -391,10 +391,11 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>
> mmap_read_lock(current->mm);
> } else {
> + unsigned long sum;
> struct vm_area_struct *vma;
>
> /* Check for overflow. */
With your nice self-documenting code, you can probably drop that
comment.
With or without the change,
Reviewed-by: Liam R. Howlett <[email protected]>
> - if (addr + len < addr)
> + if (check_add_overflow(addr, len, &sum))
> goto out;
>
> /*
> @@ -403,7 +404,7 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> */
> mmap_read_lock(current->mm);
> vma = vma_lookup(current->mm, addr);
> - if (!vma || addr + len > vma->vm_end)
> + if (!vma || sum > vma->vm_end)
> goto out_unlock;
> }
>
> --
> 2.34.1
>
On 1/22/24 4:27 PM, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Alexei Starovoitov <[email protected]>
> Cc: Daniel Borkmann <[email protected]>
> Cc: John Fastabend <[email protected]>
> Cc: Andrii Nakryiko <[email protected]>
> Cc: Martin KaFai Lau <[email protected]>
> Cc: Song Liu <[email protected]>
> Cc: Yonghong Song <[email protected]>
> Cc: KP Singh <[email protected]>
> Cc: Stanislav Fomichev <[email protected]>
> Cc: Hao Luo <[email protected]>
> Cc: Jiri Olsa <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> kernel/bpf/verifier.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 65f598694d55..21e3f30c8757 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -12901,8 +12901,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
> dst_reg->smin_value = smin_ptr + smin_val;
> dst_reg->smax_value = smax_ptr + smax_val;
> }
> - if (umin_ptr + umin_val < umin_ptr ||
> - umax_ptr + umax_val < umax_ptr) {
> + if (add_would_overflow(umin_ptr, umin_val) ||
> + add_would_overflow(umax_ptr, umax_val)) {
Maybe you could give a reference to the definition of add_would_overflow()?
A link or a patch with add_would_overflow() defined cc'ed to bpf program.
The patch itselfs looks good to me.
> dst_reg->umin_value = 0;
> dst_reg->umax_value = U64_MAX;
> } else {
> @@ -13023,8 +13023,8 @@ static void scalar32_min_max_add(struct bpf_reg_state *dst_reg,
> dst_reg->s32_min_value += smin_val;
> dst_reg->s32_max_value += smax_val;
> }
> - if (dst_reg->u32_min_value + umin_val < umin_val ||
> - dst_reg->u32_max_value + umax_val < umax_val) {
> + if (add_would_overflow(umin_val, dst_reg->u32_min_value) ||
> + add_would_overflow(umax_val, dst_reg->u32_max_value)) {
> dst_reg->u32_min_value = 0;
> dst_reg->u32_max_value = U32_MAX;
> } else {
> @@ -13049,8 +13049,8 @@ static void scalar_min_max_add(struct bpf_reg_state *dst_reg,
> dst_reg->smin_value += smin_val;
> dst_reg->smax_value += smax_val;
> }
> - if (dst_reg->umin_value + umin_val < umin_val ||
> - dst_reg->umax_value + umax_val < umax_val) {
> + if (add_would_overflow(umin_val, dst_reg->umin_value) ||
> + add_would_overflow(umax_val, dst_reg->umax_value)) {
> dst_reg->umin_value = 0;
> dst_reg->umax_value = U64_MAX;
> } else {
On January 22, 2024 8:00:26 PM PST, Yonghong Song <[email protected]> wrote:
>
>On 1/22/24 4:27 PM, Kees Cook wrote:
>> In an effort to separate intentional arithmetic wrap-around from
>> unexpected wrap-around, we need to refactor places that depend on this
>> kind of math. One of the most common code patterns of this is:
>>
>> VAR + value < VAR
>>
>> Notably, this is considered "undefined behavior" for signed and pointer
>> types, which the kernel works around by using the -fno-strict-overflow
>> option in the build[1] (which used to just be -fwrapv). Regardless, we
>> want to get the kernel source to the position where we can meaningfully
>> instrument arithmetic wrap-around conditions and catch them when they
>> are unexpected, regardless of whether they are signed[2], unsigned[3],
>> or pointer[4] types.
>>
>> Refactor open-coded wrap-around addition test to use add_would_overflow().
>> This paves the way to enabling the wrap-around sanitizers in the future.
>>
>> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
>> Link: https://github.com/KSPP/linux/issues/26 [2]
>> Link: https://github.com/KSPP/linux/issues/27 [3]
>> Link: https://github.com/KSPP/linux/issues/344 [4]
>> Cc: Alexei Starovoitov <[email protected]>
>> Cc: Daniel Borkmann <[email protected]>
>> Cc: John Fastabend <[email protected]>
>> Cc: Andrii Nakryiko <[email protected]>
>> Cc: Martin KaFai Lau <[email protected]>
>> Cc: Song Liu <[email protected]>
>> Cc: Yonghong Song <[email protected]>
>> Cc: KP Singh <[email protected]>
>> Cc: Stanislav Fomichev <[email protected]>
>> Cc: Hao Luo <[email protected]>
>> Cc: Jiri Olsa <[email protected]>
>> Cc: [email protected]
>> Signed-off-by: Kees Cook <[email protected]>
>> ---
>> kernel/bpf/verifier.c | 12 ++++++------
>> 1 file changed, 6 insertions(+), 6 deletions(-)
>>
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 65f598694d55..21e3f30c8757 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -12901,8 +12901,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
>> dst_reg->smin_value = smin_ptr + smin_val;
>> dst_reg->smax_value = smax_ptr + smax_val;
>> }
>> - if (umin_ptr + umin_val < umin_ptr ||
>> - umax_ptr + umax_val < umax_ptr) {
>> + if (add_would_overflow(umin_ptr, umin_val) ||
>> + add_would_overflow(umax_ptr, umax_val)) {
>
>Maybe you could give a reference to the definition of add_would_overflow()?
>A link or a patch with add_would_overflow() defined cc'ed to bpf program.
Sure! It was earlier in the series:
https://lore.kernel.org/linux-hardening/[email protected]/
The cover letter also has more details:
https://lore.kernel.org/linux-hardening/[email protected]/
>The patch itselfs looks good to me.
Thanks!
-Kees
--
Kees Cook
On January 22, 2024 6:24:14 PM PST, Miguel Ojeda <[email protected]> wrote:
>On Tue, Jan 23, 2024 at 1:28 AM Kees Cook <[email protected]> wrote:
>>
>> Because the kernel is built with -fno-strict-overflow, signed and pointer
>> arithmetic is defined to always wrap around instead of "overflowing"
>> (which would either be elided due to being undefined behavior or would
>> wrap around, which led to very weird bugs in the kernel).
>
>By elided I guess you also mean assumed to not happen and thus the
>usual chain-of-logic magic?
Yes. We removed this bad behavior by using -fno-strict-overflow, and we will want to keep it enabled.
>
>> So, the config options are added back as CONFIG_UBSAN_SIGNED_WRAP and
>> CONFIG_UBSAN_UNSIGNED_WRAP. Since the kernel has several places that
>> explicitly depend on wrap-around behavior (e.g. counters, atomics, etc),
>> also introduce the __signed_wrap and __unsigned_wrap function attributes
>> for annotating functions where wrapping is expected and should not
>> be caught. This will allow us to distinguish in the kernel between
>> intentional and unintentional cases of arithmetic wrap-around.
>
>Sounds good -- it seems to go in the direction of Rust, i.e. to have a
>way to mark expected wrap-arounds so that we can start catching the
>unintended ones.
Yup! That's the plan.
>
>> + depends on !COMPILE_TEST
>> + depends on $(cc-option,-fsanitize=signed-integer-overflow)
>
>Maybe this line goes above the other, to be consistent with the
>unsigned case? (or the other way around)
Sure, I can move it around.
>
>> + depends on !X86_32 # avoid excessive stack usage on x86-32/clang
>> + depends on !COMPILE_TEST
>> + help
>> + This option enables -fsanitize=unsigned-integer-overflow which checks
>> + for wrap-around of any arithmetic operations with unsigned integers. This
>> + currently causes x86 to fail to boot.
>
>Is it related to the excessive stack usage? In that case, users would
>not reach the point to see this description, right? If so, I guess it
>could be removed from the `help` and moved into the comment above or
>similar.
The stack usage is separate. (This may even be fixed in modern Clang; this comes from the original version of this Kconfig.) The not booting part is separate and has not been tracked down yet.
>
>> +static void test_ubsan_sub_overflow(void)
>> +{
>> + volatile int val = INT_MIN;
>> + volatile unsigned int uval = 0;
>> + volatile int val2 = 2;
>
>In the other tests you use a constant instead of `val2`, I am curious
>if there is a reason for it?
I wondered the same -- they were this way when they were removed, so I just restored them as they were. :)
-Kees
--
Kees Cook
On 1/22/24 8:07 PM, Kees Cook wrote:
>
> On January 22, 2024 8:00:26 PM PST, Yonghong Song <[email protected]> wrote:
>> On 1/22/24 4:27 PM, Kees Cook wrote:
>>> In an effort to separate intentional arithmetic wrap-around from
>>> unexpected wrap-around, we need to refactor places that depend on this
>>> kind of math. One of the most common code patterns of this is:
>>>
>>> VAR + value < VAR
>>>
>>> Notably, this is considered "undefined behavior" for signed and pointer
>>> types, which the kernel works around by using the -fno-strict-overflow
>>> option in the build[1] (which used to just be -fwrapv). Regardless, we
>>> want to get the kernel source to the position where we can meaningfully
>>> instrument arithmetic wrap-around conditions and catch them when they
>>> are unexpected, regardless of whether they are signed[2], unsigned[3],
>>> or pointer[4] types.
>>>
>>> Refactor open-coded wrap-around addition test to use add_would_overflow().
>>> This paves the way to enabling the wrap-around sanitizers in the future.
>>>
>>> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
>>> Link: https://github.com/KSPP/linux/issues/26 [2]
>>> Link: https://github.com/KSPP/linux/issues/27 [3]
>>> Link: https://github.com/KSPP/linux/issues/344 [4]
>>> Cc: Alexei Starovoitov <[email protected]>
>>> Cc: Daniel Borkmann <[email protected]>
>>> Cc: John Fastabend <[email protected]>
>>> Cc: Andrii Nakryiko <[email protected]>
>>> Cc: Martin KaFai Lau <[email protected]>
>>> Cc: Song Liu <[email protected]>
>>> Cc: Yonghong Song <[email protected]>
>>> Cc: KP Singh <[email protected]>
>>> Cc: Stanislav Fomichev <[email protected]>
>>> Cc: Hao Luo <[email protected]>
>>> Cc: Jiri Olsa <[email protected]>
>>> Cc: [email protected]
>>> Signed-off-by: Kees Cook <[email protected]>
>>> ---
>>> kernel/bpf/verifier.c | 12 ++++++------
>>> 1 file changed, 6 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>>> index 65f598694d55..21e3f30c8757 100644
>>> --- a/kernel/bpf/verifier.c
>>> +++ b/kernel/bpf/verifier.c
>>> @@ -12901,8 +12901,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
>>> dst_reg->smin_value = smin_ptr + smin_val;
>>> dst_reg->smax_value = smax_ptr + smax_val;
>>> }
>>> - if (umin_ptr + umin_val < umin_ptr ||
>>> - umax_ptr + umax_val < umax_ptr) {
>>> + if (add_would_overflow(umin_ptr, umin_val) ||
>>> + add_would_overflow(umax_ptr, umax_val)) {
>> Maybe you could give a reference to the definition of add_would_overflow()?
>> A link or a patch with add_would_overflow() defined cc'ed to bpf program.
> Sure! It was earlier in the series:
> https://lore.kernel.org/linux-hardening/[email protected]/
>
> The cover letter also has more details:
> https://lore.kernel.org/linux-hardening/[email protected]/
Thanks for the pointer.
Acked-by: Yonghong Song <[email protected]>
>
>> The patch itselfs looks good to me.
> Thanks!
>
> -Kees
>
On 23/01/24 02:27, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Peter Zijlstra <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Arnaldo Carvalho de Melo <[email protected]>
> Cc: Mark Rutland <[email protected]>
> Cc: Alexander Shishkin <[email protected]>
> Cc: Jiri Olsa <[email protected]>
> Cc: Namhyung Kim <[email protected]>
> Cc: Ian Rogers <[email protected]>
> Cc: Adrian Hunter <[email protected]>
> Cc: John Garry <[email protected]>
> Cc: Fangrui Song <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> tools/perf/util/dso.c | 2 +-
> tools/perf/util/unwind-libdw.c | 2 +-
> tools/perf/util/unwind-libunwind-local.c | 2 +-
> 3 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
> index 22fd5fa806ed..470a86f1cdfd 100644
> --- a/tools/perf/util/dso.c
> +++ b/tools/perf/util/dso.c
> @@ -1122,7 +1122,7 @@ static ssize_t data_read_write_offset(struct dso *dso, struct machine *machine,
> if (offset > dso->data.file_size)
> return -1;
>
> - if (offset + size < offset)
> + if (add_would_overflow(offset, size))
perf tools has separate includes to the kernel, so does not
seem to include add_would_overflow() in any of its include
files at this point. Need to update
tools/include/linux/overflow.h first.
Kees Cook <[email protected]> writes:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Kalle Valo <[email protected]>
> Cc: Johannes Berg <[email protected]>
> Cc: Max Chen <[email protected]>
> Cc: Yang Shen <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
I assume this goes via some other tree than wireless-next so:
Acked-by: Kalle Valo <[email protected]>
--
https://patchwork.kernel.org/project/linux-wireless/list/
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
On Mon, Jan 22, 2024 at 04:27:17PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Kent Overstreet <[email protected]>
> Cc: Brian Foster <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Acked-by: Kent Overstreet <[email protected]>
Hello Kees,
On Mon, 2024-01-22 at 16:27 -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Yoshinori Sato <[email protected]>
> Cc: Rich Felker <[email protected]>
> Cc: John Paul Adrian Glaubitz <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/sh/kernel/sys_sh.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
> index a5a7b33ed81a..e390caeb8c00 100644
> --- a/arch/sh/kernel/sys_sh.c
> +++ b/arch/sh/kernel/sys_sh.c
> @@ -66,7 +66,7 @@ asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op)
> * Verify that the specified address region actually belongs
> * to this process.
> */
> - if (addr + len < addr)
> + if (add_would_overflow(addr, len))
> return -EFAULT;
>
> mmap_read_lock(current->mm);
Sounds like a very sensible change to me.
Acked-by: John Paul Adrian Glaubitz <[email protected]>
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer
`. `' Physicist
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
On 23.01.2024 01:27, Kees Cook wrote:
> --- a/drivers/net/xen-netback/hash.c
> +++ b/drivers/net/xen-netback/hash.c
> @@ -345,7 +345,7 @@ u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len,
> .flags = GNTCOPY_source_gref
> }};
>
> - if ((off + len < off) || (off + len > vif->hash.size) ||
> + if ((add_would_overflow(off, len)) || (off + len > vif->hash.size) ||
I'm not maintainer of this code, but if I was I would ask that the
excess parentheses be removed, to improve readability.
Jan
On 23/01/2024 01.26, Kees Cook wrote:
> For instances where only the overflow needs to be checked (and the sum
> isn't used), provide the new helper add_would_overflow(), which is
> a wrapper for check_add_overflow().
>
> Cc: "Gustavo A. R. Silva" <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> include/linux/overflow.h | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> index 099f2e559aa8..ac088f73e0fd 100644
> --- a/include/linux/overflow.h
> +++ b/include/linux/overflow.h
> @@ -108,6 +108,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
> __builtin_add_overflow(__filter_integral(a), b, \
> __filter_ptrint(d))))
>
> +/**
> + * add_would_overflow() - Check if an addition would overflow
> + * @a: first addend
> + * @b: second addend
> + *
> + * Returns true if the sum would overflow.
> + *
> + * To keep a copy of the sum when the addition doesn't overflow, use
> + * check_add_overflow() instead.
> + */
> +#define add_would_overflow(a, b) \
> + __must_check_overflow(({ \
> + size_t __result; \
> + check_add_overflow(a, b, &__result);\
> + }))
Hm, I think this is a bit too ill-defined. Why is the target type
hard-coded as size_t? What if a and b are u64, and we're on a 32 bit
target? Then a+b might not overflow but this helper would claim it did.
But we also cannot just use typeof(a+b) instead of size_t, since that
breaks when a and b are narrower than int (adding two u16 never
overflows since they get promoted to int, but then if assigning the
result to a u16 one truncates...).
Perhaps the target type must be explicit? sum_fits_in_type(T, a, b) ?
IDK, I just don't think size_t is the right thing to use in something
that is otherwise supposed to be type-generic.
Rasmus
Hi Kees,
On Tue, Jan 23, 2024 at 1:35 AM Kees Cook <[email protected]> wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> unsigned wrap-around sanitizer[2] in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Andrew Morton <[email protected]>
> Cc: Arnd Bergmann <[email protected]>
> Cc: Liam Howlett <[email protected]>
> Cc: "Matthew Wilcox (Oracle)" <[email protected]>
> Cc: Hugh Dickins <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Thanks for your patch!
> --- a/arch/m68k/kernel/sys_m68k.c
> +++ b/arch/m68k/kernel/sys_m68k.c
> @@ -391,10 +391,11 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>
> mmap_read_lock(current->mm);
> } else {
> + unsigned long sum;
"sum" sounds like this is a dummy variable, to please the third
parameter of check_add_overflow()...
> struct vm_area_struct *vma;
>
> /* Check for overflow. */
I agree with Liam: please drop the comment.
> - if (addr + len < addr)
> + if (check_add_overflow(addr, len, &sum))
> goto out;
>
> /*
> @@ -403,7 +404,7 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> */
> mmap_read_lock(current->mm);
> vma = vma_lookup(current->mm, addr);
> - if (!vma || addr + len > vma->vm_end)
> + if (!vma || sum > vma->vm_end)
.. Oh, it is actually used. What about renaming it to "end" instead?
> goto out_unlock;
> }
With the above fixed:
Reviewed-by: Geert Uytterhoeven <[email protected]>
Acked-by: Geert Uytterhoeven <[email protected]>
If you want me to take this through the m68k tree (for v6.9), please
let me know.
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68korg
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
On 23/01/2024 01.26, Kees Cook wrote:
> Provide a helper that will perform wrapping addition without tripping
> the arithmetic wrap-around sanitizers.
>
> Cc: "Gustavo A. R. Silva" <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> include/linux/overflow.h | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> index ac088f73e0fd..30779905a77a 100644
> --- a/include/linux/overflow.h
> +++ b/include/linux/overflow.h
> @@ -124,6 +124,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
> check_add_overflow(a, b, &__result);\
> }))
>
> +/**
> + * add_wrap() - Intentionally perform a wrapping addition
> + * @a: first addend
> + * @b: second addend
> + *
> + * Return the potentially wrapped-around addition without
> + * tripping any overflow sanitizers that may be enabled.
> + */
> +#define add_wrap(a, b) \
> + ({ \
> + typeof(a) __sum; \
> + if (check_add_overflow(a, b, &__sum)) \
> + /* do nothing */; \
> + __sum; \
> + })
> +
I don't know where this is supposed to be used, but at first glance this
seems to introduce a footgun. This is not symmetric in a and b, so both
the type and value of the result may differ between add_wrap(a, b) and
add_wrap(b, a). That seems dangerous.
Rasmus
On Tue Jan 23, 2024 at 12:26 AM UTC, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Jarkko Sakkinen <[email protected]>
> Cc: Dave Hansen <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Borislav Petkov <[email protected]>
> Cc: [email protected]
> Cc: "H. Peter Anvin" <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/x86/kernel/cpu/sgx/ioctl.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
> index b65ab214bdf5..4b8f6c9f8ef5 100644
> --- a/arch/x86/kernel/cpu/sgx/ioctl.c
> +++ b/arch/x86/kernel/cpu/sgx/ioctl.c
> @@ -350,16 +350,18 @@ static int sgx_validate_offset_length(struct sgx_encl *encl,
> unsigned long offset,
> unsigned long length)
> {
> + unsigned long sum;
> +
> if (!IS_ALIGNED(offset, PAGE_SIZE))
> return -EINVAL;
>
> if (!length || !IS_ALIGNED(length, PAGE_SIZE))
> return -EINVAL;
>
> - if (offset + length < offset)
> + if (check_add_overflow(offset, length, &sum))
> return -EINVAL;
>
> - if (offset + length - PAGE_SIZE >= encl->size)
> + if (sum - PAGE_SIZE >= encl->size)
> return -EINVAL;
>
> return 0;
Reviewed-by: Jarkko Sakkinen <[email protected]>
BR, Jarkko
On Mon, Jan 22, 2024 at 04:26:38PM -0800, Kees Cook wrote:
> Provide a helper that will perform wrapping addition without tripping
> the arithmetic wrap-around sanitizers.
>
> Cc: "Gustavo A. R. Silva" <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> include/linux/overflow.h | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> index ac088f73e0fd..30779905a77a 100644
> --- a/include/linux/overflow.h
> +++ b/include/linux/overflow.h
> @@ -124,6 +124,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
> check_add_overflow(a, b, &__result);\
> }))
>
> +/**
> + * add_wrap() - Intentionally perform a wrapping addition
> + * @a: first addend
> + * @b: second addend
> + *
> + * Return the potentially wrapped-around addition without
> + * tripping any overflow sanitizers that may be enabled.
> + */
> +#define add_wrap(a, b) \
> + ({ \
> + typeof(a) __sum; \
> + if (check_add_overflow(a, b, &__sum)) \
> + /* do nothing */; \
> + __sum; \
> + })
It's really difficult to see the semicolon for the empty statement here; could
we make that part:
if ((check_add_overflow(a, b, &__sum)) { \
/* do nothing */ \
} \
.. to be a little clearer (and less at risk of breakage in a refactoring)?
I realise coding style says not to use braces for a single statement, but IMO
it's far clearer in this instance with the braces.
Mark.
> +
> /**
> * check_sub_overflow() - Calculate subtraction with overflow checking
> * @a: minuend; value to subtract from
> --
> 2.34.1
>
>
On Mon, Jan 22, 2024 at 04:26:45PM -0800, Kees Cook wrote:
> Annotate atomic_add_return() to avoid signed overflow instrumentation.
> It is expected to wrap around.
>
> Cc: Will Deacon <[email protected]>
> Cc: Peter Zijlstra <[email protected]>
> Cc: Boqun Feng <[email protected]>
> Cc: Mark Rutland <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Borislav Petkov <[email protected]>
> Cc: Dave Hansen <[email protected]>
> Cc: [email protected]
> Cc: "H. Peter Anvin" <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/x86/include/asm/atomic.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
> index 55a55ec04350..4120cdd87da8 100644
> --- a/arch/x86/include/asm/atomic.h
> +++ b/arch/x86/include/asm/atomic.h
> @@ -80,7 +80,7 @@ static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v)
> }
> #define arch_atomic_add_negative arch_atomic_add_negative
>
> -static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
> +static __always_inline __signed_wrap int arch_atomic_add_return(int i, atomic_t *v)
> {
> return i + xadd(&v->counter, i);
> }
I think that here (and in the arm64 patch) it'd be better to use add_wrap() on
the specific statement, i.e. have:
static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
{
return add_wrap(i, xadd(&v->counter, i));
}
.. since otherwise the annotation could applly to the '+' or something else
(e.g. if the 'xadd() part is a special macro), and the annotation might
unexpectedly hide things if we add other statements here in future.
Mark.
> --
> 2.34.1
>
On Mon, Jan 22, 2024 at 04:26:35PM -0800, Kees Cook wrote:
> Hi,
Hi Kees,
> In our continuing effort to eliminate root causes of flaws in the kernel,
> this series is the start to providing a way to have sensible coverage
> for catching unexpected arithmetic wrap-around.
>
> A quick word on language: while discussing[1] the finer details of
> the C standard's view on arithmetic, I was disabused of using the term
> "overflow" when what I really mean is "wrap-around". When describing
> security vulnerabilities, "overflow" is the common term and often used
> interchangeably with "wrap-around". Strictly speaking, though, "overflow"
> applies only to signed[2] and pointer[3] types, and "wrap-around" is for
> unsigned[4]. An arithmetic "overflow" is considered undefined behavior,
> which has caused our builds pain in the past, since "impossible"
> conditions might get elided by the compiler. As a result, we build
> with -fno-strict-overflow which coverts all "overflow" conditions into
> "wrap-around" (i.e. 2s complement), regardless of type.
>
> All this is to say I am discussing arithmetic wrap-around, which is
> the condition where the value exceeds a type's maximum value (or goes
> below its minimum value) and wraps around. I'm not interested in the
> narrow definition of "undefined behavior" -- we need to stamp out the
> _unexpected_ behavior, where the kernel operates on a pathological value
> that wrapped around without the code author's intent.
With that in mind, I note that this patch primarily modifies addition
operations, but leaves subtraction operations unchanged (even though those
permit the value to go below the minimum, or above the maximum if a negative
value is used as the subtrahend).
Shouldn't we address both at the same time? I'll note that in many places the
same logic is used for both the add and sub, and can legitimately overflow or
underflow; I hope that whatever we use to suppress overflow warnings also
ignores underflow.
[...]
Looking at the diffstat, I think you've missed a few places:
> Documentation/process/deprecated.rst | 36 ++++++++
> arch/arc/kernel/unwind.c | 7 +-
> arch/arm/nwfpe/softfloat.c | 2 +-
> arch/arm64/include/asm/atomic_lse.h | 8 +-
> arch/arm64/include/asm/stacktrace/common.h | 2 +-
> arch/arm64/kvm/vgic/vgic-kvm-device.c | 6 +-
> arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +-
> arch/arm64/kvm/vgic/vgic-v2.c | 10 ++-
> arch/m68k/kernel/sys_m68k.c | 5 +-
> arch/nios2/kernel/sys_nios2.c | 2 +-
> arch/powerpc/platforms/powernv/opal-prd.c | 2 +-
> arch/powerpc/xmon/xmon.c | 2 +-
> arch/s390/include/asm/stacktrace.h | 6 +-
> arch/s390/kernel/machine_kexec_file.c | 5 +-
> arch/s390/mm/gmap.c | 4 +-
> arch/s390/mm/vmem.c | 2 +-
> arch/sh/kernel/sys_sh.c | 2 +-
> arch/x86/include/asm/atomic.h | 2 +-
> arch/x86/kernel/cpu/sgx/ioctl.c | 6 +-
> arch/x86/kvm/svm/sev.c | 5 +-
> crypto/adiantum.c | 2 +-
> drivers/acpi/custom_method.c | 2 +-
> drivers/char/agp/generic.c | 2 +-
> drivers/crypto/amcc/crypto4xx_alg.c | 2 +-
> drivers/crypto/axis/artpec6_crypto.c | 2 +-
> drivers/dma-buf/dma-buf.c | 7 +-
> drivers/fpga/dfl.c | 5 +-
> drivers/fsi/fsi-core.c | 6 +-
> drivers/gpu/drm/i915/i915_vma.c | 2 +-
> drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c | 8 +-
> drivers/gpu/drm/vc4/vc4_validate.c | 7 +-
> drivers/md/dm-switch.c | 2 +-
> drivers/md/dm-verity-target.c | 2 +-
> drivers/md/dm-writecache.c | 2 +-
> drivers/net/ethernet/sun/niu.c | 5 +-
> drivers/net/wireless/ath/wil6210/wmi.c | 2 +-
> drivers/net/wireless/marvell/mwifiex/pcie.c | 6 +-
> drivers/net/xen-netback/hash.c | 2 +-
> drivers/pci/pci.c | 2 +-
> drivers/remoteproc/pru_rproc.c | 2 +-
> drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
> drivers/remoteproc/remoteproc_virtio.c | 4 +-
> drivers/scsi/mpt3sas/mpt3sas_ctl.c | 2 +-
> drivers/scsi/sd_zbc.c | 2 +-
> drivers/staging/vme_user/vme.c | 2 +-
> drivers/vhost/vringh.c | 8 +-
> drivers/virtio/virtio_pci_modern_dev.c | 4 +-
> fs/aio.c | 2 +-
> fs/bcachefs/bkey.c | 4 +-
> fs/bcachefs/fs.c | 2 +-
> fs/bcachefs/quota.c | 2 +-
> fs/bcachefs/util.c | 2 +-
> fs/btrfs/extent_map.c | 6 +-
> fs/btrfs/extent_map.h | 6 +-
> fs/btrfs/ordered-data.c | 2 +-
> fs/ext4/block_validity.c | 2 +-
> fs/ext4/extents.c | 5 +-
> fs/ext4/resize.c | 2 +-
> fs/f2fs/file.c | 2 +-
> fs/f2fs/verity.c | 2 +-
> fs/hpfs/alloc.c | 2 +-
> fs/ntfs3/record.c | 4 +-
> fs/ocfs2/resize.c | 2 +-
> fs/read_write.c | 8 +-
> fs/remap_range.c | 2 +-
> fs/select.c | 13 +--
> fs/smb/client/readdir.c | 5 +-
> fs/smb/client/smb2pdu.c | 4 +-
> fs/udf/balloc.c | 4 +-
> include/linux/compiler_types.h | 29 +++++-
This misses the include/asm-generic/{atomic,atomic64}.h implementations.
This also misses the include/linux/atomic/atomic-arch-fallback.h
implementations. Those are generated from the scripts/atomic/fallbacks/*
templates, and you'll need to adjust at least fetch_add_unless and
inc_unless_negative. As noted on other patches, my preference is to use
add_wrap() in those.
> include/linux/overflow.h | 76 +++++++++++++++-
> ipc/mqueue.c | 2 +-
> ipc/shm.c | 6 +-
> kernel/bpf/verifier.c | 12 +--
> kernel/time/timekeeping.c | 2 +-
> lib/Kconfig.ubsan | 27 ++++++
This misses lib/atomic64.c.
Thanks,
Mark.
On Mon, Jan 22, 2024 at 04:26:46PM -0800, Kees Cook wrote:
> Annotate atomic_add_return() and atomic_sub_return() to avoid signed
> overflow instrumentation. They are expected to wrap around.
>
> Cc: Will Deacon <[email protected]>
> Cc: Peter Zijlstra <[email protected]>
> Cc: Boqun Feng <[email protected]>
> Cc: Mark Rutland <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/arm64/include/asm/atomic_lse.h | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h
> index 87f568a94e55..30572458d702 100644
> --- a/arch/arm64/include/asm/atomic_lse.h
> +++ b/arch/arm64/include/asm/atomic_lse.h
> @@ -79,13 +79,13 @@ ATOMIC_FETCH_OP_SUB( )
> #undef ATOMIC_FETCH_OP_SUB
>
> #define ATOMIC_OP_ADD_SUB_RETURN(name) \
> -static __always_inline int \
> +static __always_inline __signed_wrap int \
> __lse_atomic_add_return##name(int i, atomic_t *v) \
> { \
> return __lse_atomic_fetch_add##name(i, v) + i; \
> } \
I'd strongly prefer using add_wrap() rather than annotating the function, i.e.
make this:
static __always_inline int \
__lse_atomic_add_return##name(int i, atomic_t *v) \
{ \
return add_wrap(__lse_atomic_fetch_add##name(i, v), i); \
} \
Likewise for the other instances below.
With that, this looks fine to me.
Mark.
> \
> -static __always_inline int \
> +static __always_inline __signed_wrap int \
> __lse_atomic_sub_return##name(int i, atomic_t *v) \
> { \
> return __lse_atomic_fetch_sub(i, v) - i; \
> @@ -186,13 +186,13 @@ ATOMIC64_FETCH_OP_SUB( )
> #undef ATOMIC64_FETCH_OP_SUB
>
> #define ATOMIC64_OP_ADD_SUB_RETURN(name) \
> -static __always_inline long \
> +static __always_inline __signed_wrap long \
> __lse_atomic64_add_return##name(s64 i, atomic64_t *v) \
> { \
> return __lse_atomic64_fetch_add##name(i, v) + i; \
> } \
> \
> -static __always_inline long \
> +static __always_inline __signed_wrap long \
> __lse_atomic64_sub_return##name(s64 i, atomic64_t *v) \
> { \
> return __lse_atomic64_fetch_sub##name(i, v) - i; \
> --
> 2.34.1
>
The commit title is odd here; '3117/1' is the patch tracker name for the last
patch. The title should probably be:
arm: nwfpe: Refactor intentional wrap-around test
Mark.
On Mon, Jan 22, 2024 at 04:27:13PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Russell King <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/arm/nwfpe/softfloat.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c
> index ffa6b438786b..0635b1eda1d3 100644
> --- a/arch/arm/nwfpe/softfloat.c
> +++ b/arch/arm/nwfpe/softfloat.c
> @@ -603,7 +603,7 @@ static floatx80
> roundBits = zSig0 & roundMask;
> if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
> if ( ( 0x7FFE < zExp )
> - || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
> + || ( ( zExp == 0x7FFE ) && (add_would_overflow(zSig0, roundIncrement)) )
> ) {
> goto overflow;
> }
> --
> 2.34.1
>
>
On Mon, Jan 22, 2024 at 04:27:15PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Kalesh Singh <[email protected]>
> Cc: Fuad Tabba <[email protected]>
> Cc: Mark Brown <[email protected]>
> Cc: "Madhavan T. Venkataraman" <[email protected]>
> Cc: Marc Zyngier <[email protected]>
> Cc: Mark Rutland <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/arm64/include/asm/stacktrace/common.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h
> index f63dc654e545..6e0cb84961f8 100644
> --- a/arch/arm64/include/asm/stacktrace/common.h
> +++ b/arch/arm64/include/asm/stacktrace/common.h
> @@ -49,7 +49,7 @@ static inline bool stackinfo_on_stack(const struct stack_info *info,
> if (!info->low)
> return false;
>
> - if (sp < info->low || sp + size < sp || sp + size > info->high)
> + if (sp < info->low || add_would_overflow(sp, size) || sp + size > info->high)
> return false;
This looks fine to me, so FWIW:
Acked-by: Mark Rutland <[email protected]>
Mark.
>
> return true;
> --
> 2.34.1
>
On Tue, 23 Jan 2024 00:26:59 +0000,
Kees Cook <[email protected]> wrote:
>
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Marc Zyngier <[email protected]>
> Cc: Oliver Upton <[email protected]>
> Cc: James Morse <[email protected]>
> Cc: Suzuki K Poulose <[email protected]>
> Cc: Zenghui Yu <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Reiji Watanabe <[email protected]>
> Cc: Eric Auger <[email protected]>
> Cc: Ricardo Koller <[email protected]>
> Cc: Raghavendra Rao Ananta <[email protected]>
> Cc: Quentin Perret <[email protected]>
> Cc: Jean-Philippe Brucker <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/arm64/kvm/vgic/vgic-kvm-device.c | 6 ++++--
> arch/arm64/kvm/vgic/vgic-v2.c | 10 ++++++----
> 2 files changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
> index f48b8dab8b3d..0eec5344d203 100644
> --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
> +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
> @@ -18,17 +18,19 @@ int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,
> phys_addr_t addr, phys_addr_t alignment,
> phys_addr_t size)
> {
> + phys_addr_t sum;
> +
> if (!IS_VGIC_ADDR_UNDEF(ioaddr))
> return -EEXIST;
>
> if (!IS_ALIGNED(addr, alignment) || !IS_ALIGNED(size, alignment))
> return -EINVAL;
>
> - if (addr + size < addr)
> + if (check_add_overflow(addr, size, &sum))
> return -EINVAL;
>
> if (addr & ~kvm_phys_mask(&kvm->arch.mmu) ||
> - (addr + size) > kvm_phys_size(&kvm->arch.mmu))
> + sum > kvm_phys_size(&kvm->arch.mmu))
nit: 'sum' doesn't mean much in this context. Something like 'end'
would be much more descriptive.
> return -E2BIG;
>
> return 0;
> diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c
> index 7e9cdb78f7ce..c8d1e965d3b7 100644
> --- a/arch/arm64/kvm/vgic/vgic-v2.c
> +++ b/arch/arm64/kvm/vgic/vgic-v2.c
> @@ -273,14 +273,16 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
> /* check for overlapping regions and for regions crossing the end of memory */
> static bool vgic_v2_check_base(gpa_t dist_base, gpa_t cpu_base)
> {
> - if (dist_base + KVM_VGIC_V2_DIST_SIZE < dist_base)
> + gpa_t dist_sum, cpu_sum;
Same here: dist_end, cpu_end.
> +
> + if (check_add_overflow(dist_base, KVM_VGIC_V2_DIST_SIZE, &dist_sum))
> return false;
> - if (cpu_base + KVM_VGIC_V2_CPU_SIZE < cpu_base)
> + if (check_add_overflow(cpu_base, KVM_VGIC_V2_CPU_SIZE, &cpu_sum))
> return false;
>
> - if (dist_base + KVM_VGIC_V2_DIST_SIZE <= cpu_base)
> + if (dist_sum <= cpu_base)
> return true;
> - if (cpu_base + KVM_VGIC_V2_CPU_SIZE <= dist_base)
> + if (cpu_sum <= dist_base)
> return true;
>
> return false;
With these nits addressed, and assuming you intend to merge the whole
series yourself:
Acked-by: Marc Zyngier <[email protected]>
M.
--
Without deviation from the norm, progress is not possible.
On Tue, 23 Jan 2024 00:27:32 +0000,
Kees Cook <[email protected]> wrote:
>
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Marc Zyngier <[email protected]>
> Cc: Oliver Upton <[email protected]>
> Cc: James Morse <[email protected]>
> Cc: Suzuki K Poulose <[email protected]>
> Cc: Zenghui Yu <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Eric Auger <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
> index c15ee1df036a..860b774c0c13 100644
> --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
> +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
> @@ -863,7 +863,7 @@ static int vgic_v3_alloc_redist_region(struct kvm *kvm, uint32_t index,
> int ret;
>
> /* cross the end of memory ? */
> - if (base + size < base)
> + if (add_would_overflow(base, size))
> return -EINVAL;
>
> if (list_empty(rd_regions)) {
Acked-by: Marc Zyngier <[email protected]>
M.
--
Without deviation from the norm, progress is not possible.
On Tue, Jan 23, 2024 at 5:45 AM Kees Cook <[email protected]> wrote:
>
> Yes. We removed this bad behavior by using -fno-strict-overflow, and we will want to keep it enabled.
Yeah, I only meant that the wording of the commit seems to say there
is something special about the "overflowing behavior", i.e. I was
expecting just UB with the usual implications, but given the extra
text in the parenthesis, I wondered while reading it if there was
something different/special going on.
> The stack usage is separate. (This may even be fixed in modern Clang; this comes from the original version of this Kconfig.) The not booting part is separate and has not been tracked down yet.
I see. Thanks! In any case, if the sentence means only 32-bit x86,
users couldn't still see it. But since this was already in the revert
now that I take a look, I guess ignore this :)
> I wondered the same -- they were this way when they were removed, so I just restored them as they were. :)
Makes sense :)
Cheers,
Miguel
On 1/22/24 18:27, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Dinh Nguyen <[email protected]>
> Cc: Jann Horn <[email protected]>
> Cc: Ley Foon Tan <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/nios2/kernel/sys_nios2.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Acked-by: Dinh Nguyen <[email protected]>
Hi,
On 23.1.2024 10.13, Geert Uytterhoeven wrote:
> On Tue, Jan 23, 2024 at 1:35 AM Kees Cook <[email protected]> wrote:
>> In an effort to separate intentional arithmetic wrap-around from
>> unexpected wrap-around, we need to refactor places that depend on this
>> kind of math. One of the most common code patterns of this is:
>>
>> VAR + value < VAR
>>
>> Notably, this is considered "undefined behavior" for signed and pointer
>> types, which the kernel works around by using the -fno-strict-overflow
>> option in the build[1] (which used to just be -fwrapv). Regardless, we
>> want to get the kernel source to the position where we can meaningfully
>> instrument arithmetic wrap-around conditions and catch them when they
>> are unexpected, regardless of whether they are signed[2], unsigned[3],
>> or pointer[4] types.
>>
>> Refactor open-coded unsigned wrap-around addition test to use
>> check_add_overflow(), retaining the result for later usage (which removes
>> the redundant open-coded addition). This paves the way to enabling the
>> unsigned wrap-around sanitizer[2] in the future.
>>
>> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
>> Link: https://github.com/KSPP/linux/issues/26 [2]
>> Link: https://github.com/KSPP/linux/issues/27 [3]
>> Link: https://github.com/KSPP/linux/issues/344 [4]
>> Cc: Geert Uytterhoeven <[email protected]>
>> Cc: Andrew Morton <[email protected]>
>> Cc: Arnd Bergmann <[email protected]>
>> Cc: Liam Howlett <[email protected]>
>> Cc: "Matthew Wilcox (Oracle)" <[email protected]>
>> Cc: Hugh Dickins <[email protected]>
>> Cc: [email protected]
>> Signed-off-by: Kees Cook <[email protected]>
>
> Thanks for your patch!
>
>> --- a/arch/m68k/kernel/sys_m68k.c
>> +++ b/arch/m68k/kernel/sys_m68k.c
>> @@ -391,10 +391,11 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>>
>> mmap_read_lock(current->mm);
>> } else {
>> + unsigned long sum;
>
> "sum" sounds like this is a dummy variable, to please the third
> parameter of check_add_overflow()...
>
>> struct vm_area_struct *vma;
>>
>> /* Check for overflow. */
>
> I agree with Liam: please drop the comment.
>
>> - if (addr + len < addr)
>> + if (check_add_overflow(addr, len, &sum))
>> goto out;
>>
>> /*
>> @@ -403,7 +404,7 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>> */
>> mmap_read_lock(current->mm);
>> vma = vma_lookup(current->mm, addr);
>> - if (!vma || addr + len > vma->vm_end)
>> + if (!vma || sum > vma->vm_end)
>
> ... Oh, it is actually used. What about renaming it to "end" instead?
IMHO this is more descriptive:
+ if (check_add_overflow(addr, len, &sum))
than this:
+ if (check_add_overflow(addr, len, &end))
"sum" is IMHO quite obviously sum of the preceding args, whereas I do
not know what "end" would be.
- Eero
>> goto out_unlock;
>> }
>
> With the above fixed:
>
> Reviewed-by: Geert Uytterhoeven <[email protected]>
> Acked-by: Geert Uytterhoeven <[email protected]>
>
> If you want me to take this through the m68k tree (for v6.9), please
> let me know.
> Thanks!
>
> Gr{oetje,eeting}s,
>
> Geert
>
Hi Eero,
On Tue, Jan 23, 2024 at 2:30 PM Eero Tamminen <[email protected]> wrote:
> On 23.1.2024 10.13, Geert Uytterhoeven wrote:
> > On Tue, Jan 23, 2024 at 1:35 AM Kees Cook <[email protected]> wrote:
> >> In an effort to separate intentional arithmetic wrap-around from
> >> unexpected wrap-around, we need to refactor places that depend on this
> >> kind of math. One of the most common code patterns of this is:
> >>
> >> VAR + value < VAR
> >>
> >> Notably, this is considered "undefined behavior" for signed and pointer
> >> types, which the kernel works around by using the -fno-strict-overflow
> >> option in the build[1] (which used to just be -fwrapv). Regardless, we
> >> want to get the kernel source to the position where we can meaningfully
> >> instrument arithmetic wrap-around conditions and catch them when they
> >> are unexpected, regardless of whether they are signed[2], unsigned[3],
> >> or pointer[4] types.
> >>
> >> Refactor open-coded unsigned wrap-around addition test to use
> >> check_add_overflow(), retaining the result for later usage (which removes
> >> the redundant open-coded addition). This paves the way to enabling the
> >> unsigned wrap-around sanitizer[2] in the future.
> >>
> >> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> >> Link: https://github.com/KSPP/linux/issues/26 [2]
> >> Link: https://github.com/KSPP/linux/issues/27 [3]
> >> Link: https://github.com/KSPP/linux/issues/344 [4]
> >> Cc: Geert Uytterhoeven <[email protected]>
> >> Cc: Andrew Morton <[email protected]>
> >> Cc: Arnd Bergmann <[email protected]>
> >> Cc: Liam Howlett <[email protected]>
> >> Cc: "Matthew Wilcox (Oracle)" <[email protected]>
> >> Cc: Hugh Dickins <[email protected]>
> >> Cc: [email protected]
> >> Signed-off-by: Kees Cook <[email protected]>
> >
> > Thanks for your patch!
> >
> >> --- a/arch/m68k/kernel/sys_m68k.c
> >> +++ b/arch/m68k/kernel/sys_m68k.c
> >> @@ -391,10 +391,11 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> >>
> >> mmap_read_lock(current->mm);
> >> } else {
> >> + unsigned long sum;
> >
> > "sum" sounds like this is a dummy variable, to please the third
> > parameter of check_add_overflow()...
> >
> >> struct vm_area_struct *vma;
> >>
> >> /* Check for overflow. */
> >
> > I agree with Liam: please drop the comment.
> >
> >> - if (addr + len < addr)
> >> + if (check_add_overflow(addr, len, &sum))
> >> goto out;
> >>
> >> /*
> >> @@ -403,7 +404,7 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> >> */
> >> mmap_read_lock(current->mm);
> >> vma = vma_lookup(current->mm, addr);
> >> - if (!vma || addr + len > vma->vm_end)
> >> + if (!vma || sum > vma->vm_end)
> >
> > ... Oh, it is actually used. What about renaming it to "end" instead?
>
> IMHO this is more descriptive:
> + if (check_add_overflow(addr, len, &sum))
>
> than this:
> + if (check_add_overflow(addr, len, &end))
>
> "sum" is IMHO quite obviously sum of the preceding args, whereas I do
> not know what "end" would be.
"end" is the end of the block of size "len" pointed to by "addr".
IMHO "if (sum > vma->vm_end)" is less descriptive...
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68korg
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
On Mon, Jan 22, 2024 at 04:27:12PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Benjamin LaHaise <[email protected]>
> Cc: Alexander Viro <[email protected]>
> Cc: Christian Brauner <[email protected]>
> Cc: Jan Kara <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
What's the plan?
Merge the generic infrastructure and we can pick the individual patches?
On Mon 22-01-24 16:27:51, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Jan Kara <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <[email protected]>
Honza
> ---
> fs/udf/balloc.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
> index ab3ffc355949..5c88300c3de7 100644
> --- a/fs/udf/balloc.c
> +++ b/fs/udf/balloc.c
> @@ -139,7 +139,7 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
>
> mutex_lock(&sbi->s_alloc_mutex);
> partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
> - if (bloc->logicalBlockNum + count < count ||
> + if (add_would_overflow(count, bloc->logicalBlockNum) ||
> (bloc->logicalBlockNum + count) > partmap->s_partition_len) {
> udf_debug("%u < %d || %u + %u > %u\n",
> bloc->logicalBlockNum, 0,
> @@ -390,7 +390,7 @@ static void udf_table_free_blocks(struct super_block *sb,
>
> mutex_lock(&sbi->s_alloc_mutex);
> partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
> - if (bloc->logicalBlockNum + count < count ||
> + if (add_would_overflow(count, bloc->logicalBlockNum) ||
> (bloc->logicalBlockNum + count) > partmap->s_partition_len) {
> udf_debug("%u < %d || %u + %u > %u\n",
> bloc->logicalBlockNum, 0,
> --
> 2.34.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR
On Mon 22-01-24 16:26:44, Kees Cook wrote:
> The mix of int, unsigned int, and unsigned long used by struct
> poll_list::len, todo, len, and j meant that the signed overflow
> sanitizer got worried it needed to instrument several places where
> arithmetic happens between these variables. Since all of the variables
> are always positive and bounded by unsigned int, use a single type in
> all places. Additionally expand the zero-test into an explicit range
> check before updating "todo".
>
> This keeps sanitizer instrumentation[1] out of a UACCESS path:
>
> vmlinux.o: warning: objtool: do_sys_poll+0x285: call to __ubsan_handle_sub_overflow() with UACCESS enabled
>
> Cc: Alexander Viro <[email protected]>
> Cc: Christian Brauner <[email protected]>
> Cc: Jan Kara <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <[email protected]>
Honza
> ---
> fs/select.c | 13 +++++++------
> 1 file changed, 7 insertions(+), 6 deletions(-)
>
> diff --git a/fs/select.c b/fs/select.c
> index 0ee55af1a55c..11a3b1312abe 100644
> --- a/fs/select.c
> +++ b/fs/select.c
> @@ -839,7 +839,7 @@ SYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg)
>
> struct poll_list {
> struct poll_list *next;
> - int len;
> + unsigned int len;
> struct pollfd entries[];
> };
>
> @@ -975,14 +975,15 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
> struct timespec64 *end_time)
> {
> struct poll_wqueues table;
> - int err = -EFAULT, fdcount, len;
> + int err = -EFAULT, fdcount;
> /* Allocate small arguments on the stack to save memory and be
> faster - use long to make sure the buffer is aligned properly
> on 64 bit archs to avoid unaligned access */
> long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
> struct poll_list *const head = (struct poll_list *)stack_pps;
> struct poll_list *walk = head;
> - unsigned long todo = nfds;
> + unsigned int todo = nfds;
> + unsigned int len;
>
> if (nfds > rlimit(RLIMIT_NOFILE))
> return -EINVAL;
> @@ -998,9 +999,9 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
> sizeof(struct pollfd) * walk->len))
> goto out_fds;
>
> - todo -= walk->len;
> - if (!todo)
> + if (walk->len >= todo)
> break;
> + todo -= walk->len;
>
> len = min(todo, POLLFD_PER_PAGE);
> walk = walk->next = kmalloc(struct_size(walk, entries, len),
> @@ -1020,7 +1021,7 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
>
> for (walk = head; walk; walk = walk->next) {
> struct pollfd *fds = walk->entries;
> - int j;
> + unsigned int j;
>
> for (j = walk->len; j; fds++, ufds++, j--)
> unsafe_put_user(fds->revents, &ufds->revents, Efault);
> --
> 2.34.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR
On Mon, Jan 22, 2024 at 04:27:19PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Chris Mason <[email protected]>
> Cc: Josef Bacik <[email protected]>
> Cc: David Sterba <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Acked-by: David Sterba <[email protected]>
On Mon 22-01-24 16:26:54, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Alexander Viro <[email protected]>
> Cc: Christian Brauner <[email protected]>
> Cc: Jan Kara <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <[email protected]>
Honza
> ---
> fs/read_write.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/fs/read_write.c b/fs/read_write.c
> index d4c036e82b6c..e24b94a8937d 100644
> --- a/fs/read_write.c
> +++ b/fs/read_write.c
> @@ -1417,6 +1417,7 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
> struct inode *inode_out = file_inode(file_out);
> uint64_t count = *req_count;
> loff_t size_in;
> + loff_t sum_in, sum_out;
> int ret;
>
> ret = generic_file_rw_checks(file_in, file_out);
> @@ -1451,7 +1452,8 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
> return -ETXTBSY;
>
> /* Ensure offsets don't wrap. */
> - if (pos_in + count < pos_in || pos_out + count < pos_out)
> + if (check_add_overflow(pos_in, count, &sum_in) ||
> + check_add_overflow(pos_out, count, &sum_out))
> return -EOVERFLOW;
>
> /* Shorten the copy to EOF */
> @@ -1467,8 +1469,8 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
>
> /* Don't allow overlapped copying within the same file. */
> if (inode_in == inode_out &&
> - pos_out + count > pos_in &&
> - pos_out < pos_in + count)
> + sum_out > pos_in &&
> + pos_out < sum_in)
> return -EINVAL;
>
> *req_count = count;
> --
> 2.34.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR
Kees Cook <[email protected]> wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
Acked-by: Florian Westphal <[email protected]>
On Mon 22-01-24 16:27:12, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Benjamin LaHaise <[email protected]>
> Cc: Alexander Viro <[email protected]>
> Cc: Christian Brauner <[email protected]>
> Cc: Jan Kara <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <[email protected]>
Honza
> ---
> fs/aio.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/aio.c b/fs/aio.c
> index bb2ff48991f3..edd19be3f4b1 100644
> --- a/fs/aio.c
> +++ b/fs/aio.c
> @@ -796,7 +796,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
> /* limit the number of system wide aios */
> spin_lock(&aio_nr_lock);
> if (aio_nr + ctx->max_reqs > aio_max_nr ||
> - aio_nr + ctx->max_reqs < aio_nr) {
> + add_would_overflow(aio_nr, ctx->max_reqs)) {
> spin_unlock(&aio_nr_lock);
> err = -EAGAIN;
> goto err_ctx;
> --
> 2.34.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR
On Mon, 22 Jan 2024 at 17:38, Kees Cook <[email protected]> wrote:
>
> I've tried to find the right balance between not enough details and too
> much. I guess I got it wrong.
My complaint isn't about the level of detail.
My complaint is about how the commit log IS ACTIVELY MISLEADING
GARBAGE and does not match the actual patch in any way, shape, or
form.
It talks about completely irrelevant issues that simply have nothing
to do with it.
It talks about undefined behavior and about a "unsigned wrap-around
sanitizer[2]", which is nonsensical, since there is no undefined
behavior to sanitize. It literally gives a link to a github "issue"
for that claim, but when you follow the link, it's actually about
*signed* overflow, which is something entirely different.
And honestly, the patch itself is garbage. The code is fine. Any
"sanitizer" that complains about that code is pure and utter shite.
Really.
If you actually have some real "detect unsigned wraparound" tool
(NOTE: that is *NOT* undefined behavior, and that is *NOT* a
"sanitizer", it's at most some helpful checker), then such a tool had
better recognize the perfectly fine traditional idiom for this, which
is to do the addition and check that the result is smaller. Like the
code does.
See what I'm saying? The patch is garbage. Any sanitizer that would
complain about the old code is garbage. And the commit message is
worse than garbage, it is actively misleading to the point that I'd
call it lying, trying to confuse the issues by bringing up things that
are utterly and entirely irrelevant to the patch.
So:
- get rid of that commit message that is lying garbage
- fix the so-called "sanitizer".
- stop calling the unsigned wrap-around a "sanitizer" and talking
about "undefined behavior" in the same sentence, since it's neither.
Do you really not see why I think that thing is actively *WRONG*?
Linus
On Mon 22-01-24 16:27:28, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Alexander Viro <[email protected]>
> Cc: Christian Brauner <[email protected]>
> Cc: Jan Kara <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Looks good atlhough I'd prefer wrapping the line to not overflow 80 chars.
Anyway feel free to add:
Reviewed-by: Jan Kara <[email protected]>
Honza
> ---
> fs/remap_range.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/remap_range.c b/fs/remap_range.c
> index f8c1120b8311..15e91bf2c5e3 100644
> --- a/fs/remap_range.c
> +++ b/fs/remap_range.c
> @@ -45,7 +45,7 @@ static int generic_remap_checks(struct file *file_in, loff_t pos_in,
> return -EINVAL;
>
> /* Ensure offsets don't wrap. */
> - if (pos_in + count < pos_in || pos_out + count < pos_out)
> + if (add_would_overflow(pos_in, count) || add_would_overflow(pos_out, count))
> return -EINVAL;
>
> size_in = i_size_read(inode_in);
> --
> 2.34.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR
On Tue, Jan 23, 2024 at 10:06:12AM -0800, Linus Torvalds wrote:
> So:
>
> - get rid of that commit message that is lying garbage
>
> - fix the so-called "sanitizer".
>
> - stop calling the unsigned wrap-around a "sanitizer" and talking
> about "undefined behavior" in the same sentence, since it's neither.
>
> Do you really not see why I think that thing is actively *WRONG*?
Yes -- I was trying to head off the confusion about what the larger goal
is (trapping unexpected wrap-around) so that people don't assume I'm
talking about Undefined Behavior (we don't have any UB arithmetic in the
kernel, very intentionally). I did not succeed! I'll rewrite it all.
--
Kees Cook
On Tue, Jan 23, 2024 at 08:21:41AM +0200, Adrian Hunter wrote:
> perf tools has separate includes to the kernel, so does not
> seem to include add_would_overflow() in any of its include
> files at this point. Need to update
> tools/include/linux/overflow.h first.
Oops, thank you! I will adjust this.
--
Kees Cook
On Tue, Jan 23, 2024 at 08:55:44AM +0100, Jan Beulich wrote:
> On 23.01.2024 01:27, Kees Cook wrote:
> > --- a/drivers/net/xen-netback/hash.c
> > +++ b/drivers/net/xen-netback/hash.c
> > @@ -345,7 +345,7 @@ u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len,
> > .flags = GNTCOPY_source_gref
> > }};
> >
> > - if ((off + len < off) || (off + len > vif->hash.size) ||
> > + if ((add_would_overflow(off, len)) || (off + len > vif->hash.size) ||
>
> I'm not maintainer of this code, but if I was I would ask that the
> excess parentheses be removed, to improve readability.
Good call. I will adjust that. Thanks!
-Kees
--
Kees Cook
On Tue, Jan 23, 2024 at 09:03:10AM +0100, Rasmus Villemoes wrote:
> On 23/01/2024 01.26, Kees Cook wrote:
> > For instances where only the overflow needs to be checked (and the sum
> > isn't used), provide the new helper add_would_overflow(), which is
> > a wrapper for check_add_overflow().
> >
> > Cc: "Gustavo A. R. Silva" <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > include/linux/overflow.h | 16 ++++++++++++++++
> > 1 file changed, 16 insertions(+)
> >
> > diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> > index 099f2e559aa8..ac088f73e0fd 100644
> > --- a/include/linux/overflow.h
> > +++ b/include/linux/overflow.h
> > @@ -108,6 +108,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
> > __builtin_add_overflow(__filter_integral(a), b, \
> > __filter_ptrint(d))))
> >
> > +/**
> > + * add_would_overflow() - Check if an addition would overflow
> > + * @a: first addend
> > + * @b: second addend
> > + *
> > + * Returns true if the sum would overflow.
> > + *
> > + * To keep a copy of the sum when the addition doesn't overflow, use
> > + * check_add_overflow() instead.
> > + */
> > +#define add_would_overflow(a, b) \
> > + __must_check_overflow(({ \
> > + size_t __result; \
> > + check_add_overflow(a, b, &__result);\
> > + }))
>
> Hm, I think this is a bit too ill-defined. Why is the target type
> hard-coded as size_t? What if a and b are u64, and we're on a 32 bit
> target? Then a+b might not overflow but this helper would claim it did.
Oooh, yes. That's no good. Thanks.
> But we also cannot just use typeof(a+b) instead of size_t, since that
> breaks when a and b are narrower than int (adding two u16 never
> overflows since they get promoted to int, but then if assigning the
> result to a u16 one truncates...).
The add_would_overflow() is aimed at replacing the "v + o < v" pattern,
so perhaps use typeof(a) ?
> Perhaps the target type must be explicit? sum_fits_in_type(T, a, b) ?
> IDK, I just don't think size_t is the right thing to use in something
> that is otherwise supposed to be type-generic.
I will use typeof(a) and check binary differences to see if there are
any places doing something unexpected...
-Kees
--
Kees Cook
On Tue, Jan 23, 2024 at 09:14:20AM +0100, Rasmus Villemoes wrote:
> On 23/01/2024 01.26, Kees Cook wrote:
> > Provide a helper that will perform wrapping addition without tripping
> > the arithmetic wrap-around sanitizers.
> >
> > Cc: "Gustavo A. R. Silva" <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > include/linux/overflow.h | 16 ++++++++++++++++
> > 1 file changed, 16 insertions(+)
> >
> > diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> > index ac088f73e0fd..30779905a77a 100644
> > --- a/include/linux/overflow.h
> > +++ b/include/linux/overflow.h
> > @@ -124,6 +124,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
> > check_add_overflow(a, b, &__result);\
> > }))
> >
> > +/**
> > + * add_wrap() - Intentionally perform a wrapping addition
> > + * @a: first addend
> > + * @b: second addend
> > + *
> > + * Return the potentially wrapped-around addition without
> > + * tripping any overflow sanitizers that may be enabled.
> > + */
> > +#define add_wrap(a, b) \
> > + ({ \
> > + typeof(a) __sum; \
> > + if (check_add_overflow(a, b, &__sum)) \
> > + /* do nothing */; \
> > + __sum; \
> > + })
> > +
>
> I don't know where this is supposed to be used, but at first glance this
> seems to introduce a footgun. This is not symmetric in a and b, so both
> the type and value of the result may differ between add_wrap(a, b) and
> add_wrap(b, a). That seems dangerous.
I see three options here (and for add_would_overflow()):
1- document that it is typed to the first argument (but this seems weak)
2- require a and b have the same type, and use typeof(a) (but is possibly
inflexible, like the problems we've had with min()/max())
3- explicitly require a result type (this seems overly verbose, and might
have problems like we've had with min_t()/max_t())
In the one place this series uses add_wrap(), I have these arguments:
int segs
u32 delta
and the result type is expected to be int:
return atomic_add_return(add_wrap(segs, delta), p_id) - segs;
So as written (option 1) it's (accidentally?) correct.
It would be rejected with option 2, which seems a strong signal that
it's not a good option.
So, your idea about explicit typing is probably best, since I can't
examine the lvalue type within the macro.
return atomic_add_return(add_wrap(int, segs, delta), p_id) - segs;
I'll give this a try and check for binary differences.
-Kees
--
Kees Cook
On Tue, Jan 23, 2024 at 09:27:26AM +0000, Mark Rutland wrote:
> On Mon, Jan 22, 2024 at 04:26:45PM -0800, Kees Cook wrote:
> > Annotate atomic_add_return() to avoid signed overflow instrumentation.
> > It is expected to wrap around.
> >
> > Cc: Will Deacon <[email protected]>
> > Cc: Peter Zijlstra <[email protected]>
> > Cc: Boqun Feng <[email protected]>
> > Cc: Mark Rutland <[email protected]>
> > Cc: Thomas Gleixner <[email protected]>
> > Cc: Ingo Molnar <[email protected]>
> > Cc: Borislav Petkov <[email protected]>
> > Cc: Dave Hansen <[email protected]>
> > Cc: [email protected]
> > Cc: "H. Peter Anvin" <[email protected]>
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > arch/x86/include/asm/atomic.h | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
> > index 55a55ec04350..4120cdd87da8 100644
> > --- a/arch/x86/include/asm/atomic.h
> > +++ b/arch/x86/include/asm/atomic.h
> > @@ -80,7 +80,7 @@ static __always_inline bool arch_atomic_add_negative(int i, atomic_t *v)
> > }
> > #define arch_atomic_add_negative arch_atomic_add_negative
> >
> > -static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
> > +static __always_inline __signed_wrap int arch_atomic_add_return(int i, atomic_t *v)
> > {
> > return i + xadd(&v->counter, i);
> > }
>
> I think that here (and in the arm64 patch) it'd be better to use add_wrap() on
> the specific statement, i.e. have:
>
> static __always_inline int arch_atomic_add_return(int i, atomic_t *v)
> {
> return add_wrap(i, xadd(&v->counter, i));
> }
>
> ... since otherwise the annotation could applly to the '+' or something else
> (e.g. if the 'xadd() part is a special macro), and the annotation might
> unexpectedly hide things if we add other statements here in future.
Okay, sure, I can do that. I may have some header inclusion problems,
but I'll give it a shot.
--
Kees Cook
On Tue, Jan 23, 2024 at 09:46:35AM +0000, Mark Rutland wrote:
> With that in mind, I note that this patch primarily modifies addition
> operations, but leaves subtraction operations unchanged (even though those
> permit the value to go below the minimum, or above the maximum if a negative
> value is used as the subtrahend).
Right, this was kind of a "first pass" on what I'd found so far.
> Shouldn't we address both at the same time? I'll note that in many places the
> same logic is used for both the add and sub, and can legitimately overflow or
> underflow; I hope that whatever we use to suppress overflow warnings also
> ignores underflow.
>
> [...]
>
> Looking at the diffstat, I think you've missed a few places:
>
> [...]
>
> This misses the include/asm-generic/{atomic,atomic64}.h implementations.
>
> This also misses the include/linux/atomic/atomic-arch-fallback.h
> implementations. Those are generated from the scripts/atomic/fallbacks/*
> templates, and you'll need to adjust at least fetch_add_unless and
> inc_unless_negative. As noted on other patches, my preference is to use
> add_wrap() in those.
> [...]
> This misses lib/atomic64.c.
Thanks! I'll take a closer look at places we can use the helpers on the
atomics.
-Kees
--
Kees Cook
On Tue, Jan 23, 2024 at 09:22:52AM +0000, Mark Rutland wrote:
> On Mon, Jan 22, 2024 at 04:26:38PM -0800, Kees Cook wrote:
> > Provide a helper that will perform wrapping addition without tripping
> > the arithmetic wrap-around sanitizers.
> >
> > Cc: "Gustavo A. R. Silva" <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > include/linux/overflow.h | 16 ++++++++++++++++
> > 1 file changed, 16 insertions(+)
> >
> > diff --git a/include/linux/overflow.h b/include/linux/overflow.h
> > index ac088f73e0fd..30779905a77a 100644
> > --- a/include/linux/overflow.h
> > +++ b/include/linux/overflow.h
> > @@ -124,6 +124,22 @@ static inline bool __must_check __must_check_overflow(bool overflow)
> > check_add_overflow(a, b, &__result);\
> > }))
> >
> > +/**
> > + * add_wrap() - Intentionally perform a wrapping addition
> > + * @a: first addend
> > + * @b: second addend
> > + *
> > + * Return the potentially wrapped-around addition without
> > + * tripping any overflow sanitizers that may be enabled.
> > + */
> > +#define add_wrap(a, b) \
> > + ({ \
> > + typeof(a) __sum; \
> > + if (check_add_overflow(a, b, &__sum)) \
> > + /* do nothing */; \
> > + __sum; \
> > + })
>
> It's really difficult to see the semicolon for the empty statement here; could
> we make that part:
>
> if ((check_add_overflow(a, b, &__sum)) { \
> /* do nothing */ \
> } \
>
> ... to be a little clearer (and less at risk of breakage in a refactoring)?
Yeah, agreed -- that stands out more clearly.
-Kees
--
Kees Cook
On Tue, Jan 23, 2024 at 09:56:22AM +0000, Mark Rutland wrote:
> The commit title is odd here; '3117/1' is the patch tracker name for the last
> patch. The title should probably be:
>
> arm: nwfpe: Refactor intentional wrap-around test
Whoops, yes. I need to teach my prefix-guessing script to drop the ARM
patch tracker numbers...
-Kees
>
> Mark.
>
> On Mon, Jan 22, 2024 at 04:27:13PM -0800, Kees Cook wrote:
> > In an effort to separate intentional arithmetic wrap-around from
> > unexpected wrap-around, we need to refactor places that depend on this
> > kind of math. One of the most common code patterns of this is:
> >
> > VAR + value < VAR
> >
> > Notably, this is considered "undefined behavior" for signed and pointer
> > types, which the kernel works around by using the -fno-strict-overflow
> > option in the build[1] (which used to just be -fwrapv). Regardless, we
> > want to get the kernel source to the position where we can meaningfully
> > instrument arithmetic wrap-around conditions and catch them when they
> > are unexpected, regardless of whether they are signed[2], unsigned[3],
> > or pointer[4] types.
> >
> > Refactor open-coded wrap-around addition test to use add_would_overflow().
> > This paves the way to enabling the wrap-around sanitizers in the future.
> >
> > Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> > Link: https://github.com/KSPP/linux/issues/26 [2]
> > Link: https://github.com/KSPP/linux/issues/27 [3]
> > Link: https://github.com/KSPP/linux/issues/344 [4]
> > Cc: Russell King <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > arch/arm/nwfpe/softfloat.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c
> > index ffa6b438786b..0635b1eda1d3 100644
> > --- a/arch/arm/nwfpe/softfloat.c
> > +++ b/arch/arm/nwfpe/softfloat.c
> > @@ -603,7 +603,7 @@ static floatx80
> > roundBits = zSig0 & roundMask;
> > if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
> > if ( ( 0x7FFE < zExp )
> > - || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
> > + || ( ( zExp == 0x7FFE ) && (add_would_overflow(zSig0, roundIncrement)) )
> > ) {
> > goto overflow;
> > }
> > --
> > 2.34.1
> >
> >
--
Kees Cook
On 1/23/24 01:27, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Marc Zyngier <[email protected]>
> Cc: Oliver Upton <[email protected]>
> Cc: James Morse <[email protected]>
> Cc: Suzuki K Poulose <[email protected]>
> Cc: Zenghui Yu <[email protected]>
> Cc: Catalin Marinas <[email protected]>
> Cc: Will Deacon <[email protected]>
> Cc: Eric Auger <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Reviewed-by: Eric Auger <[email protected]>
Eric
> ---
> arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
> index c15ee1df036a..860b774c0c13 100644
> --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
> +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
> @@ -863,7 +863,7 @@ static int vgic_v3_alloc_redist_region(struct kvm *kvm, uint32_t index,
> int ret;
>
> /* cross the end of memory ? */
> - if (base + size < base)
> + if (add_would_overflow(base, size))
> return -EINVAL;
>
> if (list_empty(rd_regions)) {
On 1/23/24 11:49, Marc Zyngier wrote:
> On Tue, 23 Jan 2024 00:26:59 +0000,
> Kees Cook <[email protected]> wrote:
>> In an effort to separate intentional arithmetic wrap-around from
>> unexpected wrap-around, we need to refactor places that depend on this
>> kind of math. One of the most common code patterns of this is:
>>
>> VAR + value < VAR
>>
>> Notably, this is considered "undefined behavior" for signed and pointer
>> types, which the kernel works around by using the -fno-strict-overflow
>> option in the build[1] (which used to just be -fwrapv). Regardless, we
>> want to get the kernel source to the position where we can meaningfully
>> instrument arithmetic wrap-around conditions and catch them when they
>> are unexpected, regardless of whether they are signed[2], unsigned[3],
>> or pointer[4] types.
>>
>> Refactor open-coded unsigned wrap-around addition test to use
>> check_add_overflow(), retaining the result for later usage (which removes
>> the redundant open-coded addition). This paves the way to enabling the
>> wrap-around sanitizers in the future.
>>
>> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
>> Link: https://github.com/KSPP/linux/issues/26 [2]
>> Link: https://github.com/KSPP/linux/issues/27 [3]
>> Link: https://github.com/KSPP/linux/issues/344 [4]
>> Cc: Marc Zyngier <[email protected]>
>> Cc: Oliver Upton <[email protected]>
>> Cc: James Morse <[email protected]>
>> Cc: Suzuki K Poulose <[email protected]>
>> Cc: Zenghui Yu <[email protected]>
>> Cc: Catalin Marinas <[email protected]>
>> Cc: Will Deacon <[email protected]>
>> Cc: Reiji Watanabe <[email protected]>
>> Cc: Eric Auger <[email protected]>
>> Cc: Ricardo Koller <[email protected]>
>> Cc: Raghavendra Rao Ananta <[email protected]>
>> Cc: Quentin Perret <[email protected]>
>> Cc: Jean-Philippe Brucker <[email protected]>
>> Cc: [email protected]
>> Cc: [email protected]
>> Signed-off-by: Kees Cook <[email protected]>
>> ---
>> arch/arm64/kvm/vgic/vgic-kvm-device.c | 6 ++++--
>> arch/arm64/kvm/vgic/vgic-v2.c | 10 ++++++----
>> 2 files changed, 10 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
>> index f48b8dab8b3d..0eec5344d203 100644
>> --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
>> +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
>> @@ -18,17 +18,19 @@ int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,
>> phys_addr_t addr, phys_addr_t alignment,
>> phys_addr_t size)
>> {
>> + phys_addr_t sum;
>> +
>> if (!IS_VGIC_ADDR_UNDEF(ioaddr))
>> return -EEXIST;
>>
>> if (!IS_ALIGNED(addr, alignment) || !IS_ALIGNED(size, alignment))
>> return -EINVAL;
>>
>> - if (addr + size < addr)
>> + if (check_add_overflow(addr, size, &sum))
>> return -EINVAL;
>>
>> if (addr & ~kvm_phys_mask(&kvm->arch.mmu) ||
>> - (addr + size) > kvm_phys_size(&kvm->arch.mmu))
>> + sum > kvm_phys_size(&kvm->arch.mmu))
> nit: 'sum' doesn't mean much in this context. Something like 'end'
> would be much more descriptive.
>
>> return -E2BIG;
>>
>> return 0;
>> diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c
>> index 7e9cdb78f7ce..c8d1e965d3b7 100644
>> --- a/arch/arm64/kvm/vgic/vgic-v2.c
>> +++ b/arch/arm64/kvm/vgic/vgic-v2.c
>> @@ -273,14 +273,16 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)
>> /* check for overlapping regions and for regions crossing the end of memory */
>> static bool vgic_v2_check_base(gpa_t dist_base, gpa_t cpu_base)
>> {
>> - if (dist_base + KVM_VGIC_V2_DIST_SIZE < dist_base)
>> + gpa_t dist_sum, cpu_sum;
> Same here: dist_end, cpu_end.
I do agree.
>
>> +
>> + if (check_add_overflow(dist_base, KVM_VGIC_V2_DIST_SIZE, &dist_sum))
>> return false;
>> - if (cpu_base + KVM_VGIC_V2_CPU_SIZE < cpu_base)
>> + if (check_add_overflow(cpu_base, KVM_VGIC_V2_CPU_SIZE, &cpu_sum))
>> return false;
>>
>> - if (dist_base + KVM_VGIC_V2_DIST_SIZE <= cpu_base)
>> + if (dist_sum <= cpu_base)
>> return true;
>> - if (cpu_base + KVM_VGIC_V2_CPU_SIZE <= dist_base)
>> + if (cpu_sum <= dist_base)
>> return true;
>>
>> return false;
> With these nits addressed, and assuming you intend to merge the whole
> series yourself:
>
> Acked-by: Marc Zyngier <[email protected]>
assuming above suggested changes,
Reviewed-by: Eric Auger <[email protected]>
Eric
>
> M.
>
On Mon, Jan 22, 2024, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> wrap-around sanitizers in the future.
IIUC, the plan is to get UBSAN to detect unexpected overflow, at which point an
explicit annotation will be needed to avoid false positives. If that's correct,
can you put something like that in these changelogs? Nothing in the changelog
actually says _why_ open coded wrap-around checks will be problematic.
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Sean Christopherson <[email protected]>
> Cc: Paolo Bonzini <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Borislav Petkov <[email protected]>
> Cc: Dave Hansen <[email protected]>
> Cc: [email protected]
> Cc: "H. Peter Anvin" <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/x86/kvm/svm/sev.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index f760106c31f8..12a6a2b1ac81 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -400,16 +400,17 @@ static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
> unsigned long locked, lock_limit;
> struct page **pages;
> unsigned long first, last;
> + unsigned long sum;
Similar to Marc's comments, I would much prefer to call this uaddr_last.
> int ret;
>
> lockdep_assert_held(&kvm->lock);
>
> - if (ulen == 0 || uaddr + ulen < uaddr)
> + if (ulen == 0 || check_add_overflow(uaddr, ulen, &sum))
> return ERR_PTR(-EINVAL);
>
> /* Calculate number of pages. */
> first = (uaddr & PAGE_MASK) >> PAGE_SHIFT;
> - last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT;
> + last = ((sum - 1) & PAGE_MASK) >> PAGE_SHIFT;
> npages = (last - first + 1);
>
> locked = sev->pages_locked + npages;
> --
> 2.34.1
>
On Mon, Jan 22, 2024, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notable, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed, unsigned, or
> pointer types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> unsigned wrap-around sanitizer[2] in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/27 [2]
> Cc: Paolo Bonzini <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> virt/kvm/coalesced_mmio.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c
> index 1b90acb6e3fe..0a3b706fbf4c 100644
> --- a/virt/kvm/coalesced_mmio.c
> +++ b/virt/kvm/coalesced_mmio.c
> @@ -25,17 +25,19 @@ static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev)
> static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev,
> gpa_t addr, int len)
> {
> + gpa_t sum;
s/sum/end?
Also, given that your're fixing a gpa_t, which is a u64, presumably that means
that this code in __kvm_set_memory_region() also needs to be fixed:
if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
return -EINVAL;
and for that one I'd really like to avoid an ignored output parameter (KVM
converts the incoming mem->memory_size to pages, so the "sum" is never used
directly).
Would it make sense to add an API that feeds a dummy "sum" value? I assume UBSAN
won't fire on the usage of the known good value, i.e. using the output parameter
isn't necessary for functional correctness. Having an API that does just the
check would trim down the size of many of these patches and avoid having to come
up with names for the local variables. And IMO, the existing code is a wee bit
more intuitive, it'd be nice to give developers the flexibility to choose which
flavor yields the "best" code on a case-by-case basis.
> +
> /* is it in a batchable area ?
> * (addr,len) is fully included in
> * (zone->addr, zone->size)
> */
> if (len < 0)
> return 0;
> - if (addr + len < addr)
> + if (check_add_overflow(addr, len, &sum))
> return 0;
> if (addr < dev->zone.addr)
> return 0;
> - if (addr + len > dev->zone.addr + dev->zone.size)
> + if (sum > dev->zone.addr + dev->zone.size)
> return 0;
> return 1;
> }
> --
> 2.34.1
>
On Mon, Jan 22 2024 at 16:27, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: John Stultz <[email protected]>
> Cc: Thomas Gleixner <[email protected]>
> Cc: Stephen Boyd <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
Reviewed-by: Thomas Gleixner <[email protected]>
On Tue, Jan 23, 2024 at 2:03 AM Kees Cook <[email protected]> wrote:
>
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: "Rafael J. Wysocki" <[email protected]>
> Cc: Len Brown <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> drivers/acpi/custom_method.c | 2 +-
I may attempt to drop custom_method.c in this cycle, is there a
problem if I take this into my tree for now?
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
> index d39a9b474727..0789317f4a1a 100644
> --- a/drivers/acpi/custom_method.c
> +++ b/drivers/acpi/custom_method.c
> @@ -54,7 +54,7 @@ static ssize_t cm_write(struct file *file, const char __user *user_buf,
>
> if ((*ppos > max_size) ||
> (*ppos + count > max_size) ||
> - (*ppos + count < count) ||
> + (add_would_overflow(count, *ppos)) ||
> (count > uncopied_bytes)) {
> kfree(buf);
> buf = NULL;
> --
> 2.34.1
>
On Wed, Jan 24, 2024 at 08:52:48PM +0100, Rafael J. Wysocki wrote:
> On Tue, Jan 23, 2024 at 2:03 AM Kees Cook <[email protected]> wrote:
> >
> > In an effort to separate intentional arithmetic wrap-around from
> > unexpected wrap-around, we need to refactor places that depend on this
> > kind of math. One of the most common code patterns of this is:
> >
> > VAR + value < VAR
> >
> > Notably, this is considered "undefined behavior" for signed and pointer
> > types, which the kernel works around by using the -fno-strict-overflow
> > option in the build[1] (which used to just be -fwrapv). Regardless, we
> > want to get the kernel source to the position where we can meaningfully
> > instrument arithmetic wrap-around conditions and catch them when they
> > are unexpected, regardless of whether they are signed[2], unsigned[3],
> > or pointer[4] types.
> >
> > Refactor open-coded wrap-around addition test to use add_would_overflow().
> > This paves the way to enabling the wrap-around sanitizers in the future.
> >
> > Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> > Link: https://github.com/KSPP/linux/issues/26 [2]
> > Link: https://github.com/KSPP/linux/issues/27 [3]
> > Link: https://github.com/KSPP/linux/issues/344 [4]
> > Cc: "Rafael J. Wysocki" <[email protected]>
> > Cc: Len Brown <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > drivers/acpi/custom_method.c | 2 +-
>
> I may attempt to drop custom_method.c in this cycle, is there a
> problem if I take this into my tree for now?
The helper doesn't exist in tree yet, but it may be a bit before these
refactors land, so if custom_method vanishes before then, that's great!
:)
-Kees
--
Kees Cook
On Tue, Jan 23, 2024 at 1:29 AM Kees Cook <[email protected]> wrote:
>
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Andrey Ryabinin <[email protected]>
> Cc: Alexander Potapenko <[email protected]>
> Cc: Andrey Konovalov <[email protected]>
> Cc: Dmitry Vyukov <[email protected]>
> Cc: Vincenzo Frascino <[email protected]>
> Cc: Andrew Morton <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> mm/kasan/generic.c | 2 +-
> mm/kasan/sw_tags.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
> index df6627f62402..f9bc29ae09bd 100644
> --- a/mm/kasan/generic.c
> +++ b/mm/kasan/generic.c
> @@ -171,7 +171,7 @@ static __always_inline bool check_region_inline(const void *addr,
> if (unlikely(size == 0))
> return true;
>
> - if (unlikely(addr + size < addr))
> + if (unlikely(add_would_overflow(addr, size)))
> return !kasan_report(addr, size, write, ret_ip);
>
> if (unlikely(!addr_has_metadata(addr)))
> diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
> index 220b5d4c6876..79a3bbd66c32 100644
> --- a/mm/kasan/sw_tags.c
> +++ b/mm/kasan/sw_tags.c
> @@ -80,7 +80,7 @@ bool kasan_check_range(const void *addr, size_t size, bool write,
> if (unlikely(size == 0))
> return true;
>
> - if (unlikely(addr + size < addr))
> + if (unlikely(add_would_overflow(addr, size)))
> return !kasan_report(addr, size, write, ret_ip);
>
> tag = get_tag((const void *)addr);
> --
> 2.34.1
>
Acked-by: Andrey Konovalov <[email protected]>
Thanks!
On Tue, Jan 23, 2024 at 2:42 AM Kees Cook <[email protected]> wrote:
>
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> unsigned wrap-around sanitizer[2] in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: "Michael S. Tsirkin" <[email protected]>
> Cc: Jason Wang <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> drivers/vhost/vringh.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
> index 7b8fd977f71c..07442f0a52bd 100644
> --- a/drivers/vhost/vringh.c
> +++ b/drivers/vhost/vringh.c
> @@ -145,6 +145,8 @@ static inline bool range_check(struct vringh *vrh, u64 addr, size_t *len,
> bool (*getrange)(struct vringh *,
> u64, struct vringh_range *))
> {
> + u64 sum;
I understand this is part of a bulk change so little time to think
about names :). But what about "end" or similar?
Either way,
Acked-by: Eugenio Pérez <[email protected]>
> +
> if (addr < range->start || addr > range->end_incl) {
> if (!getrange(vrh, addr, range))
> return false;
> @@ -152,20 +154,20 @@ static inline bool range_check(struct vringh *vrh, u64 addr, size_t *len,
> BUG_ON(addr < range->start || addr > range->end_incl);
>
> /* To end of memory? */
> - if (unlikely(addr + *len == 0)) {
> + if (unlikely(U64_MAX - addr == *len)) {
> if (range->end_incl == -1ULL)
> return true;
> goto truncate;
> }
>
> /* Otherwise, don't wrap. */
> - if (addr + *len < addr) {
> + if (check_add_overflow(addr, *len, &sum)) {
> vringh_bad("Wrapping descriptor %zu@0x%llx",
> *len, (unsigned long long)addr);
> return false;
> }
>
> - if (unlikely(addr + *len - 1 > range->end_incl))
> + if (unlikely(sum - 1 > range->end_incl))
> goto truncate;
> return true;
>
> --
> 2.34.1
>
>
On Tue, Jan 23, 2024 at 2:28 AM Kees Cook <[email protected]> wrote:
>
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: "Michael S. Tsirkin" <[email protected]>
> Cc: Jason Wang <[email protected]>
> Cc: Xuan Zhuo <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Reviewed-by: Eugenio Pérez <[email protected]>
> ---
> drivers/virtio/virtio_pci_modern_dev.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/virtio/virtio_pci_modern_dev.c b/drivers/virtio/virtio_pci_modern_dev.c
> index 0d3dbfaf4b23..710d3bd45b4f 100644
> --- a/drivers/virtio/virtio_pci_modern_dev.c
> +++ b/drivers/virtio/virtio_pci_modern_dev.c
> @@ -59,7 +59,7 @@ vp_modern_map_capability(struct virtio_pci_modern_device *mdev, int off,
>
> length -= start;
>
> - if (start + offset < offset) {
> + if (add_would_overflow(offset, start)) {
> dev_err(&dev->dev,
> "virtio_pci: map wrap-around %u+%u\n",
> start, offset);
> @@ -81,7 +81,7 @@ vp_modern_map_capability(struct virtio_pci_modern_device *mdev, int off,
> if (len)
> *len = length;
>
> - if (minlen + offset < minlen ||
> + if (add_would_overflow(minlen, offset) ||
> minlen + offset > pci_resource_len(dev, bar)) {
> dev_err(&dev->dev,
> "virtio_pci: map virtio %zu@%u "
> --
> 2.34.1
>
>
On Fri, Jan 26, 2024 at 08:31:04PM +0100, Eugenio Perez Martin wrote:
> On Tue, Jan 23, 2024 at 2:42 AM Kees Cook <[email protected]> wrote:
> >
> > In an effort to separate intentional arithmetic wrap-around from
> > unexpected wrap-around, we need to refactor places that depend on this
> > kind of math. One of the most common code patterns of this is:
> >
> > VAR + value < VAR
> >
> > Notably, this is considered "undefined behavior" for signed and pointer
> > types, which the kernel works around by using the -fno-strict-overflow
> > option in the build[1] (which used to just be -fwrapv). Regardless, we
> > want to get the kernel source to the position where we can meaningfully
> > instrument arithmetic wrap-around conditions and catch them when they
> > are unexpected, regardless of whether they are signed[2], unsigned[3],
> > or pointer[4] types.
> >
> > Refactor open-coded unsigned wrap-around addition test to use
> > check_add_overflow(), retaining the result for later usage (which removes
> > the redundant open-coded addition). This paves the way to enabling the
> > unsigned wrap-around sanitizer[2] in the future.
> >
> > Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> > Link: https://github.com/KSPP/linux/issues/26 [2]
> > Link: https://github.com/KSPP/linux/issues/27 [3]
> > Link: https://github.com/KSPP/linux/issues/344 [4]
> > Cc: "Michael S. Tsirkin" <[email protected]>
> > Cc: Jason Wang <[email protected]>
> > Cc: [email protected]
> > Cc: [email protected]
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > drivers/vhost/vringh.c | 8 +++++---
> > 1 file changed, 5 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
> > index 7b8fd977f71c..07442f0a52bd 100644
> > --- a/drivers/vhost/vringh.c
> > +++ b/drivers/vhost/vringh.c
> > @@ -145,6 +145,8 @@ static inline bool range_check(struct vringh *vrh, u64 addr, size_t *len,
> > bool (*getrange)(struct vringh *,
> > u64, struct vringh_range *))
> > {
> > + u64 sum;
>
> I understand this is part of a bulk change so little time to think
> about names :). But what about "end" or similar?
>
> Either way,
> Acked-by: Eugenio Pérez <[email protected]>
Thanks! Yeah, you are not alone in suggesting "end" in a several of
these patches. :)
-Kees
--
Kees Cook
On Tue, Jan 23, 2024 at 09:46:35AM +0000, Mark Rutland wrote:
> This also misses the include/linux/atomic/atomic-arch-fallback.h
> implementations. Those are generated from the scripts/atomic/fallbacks/*
> templates, and you'll need to adjust at least fetch_add_unless and
> inc_unless_negative. As noted on other patches, my preference is to use
> add_wrap() in those.
How do I regenerate the header files using the templates? I found a
script, but its use eluded me, and it doesn't seem wired up to the
top-level Makefile? Maybe I missed something obvious...
--
Kees Cook
On Mon, Jan 22, 2024 at 04:27:08PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded unsigned wrap-around addition test to use
> check_add_overflow(), retaining the result for later usage (which removes
> the redundant open-coded addition). This paves the way to enabling the
> unsigned wrap-around sanitizer[2] in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Andrew Morton <[email protected]>
> Cc: Uladzislau Rezki <[email protected]>
> Cc: Christoph Hellwig <[email protected]>
> Cc: Lorenzo Stoakes <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> mm/vmalloc.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index d12a17fc0c17..7932ac99e9d3 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -1223,6 +1223,7 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> unsigned long align, unsigned long vstart)
> {
> unsigned long nva_start_addr;
> + unsigned long sum;
>
> if (va->va_start > vstart)
> nva_start_addr = ALIGN(va->va_start, align);
> @@ -1230,11 +1231,11 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> nva_start_addr = ALIGN(vstart, align);
>
> /* Can be overflowed due to big size or alignment. */
> - if (nva_start_addr + size < nva_start_addr ||
> + if (check_add_overflow(nva_start_addr, size, &sum) ||
> nva_start_addr < vstart)
> return false;
>
> - return (nva_start_addr + size <= va->va_end);
> + return (sum <= va->va_end);
> }
>
> /*
> --
> 2.34.1
>
Looks good to me,
Reviewed-by: Lorenzo Stoakes <[email protected]>
On Mon, Jan 22, 2024 at 04:27:53PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Andrew Morton <[email protected]>
> Cc: Uladzislau Rezki <[email protected]>
> Cc: Christoph Hellwig <[email protected]>
> Cc: Lorenzo Stoakes <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> mm/vmalloc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index 7932ac99e9d3..3d73f2ac6957 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -3750,7 +3750,7 @@ long vread_iter(struct iov_iter *iter, const char *addr, size_t count)
> addr = kasan_reset_tag(addr);
>
> /* Don't allow overflow */
> - if ((unsigned long) addr + count < count)
> + if (add_would_overflow(count, (unsigned long)addr))
> count = -(unsigned long) addr;
>
> remains = count;
> --
> 2.34.1
>
Looks good to me,
Reviewed-by: Lorenzo Stoakes <[email protected]>
On Mon, Jan 22 2024 at 7:27P -0500,
Kees Cook <[email protected]> wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Alasdair Kergon <[email protected]>
> Cc: Mike Snitzer <[email protected]>
> Cc: Mikulas Patocka <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
Please change subject to:
"dm: Refactor intentional wrap-around test in a few targets"
Reviewed-by: Mike Snitzer <[email protected]>
On Tue, Jan 30, 2024 at 06:55:57PM +0000, Lorenzo Stoakes wrote:
> On Mon, Jan 22, 2024 at 04:27:08PM -0800, Kees Cook wrote:
> > In an effort to separate intentional arithmetic wrap-around from
> > unexpected wrap-around, we need to refactor places that depend on this
> > kind of math. One of the most common code patterns of this is:
> >
> > VAR + value < VAR
> >
> > Notably, this is considered "undefined behavior" for signed and pointer
> > types, which the kernel works around by using the -fno-strict-overflow
> > option in the build[1] (which used to just be -fwrapv). Regardless, we
> > want to get the kernel source to the position where we can meaningfully
> > instrument arithmetic wrap-around conditions and catch them when they
> > are unexpected, regardless of whether they are signed[2], unsigned[3],
> > or pointer[4] types.
> >
> > Refactor open-coded unsigned wrap-around addition test to use
> > check_add_overflow(), retaining the result for later usage (which removes
> > the redundant open-coded addition). This paves the way to enabling the
> > unsigned wrap-around sanitizer[2] in the future.
> >
> > Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> > Link: https://github.com/KSPP/linux/issues/26 [2]
> > Link: https://github.com/KSPP/linux/issues/27 [3]
> > Link: https://github.com/KSPP/linux/issues/344 [4]
> > Cc: Andrew Morton <[email protected]>
> > Cc: Uladzislau Rezki <[email protected]>
> > Cc: Christoph Hellwig <[email protected]>
> > Cc: Lorenzo Stoakes <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Kees Cook <[email protected]>
> > ---
> > mm/vmalloc.c | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> > index d12a17fc0c17..7932ac99e9d3 100644
> > --- a/mm/vmalloc.c
> > +++ b/mm/vmalloc.c
> > @@ -1223,6 +1223,7 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> > unsigned long align, unsigned long vstart)
> > {
> > unsigned long nva_start_addr;
> > + unsigned long sum;
> >
> > if (va->va_start > vstart)
> > nva_start_addr = ALIGN(va->va_start, align);
> > @@ -1230,11 +1231,11 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> > nva_start_addr = ALIGN(vstart, align);
> >
> > /* Can be overflowed due to big size or alignment. */
> > - if (nva_start_addr + size < nva_start_addr ||
> > + if (check_add_overflow(nva_start_addr, size, &sum) ||
> > nva_start_addr < vstart)
> > return false;
> >
> > - return (nva_start_addr + size <= va->va_end);
> > + return (sum <= va->va_end);
> > }
> >
> > /*
> > --
> > 2.34.1
> >
>
> Looks good to me,
>
> Reviewed-by: Lorenzo Stoakes <[email protected]>
>
Same here. One small nit though. The "sum" variable is not something
that it suits for. IMO, we should use a better name and replace it:
"nva_offset"?
--
Uladzislau Rezki
On Tue, Jan 30, 2024 at 08:54:00PM +0100, Uladzislau Rezki wrote:
> On Tue, Jan 30, 2024 at 06:55:57PM +0000, Lorenzo Stoakes wrote:
> > On Mon, Jan 22, 2024 at 04:27:08PM -0800, Kees Cook wrote:
> > > In an effort to separate intentional arithmetic wrap-around from
> > > unexpected wrap-around, we need to refactor places that depend on this
> > > kind of math. One of the most common code patterns of this is:
> > >
> > > VAR + value < VAR
> > >
> > > Notably, this is considered "undefined behavior" for signed and pointer
> > > types, which the kernel works around by using the -fno-strict-overflow
> > > option in the build[1] (which used to just be -fwrapv). Regardless, we
> > > want to get the kernel source to the position where we can meaningfully
> > > instrument arithmetic wrap-around conditions and catch them when they
> > > are unexpected, regardless of whether they are signed[2], unsigned[3],
> > > or pointer[4] types.
> > >
> > > Refactor open-coded unsigned wrap-around addition test to use
> > > check_add_overflow(), retaining the result for later usage (which removes
> > > the redundant open-coded addition). This paves the way to enabling the
> > > unsigned wrap-around sanitizer[2] in the future.
> > >
> > > Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> > > Link: https://github.com/KSPP/linux/issues/26 [2]
> > > Link: https://github.com/KSPP/linux/issues/27 [3]
> > > Link: https://github.com/KSPP/linux/issues/344 [4]
> > > Cc: Andrew Morton <[email protected]>
> > > Cc: Uladzislau Rezki <[email protected]>
> > > Cc: Christoph Hellwig <[email protected]>
> > > Cc: Lorenzo Stoakes <[email protected]>
> > > Cc: [email protected]
> > > Signed-off-by: Kees Cook <[email protected]>
> > > ---
> > > mm/vmalloc.c | 5 +++--
> > > 1 file changed, 3 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> > > index d12a17fc0c17..7932ac99e9d3 100644
> > > --- a/mm/vmalloc.c
> > > +++ b/mm/vmalloc.c
> > > @@ -1223,6 +1223,7 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> > > unsigned long align, unsigned long vstart)
> > > {
> > > unsigned long nva_start_addr;
> > > + unsigned long sum;
> > >
> > > if (va->va_start > vstart)
> > > nva_start_addr = ALIGN(va->va_start, align);
> > > @@ -1230,11 +1231,11 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> > > nva_start_addr = ALIGN(vstart, align);
> > >
> > > /* Can be overflowed due to big size or alignment. */
> > > - if (nva_start_addr + size < nva_start_addr ||
> > > + if (check_add_overflow(nva_start_addr, size, &sum) ||
> > > nva_start_addr < vstart)
> > > return false;
> > >
> > > - return (nva_start_addr + size <= va->va_end);
> > > + return (sum <= va->va_end);
> > > }
> > >
> > > /*
> > > --
> > > 2.34.1
> > >
> >
> > Looks good to me,
> >
> > Reviewed-by: Lorenzo Stoakes <[email protected]>
> >
> Same here. One small nit though. The "sum" variable is not something
> that it suits for. IMO, we should use a better name and replace it:
>
> "nva_offset"?
Sure, I can use that. Other folks in other patches have suggested "end",
so maybe nva_end or nva_end_addr ?
-Kees
--
Kees Cook
On Tue, Jan 30, 2024 at 01:57:12PM -0800, Kees Cook wrote:
> On Tue, Jan 30, 2024 at 08:54:00PM +0100, Uladzislau Rezki wrote:
> > On Tue, Jan 30, 2024 at 06:55:57PM +0000, Lorenzo Stoakes wrote:
> > > On Mon, Jan 22, 2024 at 04:27:08PM -0800, Kees Cook wrote:
> > > > In an effort to separate intentional arithmetic wrap-around from
> > > > unexpected wrap-around, we need to refactor places that depend on this
> > > > kind of math. One of the most common code patterns of this is:
> > > >
> > > > VAR + value < VAR
> > > >
> > > > Notably, this is considered "undefined behavior" for signed and pointer
> > > > types, which the kernel works around by using the -fno-strict-overflow
> > > > option in the build[1] (which used to just be -fwrapv). Regardless, we
> > > > want to get the kernel source to the position where we can meaningfully
> > > > instrument arithmetic wrap-around conditions and catch them when they
> > > > are unexpected, regardless of whether they are signed[2], unsigned[3],
> > > > or pointer[4] types.
> > > >
> > > > Refactor open-coded unsigned wrap-around addition test to use
> > > > check_add_overflow(), retaining the result for later usage (which removes
> > > > the redundant open-coded addition). This paves the way to enabling the
> > > > unsigned wrap-around sanitizer[2] in the future.
> > > >
> > > > Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> > > > Link: https://github.com/KSPP/linux/issues/26 [2]
> > > > Link: https://github.com/KSPP/linux/issues/27 [3]
> > > > Link: https://github.com/KSPP/linux/issues/344 [4]
> > > > Cc: Andrew Morton <[email protected]>
> > > > Cc: Uladzislau Rezki <[email protected]>
> > > > Cc: Christoph Hellwig <[email protected]>
> > > > Cc: Lorenzo Stoakes <[email protected]>
> > > > Cc: [email protected]
> > > > Signed-off-by: Kees Cook <[email protected]>
> > > > ---
> > > > mm/vmalloc.c | 5 +++--
> > > > 1 file changed, 3 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> > > > index d12a17fc0c17..7932ac99e9d3 100644
> > > > --- a/mm/vmalloc.c
> > > > +++ b/mm/vmalloc.c
> > > > @@ -1223,6 +1223,7 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> > > > unsigned long align, unsigned long vstart)
> > > > {
> > > > unsigned long nva_start_addr;
> > > > + unsigned long sum;
> > > >
> > > > if (va->va_start > vstart)
> > > > nva_start_addr = ALIGN(va->va_start, align);
> > > > @@ -1230,11 +1231,11 @@ is_within_this_va(struct vmap_area *va, unsigned long size,
> > > > nva_start_addr = ALIGN(vstart, align);
> > > >
> > > > /* Can be overflowed due to big size or alignment. */
> > > > - if (nva_start_addr + size < nva_start_addr ||
> > > > + if (check_add_overflow(nva_start_addr, size, &sum) ||
> > > > nva_start_addr < vstart)
> > > > return false;
> > > >
> > > > - return (nva_start_addr + size <= va->va_end);
> > > > + return (sum <= va->va_end);
> > > > }
> > > >
> > > > /*
> > > > --
> > > > 2.34.1
> > > >
> > >
> > > Looks good to me,
> > >
> > > Reviewed-by: Lorenzo Stoakes <[email protected]>
> > >
> > Same here. One small nit though. The "sum" variable is not something
> > that it suits for. IMO, we should use a better name and replace it:
> >
> > "nva_offset"?
>
> Sure, I can use that. Other folks in other patches have suggested "end",
> so maybe nva_end or nva_end_addr ?
>
nva_end_addr is probably the best fit.
--
Uladzislau Rezki
On Mon, Jan 22, 2024 at 04:27:05PM -0800, Kees Cook wrote:
Hi Kees,
..
> arch/s390/include/asm/stacktrace.h | 6 ++++--
> arch/s390/kernel/machine_kexec_file.c | 5 +++--
Subject does not match. These need to be two separate commits.
> 2 files changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h
> index 31ec4f545e03..3ce08d32a8ad 100644
> --- a/arch/s390/include/asm/stacktrace.h
> +++ b/arch/s390/include/asm/stacktrace.h
> @@ -34,11 +34,13 @@ int get_stack_info(unsigned long sp, struct task_struct *task,
> static inline bool on_stack(struct stack_info *info,
> unsigned long addr, size_t len)
> {
> + unsigned long sum;
> +
> if (info->type == STACK_TYPE_UNKNOWN)
> return false;
> - if (addr + len < addr)
> + if (check_add_overflow(addr, len, &sum))
Why not add_would_overflow()?
> return false;
> - return addr >= info->begin && addr + len <= info->end;
> + return addr >= info->begin && sum <= info->end;
> }
>
> /*
> diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c
> index 8d207b82d9fe..e5e925423061 100644
> --- a/arch/s390/kernel/machine_kexec_file.c
> +++ b/arch/s390/kernel/machine_kexec_file.c
> @@ -238,6 +238,7 @@ void *kexec_file_add_components(struct kimage *image,
> unsigned long max_command_line_size = LEGACY_COMMAND_LINE_SIZE;
> struct s390_load_data data = {0};
> unsigned long minsize;
> + unsigned long sum;
Please, use min_kernel_buf_len instead of sum.
@Sven, could you please correct me if (minsize + max_command_line_size)
means something else.
> int ret;
>
> data.report = ipl_report_init(&ipl_block);
> @@ -256,10 +257,10 @@ void *kexec_file_add_components(struct kimage *image,
> if (data.parm->max_command_line_size)
> max_command_line_size = data.parm->max_command_line_size;
>
> - if (minsize + max_command_line_size < minsize)
> + if (check_add_overflow(minsize, max_command_line_size, &sum))
> goto out;
>
> - if (image->kernel_buf_len < minsize + max_command_line_size)
> + if (image->kernel_buf_len < sum)
> goto out;
>
> if (image->cmdline_buf_len >= max_command_line_size)
Thanks!
Alexander Gordeev <[email protected]> writes:
> On Mon, Jan 22, 2024 at 04:27:05PM -0800, Kees Cook wrote:
>> diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c
>> index 8d207b82d9fe..e5e925423061 100644
>> --- a/arch/s390/kernel/machine_kexec_file.c
>> +++ b/arch/s390/kernel/machine_kexec_file.c
>> @@ -238,6 +238,7 @@ void *kexec_file_add_components(struct kimage *image,
>> unsigned long max_command_line_size = LEGACY_COMMAND_LINE_SIZE;
>> struct s390_load_data data = {0};
>> unsigned long minsize;
>> + unsigned long sum;
>
> Please, use min_kernel_buf_len instead of sum.
>
> @Sven, could you please correct me if (minsize + max_command_line_size)
> means something else.
Your understanding is correct, minsize + max_command_line_size is the
minimum required size of the kernel image.
On Mon, Jan 22, 2024 at 04:27:45PM -0800, Kees Cook wrote:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Bjorn Andersson <[email protected]>
Acked-by: Bjorn Andersson <[email protected]>
Regards,
Bjorn
> Cc: Mathieu Poirier <[email protected]>
> Cc: [email protected]
> Signed-off-by: Kees Cook <[email protected]>
> ---
> drivers/remoteproc/pru_rproc.c | 2 +-
> drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
> drivers/remoteproc/remoteproc_virtio.c | 4 ++--
> 3 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
> index 327f0c7ee3d6..834249ee3dd3 100644
> --- a/drivers/remoteproc/pru_rproc.c
> +++ b/drivers/remoteproc/pru_rproc.c
> @@ -893,7 +893,7 @@ pru_rproc_find_interrupt_map(struct device *dev, const struct firmware *fw)
> continue;
>
> /* make sure we have the entire irq map */
> - if (offset + size > fw->size || offset + size < size) {
> + if (offset + size > fw->size || add_would_overflow(size, offset)) {
> dev_err(dev, ".pru_irq_map section truncated\n");
> return ERR_PTR(-EINVAL);
> }
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 94177e416047..b9231cf46d68 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -278,7 +278,7 @@ find_table(struct device *dev, const struct firmware *fw)
> table = (struct resource_table *)(elf_data + offset);
>
> /* make sure we have the entire table */
> - if (offset + size > fw_size || offset + size < size) {
> + if (offset + size > fw_size || add_would_overflow(size, offset)) {
> dev_err(dev, "resource table truncated\n");
> return NULL;
> }
> diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
> index 83d76915a6ad..58742c666e35 100644
> --- a/drivers/remoteproc/remoteproc_virtio.c
> +++ b/drivers/remoteproc/remoteproc_virtio.c
> @@ -298,7 +298,7 @@ static void rproc_virtio_get(struct virtio_device *vdev, unsigned int offset,
> rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
> cfg = &rsc->vring[rsc->num_of_vrings];
>
> - if (offset + len > rsc->config_len || offset + len < len) {
> + if (offset + len > rsc->config_len || add_would_overflow(len, offset)) {
> dev_err(&vdev->dev, "rproc_virtio_get: access out of bounds\n");
> return;
> }
> @@ -316,7 +316,7 @@ static void rproc_virtio_set(struct virtio_device *vdev, unsigned int offset,
> rsc = (void *)rvdev->rproc->table_ptr + rvdev->rsc_offset;
> cfg = &rsc->vring[rsc->num_of_vrings];
>
> - if (offset + len > rsc->config_len || offset + len < len) {
> + if (offset + len > rsc->config_len || add_would_overflow(len, offset)) {
> dev_err(&vdev->dev, "rproc_virtio_set: access out of bounds\n");
> return;
> }
> --
> 2.34.1
>
Kees Cook <[email protected]> writes:
> In an effort to separate intentional arithmetic wrap-around from
> unexpected wrap-around, we need to refactor places that depend on this
> kind of math. One of the most common code patterns of this is:
>
> VAR + value < VAR
>
> Notably, this is considered "undefined behavior" for signed and pointer
> types, which the kernel works around by using the -fno-strict-overflow
> option in the build[1] (which used to just be -fwrapv). Regardless, we
> want to get the kernel source to the position where we can meaningfully
> instrument arithmetic wrap-around conditions and catch them when they
> are unexpected, regardless of whether they are signed[2], unsigned[3],
> or pointer[4] types.
>
> Refactor open-coded wrap-around addition test to use add_would_overflow().
> This paves the way to enabling the wrap-around sanitizers in the future.
>
> Link: https://git.kernel.org/linus/68df3755e383e6fecf2354a67b08f92f18536594 [1]
> Link: https://github.com/KSPP/linux/issues/26 [2]
> Link: https://github.com/KSPP/linux/issues/27 [3]
> Link: https://github.com/KSPP/linux/issues/344 [4]
> Cc: Michael Ellerman <[email protected]>
> Cc: Nicholas Piggin <[email protected]>
> Cc: Christophe Leroy <[email protected]>
> Cc: "Aneesh Kumar K.V" <[email protected]>
> Cc: "Naveen N. Rao" <[email protected]>
> Cc: Mahesh Salgaonkar <[email protected]>
> Cc: Vasant Hegde <[email protected]>
> Cc: dingsenjie <[email protected]>
> Cc: [email protected]
> Cc: Aneesh Kumar K.V <[email protected]>
> Cc: Naveen N. Rao <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
> ---
> arch/powerpc/platforms/powernv/opal-prd.c | 2 +-
> arch/powerpc/xmon/xmon.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
Acked-by: Michael Ellerman <[email protected]> (powerpc)
cheers