From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A86DAECAAD8 for ; Fri, 23 Sep 2022 08:27:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231315AbiIWI1F (ORCPT ); Fri, 23 Sep 2022 04:27:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58720 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231303AbiIWI06 (ORCPT ); Fri, 23 Sep 2022 04:26:58 -0400 Received: from mga06.intel.com (mga06b.intel.com [134.134.136.31]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 59A231231D7 for ; Fri, 23 Sep 2022 01:26:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921616; x=1695457616; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XWBYdD1ObzFq50XzTqzGCqgjFHQYHlZB2Hh75JFYz2c=; b=dg6hcCGIOinmhaf5jf766JEffe+ERZ3xGEruwaKJrjqPVluTVFpR+7Ad j/7Ys76Lu8Lgd6zF/Gzr12vu3VEAkp5pgQ1VuhhxMW0s/UVlVrhyTAz6B KZbyztq8W9JT+LFmPgrOWZJK/XRRaLR3eu9AcebiLMzGBHujLYqEZK9hV EDkDXLJQBmQ8cVIU418QKVPAVAMk4oUzpECKG6f/K6BKpyw4d7KaOFRo5 y7kvE/pLctibIZg6uQ6Wv7tN+hRPQktjjSehChWM+Rw7+6JT9dBIyCYKC JLCJupoXcl+CR6+as88+dnHFAieYRpAIKjTHFuGwYHQgtfxpNEkqzkXpM w==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="362354260" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="362354260" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:26:55 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444133" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:26:49 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 1/9] overflow: Allow mixed type arguments Date: Fri, 23 Sep 2022 11:26:20 +0300 Message-Id: <20220923082628.3061408-2-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Kees Cook When the check_[op]_overflow() helpers were introduced, all arguments were required to be the same type to make the fallback macros simpler. However, now that the fallback macros have been removed[1], it is fine to allow mixed types, which makes using the helpers much more useful, as they can be used to test for type-based overflows (e.g. adding two large ints but storing into a u8), as would be handy in the drm core[2]. Remove the restriction, and add additional self-tests that exercise some of the mixed-type overflow cases, and double-check for accidental macro side-effects. [1] https://git.kernel.org/linus/4eb6bd55cfb22ffc20652732340c4962f3ac9a91 [2] https://lore.kernel.org/lkml/20220824084514.2261614-2-gwan-gyeong.mun@i= ntel.com Cc: Rasmus Villemoes Cc: Andrzej Hajda Cc: "Gustavo A. R. Silva" Cc: Nick Desaulniers Cc: linux-hardening@vger.kernel.org Signed-off-by: Kees Cook Signed-off-by: Gwan-gyeong Mun Reviewed-by: Andrzej Hajda --- include/linux/overflow.h | 72 ++++++++++++++++------------ lib/overflow_kunit.c | 101 ++++++++++++++++++++++++++++----------- 2 files changed, 113 insertions(+), 60 deletions(-) diff --git a/include/linux/overflow.h b/include/linux/overflow.h index 0eb3b192f07a..19dfdd74835e 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -51,40 +51,50 @@ static inline bool __must_check __must_check_overflow(b= ool overflow) return unlikely(overflow); } =20 -/* - * For simplicity and code hygiene, the fallback code below insists on - * a, b and *d having the same type (similar to the min() and max() - * macros), whereas gcc's type-generic overflow checkers accept - * different types. Hence we don't just make check_add_overflow an - * alias for __builtin_add_overflow, but add type checks similar to - * below. +/** check_add_overflow() - Calculate addition with overflow checking + * + * @a: first addend + * @b: second addend + * @d: pointer to store sum + * + * Returns 0 on success. + * + * *@d holds the results of the attempted addition, but is not considered + * "safe for use" on a non-zero return value, which indicates that the + * sum has overflowed or been truncated. */ -#define check_add_overflow(a, b, d) __must_check_overflow(({ \ - typeof(a) __a =3D (a); \ - typeof(b) __b =3D (b); \ - typeof(d) __d =3D (d); \ - (void) (&__a =3D=3D &__b); \ - (void) (&__a =3D=3D __d); \ - __builtin_add_overflow(__a, __b, __d); \ -})) +#define check_add_overflow(a, b, d) \ + __must_check_overflow(__builtin_add_overflow(a, b, d)) =20 -#define check_sub_overflow(a, b, d) __must_check_overflow(({ \ - typeof(a) __a =3D (a); \ - typeof(b) __b =3D (b); \ - typeof(d) __d =3D (d); \ - (void) (&__a =3D=3D &__b); \ - (void) (&__a =3D=3D __d); \ - __builtin_sub_overflow(__a, __b, __d); \ -})) +/** check_sub_overflow() - Calculate subtraction with overflow checking + * + * @a: minuend; value to subtract from + * @b: subtrahend; value to subtract from @a + * @d: pointer to store difference + * + * Returns 0 on success. + * + * *@d holds the results of the attempted subtraction, but is not consider= ed + * "safe for use" on a non-zero return value, which indicates that the + * difference has underflowed or been truncated. + */ +#define check_sub_overflow(a, b, d) \ + __must_check_overflow(__builtin_sub_overflow(a, b, d)) =20 -#define check_mul_overflow(a, b, d) __must_check_overflow(({ \ - typeof(a) __a =3D (a); \ - typeof(b) __b =3D (b); \ - typeof(d) __d =3D (d); \ - (void) (&__a =3D=3D &__b); \ - (void) (&__a =3D=3D __d); \ - __builtin_mul_overflow(__a, __b, __d); \ -})) +/** check_mul_overflow() - Calculate multiplication with overflow checking + * + * @a: first factor + * @b: second factor + * @d: pointer to store product + * + * Returns 0 on success. + * + * *@d holds the results of the attempted multiplication, but is not + * considered "safe for use" on a non-zero return value, which indicates + * that the product has overflowed or been truncated. + */ +#define check_mul_overflow(a, b, d) \ + __must_check_overflow(__builtin_mul_overflow(a, b, d)) =20 /** check_shl_overflow() - Calculate a left-shifted value and check overfl= ow * diff --git a/lib/overflow_kunit.c b/lib/overflow_kunit.c index 7e3e43679b73..0d98c9bc75da 100644 --- a/lib/overflow_kunit.c +++ b/lib/overflow_kunit.c @@ -16,12 +16,15 @@ #include #include =20 -#define DEFINE_TEST_ARRAY(t) \ - static const struct test_ ## t { \ - t a, b; \ - t sum, diff, prod; \ - bool s_of, d_of, p_of; \ - } t ## _tests[] +#define DEFINE_TEST_ARRAY_TYPED(t1, t2, t) \ + static const struct test_ ## t1 ## _ ## t2 ## __ ## t { \ + t1 a; \ + t2 b; \ + t sum, diff, prod; \ + bool s_of, d_of, p_of; \ + } t1 ## _ ## t2 ## __ ## t ## _tests[] + +#define DEFINE_TEST_ARRAY(t) DEFINE_TEST_ARRAY_TYPED(t, t, t) =20 DEFINE_TEST_ARRAY(u8) =3D { {0, 0, 0, 0, 0, false, false, false}, @@ -222,21 +225,27 @@ DEFINE_TEST_ARRAY(s64) =3D { }; #endif =20 -#define check_one_op(t, fmt, op, sym, a, b, r, of) do { \ - t _r; \ - bool _of; \ - \ - _of =3D check_ ## op ## _overflow(a, b, &_r); \ - KUNIT_EXPECT_EQ_MSG(test, _of, of, \ +#define check_one_op(t, fmt, op, sym, a, b, r, of) do { \ + int _a_orig =3D a, _a_bump =3D a + 1; \ + int _b_orig =3D b, _b_bump =3D b + 1; \ + bool _of; \ + t _r; \ + \ + _of =3D check_ ## op ## _overflow(a, b, &_r); \ + KUNIT_EXPECT_EQ_MSG(test, _of, of, \ "expected "fmt" "sym" "fmt" to%s overflow (type %s)\n", \ - a, b, of ? "" : " not", #t); \ - KUNIT_EXPECT_EQ_MSG(test, _r, r, \ + a, b, of ? "" : " not", #t); \ + KUNIT_EXPECT_EQ_MSG(test, _r, r, \ "expected "fmt" "sym" "fmt" =3D=3D "fmt", got "fmt" (type %s)\n", \ - a, b, r, _r, #t); \ + a, b, r, _r, #t); \ + /* Check for internal macro side-effects. */ \ + _of =3D check_ ## op ## _overflow(_a_orig++, _b_orig++, &_r); \ + KUNIT_EXPECT_EQ_MSG(test, _a_orig, _a_bump, "Unexpected " #op " macro sid= e-effect!\n"); \ + KUNIT_EXPECT_EQ_MSG(test, _b_orig, _b_bump, "Unexpected " #op " macro sid= e-effect!\n"); \ } while (0) =20 -#define DEFINE_TEST_FUNC(t, fmt) \ -static void do_test_ ## t(struct kunit *test, const struct test_ ## t *p) \ +#define DEFINE_TEST_FUNC_TYPED(n, t, fmt) \ +static void do_test_ ## n(struct kunit *test, const struct test_ ## n *p) \ { \ check_one_op(t, fmt, add, "+", p->a, p->b, p->sum, p->s_of); \ check_one_op(t, fmt, add, "+", p->b, p->a, p->sum, p->s_of); \ @@ -245,15 +254,18 @@ static void do_test_ ## t(struct kunit *test, const s= truct test_ ## t *p) \ check_one_op(t, fmt, mul, "*", p->b, p->a, p->prod, p->p_of); \ } \ \ -static void t ## _overflow_test(struct kunit *test) { \ +static void n ## _overflow_test(struct kunit *test) { \ unsigned i; \ \ - for (i =3D 0; i < ARRAY_SIZE(t ## _tests); ++i) \ - do_test_ ## t(test, &t ## _tests[i]); \ + for (i =3D 0; i < ARRAY_SIZE(n ## _tests); ++i) \ + do_test_ ## n(test, &n ## _tests[i]); \ kunit_info(test, "%zu %s arithmetic tests finished\n", \ - ARRAY_SIZE(t ## _tests), #t); \ + ARRAY_SIZE(n ## _tests), #n); \ } =20 +#define DEFINE_TEST_FUNC(t, fmt) \ + DEFINE_TEST_FUNC_TYPED(t ## _ ## t ## __ ## t, t, fmt) + DEFINE_TEST_FUNC(u8, "%d"); DEFINE_TEST_FUNC(s8, "%d"); DEFINE_TEST_FUNC(u16, "%d"); @@ -265,6 +277,33 @@ DEFINE_TEST_FUNC(u64, "%llu"); DEFINE_TEST_FUNC(s64, "%lld"); #endif =20 +DEFINE_TEST_ARRAY_TYPED(u32, u32, u8) =3D { + {0, 0, 0, 0, 0, false, false, false}, + {U8_MAX, 2, 1, U8_MAX - 2, U8_MAX - 1, true, false, true}, + {U8_MAX + 1, 0, 0, 0, 0, true, true, false}, +}; +DEFINE_TEST_FUNC_TYPED(u32_u32__u8, u8, "%d"); + +DEFINE_TEST_ARRAY_TYPED(u32, u32, int) =3D { + {0, 0, 0, 0, 0, false, false, false}, + {U32_MAX, 0, -1, -1, 0, true, true, false}, +}; +DEFINE_TEST_FUNC_TYPED(u32_u32__int, int, "%d"); + +DEFINE_TEST_ARRAY_TYPED(u8, u8, int) =3D { + {0, 0, 0, 0, 0, false, false, false}, + {U8_MAX, U8_MAX, 2 * U8_MAX, 0, U8_MAX * U8_MAX, false, false, false}, + {1, 2, 3, -1, 2, false, false, false}, +}; +DEFINE_TEST_FUNC_TYPED(u8_u8__int, int, "%d"); + +DEFINE_TEST_ARRAY_TYPED(int, int, u8) =3D { + {0, 0, 0, 0, 0, false, false, false}, + {1, 2, 3, U8_MAX, 2, false, true, false}, + {-1, 0, U8_MAX, U8_MAX, 0, true, true, false}, +}; +DEFINE_TEST_FUNC_TYPED(int_int__u8, u8, "%d"); + static void overflow_shift_test(struct kunit *test) { int count =3D 0; @@ -649,17 +688,21 @@ static void overflow_size_helpers_test(struct kunit *= test) } =20 static struct kunit_case overflow_test_cases[] =3D { - KUNIT_CASE(u8_overflow_test), - KUNIT_CASE(s8_overflow_test), - KUNIT_CASE(u16_overflow_test), - KUNIT_CASE(s16_overflow_test), - KUNIT_CASE(u32_overflow_test), - KUNIT_CASE(s32_overflow_test), + KUNIT_CASE(u8_u8__u8_overflow_test), + KUNIT_CASE(s8_s8__s8_overflow_test), + KUNIT_CASE(u16_u16__u16_overflow_test), + KUNIT_CASE(s16_s16__s16_overflow_test), + KUNIT_CASE(u32_u32__u32_overflow_test), + KUNIT_CASE(s32_s32__s32_overflow_test), /* Clang 13 and earlier generate unwanted libcalls on 32-bit. */ #if BITS_PER_LONG =3D=3D 64 - KUNIT_CASE(u64_overflow_test), - KUNIT_CASE(s64_overflow_test), + KUNIT_CASE(u64_u64__u64_overflow_test), + KUNIT_CASE(s64_s64__s64_overflow_test), #endif + KUNIT_CASE(u32_u32__u8_overflow_test), + KUNIT_CASE(u32_u32__int_overflow_test), + KUNIT_CASE(u8_u8__int_overflow_test), + KUNIT_CASE(int_int__u8_overflow_test), KUNIT_CASE(overflow_shift_test), KUNIT_CASE(overflow_allocation_test), KUNIT_CASE(overflow_size_helpers_test), --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 62CC2C6FA82 for ; Fri, 23 Sep 2022 08:27:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231325AbiIWI1J (ORCPT ); Fri, 23 Sep 2022 04:27:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58784 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231308AbiIWI1E (ORCPT ); Fri, 23 Sep 2022 04:27:04 -0400 Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3C942122632 for ; Fri, 23 Sep 2022 01:27:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921622; x=1695457622; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=g/jEBmQQWncfe4lssnnNgOdPFAeNkc2CYgl9r2fESM8=; b=iInXmAtQ6U9kdJKKvA4E56DvBxX6JWYlTmsCQTX3fdOHJEUVAsD6VamC IRpupOpmc2S0dzAM4j5N5SCYVKYSl6qTWkopzV4j+5TfPNHv6L/nS+NxH xftC9w4C4aZfZ/BKf98p90RZIlEbL+BDdZiJzWVYVFXVftMJqmrXHflbo HFQt8w84p7jLF3mloj9kZlvtgaFFRJvTAMaUEH9ojZ4RTbzZEdpuS3kc6 LRXNz3LFgfNQ8HTNlJfOwMayBJNcf13ey/ARHER28WfctRQi30lPDU4bO tUaYe/D9qJrB+dti0m3w9SFj+DJQF/OnKpdGf3doATJM7Q61WQiVtcd9B g==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="301988989" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="301988989" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:01 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444160" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:26:55 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 2/9] overflow: Move and add few utility macros into overflow Date: Fri, 23 Sep 2022 11:26:21 +0300 Message-Id: <20220923082628.3061408-3-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Moves overflows_type utility macro into overflow header from i915_utils header. The overflows_type can be used to catch the truncaion (overflow) between different data types. And it adds check_assign() macro which performs an assigning source value into destination pointer along with an overflow check. overflow_type macro has been improved to handle the different data types between source and destination by check_add_overflow macro. It also adds check_assign_user_ptr macro which performs an assigning source value into destination pointer type variable along with an overflow check. If an explicit overflow check is required while assigning, check_assign_user_ptr() can be used to assign integers into pointers along with an overflow check. v3: Add is_type_unsigned() macro (Mauro) Modify overflows_type() macro to consider signed data types (Mauro) Fix the problem that safe_conversion() macro always returns true v4: Fix kernel-doc markups v6: Move macro addition location so that it can be used by other than drm subsystem (Jani, Mauro, Andi) Change is_type_unsigned to is_unsigned_type to have the same name form as is_signed_type macro v8: Add check_assign() and remove safe_conversion() (Kees) Fix overflows_type() to use gcc's built-in overflow function (Andrzej) Add overflows_ptr() to allow overflow checking when assigning a value into a pointer variable (G.G.) v9: Fix overflows_type() to use __builtin_add_overflow() instead of __builtin_add_overflow_p() (Andrzej) Fix overflows_ptr() to use overflows_type() with the unsigned long type (Andrzej) v10: Remove a redundant type checking for a pointer. (Andrzej) Use updated check_add_overflow macro instead of __builtin_add_overflow (G.G) Add check_assign_user_ptr() macro and drop overflows_ptr() macro(Kees) v11: Fix incorrect type assignment between different address spaces caused by the wrong use of __user macro. (kernel test robot) Update macro description (G.G) Signed-off-by: Gwan-gyeong Mun Cc: Thomas Hellstr=C3=B6m Cc: Matthew Auld Cc: Nirmoy Das Cc: Jani Nikula Cc: Andi Shyti Cc: Andrzej Hajda Cc: Mauro Carvalho Chehab Cc: Kees Cook Reviewed-by: Mauro Carvalho Chehab (v5) Reviewed-by: Andrzej Hajda (v9) Acked-by: Kees Cook Reported-by: kernel test robot --- drivers/gpu/drm/i915/i915_user_extensions.c | 6 +- drivers/gpu/drm/i915/i915_utils.h | 5 +- include/linux/overflow.h | 64 +++++++++++++++++++++ 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_user_extensions.c b/drivers/gpu/drm/= i915/i915_user_extensions.c index c822d0aafd2d..80ec8390b0d8 100644 --- a/drivers/gpu/drm/i915/i915_user_extensions.c +++ b/drivers/gpu/drm/i915/i915_user_extensions.c @@ -50,11 +50,11 @@ int i915_user_extensions(struct i915_user_extension __u= ser *ext, if (err) return err; =20 - if (get_user(next, &ext->next_extension) || - overflows_type(next, ext)) + if (get_user(next, &ext->next_extension)) return -EFAULT; =20 - ext =3D u64_to_user_ptr(next); + if (check_assign_user_ptr(next, ext)) + return -EFAULT; } =20 return 0; diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_= utils.h index 6c14d13364bf..efd3d69b78f7 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -32,6 +32,7 @@ #include #include #include +#include =20 #ifdef CONFIG_X86 #include @@ -111,10 +112,6 @@ bool i915_error_injected(void); #define range_overflows_end_t(type, start, size, max) \ range_overflows_end((type)(start), (type)(size), (type)(max)) =20 -/* Note we don't consider signbits :| */ -#define overflows_type(x, T) \ - (sizeof(x) > sizeof(T) && (x) >> BITS_PER_TYPE(T)) - #define ptr_mask_bits(ptr, n) ({ \ unsigned long __v =3D (unsigned long)(ptr); \ (typeof(ptr))(__v & -BIT(n)); \ diff --git a/include/linux/overflow.h b/include/linux/overflow.h index 19dfdd74835e..0eca3d8281b2 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -5,6 +5,7 @@ #include #include #include +#include =20 /* * We need to compute the minimum and maximum values representable in a gi= ven @@ -127,6 +128,69 @@ static inline bool __must_check __must_check_overflow(= bool overflow) (*_d >> _to_shift) !=3D _a); \ })) =20 +/** + * check_assign - perform an assigning source value into destination point= er + * along with an overflow check. + * + * @value: source value + * @ptr: Destination pointer address + * + * Returns: + * If the value would overflow the destination, it returns true. If not re= turn + * false. When overflow does not occur, the assigning into destination from + * value succeeds. It follows the return policy as other check_*_overflow() + * functions return non-zero as a failure. + */ +#define check_assign(value, ptr) __must_check_overflow(({ \ + check_add_overflow(0, value, ptr); \ +})) + +/** + * check_assign_user_ptr - perform an assigning source value into destinat= ion + * pointer type variable along with an overflow ch= eck + * + * @value: source value; a source value is expected to have a value of a s= ize + * that can be stored in a pointer-type variable. + * @ptr: destination pointer type variable + * + * u64_to_user_ptr can be used in the kernel to avoid warnings about integ= ers + * and pointers of different sizes. But u64_to_user_ptr is not performing = the + * checking of overflow. If you need an explicit overflow check while + * assigning, check_assign_user_ptr() can be used to assign integers into + * pointers along with an overflow check. If ptr is not a pointer type, + * a warning message outputs while compiling. + * + * Returns: + * If the value would overflow the destination, it returns true. If not re= turn + * false. When overflow does not occur, the assigning into ptr from value + * succeeds. It follows the return policy as other check_*_overflow() func= tions + * return non-zero as a failure. + */ +#define check_assign_user_ptr(value, ptr) __must_check_overflow(({ \ + uintptr_t kptr; \ + check_assign(value, &kptr) ? 1 : (({ ptr =3D (void __user *)kptr; }), 0);= \ +})) + +/** + * overflows_type - helper for checking the overflows between value, varia= bles, + * or data type + * + * @x: source constant value or variable for overflow check + * @T: destination variable or data type for overflow check + * + * It compares the value, variables, or data type between the first and se= cond + * argument to check whether overflow can occur when assigning the first + * argument to the variable of the second argument data type. Source and + * Destination can be different data types. + * + * Returns: + * True if overflow can occur, false otherwise. + */ +#define overflows_type(x, T) __must_check_overflow(({ \ + typeof(T) v =3D 0; \ + check_add_overflow((x), v, &v); \ +})) + /** * size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX * --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 077BBC6FA82 for ; Fri, 23 Sep 2022 08:27:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231371AbiIWI1W (ORCPT ); Fri, 23 Sep 2022 04:27:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58970 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231344AbiIWI1N (ORCPT ); Fri, 23 Sep 2022 04:27:13 -0400 Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 904AF1296AD for ; Fri, 23 Sep 2022 01:27:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921628; x=1695457628; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3OMmPJzbpg1ed43aaEppDeyTkksfH/91vVUpM5aF62o=; b=LeT+spCsmozNceczZTd/YQ2a1Gl6z5BnN0cBhnNcjpm9gI81hvttdUru Gj2ShtZ7F5wOeKyimWmbbHQLlPQ897etoTQQ9Mkx5lUtWGHb0LH5QcWte p11XKqnTcbuw+BIQSc75AxW42TyuhfDSqT4TObne2o1KsndwZ+5GQzYv1 +3Jy4JgsSMHApjUvBGvzJWP4m7LaRP3eHl1Nm6e4wSlKAOI3FbQP98LLN uw1rBYiAH8EDX3y9xEIHgY5/x0aR9VcKbdTYxoE5951I5lYqFbr4T48UC T4Od2fUh+XyLZdSmkyiDVz3TSZNBO193j5XKBWHqwL5UOYmD6/cZ1zAZz g==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="301425913" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="301425913" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:07 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444172" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:01 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 3/9] compiler_types.h: Add assert_same_type to catch type mis-match while compiling Date: Fri, 23 Sep 2022 11:26:22 +0300 Message-Id: <20220923082628.3061408-4-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Adds assert_same_type and assert_same_typable macros to catch type mis-match while compiling. The existing typecheck() macro outputs build warnings, but the newly added assert_same_type() macro uses the static_assert macro (which uses _Static_assert keyword and it introduced in C11) to generate a build break when the types are different and can be used to detect explicit build errors. Unlike the assert_same_type() macro, assert_same_typable() macro allows a constant value as the second argument. Since static_assert is used at compile time and it requires constant-expression as an argument [1][2], overflows_type_ret_const_expr() is newly added. There is overflows_type() that has the same behavior, but the macro uses __builtin_add_overflow() internally, and __builtin_add_overflows returns a bool type [3], so it is difficult to use as an argument of _Static_assert. The assert_same_type and assert_same_typable macros have been added to compiler_types.h, but the overflows_type_ret_const_expr macro has been added to overflow.h So, overflow.h has to be included to use assert_same_typable which internally uses overflows_type_ret_const_expr. And it adds unit tests for overflows_type, overflows_type_ret_const_expr, assert_same_type and assert_same_typable. The overflows_type has been added as well to compare whether the overflows_type_ret_const_expr unit test has the same as the result. [1] https://en.cppreference.com/w/c/language/_Static_assert [2] C11 standard (ISO/IEC 9899:2011): 6.7.10 Static assertions [3] https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html 6.56 Built-in Functions to Perform Arithmetic with Overflow Checking Built-in Function: bool __builtin_add_overflow (type1 a, type2 b, type3 *res) v11: Update macro description (Andi) Change _Static_assert to static_assert (Rasmus) Rename assert_type to assert_same_type and assert_typable to assert_same_typable (Rasmus) Update assert_same_typable macro to handle an overflow check on the target type when a constant value is used. (Kees) Add overflows_type_ret_const_expr which returns constant-expression value (G.G) Add is_unsigned_type (G.G) Add unit tests for overflows_type, overflows_type_ret_const_expr, assert_same_type and assert_same_typable. (Kees) Suggested-by: Kees Cook Signed-off-by: Gwan-gyeong Mun Cc: Thomas Hellstr=C3=B6m Cc: Matthew Auld Cc: Nirmoy Das Cc: Jani Nikula Cc: Andi Shyti Cc: Mauro Carvalho Chehab Cc: Andrzej Hajda Cc: Kees Cook Cc: Rasmus Villemoes --- include/linux/compiler.h | 1 + include/linux/compiler_types.h | 43 +++++ include/linux/overflow.h | 27 ++++ lib/overflow_kunit.c | 283 +++++++++++++++++++++++++++++++++ 4 files changed, 354 insertions(+) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 7713d7bcdaea..c631107e93b1 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -244,6 +244,7 @@ static inline void *offset_to_ptr(const int *off) * bool and also pointer types. */ #define is_signed_type(type) (((type)(-1)) < (__force type)1) +#define is_unsigned_type(type) (!is_signed_type(type)) =20 /* * This is needed in functions which generate the stack canary, see diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 4f2a819fd60a..e6f5d68e5eba 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -294,6 +294,49 @@ struct ftrace_likely_data { /* Are two types/vars the same type (ignoring qualifiers)? */ #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b= )) =20 +/** + * assert_same_type - abort compilation if the first argument's data type = and + * the second argument's data type are not the same + * @t1: data type or variable + * @t2: data type or variable + * + * The first and second arguments can be data types or variables or mixed = (the + * first argument is the data type and the second argument is variable or = vice + * versa). It determines whether the first argument's data type and the se= cond + * argument's data type are the same while compiling, and it aborts compil= ation + * if the two types are not the same. + * See also assert_same_typable(). + */ +#define assert_same_type(t1, t2) static_assert(__same_type(t1, t2)) + +/** + * assert_same_typable - abort compilation if the first argument's data ty= pe and + * the second argument's data type are not the same + * @t: data type or variable + * @n: data type or variable or constant value + * + * The first and second arguments can be data types or variables or mixed = (the + * first argument is the data type and the second argument is variable or = vice + * versa). Unlike the assert_same_type() macro, this macro allows a consta= nt + * value as the second argument. And if the second argument is a constant + * value, it checks overflows between the first argument's data type and t= he + * second argument's constant value to check whether overflow can occur wh= en + * assigning the second argument to the variable of the first argument. An= d it + * aborts compilation if the overflow can occur. Since static assert used = at + * compile time requires constant-expression as an argument, + * overflows_type_ret_const_expr() is used internally instead of + * overflows_type(). When a constant value is not used as a second argumen= t, it + * determines whether the first argument's data type and the second argume= nt's + * data type are the same while compiling, and it aborts compilation if th= e two + * types are not the same. + * See also assert_same_type(), overflows_type_ret_const_expr() and + * overflows_type(). + */ +#define assert_same_typable(t, n) static_assert( \ + __builtin_choose_expr(__builtin_constant_p(n), \ + overflows_type_ret_const_expr(n,t) =3D=3D 0, \ + __same_type(t, n))) + /* * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving * non-scalar types unchanged. diff --git a/include/linux/overflow.h b/include/linux/overflow.h index 0eca3d8281b2..6e481ad2e46e 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -191,6 +191,33 @@ static inline bool __must_check __must_check_overflow(= bool overflow) check_add_overflow((x), v, &v); \ })) =20 +/** + * overflows_type_ret_const_expr - helper for checking the overflows betwe= en + * value, variables, or data type + * + * @x: source constant value or variable for overflow check + * @T: destination variable or data type for overflow check + * + * It compares the value, variables, or data type between the first and se= cond + * argument to check whether overflow can occur when assigning the first + * argument to the variable of the second argument data type. Source and + * Destination can be different data types. Unlike overflows_type(), it re= turns + * a constant-expression value. It is recommended to use this macro only w= hen a + * constant-expression value is absolutely necessary at compile time. In o= ther + * cases, it is recommended to use overflows_type(). + * + * See also overflows_type() and assert_same_typable(). + * + * Returns: + * 1 if overflow can occur, 0 otherwise. + */ +#define overflows_type_ret_const_expr(x,T) ( \ + is_unsigned_type(typeof(x)) ? \ + x > type_max(typeof(T)) ? 1 : 0 \ + : is_unsigned_type(typeof(T)) ? \ + x < 0 || x > type_max(typeof(T)) ? 1 : 0 \ + : x < type_min(typeof(T)) || x > type_max(typeof(T)) ? 1 : 0 ) + /** * size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX * diff --git a/lib/overflow_kunit.c b/lib/overflow_kunit.c index 0d98c9bc75da..a9c99a116e3c 100644 --- a/lib/overflow_kunit.c +++ b/lib/overflow_kunit.c @@ -687,6 +687,287 @@ static void overflow_size_helpers_test(struct kunit *= test) #undef check_one_size_helper } =20 +static void overflows_type_test(struct kunit *test) +{ +/* Args are: first type, secound type, value, overflow expected */ +#define TEST_OVERFLOWS_TYPE(t1, t2, v, of) do { \ + t1 __t1 =3D v; \ + t2 __t2; \ + bool __of; \ + __of =3D overflows_type(v, t2); \ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type(%s, %s) to%s overflow\n", \ + #v, #t2, of ? "" : " not"); \ + } \ + __of =3D overflows_type(v, __t2); \ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type(%s, %s) to%s overflow\n", \ + #v, #t2" __t2", of ? "" : " not"); \ + } \ + __of =3D overflows_type(__t1, t2); \ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type(%s, %s) to%s overflow\n", \ + #t1" __t1 =3D "#v, #t2, of ? "" : " not"); \ + } \ + __of =3D overflows_type(__t1, __t2); \ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type(%s, %s) to%s overflow\n", \ + #t1" __t1 =3D "#v, #t2" __t2", of ? "" : " not"); \ + } \ + __of =3D overflows_type_ret_const_expr(v, t2) ? true : false; \ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type_ret_const_expr(%s, %s) to%s overflow\n", \ + #v, #t2, of ? "" : " not"); \ + } \ + __of =3D overflows_type_ret_const_expr(v, __t2) ? true : false; \ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type_ret_const_expr(%s, %s) to%s overflow\n", \ + #v, #t2" __t2", of ? "" : " not"); \ + } \ + __of =3D overflows_type_ret_const_expr(__t1, t2) ? true : false; \ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type_ret_const_expr(%s, %s) to%s overflow\n", \ + #t1" __t1 =3D "#v, #t2, of ? "" : " not"); \ + } \ + __of =3D overflows_type_ret_const_expr(__t1, __t2) ? true : false;\ + if (__of !=3D of) { \ + KUNIT_EXPECT_EQ_MSG(test, __of, of, \ + "expected overflows_type_ret_const_expr(%s, %s) to%s overflow\n", \ + #t1" __t1 =3D "#v, #t2" __t2", of ? "" : " not"); \ + } \ +} while(0) + + TEST_OVERFLOWS_TYPE(u8, u8, U8_MAX, false); + TEST_OVERFLOWS_TYPE(u8, u16, U8_MAX, false); + TEST_OVERFLOWS_TYPE(u8, s8, U8_MAX, true); + TEST_OVERFLOWS_TYPE(u8, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(u8, s8, (u8)S8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u8, s16, U8_MAX, false); + TEST_OVERFLOWS_TYPE(s8, u8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s8, u8, -1, true); + TEST_OVERFLOWS_TYPE(s8, u8, S8_MIN, true); + TEST_OVERFLOWS_TYPE(s8, u16, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s8, u16, -1, true); + TEST_OVERFLOWS_TYPE(s8, u16, S8_MIN, true); + TEST_OVERFLOWS_TYPE(s8, u32, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s8, u32, -1, true); + TEST_OVERFLOWS_TYPE(s8, u32, S8_MIN, true); +#if BITS_PER_LONG =3D=3D 64 + TEST_OVERFLOWS_TYPE(s8, u64, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s8, u64, -1, true); + TEST_OVERFLOWS_TYPE(s8, u64, S8_MIN, true); +#endif + TEST_OVERFLOWS_TYPE(s8, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s8, s8, S8_MIN, false); + TEST_OVERFLOWS_TYPE(s8, s16, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s8, s16, S8_MIN, false); + TEST_OVERFLOWS_TYPE(u16, u8, U8_MAX, false); + TEST_OVERFLOWS_TYPE(u16, u8, (u16)U8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u16, u8, U16_MAX, true); + TEST_OVERFLOWS_TYPE(u16, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(u16, s8, (u16)S8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u16, s8, U16_MAX, true); + TEST_OVERFLOWS_TYPE(u16, s16, S16_MAX, false); + TEST_OVERFLOWS_TYPE(u16, s16, (u16)S16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u16, s16, U16_MAX, true); + TEST_OVERFLOWS_TYPE(u16, u32, U16_MAX, false); + TEST_OVERFLOWS_TYPE(u16, s32, U16_MAX, false); + TEST_OVERFLOWS_TYPE(s16, u8, U8_MAX, false); + TEST_OVERFLOWS_TYPE(s16, u8, (s16)U8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s16, u8, -1, true); + TEST_OVERFLOWS_TYPE(s16, u8, S16_MIN, true); + TEST_OVERFLOWS_TYPE(s16, u16, S16_MAX, false); + TEST_OVERFLOWS_TYPE(s16, u16, -1, true); + TEST_OVERFLOWS_TYPE(s16, u16, S16_MIN, true); + TEST_OVERFLOWS_TYPE(s16, u32, S16_MAX, false); + TEST_OVERFLOWS_TYPE(s16, u32, -1, true); + TEST_OVERFLOWS_TYPE(s16, u32, S16_MIN, true); +#if BITS_PER_LONG =3D=3D 64 + TEST_OVERFLOWS_TYPE(s16, u64, S16_MAX, false); + TEST_OVERFLOWS_TYPE(s16, u64, -1, true); + TEST_OVERFLOWS_TYPE(s16, u64, S16_MIN, true); +#endif + TEST_OVERFLOWS_TYPE(s16, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s16, s8, S8_MIN, false); + TEST_OVERFLOWS_TYPE(s16, s8, (s16)S8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s16, s8, (s16)S8_MIN - 1, true); + TEST_OVERFLOWS_TYPE(s16, s8, S16_MAX, true); + TEST_OVERFLOWS_TYPE(s16, s8, S16_MIN, true); + TEST_OVERFLOWS_TYPE(s16, s16, S16_MAX, false); + TEST_OVERFLOWS_TYPE(s16, s16, S16_MIN, false); + TEST_OVERFLOWS_TYPE(s16, s32, S16_MAX, false); + TEST_OVERFLOWS_TYPE(s16, s32, S16_MIN, false); + TEST_OVERFLOWS_TYPE(u32, u8, U8_MAX, false); + TEST_OVERFLOWS_TYPE(u32, u8, (u32)U8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u32, u8, U32_MAX, true); + TEST_OVERFLOWS_TYPE(u32, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(u32, s8, (u32)S8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u32, s8, U32_MAX, true); + TEST_OVERFLOWS_TYPE(u32, u16, U16_MAX, false); + TEST_OVERFLOWS_TYPE(u32, u16, U16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u32, u16, U32_MAX, true); + TEST_OVERFLOWS_TYPE(u32, s16, S16_MAX, false); + TEST_OVERFLOWS_TYPE(u32, s16, (u32)S16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u32, s16, U32_MAX, true); + TEST_OVERFLOWS_TYPE(u32, u32, U32_MAX, false); + TEST_OVERFLOWS_TYPE(u32, s32, S32_MAX, false); + TEST_OVERFLOWS_TYPE(u32, s32, U32_MAX, true); + TEST_OVERFLOWS_TYPE(u32, s32, (u32)S32_MAX + 1, true); +#if BITS_PER_LONG =3D=3D 64 + TEST_OVERFLOWS_TYPE(u32, u64, U32_MAX, false); + TEST_OVERFLOWS_TYPE(u32, s64, U32_MAX, false); +#endif + TEST_OVERFLOWS_TYPE(s32, u8, U8_MAX, false); + TEST_OVERFLOWS_TYPE(s32, u8, (s32)U8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s32, u16, S32_MAX, true); + TEST_OVERFLOWS_TYPE(s32, u8, -1, true); + TEST_OVERFLOWS_TYPE(s32, u8, S32_MIN, true); + TEST_OVERFLOWS_TYPE(s32, u16, U16_MAX, false); + TEST_OVERFLOWS_TYPE(s32, u16, (s32)U16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s32, u16, S32_MAX, true); + TEST_OVERFLOWS_TYPE(s32, u16, -1, true); + TEST_OVERFLOWS_TYPE(s32, u16, S32_MIN, true); + TEST_OVERFLOWS_TYPE(s32, u32, S32_MAX, false); + TEST_OVERFLOWS_TYPE(s32, u32, -1, true); + TEST_OVERFLOWS_TYPE(s32, u32, S32_MIN, true); +#if BITS_PER_LONG =3D=3D 64 + TEST_OVERFLOWS_TYPE(s32, u64, S32_MAX, false); + TEST_OVERFLOWS_TYPE(s32, u64, -1, true); + TEST_OVERFLOWS_TYPE(s32, u64, S32_MIN, true); +#endif + TEST_OVERFLOWS_TYPE(s32, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s32, s8, S8_MIN, false); + TEST_OVERFLOWS_TYPE(s32, s8, (s32)S8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s32, s8, (s32)S8_MIN - 1, true); + TEST_OVERFLOWS_TYPE(s32, s8, S32_MAX, true); + TEST_OVERFLOWS_TYPE(s32, s8, S32_MIN, true); + TEST_OVERFLOWS_TYPE(s32, s16, S16_MAX, false); + TEST_OVERFLOWS_TYPE(s32, s16, S16_MIN, false); + TEST_OVERFLOWS_TYPE(s32, s16, (s32)S16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s32, s16, (s32)S16_MIN - 1, true); + TEST_OVERFLOWS_TYPE(s32, s16, S32_MAX, true); + TEST_OVERFLOWS_TYPE(s32, s16, S32_MIN, true); + TEST_OVERFLOWS_TYPE(s32, s32, S32_MAX, false); + TEST_OVERFLOWS_TYPE(s32, s32, S32_MIN, false); +#if BITS_PER_LONG =3D=3D 64 + TEST_OVERFLOWS_TYPE(s32, s64, S32_MAX, false); + TEST_OVERFLOWS_TYPE(s32, s64, S32_MIN, false); + TEST_OVERFLOWS_TYPE(u64, u8, U64_MAX, true); + TEST_OVERFLOWS_TYPE(u64, u8, U8_MAX, false); + TEST_OVERFLOWS_TYPE(u64, u8, (u64)U8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u64, u16, U64_MAX, true); + TEST_OVERFLOWS_TYPE(u64, u16, U16_MAX, false); + TEST_OVERFLOWS_TYPE(u64, u16, (u64)U16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u64, u32, U64_MAX, true); + TEST_OVERFLOWS_TYPE(u64, u32, U32_MAX, false); + TEST_OVERFLOWS_TYPE(u64, u32, (u64)U32_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u64, u64, U64_MAX, false); + TEST_OVERFLOWS_TYPE(u64, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(u64, s8, (u64)S8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u64, s8, U64_MAX, true); + TEST_OVERFLOWS_TYPE(u64, s16, S16_MAX, false); + TEST_OVERFLOWS_TYPE(u64, s16, (u64)S16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u64, s16, U64_MAX, true); + TEST_OVERFLOWS_TYPE(u64, s32, S32_MAX, false); + TEST_OVERFLOWS_TYPE(u64, s32, (u64)S32_MAX + 1, true); + TEST_OVERFLOWS_TYPE(u64, s32, U64_MAX, true); + TEST_OVERFLOWS_TYPE(u64, s64, S64_MAX, false); + TEST_OVERFLOWS_TYPE(u64, s64, U64_MAX, true); + TEST_OVERFLOWS_TYPE(u64, s64, (u64)S64_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s64, u8, S64_MAX, true); + TEST_OVERFLOWS_TYPE(s64, u8, S64_MIN, true); + TEST_OVERFLOWS_TYPE(s64, u8, -1, true); + TEST_OVERFLOWS_TYPE(s64, u8, U8_MAX, false); + TEST_OVERFLOWS_TYPE(s64, u8, (s64)U8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s64, u16, S64_MAX, true); + TEST_OVERFLOWS_TYPE(s64, u16, S64_MIN, true); + TEST_OVERFLOWS_TYPE(s64, u16, -1, true); + TEST_OVERFLOWS_TYPE(s64, u16, U16_MAX, false); + TEST_OVERFLOWS_TYPE(s64, u16, (s64)U16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s64, u32, S64_MAX, true); + TEST_OVERFLOWS_TYPE(s64, u32, S64_MIN, true); + TEST_OVERFLOWS_TYPE(s64, u32, -1, true); + TEST_OVERFLOWS_TYPE(s64, u32, U32_MAX, false); + TEST_OVERFLOWS_TYPE(s64, u32, (s64)U32_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s64, u64, S64_MAX, false); + TEST_OVERFLOWS_TYPE(s64, u64, S64_MIN, true); + TEST_OVERFLOWS_TYPE(s64, u64, -1, true); + TEST_OVERFLOWS_TYPE(s64, s8, S8_MAX, false); + TEST_OVERFLOWS_TYPE(s64, s8, S8_MIN, false); + TEST_OVERFLOWS_TYPE(s64, s8, (s64)S8_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s64, s8, (s64)S8_MIN - 1, true); + TEST_OVERFLOWS_TYPE(s64, s8, S64_MAX, true); + TEST_OVERFLOWS_TYPE(s64, s16, S16_MAX, false); + TEST_OVERFLOWS_TYPE(s64, s16, S16_MIN, false); + TEST_OVERFLOWS_TYPE(s64, s16, (s64)S16_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s64, s16, (s64)S16_MIN - 1, true); + TEST_OVERFLOWS_TYPE(s64, s16, S64_MAX, true); + TEST_OVERFLOWS_TYPE(s64, s32, S32_MAX, false); + TEST_OVERFLOWS_TYPE(s64, s32, S32_MIN, false); + TEST_OVERFLOWS_TYPE(s64, s32, (s64)S32_MAX + 1, true); + TEST_OVERFLOWS_TYPE(s64, s32, (s64)S32_MIN - 1, true); + TEST_OVERFLOWS_TYPE(s64, s32, S64_MAX, true); + TEST_OVERFLOWS_TYPE(s64, s64, S64_MAX, false); + TEST_OVERFLOWS_TYPE(s64, s64, S64_MIN, false); +#endif +#undef TEST_OVERFLOWS_TYPE +} + +static void assert_same_type_test(struct kunit *test) +{ +/* Arg is: type */ +#define TEST_ASSERT_SAME_TYPE(t) do { \ + typeof(t) __t1 =3D type_max(t); \ + typeof(t) __t2 =3D type_min(t); \ + assert_same_type(t, t); \ + assert_same_type(t, __t1); \ + assert_same_type(__t1, t); \ + assert_same_type(__t1, __t2); \ +} while (0) + +/* Arg is: type */ +#define TEST_ASSERT_SAME_TYPABLE(t) do { \ + typeof(t) __t1 =3D type_max(t); \ + typeof(t) __t2 =3D type_min(t); \ + assert_same_typable(t, __t1); \ + assert_same_typable(t, type_max(t)); \ + assert_same_typable(t, type_min(t)); \ + assert_same_typable(__t1, type_max(t)); \ + assert_same_typable(__t1, type_min(t)); \ + assert_same_typable(__t1, __t2); \ +} while (0) + + TEST_ASSERT_SAME_TYPE(u8); + TEST_ASSERT_SAME_TYPE(u16); + TEST_ASSERT_SAME_TYPE(u32); + TEST_ASSERT_SAME_TYPE(s8); + TEST_ASSERT_SAME_TYPE(s16); + TEST_ASSERT_SAME_TYPE(s32); + TEST_ASSERT_SAME_TYPABLE(u8); + TEST_ASSERT_SAME_TYPABLE(u16); + TEST_ASSERT_SAME_TYPABLE(u32); + TEST_ASSERT_SAME_TYPABLE(s8); + TEST_ASSERT_SAME_TYPABLE(s16); + TEST_ASSERT_SAME_TYPABLE(s32); + +#if BITS_PER_LONG =3D=3D 64 + TEST_ASSERT_SAME_TYPE(u64); + TEST_ASSERT_SAME_TYPE(s64); + TEST_ASSERT_SAME_TYPABLE(u64); + TEST_ASSERT_SAME_TYPABLE(s64); +#endif + +#undef TEST_ASSERT_SAME_TYPABLE +#undef TEST_ASSERT_SAME_TYPE +} + static struct kunit_case overflow_test_cases[] =3D { KUNIT_CASE(u8_u8__u8_overflow_test), KUNIT_CASE(s8_s8__s8_overflow_test), @@ -706,6 +987,8 @@ static struct kunit_case overflow_test_cases[] =3D { KUNIT_CASE(overflow_shift_test), KUNIT_CASE(overflow_allocation_test), KUNIT_CASE(overflow_size_helpers_test), + KUNIT_CASE(overflows_type_test), + KUNIT_CASE(assert_same_type_test), {} }; =20 --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E8B73C6FA86 for ; Fri, 23 Sep 2022 08:27:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231402AbiIWI13 (ORCPT ); Fri, 23 Sep 2022 04:27:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231326AbiIWI1U (ORCPT ); Fri, 23 Sep 2022 04:27:20 -0400 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9CDD21257B7 for ; Fri, 23 Sep 2022 01:27:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921633; x=1695457633; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ci4/qe3eTxdRwotKlCxJYygkmTPrUxhHOzyqz7LzE6Y=; b=Q4O1z5DuKe47k6mtMCP1HG/GR355FCTbapx0CHgO81eo3eVSueIDrvu7 lznu7c6cm91gjm0uILMV7bQfzyagxIbZZ45wXmstbG+i+2HprdguBw338 wB047dwe4pyC85CB2ifTdGfw+7DZXwmj1RSiZxwOyPfH05FUVbMSa5/2f PJIqpkbG2kfhrk7YvJn/DX8ryuiFTE01TaJJZ6U+91+lGbajKe7Oib5KL qlYu1Z2/3vF8BBZjmGOk4dvIBbo3QO35jXEW+z5dS3Sl9xdqxFN6CW4NP vAV8HNyk5pWzhXS6O86iCPChrecj3EqLCe3fEpdu6o9VowjwgzHA9hefc w==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="326873960" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="326873960" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:12 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444191" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:07 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 4/9] drm/i915/gem: Typecheck page lookups Date: Fri, 23 Sep 2022 11:26:23 +0300 Message-Id: <20220923082628.3061408-5-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chris Wilson We need to check that we avoid integer overflows when looking up a page, and so fix all the instances where we have mistakenly used a plain integer instead of a more suitable long. Be pedantic and add integer typechecking to the lookup so that we can be sure that we are safe. And it also uses pgoff_t as our page lookups must remain compatible with the page cache, pgoff_t is currently exactly unsigned long. v2: Move added i915_utils's macro into drm_util header (Jani N) v3: Make not use the same macro name on a function. (Mauro) For kernel-doc, macros and functions are handled in the same namespace, the same macro name on a function prevents ever adding documentation for it. v4: Add kernel-doc markups to the kAPI functions and macros (Mauoro) v5: Fix an alignment to match open parenthesis v6: Rebase v10: Use assert_typable instead of exactly_pgoff_t() macro. (Kees) v11: Change the use of assert_typable to assert_same_typable (G.G) Signed-off-by: Chris Wilson Signed-off-by: Gwan-gyeong Mun Cc: Tvrtko Ursulin Cc: Matthew Auld Cc: Thomas Hellstr=C3=B6m Cc: Kees Cook Reviewed-by: Nirmoy Das (v2) Reviewed-by: Mauro Carvalho Chehab (v3) Reviewed-by: Andrzej Hajda (v5) --- drivers/gpu/drm/i915/gem/i915_gem_object.c | 7 +- drivers/gpu/drm/i915/gem/i915_gem_object.h | 293 ++++++++++++++++-- drivers/gpu/drm/i915/gem/i915_gem_pages.c | 27 +- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 2 +- .../drm/i915/gem/selftests/i915_gem_context.c | 12 +- .../drm/i915/gem/selftests/i915_gem_mman.c | 8 +- .../drm/i915/gem/selftests/i915_gem_object.c | 8 +- drivers/gpu/drm/i915/i915_gem.c | 18 +- drivers/gpu/drm/i915/i915_utils.h | 1 + drivers/gpu/drm/i915/i915_vma.c | 8 +- 10 files changed, 323 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i= 915/gem/i915_gem_object.c index 7ff9c7877bec..29ed0ec05d12 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -413,10 +413,11 @@ void __i915_gem_object_invalidate_frontbuffer(struct = drm_i915_gem_object *obj, static void i915_gem_object_read_from_page_kmap(struct drm_i915_gem_object *obj, u64 o= ffset, void *dst, int size) { + pgoff_t idx =3D offset >> PAGE_SHIFT; void *src_map; void *src_ptr; =20 - src_map =3D kmap_atomic(i915_gem_object_get_page(obj, offset >> PAGE_SHIF= T)); + src_map =3D kmap_atomic(i915_gem_object_get_page(obj, idx)); =20 src_ptr =3D src_map + offset_in_page(offset); if (!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ)) @@ -429,9 +430,10 @@ i915_gem_object_read_from_page_kmap(struct drm_i915_ge= m_object *obj, u64 offset, static void i915_gem_object_read_from_page_iomap(struct drm_i915_gem_object *obj, u64 = offset, void *dst, int size) { + pgoff_t idx =3D offset >> PAGE_SHIFT; + dma_addr_t dma =3D i915_gem_object_get_dma_address(obj, idx); void __iomem *src_map; void __iomem *src_ptr; - dma_addr_t dma =3D i915_gem_object_get_dma_address(obj, offset >> PAGE_SH= IFT); =20 src_map =3D io_mapping_map_wc(&obj->mm.region->iomap, dma - obj->mm.region->region.start, @@ -460,6 +462,7 @@ i915_gem_object_read_from_page_iomap(struct drm_i915_ge= m_object *obj, u64 offset */ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 of= fset, void *dst, int size) { + GEM_BUG_ON(overflows_type(offset >> PAGE_SHIFT, pgoff_t)); GEM_BUG_ON(offset >=3D obj->base.size); GEM_BUG_ON(offset_in_page(offset) > PAGE_SIZE - size); GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj)); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i= 915/gem/i915_gem_object.h index 7317d4102955..f2c4de31d563 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -27,8 +27,10 @@ enum intel_region_id; * spot such a local variable, please consider fixing! * * Aside from our own locals (for which we have no excuse!): - * - sg_table embeds unsigned int for num_pages - * - get_user_pages*() mixed ints with longs + * - sg_table embeds unsigned int for nents + * + * We can check for invalidly typed locals with typecheck(), see for examp= le + * i915_gem_object_get_sg(). */ #define GEM_CHECK_SIZE_OVERFLOW(sz) \ GEM_WARN_ON((sz) >> PAGE_SHIFT > INT_MAX) @@ -363,44 +365,289 @@ i915_gem_object_get_tile_row_size(const struct drm_i= 915_gem_object *obj) int i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, unsigned int tiling, unsigned int stride); =20 +/** + * __i915_gem_object_page_iter_get_sg - helper to find the target scatterl= ist + * pointer and the target page position using pgoff_t n input argument and + * i915_gem_object_page_iter + * @obj: i915 GEM buffer object + * @iter: i915 GEM buffer object page iterator + * @n: page offset + * @offset: searched physical offset, + * it will be used for returning physical page offset value + * + * Context: Takes and releases the mutex lock of the i915_gem_object_page_= iter. + * Takes and releases the RCU lock to search the radix_tree of + * i915_gem_object_page_iter. + * + * Returns: + * The target scatterlist pointer and the target page position. + * + * Recommended to use wrapper macro: i915_gem_object_page_iter_get_sg() + */ struct scatterlist * -__i915_gem_object_get_sg(struct drm_i915_gem_object *obj, - struct i915_gem_object_page_iter *iter, - unsigned int n, - unsigned int *offset, bool dma); +__i915_gem_object_page_iter_get_sg(struct drm_i915_gem_object *obj, + struct i915_gem_object_page_iter *iter, + pgoff_t n, + unsigned int *offset); =20 +/** + * i915_gem_object_page_iter_get_sg - wrapper macro for + * __i915_gem_object_page_iter_get_sg() + * @obj: i915 GEM buffer object + * @it: i915 GEM buffer object page iterator + * @n: page offset + * @offset: searched physical offset, + * it will be used for returning physical page offset value + * + * Context: Takes and releases the mutex lock of the i915_gem_object_page_= iter. + * Takes and releases the RCU lock to search the radix_tree of + * i915_gem_object_page_iter. + * + * Returns: + * The target scatterlist pointer and the target page position. + * + * In order to avoid the truncation of the input parameter, it checks the = page + * offset n's type from the input parameter before calling + * __i915_gem_object_page_iter_get_sg(). + */ +#define i915_gem_object_page_iter_get_sg(obj, it, n, offset) ({ \ + assert_same_typable(pgoff_t, n); \ + __i915_gem_object_page_iter_get_sg(obj, it, n, offset); \ +}) + +/** + * __i915_gem_object_get_sg - helper to find the target scatterlist + * pointer and the target page position using pgoff_t n input argument and + * drm_i915_gem_object. It uses an internal shmem scatterlist lookup funct= ion. + * @obj: i915 GEM buffer object + * @n: page offset + * @offset: searched physical offset, + * it will be used for returning physical page offset value + * + * It uses drm_i915_gem_object's internal shmem scatterlist lookup functio= n as + * i915_gem_object_page_iter and calls __i915_gem_object_page_iter_get_sg(= ). + * + * Returns: + * The target scatterlist pointer and the target page position. + * + * Recommended to use wrapper macro: i915_gem_object_get_sg() + * See also __i915_gem_object_page_iter_get_sg() + */ static inline struct scatterlist * -i915_gem_object_get_sg(struct drm_i915_gem_object *obj, - unsigned int n, - unsigned int *offset) +__i915_gem_object_get_sg(struct drm_i915_gem_object *obj, pgoff_t n, + unsigned int *offset) { - return __i915_gem_object_get_sg(obj, &obj->mm.get_page, n, offset, false); + return __i915_gem_object_page_iter_get_sg(obj, &obj->mm.get_page, n, offs= et); } =20 +/** + * i915_gem_object_get_sg - wrapper macro for __i915_gem_object_get_sg() + * @obj: i915 GEM buffer object + * @n: page offset + * @offset: searched physical offset, + * it will be used for returning physical page offset value + * + * Returns: + * The target scatterlist pointer and the target page position. + * + * In order to avoid the truncation of the input parameter, it checks the = page + * offset n's type from the input parameter before calling + * __i915_gem_object_get_sg(). + * See also __i915_gem_object_page_iter_get_sg() + */ +#define i915_gem_object_get_sg(obj, n, offset) ({ \ + assert_same_typable(pgoff_t, n); \ + __i915_gem_object_get_sg(obj, n, offset); \ +}) + +/** + * __i915_gem_object_get_sg_dma - helper to find the target scatterlist + * pointer and the target page position using pgoff_t n input argument and + * drm_i915_gem_object. It uses an internal DMA mapped scatterlist lookup = function + * @obj: i915 GEM buffer object + * @n: page offset + * @offset: searched physical offset, + * it will be used for returning physical page offset value + * + * It uses drm_i915_gem_object's internal DMA mapped scatterlist lookup fu= nction + * as i915_gem_object_page_iter and calls __i915_gem_object_page_iter_get_= sg(). + * + * Returns: + * The target scatterlist pointer and the target page position. + * + * Recommended to use wrapper macro: i915_gem_object_get_sg_dma() + * See also __i915_gem_object_page_iter_get_sg() + */ static inline struct scatterlist * -i915_gem_object_get_sg_dma(struct drm_i915_gem_object *obj, - unsigned int n, - unsigned int *offset) +__i915_gem_object_get_sg_dma(struct drm_i915_gem_object *obj, pgoff_t n, + unsigned int *offset) { - return __i915_gem_object_get_sg(obj, &obj->mm.get_dma_page, n, offset, tr= ue); + return __i915_gem_object_page_iter_get_sg(obj, &obj->mm.get_dma_page, n, = offset); } =20 +/** + * i915_gem_object_get_sg_dma - wrapper macro for __i915_gem_object_get_sg= _dma() + * @obj: i915 GEM buffer object + * @n: page offset + * @offset: searched physical offset, + * it will be used for returning physical page offset value + * + * Returns: + * The target scatterlist pointer and the target page position. + * + * In order to avoid the truncation of the input parameter, it checks the = page + * offset n's type from the input parameter before calling + * __i915_gem_object_get_sg_dma(). + * See also __i915_gem_object_page_iter_get_sg() + */ +#define i915_gem_object_get_sg_dma(obj, n, offset) ({ \ + assert_same_typable(pgoff_t, n); \ + __i915_gem_object_get_sg_dma(obj, n, offset); \ +}) + +/** + * __i915_gem_object_get_page - helper to find the target page with a page= offset + * @obj: i915 GEM buffer object + * @n: page offset + * + * It uses drm_i915_gem_object's internal shmem scatterlist lookup functio= n as + * i915_gem_object_page_iter and calls __i915_gem_object_page_iter_get_sg() + * internally. + * + * Returns: + * The target page pointer. + * + * Recommended to use wrapper macro: i915_gem_object_get_page() + * See also __i915_gem_object_page_iter_get_sg() + */ struct page * -i915_gem_object_get_page(struct drm_i915_gem_object *obj, - unsigned int n); +__i915_gem_object_get_page(struct drm_i915_gem_object *obj, pgoff_t n); =20 +/** + * i915_gem_object_get_page - wrapper macro for __i915_gem_object_get_page + * @obj: i915 GEM buffer object + * @n: page offset + * + * Returns: + * The target page pointer. + * + * In order to avoid the truncation of the input parameter, it checks the = page + * offset n's type from the input parameter before calling + * __i915_gem_object_get_page(). + * See also __i915_gem_object_page_iter_get_sg() + */ +#define i915_gem_object_get_page(obj, n) ({ \ + assert_same_typable(pgoff_t, n); \ + __i915_gem_object_get_page(obj, n); \ +}) + +/** + * __i915_gem_object_get_dirty_page - helper to find the target page with = a page + * offset + * @obj: i915 GEM buffer object + * @n: page offset + * + * It works like i915_gem_object_get_page(), but it marks the returned pag= e dirty. + * + * Returns: + * The target page pointer. + * + * Recommended to use wrapper macro: i915_gem_object_get_dirty_page() + * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get= _page() + */ struct page * -i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, - unsigned int n); +__i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, pgoff_t = n); + +/** + * i915_gem_object_get_dirty_page - wrapper macro for __i915_gem_object_ge= t_dirty_page + * @obj: i915 GEM buffer object + * @n: page offset + * + * Returns: + * The target page pointer. + * + * In order to avoid the truncation of the input parameter, it checks the = page + * offset n's type from the input parameter before calling + * __i915_gem_object_get_dirty_page(). + * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get= _page() + */ +#define i915_gem_object_get_dirty_page(obj, n) ({ \ + assert_same_typable(pgoff_t, n); \ + __i915_gem_object_get_dirty_page(obj, n); \ +}) =20 +/** + * __i915_gem_object_get_dma_address_len - helper to get bus addresses of + * targeted DMA mapped scatterlist from i915 GEM buffer object and it's le= ngth + * @obj: i915 GEM buffer object + * @n: page offset + * @len: DMA mapped scatterlist's DMA bus addresses length to return + * + * Returns: + * Bus addresses of targeted DMA mapped scatterlist + * + * Recommended to use wrapper macro: i915_gem_object_get_dma_address_len() + * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get= _sg_dma() + */ dma_addr_t -i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, - unsigned long n, - unsigned int *len); +__i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, pgo= ff_t n, + unsigned int *len); =20 +/** + * i915_gem_object_get_dma_address_len - wrapper macro for + * __i915_gem_object_get_dma_address_len + * @obj: i915 GEM buffer object + * @n: page offset + * @len: DMA mapped scatterlist's DMA bus addresses length to return + * + * Returns: + * Bus addresses of targeted DMA mapped scatterlist + * + * In order to avoid the truncation of the input parameter, it checks the = page + * offset n's type from the input parameter before calling + * __i915_gem_object_get_dma_address_len(). + * See also __i915_gem_object_page_iter_get_sg() and + * __i915_gem_object_get_dma_address_len() + */ +#define i915_gem_object_get_dma_address_len(obj, n, len) ({ \ + assert_same_typable(pgoff_t, n); \ + __i915_gem_object_get_dma_address_len(obj, n, len); \ +}) + +/** + * __i915_gem_object_get_dma_address - helper to get bus addresses of + * targeted DMA mapped scatterlist from i915 GEM buffer object + * @obj: i915 GEM buffer object + * @n: page offset + * + * Returns: + * Bus addresses of targeted DMA mapped scatterlis + * + * Recommended to use wrapper macro: i915_gem_object_get_dma_address() + * See also __i915_gem_object_page_iter_get_sg() and __i915_gem_object_get= _sg_dma() + */ dma_addr_t -i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj, - unsigned long n); +__i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj, pgoff_t= n); + +/** + * i915_gem_object_get_dma_address - wrapper macro for + * __i915_gem_object_get_dma_address + * @obj: i915 GEM buffer object + * @n: page offset + * + * Returns: + * Bus addresses of targeted DMA mapped scatterlist + * + * In order to avoid the truncation of the input parameter, it checks the = page + * offset n's type from the input parameter before calling + * __i915_gem_object_get_dma_address(). + * See also __i915_gem_object_page_iter_get_sg() and + * __i915_gem_object_get_dma_address() + */ +#define i915_gem_object_get_dma_address(obj, n) ({ \ + assert_same_typable(pgoff_t, n); \ + __i915_gem_object_get_dma_address(obj, n); \ +}) =20 void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, struct sg_table *pages, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i9= 15/gem/i915_gem_pages.c index 4df50b049cea..015b6cd071e4 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -510,14 +510,16 @@ void __i915_gem_object_release_map(struct drm_i915_ge= m_object *obj) } =20 struct scatterlist * -__i915_gem_object_get_sg(struct drm_i915_gem_object *obj, - struct i915_gem_object_page_iter *iter, - unsigned int n, - unsigned int *offset, - bool dma) +__i915_gem_object_page_iter_get_sg(struct drm_i915_gem_object *obj, + struct i915_gem_object_page_iter *iter, + pgoff_t n, + unsigned int *offset) + { - struct scatterlist *sg; + const bool dma =3D iter =3D=3D &obj->mm.get_dma_page || + iter =3D=3D &obj->ttm.get_io_page; unsigned int idx, count; + struct scatterlist *sg; =20 might_sleep(); GEM_BUG_ON(n >=3D obj->base.size >> PAGE_SHIFT); @@ -625,7 +627,7 @@ __i915_gem_object_get_sg(struct drm_i915_gem_object *ob= j, } =20 struct page * -i915_gem_object_get_page(struct drm_i915_gem_object *obj, unsigned int n) +__i915_gem_object_get_page(struct drm_i915_gem_object *obj, pgoff_t n) { struct scatterlist *sg; unsigned int offset; @@ -638,8 +640,7 @@ i915_gem_object_get_page(struct drm_i915_gem_object *ob= j, unsigned int n) =20 /* Like i915_gem_object_get_page(), but mark the returned page dirty */ struct page * -i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, - unsigned int n) +__i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, pgoff_t = n) { struct page *page; =20 @@ -651,9 +652,8 @@ i915_gem_object_get_dirty_page(struct drm_i915_gem_obje= ct *obj, } =20 dma_addr_t -i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, - unsigned long n, - unsigned int *len) +__i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, + pgoff_t n, unsigned int *len) { struct scatterlist *sg; unsigned int offset; @@ -667,8 +667,7 @@ i915_gem_object_get_dma_address_len(struct drm_i915_gem= _object *obj, } =20 dma_addr_t -i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj, - unsigned long n) +__i915_gem_object_get_dma_address(struct drm_i915_gem_object *obj, pgoff_t= n) { return i915_gem_object_get_dma_address_len(obj, n, NULL); } diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915= /gem/i915_gem_ttm.c index e3fc38dd5db0..004fc7478b41 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -694,7 +694,7 @@ static unsigned long i915_ttm_io_mem_pfn(struct ttm_buf= fer_object *bo, GEM_WARN_ON(bo->ttm); =20 base =3D obj->mm.region->iomap.base - obj->mm.region->region.start; - sg =3D __i915_gem_object_get_sg(obj, &obj->ttm.get_io_page, page_offset, = &ofs, true); + sg =3D i915_gem_object_page_iter_get_sg(obj, &obj->ttm.get_io_page, page_= offset, &ofs); =20 return ((base + sg_dma_address(sg)) >> PAGE_SHIFT) + ofs; } diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/driver= s/gpu/drm/i915/gem/selftests/i915_gem_context.c index c6ad67b90e8a..a18a890e681f 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c @@ -455,7 +455,8 @@ static int gpu_fill(struct intel_context *ce, static int cpu_fill(struct drm_i915_gem_object *obj, u32 value) { const bool has_llc =3D HAS_LLC(to_i915(obj->base.dev)); - unsigned int n, m, need_flush; + unsigned int need_flush; + unsigned long n, m; int err; =20 i915_gem_object_lock(obj, NULL); @@ -485,7 +486,8 @@ static int cpu_fill(struct drm_i915_gem_object *obj, u3= 2 value) static noinline int cpu_check(struct drm_i915_gem_object *obj, unsigned int idx, unsigned int max) { - unsigned int n, m, needs_flush; + unsigned int needs_flush; + unsigned long n; int err; =20 i915_gem_object_lock(obj, NULL); @@ -494,7 +496,7 @@ static noinline int cpu_check(struct drm_i915_gem_objec= t *obj, goto out_unlock; =20 for (n =3D 0; n < real_page_count(obj); n++) { - u32 *map; + u32 *map, m; =20 map =3D kmap_atomic(i915_gem_object_get_page(obj, n)); if (needs_flush & CLFLUSH_BEFORE) @@ -502,7 +504,7 @@ static noinline int cpu_check(struct drm_i915_gem_objec= t *obj, =20 for (m =3D 0; m < max; m++) { if (map[m] !=3D m) { - pr_err("%pS: Invalid value at object %d page %d/%ld, offset %d/%d: fou= nd %x expected %x\n", + pr_err("%pS: Invalid value at object %d page %ld/%ld, offset %d/%d: fo= und %x expected %x\n", __builtin_return_address(0), idx, n, real_page_count(obj), m, max, map[m], m); @@ -513,7 +515,7 @@ static noinline int cpu_check(struct drm_i915_gem_objec= t *obj, =20 for (; m < DW_PER_PAGE; m++) { if (map[m] !=3D STACK_MAGIC) { - pr_err("%pS: Invalid value at object %d page %d, offset %d: found %x e= xpected %x (uninitialised)\n", + pr_err("%pS: Invalid value at object %d page %ld, offset %d: found %x = expected %x (uninitialised)\n", __builtin_return_address(0), idx, n, m, map[m], STACK_MAGIC); err =3D -EINVAL; diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/g= pu/drm/i915/gem/selftests/i915_gem_mman.c index b73c91aa5450..4ea6e48d8689 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -95,11 +95,11 @@ static int check_partial_mapping(struct drm_i915_gem_ob= ject *obj, struct drm_i915_private *i915 =3D to_i915(obj->base.dev); struct i915_gtt_view view; struct i915_vma *vma; + unsigned long offset; unsigned long page; u32 __iomem *io; struct page *p; unsigned int n; - u64 offset; u32 *cpu; int err; =20 @@ -156,7 +156,7 @@ static int check_partial_mapping(struct drm_i915_gem_ob= ject *obj, cpu =3D kmap(p) + offset_in_page(offset); drm_clflush_virt_range(cpu, sizeof(*cpu)); if (*cpu !=3D (u32)page) { - pr_err("Partial view for %lu [%u] (offset=3D%llu, size=3D%u [%llu, row s= ize %u], fence=3D%d, tiling=3D%d, stride=3D%d) misalignment, expected write= to page (%llu + %u [0x%llx]) of 0x%x, found 0x%x\n", + pr_err("Partial view for %lu [%u] (offset=3D%llu, size=3D%u [%llu, row s= ize %u], fence=3D%d, tiling=3D%d, stride=3D%d) misalignment, expected write= to page (%lu + %u [0x%lx]) of 0x%x, found 0x%x\n", page, n, view.partial.offset, view.partial.size, @@ -212,10 +212,10 @@ static int check_partial_mappings(struct drm_i915_gem= _object *obj, for_each_prime_number_from(page, 1, npages) { struct i915_gtt_view view =3D compute_partial_view(obj, page, MIN_CHUNK_PAGES); + unsigned long offset; u32 __iomem *io; struct page *p; unsigned int n; - u64 offset; u32 *cpu; =20 GEM_BUG_ON(view.partial.size > nreal); @@ -252,7 +252,7 @@ static int check_partial_mappings(struct drm_i915_gem_o= bject *obj, cpu =3D kmap(p) + offset_in_page(offset); drm_clflush_virt_range(cpu, sizeof(*cpu)); if (*cpu !=3D (u32)page) { - pr_err("Partial view for %lu [%u] (offset=3D%llu, size=3D%u [%llu, row = size %u], fence=3D%d, tiling=3D%d, stride=3D%d) misalignment, expected writ= e to page (%llu + %u [0x%llx]) of 0x%x, found 0x%x\n", + pr_err("Partial view for %lu [%u] (offset=3D%llu, size=3D%u [%llu, row = size %u], fence=3D%d, tiling=3D%d, stride=3D%d) misalignment, expected writ= e to page (%lu + %u [0x%lx]) of 0x%x, found 0x%x\n", page, n, view.partial.offset, view.partial.size, diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c b/drivers= /gpu/drm/i915/gem/selftests/i915_gem_object.c index bdf5bb40ccf1..19e374f68ff7 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_object.c @@ -33,10 +33,10 @@ static int igt_gem_object(void *arg) =20 static int igt_gem_huge(void *arg) { - const unsigned int nreal =3D 509; /* just to be awkward */ + const unsigned long nreal =3D 509; /* just to be awkward */ struct drm_i915_private *i915 =3D arg; struct drm_i915_gem_object *obj; - unsigned int n; + unsigned long n; int err; =20 /* Basic sanitycheck of our huge fake object allocation */ @@ -49,7 +49,7 @@ static int igt_gem_huge(void *arg) =20 err =3D i915_gem_object_pin_pages_unlocked(obj); if (err) { - pr_err("Failed to allocate %u pages (%lu total), err=3D%d\n", + pr_err("Failed to allocate %lu pages (%lu total), err=3D%d\n", nreal, obj->base.size / PAGE_SIZE, err); goto out; } @@ -57,7 +57,7 @@ static int igt_gem_huge(void *arg) for (n =3D 0; n < obj->base.size / PAGE_SIZE; n++) { if (i915_gem_object_get_page(obj, n) !=3D i915_gem_object_get_page(obj, n % nreal)) { - pr_err("Page lookup mismatch at index %u [%u]\n", + pr_err("Page lookup mismatch at index %lu [%lu]\n", n, n % nreal); err =3D -EINVAL; goto out_unpin; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_ge= m.c index 88df9a35e0fe..68cbe6233eef 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -229,8 +229,9 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj, struct drm_i915_gem_pread *args) { unsigned int needs_clflush; - unsigned int idx, offset; char __user *user_data; + unsigned long offset; + pgoff_t idx; u64 remain; int ret; =20 @@ -383,13 +384,17 @@ i915_gem_gtt_pread(struct drm_i915_gem_object *obj, { struct drm_i915_private *i915 =3D to_i915(obj->base.dev); struct i915_ggtt *ggtt =3D to_gt(i915)->ggtt; + unsigned long remain, offset; intel_wakeref_t wakeref; struct drm_mm_node node; void __user *user_data; struct i915_vma *vma; - u64 remain, offset; int ret =3D 0; =20 + if (overflows_type(args->size, remain) || + overflows_type(args->offset, offset)) + return -EINVAL; + wakeref =3D intel_runtime_pm_get(&i915->runtime_pm); =20 vma =3D i915_gem_gtt_prepare(obj, &node, false); @@ -540,13 +545,17 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *= obj, struct drm_i915_private *i915 =3D to_i915(obj->base.dev); struct i915_ggtt *ggtt =3D to_gt(i915)->ggtt; struct intel_runtime_pm *rpm =3D &i915->runtime_pm; + unsigned long remain, offset; intel_wakeref_t wakeref; struct drm_mm_node node; struct i915_vma *vma; - u64 remain, offset; void __user *user_data; int ret =3D 0; =20 + if (overflows_type(args->size, remain) || + overflows_type(args->offset, offset)) + return -EINVAL; + if (i915_gem_object_has_struct_page(obj)) { /* * Avoid waking the device up if we can fallback, as @@ -654,8 +663,9 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, { unsigned int partial_cacheline_write; unsigned int needs_clflush; - unsigned int offset, idx; void __user *user_data; + unsigned long offset; + pgoff_t idx; u64 remain; int ret; =20 diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_= utils.h index efd3d69b78f7..d2144986cbf1 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -33,6 +33,7 @@ #include #include #include +#include =20 #ifdef CONFIG_X86 #include diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vm= a.c index f17c09ead7d7..bf3a30cd02bf 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -909,7 +909,7 @@ rotate_pages(struct drm_i915_gem_object *obj, unsigned = int offset, struct sg_table *st, struct scatterlist *sg) { unsigned int column, row; - unsigned int src_idx; + pgoff_t src_idx; =20 for (column =3D 0; column < width; column++) { unsigned int left; @@ -1015,7 +1015,7 @@ add_padding_pages(unsigned int count, =20 static struct scatterlist * remap_tiled_color_plane_pages(struct drm_i915_gem_object *obj, - unsigned int offset, unsigned int alignment_pad, + unsigned long offset, unsigned int alignment_pad, unsigned int width, unsigned int height, unsigned int src_stride, unsigned int dst_stride, struct sg_table *st, struct scatterlist *sg, @@ -1074,7 +1074,7 @@ remap_tiled_color_plane_pages(struct drm_i915_gem_obj= ect *obj, =20 static struct scatterlist * remap_contiguous_pages(struct drm_i915_gem_object *obj, - unsigned int obj_offset, + pgoff_t obj_offset, unsigned int count, struct sg_table *st, struct scatterlist *sg) { @@ -1107,7 +1107,7 @@ remap_contiguous_pages(struct drm_i915_gem_object *ob= j, =20 static struct scatterlist * remap_linear_color_plane_pages(struct drm_i915_gem_object *obj, - unsigned int obj_offset, unsigned int alignment_pad, + pgoff_t obj_offset, unsigned int alignment_pad, unsigned int size, struct sg_table *st, struct scatterlist *sg, unsigned int *gtt_offset) --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6B108C6FA86 for ; Fri, 23 Sep 2022 08:28:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231458AbiIWI2E (ORCPT ); Fri, 23 Sep 2022 04:28:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231377AbiIWI1i (ORCPT ); Fri, 23 Sep 2022 04:27:38 -0400 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2814E1296B1 for ; Fri, 23 Sep 2022 01:27:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921650; x=1695457650; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=To+r8DoSBWXEFxEDBPH41aSt7znF2w4YCd3jX7QhPMg=; b=IHElGTzVZJr3wvsOBcVoeDU93uwpS1XuJvdTbKSBgJJpEoCOrgbFivQ6 ueqwKMIO811Bonob4ZE0CnW+Emq8mLxpwpTusRBF9oAd2YsBd8C8fmKv7 ExWD/DCEcWNXz1pGlKjnTLLoDTsBsg7V+6iFFnI2+icH5+KvySFtF/KNa b/rmj6DibIdpUUqeAS5Up+7Y9G6tdPIfT/TfELmmWUK1nhU+XMPPiis9u hk48boyNUrOWSDSq1149P0RoUpCNdEmTy+ZOGj0L6mb9rTWFpEZgr0yZw NWKwRJNkVmctL5ZKlTszEUR7KwGP8F8FsrfvpIUQKVj3EfGwAEMPbwZCl w==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="326874002" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="326874002" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:18 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444230" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:12 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 5/9] drm/i915: Check for integer truncation on scatterlist creation Date: Fri, 23 Sep 2022 11:26:24 +0300 Message-Id: <20220923082628.3061408-6-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chris Wilson There is an impedance mismatch between the scatterlist API using unsigned int and our memory/page accounting in unsigned long. That is we may try to create a scatterlist for a large object that overflows returning a small table into which we try to fit very many pages. As the object size is under control of userspace, we have to be prudent and catch the conversion errors. To catch the implicit truncation as we switch from unsigned long into the scatterlist's unsigned int, we use overflows_type check and report E2BIG prior to the operation. This is already used in our create ioctls to indicate if the uABI request is simply too large for the backing store. Failing that type check, we have a second check at sg_alloc_table time to make sure the values we are passing into the scatterlist API are not truncated. It uses pgoff_t for locals that are dealing with page indices, in this case, the page count is the limit of the page index. And it uses safe_conversion() macro which performs a type conversion (cast) of an integer value into a new variable, checking that the destination is large enough to hold the source value. v2: Move added i915_utils's macro into drm_util header (Jani N) v5: Fix macros to be enclosed in parentheses for complex values Fix too long line warning v8: Replace safe_conversion() with check_assign() (Kees) Signed-off-by: Chris Wilson Signed-off-by: Gwan-gyeong Mun Cc: Tvrtko Ursulin Cc: Brian Welty Cc: Matthew Auld Cc: Thomas Hellstr=C3=B6m Reviewed-by: Nirmoy Das Reviewed-by: Mauro Carvalho Chehab Reviewed-by: Andrzej Hajda --- drivers/gpu/drm/i915/gem/i915_gem_internal.c | 6 ++++-- drivers/gpu/drm/i915/gem/i915_gem_object.h | 3 --- drivers/gpu/drm/i915/gem/i915_gem_phys.c | 4 ++++ drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 5 ++++- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 4 ++++ drivers/gpu/drm/i915/gem/i915_gem_userptr.c | 5 ++++- drivers/gpu/drm/i915/gvt/dmabuf.c | 9 +++++---- drivers/gpu/drm/i915/i915_scatterlist.h | 11 +++++++++++ 8 files changed, 36 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm= /i915/gem/i915_gem_internal.c index c698f95af15f..53fa27e1c950 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c @@ -37,10 +37,13 @@ static int i915_gem_object_get_pages_internal(struct dr= m_i915_gem_object *obj) struct sg_table *st; struct scatterlist *sg; unsigned int sg_page_sizes; - unsigned int npages; + pgoff_t npages; /* restricted by sg_alloc_table */ int max_order; gfp_t gfp; =20 + if (check_assign(obj->base.size >> PAGE_SHIFT, &npages)) + return -E2BIG; + max_order =3D MAX_ORDER; #ifdef CONFIG_SWIOTLB if (is_swiotlb_active(obj->base.dev->dev)) { @@ -67,7 +70,6 @@ static int i915_gem_object_get_pages_internal(struct drm_= i915_gem_object *obj) if (!st) return -ENOMEM; =20 - npages =3D obj->base.size / PAGE_SIZE; if (sg_alloc_table(st, npages, GFP_KERNEL)) { kfree(st); return -ENOMEM; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i= 915/gem/i915_gem_object.h index f2c4de31d563..b1f89b1cc0b2 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -26,9 +26,6 @@ enum intel_region_id; * this and catch if we ever need to fix it. In the meantime, if you do * spot such a local variable, please consider fixing! * - * Aside from our own locals (for which we have no excuse!): - * - sg_table embeds unsigned int for nents - * * We can check for invalidly typed locals with typecheck(), see for examp= le * i915_gem_object_get_sg(). */ diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i91= 5/gem/i915_gem_phys.c index 0d0e46dae559..88ba7266a3a5 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c @@ -28,6 +28,10 @@ static int i915_gem_object_get_pages_phys(struct drm_i91= 5_gem_object *obj) void *dst; int i; =20 + /* Contiguous chunk, with a single scatterlist element */ + if (overflows_type(obj->base.size, sg->length)) + return -E2BIG; + if (GEM_WARN_ON(i915_gem_object_needs_bit17_swizzle(obj))) return -EINVAL; =20 diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i9= 15/gem/i915_gem_shmem.c index f42ca1179f37..339b0a9cf2d0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -193,13 +193,16 @@ static int shmem_get_pages(struct drm_i915_gem_object= *obj) struct drm_i915_private *i915 =3D to_i915(obj->base.dev); struct intel_memory_region *mem =3D obj->mm.region; struct address_space *mapping =3D obj->base.filp->f_mapping; - const unsigned long page_count =3D obj->base.size / PAGE_SIZE; unsigned int max_segment =3D i915_sg_segment_size(); struct sg_table *st; struct sgt_iter sgt_iter; + pgoff_t page_count; struct page *page; int ret; =20 + if (check_assign(obj->base.size >> PAGE_SHIFT, &page_count)) + return -E2BIG; + /* * Assert that the object is not currently in any GPU domain. As it * wasn't in the GTT, there shouldn't be any way it could have been in diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915= /gem/i915_gem_ttm.c index 004fc7478b41..bf99d1f02bd9 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -792,6 +792,10 @@ static int i915_ttm_get_pages(struct drm_i915_gem_obje= ct *obj) { struct ttm_place requested, busy[I915_TTM_MAX_PLACEMENTS]; struct ttm_placement placement; + pgoff_t num_pages; + + if (check_assign(obj->base.size >> PAGE_SHIFT, &num_pages)) + return -E2BIG; =20 GEM_BUG_ON(obj->mm.n_placements > I915_TTM_MAX_PLACEMENTS); =20 diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/= i915/gem/i915_gem_userptr.c index 8423df021b71..48237e443863 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c @@ -128,13 +128,16 @@ static void i915_gem_object_userptr_drop_ref(struct d= rm_i915_gem_object *obj) =20 static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) { - const unsigned long num_pages =3D obj->base.size >> PAGE_SHIFT; unsigned int max_segment =3D i915_sg_segment_size(); struct sg_table *st; unsigned int sg_page_sizes; struct page **pvec; + pgoff_t num_pages; /* limited by sg_alloc_table_from_pages_segment */ int ret; =20 + if (check_assign(obj->base.size >> PAGE_SHIFT, &num_pages)) + return -E2BIG; + st =3D kmalloc(sizeof(*st), GFP_KERNEL); if (!st) return -ENOMEM; diff --git a/drivers/gpu/drm/i915/gvt/dmabuf.c b/drivers/gpu/drm/i915/gvt/d= mabuf.c index 01e54b45c5c1..bc6e823584ad 100644 --- a/drivers/gpu/drm/i915/gvt/dmabuf.c +++ b/drivers/gpu/drm/i915/gvt/dmabuf.c @@ -42,8 +42,7 @@ =20 #define GEN8_DECODE_PTE(pte) (pte & GENMASK_ULL(63, 12)) =20 -static int vgpu_gem_get_pages( - struct drm_i915_gem_object *obj) +static int vgpu_gem_get_pages(struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv =3D to_i915(obj->base.dev); struct intel_vgpu *vgpu; @@ -52,7 +51,10 @@ static int vgpu_gem_get_pages( int i, j, ret; gen8_pte_t __iomem *gtt_entries; struct intel_vgpu_fb_info *fb_info; - u32 page_num; + pgoff_t page_num; + + if (check_assign(obj->base.size >> PAGE_SHIFT, &page_num)) + return -E2BIG; =20 fb_info =3D (struct intel_vgpu_fb_info *)obj->gvt_info; if (drm_WARN_ON(&dev_priv->drm, !fb_info)) @@ -66,7 +68,6 @@ static int vgpu_gem_get_pages( if (unlikely(!st)) return -ENOMEM; =20 - page_num =3D obj->base.size >> PAGE_SHIFT; ret =3D sg_alloc_table(st, page_num, GFP_KERNEL); if (ret) { kfree(st); diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915= /i915_scatterlist.h index 9ddb3e743a3e..1d1802beb42b 100644 --- a/drivers/gpu/drm/i915/i915_scatterlist.h +++ b/drivers/gpu/drm/i915/i915_scatterlist.h @@ -220,4 +220,15 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(s= truct ttm_resource *res, u64 region_start, u32 page_alignment); =20 +/* Wrap scatterlist.h to sanity check for integer truncation */ +typedef unsigned int __sg_size_t; /* see linux/scatterlist.h */ +#define sg_alloc_table(sgt, nents, gfp) \ + overflows_type(nents, __sg_size_t) ? -E2BIG \ + : ((sg_alloc_table)(sgt, (__sg_size_t)(nents), gfp)) + +#define sg_alloc_table_from_pages_segment(sgt, pages, npages, offset, size= , max_segment, gfp) \ + overflows_type(npages, __sg_size_t) ? -E2BIG \ + : ((sg_alloc_table_from_pages_segment)(sgt, pages, (__sg_size_t)(npages)= , offset, \ + size, max_segment, gfp)) + #endif --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C444ECAAD8 for ; Fri, 23 Sep 2022 08:27:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231361AbiIWI1p (ORCPT ); Fri, 23 Sep 2022 04:27:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58970 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231367AbiIWI1a (ORCPT ); Fri, 23 Sep 2022 04:27:30 -0400 Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C2FB123850 for ; Fri, 23 Sep 2022 01:27:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921645; x=1695457645; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=08oKMcxxiTXt48DizpMHtSAF1zSfLPxCAGRIMbMjaVY=; b=fnAm1jNbRBR8QAAGHAkrXemq6dM3hDIWI0wr5oOF0uT3GF68GBnjLjJP 24oersmYvtQDOfePX5RMpITqPt7JlBq9lm533OmB4GbsfOskti6Lk8Mhm Ei8IapAonLvgtBksacJFUBej7L02DH5yiqzTlfLj0lbh4Mgz/T3WGVyHs G5U7iIY1JexaSigdm1wlLXzjbWfA1R6xdSQwP39iVu0aMSmxdy6G6fZmu G2+2zQ/WZiCsGgL1mkkO4FW4i/DhbHjz+supumrngZo7Mjzj15YCG1CnM lRuLivd2XRSQvyFmmAdOaha9yk+VbbkujxTci2Pai5QI09VVuVyY0eXhy w==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="301425993" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="301425993" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:24 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444250" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:18 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 6/9] drm/i915: Check for integer truncation on the configuration of ttm place Date: Fri, 23 Sep 2022 11:26:25 +0300 Message-Id: <20220923082628.3061408-7-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org There is an impedance mismatch between the first/last valid page frame number of ttm place in unsigned and our memory/page accounting in unsigned long. As the object size is under the control of userspace, we have to be prudent and catch the conversion errors. To catch the implicit truncation as we switch from unsigned long to unsigned, we use overflows_type check and report E2BIG or overflow_type prior to the operation. v3: Not to change execution inside a macro. (Mauro) Add safe_conversion_gem_bug_on() macro and remove temporal SAFE_CONVERSION() macro. v4: Fix unhandled GEM_BUG_ON() macro call from safe_conversion_gem_bug_on() v6: Fix to follow general use case for GEM_BUG_ON(). (Jani) v7: Fix to use WARN_ON() macro where GEM_BUG_ON() macro was used. (Jani) v8: Replace safe_conversion() with check_assign() (Kees) Signed-off-by: Gwan-gyeong Mun Cc: Chris Wilson Cc: Matthew Auld Cc: Thomas Hellstr=C3=B6m Cc: Jani Nikula Reviewed-by: Nirmoy Das (v2) Reviewed-by: Mauro Carvalho Chehab (v3) Reported-by: kernel test robot Reviewed-by: Andrzej Hajda (v5) --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 6 +++--- drivers/gpu/drm/i915/intel_region_ttm.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915= /gem/i915_gem_ttm.c index bf99d1f02bd9..e6bbc0f8b7e6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -140,14 +140,14 @@ i915_ttm_place_from_region(const struct intel_memory_= region *mr, if (flags & I915_BO_ALLOC_CONTIGUOUS) place->flags |=3D TTM_PL_FLAG_CONTIGUOUS; if (offset !=3D I915_BO_INVALID_OFFSET) { - place->fpfn =3D offset >> PAGE_SHIFT; - place->lpfn =3D place->fpfn + (size >> PAGE_SHIFT); + WARN_ON(check_assign(offset >> PAGE_SHIFT, &place->fpfn)); + WARN_ON(check_assign(place->fpfn + (size >> PAGE_SHIFT), &place->lpfn)); } else if (mr->io_size && mr->io_size < mr->total) { if (flags & I915_BO_ALLOC_GPU_ONLY) { place->flags |=3D TTM_PL_FLAG_TOPDOWN; } else { place->fpfn =3D 0; - place->lpfn =3D mr->io_size >> PAGE_SHIFT; + WARN_ON(check_assign(mr->io_size >> PAGE_SHIFT, &place->lpfn)); } } } diff --git a/drivers/gpu/drm/i915/intel_region_ttm.c b/drivers/gpu/drm/i915= /intel_region_ttm.c index 575d67bc6ffe..37a964b20b36 100644 --- a/drivers/gpu/drm/i915/intel_region_ttm.c +++ b/drivers/gpu/drm/i915/intel_region_ttm.c @@ -209,14 +209,23 @@ intel_region_ttm_resource_alloc(struct intel_memory_r= egion *mem, if (flags & I915_BO_ALLOC_CONTIGUOUS) place.flags |=3D TTM_PL_FLAG_CONTIGUOUS; if (offset !=3D I915_BO_INVALID_OFFSET) { - place.fpfn =3D offset >> PAGE_SHIFT; - place.lpfn =3D place.fpfn + (size >> PAGE_SHIFT); + if (WARN_ON(check_assign(offset >> PAGE_SHIFT, &place.fpfn))) { + ret =3D -E2BIG; + goto out; + } + if (WARN_ON(check_assign(place.fpfn + (size >> PAGE_SHIFT), &place.lpfn)= )) { + ret =3D -E2BIG; + goto out; + } } else if (mem->io_size && mem->io_size < mem->total) { if (flags & I915_BO_ALLOC_GPU_ONLY) { place.flags |=3D TTM_PL_FLAG_TOPDOWN; } else { place.fpfn =3D 0; - place.lpfn =3D mem->io_size >> PAGE_SHIFT; + if (WARN_ON(check_assign(mem->io_size >> PAGE_SHIFT, &place.lpfn))) { + ret =3D -E2BIG; + goto out; + } } } =20 @@ -224,6 +233,8 @@ intel_region_ttm_resource_alloc(struct intel_memory_reg= ion *mem, mock_bo.bdev =3D &mem->i915->bdev; =20 ret =3D man->func->alloc(man, &mock_bo, &place, &res); + +out: if (ret =3D=3D -ENOSPC) ret =3D -ENXIO; if (!ret) --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9DE28C6FA82 for ; Fri, 23 Sep 2022 08:28:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231378AbiIWI2Y (ORCPT ); Fri, 23 Sep 2022 04:28:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59044 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231418AbiIWI1q (ORCPT ); Fri, 23 Sep 2022 04:27:46 -0400 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9CD2A1DF08 for ; Fri, 23 Sep 2022 01:27:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921656; x=1695457656; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=fusilmdSQD+FIBKYeUukiHJrxKRQ3B5pPSTTQeO8rTk=; b=XGllR65w7VjGmtYJKPIZdNlwFwcTIJivfLo7MaAde21Td2N+yuYd+wqa URdK9OJDhY87koXdNcJtyBz+d3l8/kf4ttd8d5LOVFf62voDHZ7HQJNUt kxBuKlWQvwjVSqGloQWf1kp8dxsrbsCWYPdrNqGWtMG/V/I+KlaT7ITxE jumrLO++OgZugbqug3B4m0xv6Nlncje9iU4ELHDtRP+P9H3wqDvvhiDhi wMIKM1QvQs1c/YGPc85EwfVZOLhkH1g3BPMaxs4KahhIQ2TPrDyvk0UVY hIo5/DE5rO3RhbLkSnIuqqeP33v5IIm2h5UlVPRJCEyVUPj1XXryVCVER g==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="386833540" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="386833540" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:30 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444262" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:24 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 7/9] drm/i915: Check if the size is too big while creating shmem file Date: Fri, 23 Sep 2022 11:26:26 +0300 Message-Id: <20220923082628.3061408-8-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The __shmem_file_setup() function returns -EINVAL if size is greater than MAX_LFS_FILESIZE. To handle the same error as other code that returns -E2BIG when the size is too large, it add a code that returns -E2BIG when the size is larger than the size that can be handled. v4: If BITS_PER_LONG is 32, size > MAX_LFS_FILESIZE is always false, so it checks only when BITS_PER_LONG is 64. Signed-off-by: Gwan-gyeong Mun Cc: Chris Wilson Cc: Matthew Auld Cc: Thomas Hellstr=C3=B6m Reviewed-by: Nirmoy Das Reviewed-by: Mauro Carvalho Chehab Reported-by: kernel test robot Reviewed-by: Andrzej Hajda --- drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i9= 15/gem/i915_gem_shmem.c index 339b0a9cf2d0..ca30060e34ab 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -541,6 +541,20 @@ static int __create_shmem(struct drm_i915_private *i91= 5, =20 drm_gem_private_object_init(&i915->drm, obj, size); =20 + /* XXX: The __shmem_file_setup() function returns -EINVAL if size is + * greater than MAX_LFS_FILESIZE. + * To handle the same error as other code that returns -E2BIG when + * the size is too large, we add a code that returns -E2BIG when the + * size is larger than the size that can be handled. + * If BITS_PER_LONG is 32, size > MAX_LFS_FILESIZE is always false, + * so we only needs to check when BITS_PER_LONG is 64. + * If BITS_PER_LONG is 32, E2BIG checks are processed when + * i915_gem_object_size_2big() is called before init_object() callback + * is called. + */ + if (BITS_PER_LONG =3D=3D 64 && size > MAX_LFS_FILESIZE) + return -E2BIG; + if (i915->mm.gemfs) filp =3D shmem_file_setup_with_mnt(i915->mm.gemfs, "i915", size, flags); --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 813AFC6FA82 for ; Fri, 23 Sep 2022 08:28:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231339AbiIWI2v (ORCPT ); Fri, 23 Sep 2022 04:28:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59792 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231431AbiIWI2R (ORCPT ); Fri, 23 Sep 2022 04:28:17 -0400 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E48C11DF36 for ; Fri, 23 Sep 2022 01:27:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921661; x=1695457661; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=YqIgDiPhDFPxLISU3qiexRQnID3yCWHnQG5z64x4Sp8=; b=dgVarYZIseultyjU0fn3ZgiG0ztvd3jTGiiVFPkquB8r3/BbKJ1BKqPR SndZRMHhZ1hpX1O86c6oX4TYlWCVUKw/n+QouMP4LBIhOtPN5znWaq+dw PGXJ0QBamh+8CW9A8P7bACfi95J/S69nAZnlxdWeps00di/Bl7WZRN51m +qKWwXj38zjTlK63WfBcZPZIKtFIWqyGqfbhXOg9vfoFoJlIzbbPm4GyJ b+bqVcceydABgC9PaPXGR1pqy9b7ewYt03L2G4F5KMhubEr/tNpLYn4Jx HF1DZKxglWIknTNkV1dTlldMS5pp0DBRk9stq++I3ZfeDTHWmDrzlLqN7 Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="386833575" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="386833575" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:36 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444278" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:30 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 8/9] drm/i915: Use error code as -E2BIG when the size of gem ttm object is too large Date: Fri, 23 Sep 2022 11:26:27 +0300 Message-Id: <20220923082628.3061408-9-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The ttm_bo_init_reserved() functions returns -ENOSPC if the size is too big to add vma. The direct function that returns -ENOSPC is drm_mm_insert_node_= in_range(). To handle the same error as other code returning -E2BIG when the size is too large, it converts return value to -E2BIG. Signed-off-by: Gwan-gyeong Mun Cc: Chris Wilson Cc: Matthew Auld Cc: Thomas Hellstr=C3=B6m Reviewed-by: Nirmoy Das Reviewed-by: Mauro Carvalho Chehab Reviewed-by: Andrzej Hajda --- drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915= /gem/i915_gem_ttm.c index e6bbc0f8b7e6..62d3924a6377 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c @@ -1242,6 +1242,17 @@ int __i915_gem_ttm_object_init(struct intel_memory_r= egion *mem, ret =3D ttm_bo_init_reserved(&i915->bdev, i915_gem_to_ttm(obj), bo_type, &i915_sys_placement, page_size >> PAGE_SHIFT, &ctx, NULL, NULL, i915_ttm_bo_destroy); + + /* + * XXX: The ttm_bo_init_reserved() functions returns -ENOSPC if the size + * is too big to add vma. The direct function that returns -ENOSPC is + * drm_mm_insert_node_in_range(). To handle the same error as other code + * that returns -E2BIG when the size is too large, it converts -ENOSPC to + * -E2BIG. + */ + if (size >> PAGE_SHIFT > INT_MAX && ret =3D=3D -ENOSPC) + ret =3D -E2BIG; + if (ret) return i915_ttm_err_to_gem(ret); =20 --=20 2.37.1 From nobody Thu Apr 2 14:43:38 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 07A4AECAAD8 for ; Fri, 23 Sep 2022 08:28:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231425AbiIWI2z (ORCPT ); Fri, 23 Sep 2022 04:28:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59410 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231342AbiIWI2S (ORCPT ); Fri, 23 Sep 2022 04:28:18 -0400 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 80D9912384B for ; Fri, 23 Sep 2022 01:27:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1663921668; x=1695457668; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8kkjxfQ7mUK/V9Lc34jug0CHMM+mOcD38YV9RoicTgI=; b=VVwCgRoSCc1z4x2S6ORZabGBhOxqSeP5HAyY71y+Fg9Py2RVSfhMfMi7 1+99RyJ6sz37d0bOLjMg56P3Bb0rg+vM1CkmzniFe+ekjUCOBflbVNYyP yO9OtPAK1EFe+K41vW6hPXeCpMj6BFLfChKp7gL9QzzOcxmEG1K4LLTsz 8iGc0Unb6iBb13YhfNECa9U9ZMKfCC+iGlkbMXEsw3qm8VrKKyP35vjrl tFfPydYomZzUbCx1JpcqjM7kGqrkc4LT++7alPzCGFxdgFYdQhIJtKKPP fPSILUah8rlV/x9CBc5Bhbuo87yWz18Xt1xK7EksY8SJ9dx6Yg/xCor5C w==; X-IronPort-AV: E=McAfee;i="6500,9779,10478"; a="386833597" X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="386833597" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:40 -0700 X-IronPort-AV: E=Sophos;i="5.93,337,1654585200"; d="scan'208";a="622444299" Received: from ngoncia-mobl2.ger.corp.intel.com (HELO paris.ger.corp.intel.com) ([10.249.143.58]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2022 01:27:35 -0700 From: Gwan-gyeong Mun To: intel-gfx@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, mchehab@kernel.org, chris@chris-wilson.co.uk, matthew.auld@intel.com, thomas.hellstrom@linux.intel.com, jani.nikula@intel.com, nirmoy.das@intel.com, airlied@redhat.com, daniel@ffwll.ch, andi.shyti@linux.intel.com, andrzej.hajda@intel.com, keescook@chromium.org, mauro.chehab@linux.intel.com, linux@rasmusvillemoes.dk, vitor@massaru.org, dlatypov@google.com, ndesaulniers@google.com Subject: [PATCH v11 9/9] drm/i915: Remove truncation warning for large objects Date: Fri, 23 Sep 2022 11:26:28 +0300 Message-Id: <20220923082628.3061408-10-gwan-gyeong.mun@intel.com> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> References: <20220923082628.3061408-1-gwan-gyeong.mun@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Chris Wilson Having addressed the issues surrounding incorrect types for local variables and potential integer truncation in using the scatterlist API, we have closed all the loop holes we had previously identified with dangerously large object creation. As such, we can eliminate the warning put in place to remind us to complete the review. Signed-off-by: Chris Wilson Signed-off-by: Gwan-gyeong Mun Cc: Tvrtko Ursulin Cc: Brian Welty Cc: Matthew Auld Cc: Thomas Hellstr=C3=B6m Testcase: igt@gem_create@create-massive Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/4991 Reviewed-by: Nirmoy Das Reviewed-by: Mauro Carvalho Chehab Reviewed-by: Andrzej Hajda --- drivers/gpu/drm/i915/gem/i915_gem_object.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i= 915/gem/i915_gem_object.h index b1f89b1cc0b2..9a77fa95e771 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -20,25 +20,10 @@ =20 enum intel_region_id; =20 -/* - * XXX: There is a prevalence of the assumption that we fit the - * object's page count inside a 32bit _signed_ variable. Let's document - * this and catch if we ever need to fix it. In the meantime, if you do - * spot such a local variable, please consider fixing! - * - * We can check for invalidly typed locals with typecheck(), see for examp= le - * i915_gem_object_get_sg(). - */ -#define GEM_CHECK_SIZE_OVERFLOW(sz) \ - GEM_WARN_ON((sz) >> PAGE_SHIFT > INT_MAX) - static inline bool i915_gem_object_size_2big(u64 size) { struct drm_i915_gem_object *obj; =20 - if (GEM_CHECK_SIZE_OVERFLOW(size)) - return true; - if (overflows_type(size, obj->base.size)) return true; =20 --=20 2.37.1