* [PATCH 0/3] Fix FORTIFY=y UBSAN_LOCAL_BOUNDS=y @ 2022-08-30 20:53 Nick Desaulniers 2022-08-30 20:53 ` [PATCH 1/3] fortify: use __builtin_dynamic_object_size in __compiletime_strlen Nick Desaulniers ` (2 more replies) 0 siblings, 3 replies; 8+ messages in thread From: Nick Desaulniers @ 2022-08-30 20:53 UTC (permalink / raw) To: Kees Cook Cc: Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada, Nick Desaulniers With CONFIG_FORTIFY=y and CONFIG_UBSAN_LOCAL_BOUNDS=y enabled, we observe a runtime panic while running Android's Compatibility Test Suite's (CTS) android.hardware.input.cts.tests. This is stemming from a strlen() call in hidinput_allocate(). __builtin_object_size(str, 0 or 1) has interesting behavior for C strings when str is runtime dependent, and all possible values are known at compile time; it evaluates to the maximum of those sizes. This causes UBSAN_LOCAL_BOUNDS to insert faults for the smaller values, which we trip at runtime. Patch 1 adds a KCONFIG version check for __builtin_dynamic_object_size, and uses that in __compiletime_strlen rather than __builtin_object_size. Patch 2 and 3 are cosmetic cleanups, they're not as important to me as patch 1 is. Nick Desaulniers (3): fortify: use __builtin_dynamic_object_size in __compiletime_strlen fortify: cosmetic cleanups to __compiletime_strlen HID: avoid runtime call to strlen drivers/hid/hid-input.c | 13 ++++++++++++- include/linux/fortify-string.h | 15 ++++++++++----- init/Kconfig | 3 +++ 3 files changed, 25 insertions(+), 6 deletions(-) -- 2.37.2.672.g94769d06f0-goog ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/3] fortify: use __builtin_dynamic_object_size in __compiletime_strlen 2022-08-30 20:53 [PATCH 0/3] Fix FORTIFY=y UBSAN_LOCAL_BOUNDS=y Nick Desaulniers @ 2022-08-30 20:53 ` Nick Desaulniers 2022-08-31 18:34 ` Kees Cook 2022-08-30 20:53 ` [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen Nick Desaulniers 2022-08-30 20:53 ` [PATCH 3/3] HID: avoid runtime call to strlen Nick Desaulniers 2 siblings, 1 reply; 8+ messages in thread From: Nick Desaulniers @ 2022-08-30 20:53 UTC (permalink / raw) To: Kees Cook Cc: Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada, Nick Desaulniers With CONFIG_FORTIFY=y and CONFIG_UBSAN_LOCAL_BOUNDS=y enabled, we observe a runtime panic while running Android's Compatibility Test Suite's (CTS) android.hardware.input.cts.tests. This is stemming from a strlen() call in hidinput_allocate(). __compiletime_strlen is implemented in terms of __builtin_object_size(), then does an array access to check for NUL-termination. A quirk of __builtin_object_size() is that for strings whose values are runtime dependent, __builtin_object_size(str, 1 or 0) returns the maximum size of possible values when those sizes are determinable at compile time. Example: static const char *v = "FOO BAR"; static const char *y = "FOO BA"; unsigned long x (int z) { // Returns 8, which is: // max(__builtin_object_size(v, 1), __builtin_object_size(y, 1)) return __builtin_object_size(z ? v : y, 1); } So when FORTIFY is enabled, the current implementation of __compiletime_strlen will try to access beyond the end of y at runtime using the size of v. Mixed with UBSAN_LOCAL_BOUNDS we get a fault. hidinput_allocate() has a local C string whose value is control flow dependent on a switch statement, so __builtin_object_size(str, 1) evaluates to the maximum string length, making all other cases fault on the last character check. hidinput_allocate() could be cleaned up to avoid runtime calls to strlen() since the local variable can only have literal values, so there's no benefit to trying to fortify the strlen call site there. Add a Kconfig check for __builtin_dynamic_object_size(), then use that when available (gcc-12+, all supported versions of clang) which avoids this surprising behavior. Suggested-by: Kees Cook <keescook@chromium.org> Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> --- include/linux/fortify-string.h | 8 +++++++- init/Kconfig | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index 3b401fa0f374..c5adad596a3f 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -14,11 +14,17 @@ void __read_overflow2_field(size_t avail, size_t wanted) __compiletime_warning(" void __write_overflow(void) __compiletime_error("detected write beyond size of object (1st parameter)"); void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning("detected write beyond size of field (1st parameter); maybe use struct_group()?"); +#ifdef CONFIG_CC_HAS_BUILTIN_DYNAMIC_OBJECT_SIZE +#define __object_size __builtin_dynamic_object_size +#else +#define __object_size __builtin_object_size +#endif + #define __compiletime_strlen(p) \ ({ \ unsigned char *__p = (unsigned char *)(p); \ size_t __ret = (size_t)-1; \ - size_t __p_size = __builtin_object_size(p, 1); \ + size_t __p_size = __object_size(p, 1); \ if (__p_size != (size_t)-1) { \ size_t __p_len = __p_size - 1; \ if (__builtin_constant_p(__p[__p_len]) && \ diff --git a/init/Kconfig b/init/Kconfig index 532362fcfe31..87dd31aa54ad 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -876,6 +876,9 @@ config ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH config CC_HAS_INT128 def_bool !$(cc-option,$(m64-flag) -D__SIZEOF_INT128__=0) && 64BIT +config CC_HAS_BUILTIN_DYNAMIC_OBJECT_SIZE + def_bool !CC_IS_GCC || GCC_VERSION >= 120000 + config CC_IMPLICIT_FALLTHROUGH string default "-Wimplicit-fallthrough=5" if CC_IS_GCC && $(cc-option,-Wimplicit-fallthrough=5) -- 2.37.2.672.g94769d06f0-goog ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/3] fortify: use __builtin_dynamic_object_size in __compiletime_strlen 2022-08-30 20:53 ` [PATCH 1/3] fortify: use __builtin_dynamic_object_size in __compiletime_strlen Nick Desaulniers @ 2022-08-31 18:34 ` Kees Cook 0 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2022-08-31 18:34 UTC (permalink / raw) To: Nick Desaulniers Cc: Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada On Tue, Aug 30, 2022 at 01:53:07PM -0700, Nick Desaulniers wrote: > With CONFIG_FORTIFY=y and CONFIG_UBSAN_LOCAL_BOUNDS=y enabled, we > observe a runtime panic while running Android's Compatibility Test > Suite's (CTS) android.hardware.input.cts.tests. This is stemming from a > strlen() call in hidinput_allocate(). > > __compiletime_strlen is implemented in terms of __builtin_object_size(), > then does an array access to check for NUL-termination. A quirk of > __builtin_object_size() is that for strings whose values are runtime > dependent, __builtin_object_size(str, 1 or 0) returns the maximum size > of possible values when those sizes are determinable at compile time. > Example: > > static const char *v = "FOO BAR"; > static const char *y = "FOO BA"; > unsigned long x (int z) { > // Returns 8, which is: > // max(__builtin_object_size(v, 1), __builtin_object_size(y, 1)) > return __builtin_object_size(z ? v : y, 1); > } > > So when FORTIFY is enabled, the current implementation of > __compiletime_strlen will try to access beyond the end of y at runtime > using the size of v. Mixed with UBSAN_LOCAL_BOUNDS we get a fault. > > hidinput_allocate() has a local C string whose value is control flow > dependent on a switch statement, so __builtin_object_size(str, 1) > evaluates to the maximum string length, making all other cases fault on > the last character check. hidinput_allocate() could be cleaned up to > avoid runtime calls to strlen() since the local variable can only have > literal values, so there's no benefit to trying to fortify the strlen > call site there. > > Add a Kconfig check for __builtin_dynamic_object_size(), then use that > when available (gcc-12+, all supported versions of clang) which avoids > this surprising behavior. > > Suggested-by: Kees Cook <keescook@chromium.org> > Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> > --- > include/linux/fortify-string.h | 8 +++++++- > init/Kconfig | 3 +++ > 2 files changed, 10 insertions(+), 1 deletion(-) > > diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h > index 3b401fa0f374..c5adad596a3f 100644 > --- a/include/linux/fortify-string.h > +++ b/include/linux/fortify-string.h > @@ -14,11 +14,17 @@ void __read_overflow2_field(size_t avail, size_t wanted) __compiletime_warning(" > void __write_overflow(void) __compiletime_error("detected write beyond size of object (1st parameter)"); > void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning("detected write beyond size of field (1st parameter); maybe use struct_group()?"); > > +#ifdef CONFIG_CC_HAS_BUILTIN_DYNAMIC_OBJECT_SIZE > +#define __object_size __builtin_dynamic_object_size > +#else > +#define __object_size __builtin_object_size > +#endif Instead of a Kconfig, how about just: #if __has_builtin(__builtin_dynamic_object_size) # define __object_size __builtin_dynamic_object_size #else # define __object_size __builtin_object_size #endif ? > + > #define __compiletime_strlen(p) \ > ({ \ > unsigned char *__p = (unsigned char *)(p); \ > size_t __ret = (size_t)-1; \ > - size_t __p_size = __builtin_object_size(p, 1); \ > + size_t __p_size = __object_size(p, 1); \ > if (__p_size != (size_t)-1) { \ > size_t __p_len = __p_size - 1; \ > if (__builtin_constant_p(__p[__p_len]) && \ The fact that __builtin_object_size() will actually span control flow, and produce a size-inclusive result on the possible inputs is ... surprising and potentially quite problematic. But I'm satisfied that bdos appears to fix it here (since the "compiletime"ness will still get filtered by the __builtin_constant_p() check). -Kees -- Kees Cook ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen 2022-08-30 20:53 [PATCH 0/3] Fix FORTIFY=y UBSAN_LOCAL_BOUNDS=y Nick Desaulniers 2022-08-30 20:53 ` [PATCH 1/3] fortify: use __builtin_dynamic_object_size in __compiletime_strlen Nick Desaulniers @ 2022-08-30 20:53 ` Nick Desaulniers 2022-08-31 13:13 ` kernel test robot 2022-08-31 19:06 ` Kees Cook 2022-08-30 20:53 ` [PATCH 3/3] HID: avoid runtime call to strlen Nick Desaulniers 2 siblings, 2 replies; 8+ messages in thread From: Nick Desaulniers @ 2022-08-30 20:53 UTC (permalink / raw) To: Kees Cook Cc: Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada, Nick Desaulniers Two things I noticed in __compiletime_strlen: 1. A temporary, __p, is created+used to avoid repeated side effects from multiple evaluation of the macro parameter, but the macro parameter was being used accidentally in __builtin_object_size. 2. The temporary has a curious signedness and const-less qualification. Just use __auto_type. 3. (size_t)-1 is perhaps more readable as -1UL. 4. __p_size == -1UL when __builtin_object_size can't evaluate the object size at compile time. We could just reuse __ret and use one less variable here. Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> --- include/linux/fortify-string.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index c5adad596a3f..aaf73575050f 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -22,11 +22,10 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning(" #define __compiletime_strlen(p) \ ({ \ - unsigned char *__p = (unsigned char *)(p); \ - size_t __ret = (size_t)-1; \ - size_t __p_size = __object_size(p, 1); \ - if (__p_size != (size_t)-1) { \ - size_t __p_len = __p_size - 1; \ + __auto_type __p = (p); \ + size_t __ret = __object_size(__p, 1); \ + if (__ret != -1UL) { \ + size_t __p_len = __ret - 1; \ if (__builtin_constant_p(__p[__p_len]) && \ __p[__p_len] == '\0') \ __ret = __builtin_strlen(__p); \ -- 2.37.2.672.g94769d06f0-goog ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen 2022-08-30 20:53 ` [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen Nick Desaulniers @ 2022-08-31 13:13 ` kernel test robot 2022-08-31 19:06 ` Kees Cook 1 sibling, 0 replies; 8+ messages in thread From: kernel test robot @ 2022-08-31 13:13 UTC (permalink / raw) To: Nick Desaulniers, Kees Cook Cc: kbuild-all, Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada, Nick Desaulniers Hi Nick, I love your patch! Perhaps something to improve: [auto build test WARNING on kees/for-next/hardening] [also build test WARNING on kees/for-next/pstore hid/for-next linus/master v6.0-rc3 next-20220831] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Nick-Desaulniers/Fix-FORTIFY-y-UBSAN_LOCAL_BOUNDS-y/20220831-045536 base: https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening config: x86_64-randconfig-a004 (https://download.01.org/0day-ci/archive/20220831/202208312049.JxYsAiD2-lkp@intel.com/config) compiler: gcc-11 (Debian 11.3.0-5) 11.3.0 reproduce (this is a W=1 build): # https://github.com/intel-lab-lkp/linux/commit/ab66e7d1d8a90f6addac0da9b3ae13d77f095f76 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Nick-Desaulniers/Fix-FORTIFY-y-UBSAN_LOCAL_BOUNDS-y/20220831-045536 git checkout ab66e7d1d8a90f6addac0da9b3ae13d77f095f76 # save the config file mkdir build_dir && cp config build_dir/.config make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/mtd/ubi/ If you fix the issue, kindly add following tag where applicable Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): drivers/mtd/ubi/cdev.c: In function 'rename_volumes': >> drivers/mtd/ubi/cdev.c:710:61: warning: array subscript -1 is below array bounds of 'struct <anonymous>[32]' [-Warray-bounds] 710 | if (req->ents[i].vol_id == req->ents[n].vol_id) { | ~~~~~~~~~^~~ In file included from drivers/mtd/ubi/cdev.c:33: include/uapi/mtd/ubi-user.h:404:11: note: while referencing 'ents' 404 | } ents[UBI_MAX_RNVOL]; | ^~~~ drivers/mtd/ubi/cdev.c:715:68: warning: array subscript -1 is below array bounds of 'struct <anonymous>[32]' [-Warray-bounds] 715 | if (!strcmp(req->ents[i].name, req->ents[n].name)) { | ~~~~~~~~~~~~^~~~~ In file included from drivers/mtd/ubi/cdev.c:33: include/uapi/mtd/ubi-user.h:404:11: note: while referencing 'ents' 404 | } ents[UBI_MAX_RNVOL]; | ^~~~ vim +710 drivers/mtd/ubi/cdev.c 801c135ce73d5d Artem B. Bityutskiy 2006-06-27 668 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 669 /** f40ac9cdf69912 Artem Bityutskiy 2008-07-13 670 * rename_volumes - rename UBI volumes. f40ac9cdf69912 Artem Bityutskiy 2008-07-13 671 * @ubi: UBI device description object f40ac9cdf69912 Artem Bityutskiy 2008-07-13 672 * @req: volumes re-name request f40ac9cdf69912 Artem Bityutskiy 2008-07-13 673 * f40ac9cdf69912 Artem Bityutskiy 2008-07-13 674 * This is a helper function for the volume re-name IOCTL which validates the f40ac9cdf69912 Artem Bityutskiy 2008-07-13 675 * the request, opens the volume and calls corresponding volumes management f40ac9cdf69912 Artem Bityutskiy 2008-07-13 676 * function. Returns zero in case of success and a negative error code in case f40ac9cdf69912 Artem Bityutskiy 2008-07-13 677 * of failure. f40ac9cdf69912 Artem Bityutskiy 2008-07-13 678 */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 679 static int rename_volumes(struct ubi_device *ubi, f40ac9cdf69912 Artem Bityutskiy 2008-07-13 680 struct ubi_rnvol_req *req) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 681 { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 682 int i, n, err; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 683 struct list_head rename_list; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 684 struct ubi_rename_entry *re, *re1; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 685 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 686 if (req->count < 0 || req->count > UBI_MAX_RNVOL) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 687 return -EINVAL; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 688 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 689 if (req->count == 0) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 690 return 0; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 691 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 692 /* Validate volume IDs and names in the request */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 693 for (i = 0; i < req->count; i++) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 694 if (req->ents[i].vol_id < 0 || f40ac9cdf69912 Artem Bityutskiy 2008-07-13 695 req->ents[i].vol_id >= ubi->vtbl_slots) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 696 return -EINVAL; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 697 if (req->ents[i].name_len < 0) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 698 return -EINVAL; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 699 if (req->ents[i].name_len > UBI_VOL_NAME_MAX) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 700 return -ENAMETOOLONG; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 701 req->ents[i].name[req->ents[i].name_len] = '\0'; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 702 n = strlen(req->ents[i].name); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 703 if (n != req->ents[i].name_len) 7fbbd05799976c Dan Carpenter 2014-09-19 704 return -EINVAL; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 705 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 706 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 707 /* Make sure volume IDs and names are unique */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 708 for (i = 0; i < req->count - 1; i++) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 709 for (n = i + 1; n < req->count; n++) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 @710 if (req->ents[i].vol_id == req->ents[n].vol_id) { 326087033108e7 Tanya Brokhman 2014-10-20 711 ubi_err(ubi, "duplicated volume id %d", f40ac9cdf69912 Artem Bityutskiy 2008-07-13 712 req->ents[i].vol_id); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 713 return -EINVAL; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 714 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 715 if (!strcmp(req->ents[i].name, req->ents[n].name)) { 326087033108e7 Tanya Brokhman 2014-10-20 716 ubi_err(ubi, "duplicated volume name \"%s\"", f40ac9cdf69912 Artem Bityutskiy 2008-07-13 717 req->ents[i].name); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 718 return -EINVAL; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 719 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 720 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 721 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 722 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 723 /* Create the re-name list */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 724 INIT_LIST_HEAD(&rename_list); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 725 for (i = 0; i < req->count; i++) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 726 int vol_id = req->ents[i].vol_id; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 727 int name_len = req->ents[i].name_len; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 728 const char *name = req->ents[i].name; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 729 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 730 re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 731 if (!re) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 732 err = -ENOMEM; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 733 goto out_free; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 734 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 735 892abde56c1c5a Richard Weinberger 2014-11-24 736 re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_METAONLY); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 737 if (IS_ERR(re->desc)) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 738 err = PTR_ERR(re->desc); 326087033108e7 Tanya Brokhman 2014-10-20 739 ubi_err(ubi, "cannot open volume %d, error %d", 326087033108e7 Tanya Brokhman 2014-10-20 740 vol_id, err); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 741 kfree(re); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 742 goto out_free; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 743 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 744 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 745 /* Skip this re-naming if the name does not really change */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 746 if (re->desc->vol->name_len == name_len && f40ac9cdf69912 Artem Bityutskiy 2008-07-13 747 !memcmp(re->desc->vol->name, name, name_len)) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 748 ubi_close_volume(re->desc); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 749 kfree(re); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 750 continue; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 751 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 752 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 753 re->new_name_len = name_len; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 754 memcpy(re->new_name, name, name_len); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 755 list_add_tail(&re->list, &rename_list); 719bb84017fcfc Artem Bityutskiy 2012-08-27 756 dbg_gen("will rename volume %d from \"%s\" to \"%s\"", f40ac9cdf69912 Artem Bityutskiy 2008-07-13 757 vol_id, re->desc->vol->name, name); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 758 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 759 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 760 if (list_empty(&rename_list)) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 761 return 0; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 762 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 763 /* Find out the volumes which have to be removed */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 764 list_for_each_entry(re, &rename_list, list) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 765 struct ubi_volume_desc *desc; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 766 int no_remove_needed = 0; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 767 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 768 /* f40ac9cdf69912 Artem Bityutskiy 2008-07-13 769 * Volume @re->vol_id is going to be re-named to f40ac9cdf69912 Artem Bityutskiy 2008-07-13 770 * @re->new_name, while its current name is @name. If a volume f40ac9cdf69912 Artem Bityutskiy 2008-07-13 771 * with name @re->new_name currently exists, it has to be f40ac9cdf69912 Artem Bityutskiy 2008-07-13 772 * removed, unless it is also re-named in the request (@req). f40ac9cdf69912 Artem Bityutskiy 2008-07-13 773 */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 774 list_for_each_entry(re1, &rename_list, list) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 775 if (re->new_name_len == re1->desc->vol->name_len && f40ac9cdf69912 Artem Bityutskiy 2008-07-13 776 !memcmp(re->new_name, re1->desc->vol->name, f40ac9cdf69912 Artem Bityutskiy 2008-07-13 777 re1->desc->vol->name_len)) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 778 no_remove_needed = 1; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 779 break; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 780 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 781 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 782 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 783 if (no_remove_needed) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 784 continue; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 785 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 786 /* f40ac9cdf69912 Artem Bityutskiy 2008-07-13 787 * It seems we need to remove volume with name @re->new_name, f40ac9cdf69912 Artem Bityutskiy 2008-07-13 788 * if it exists. f40ac9cdf69912 Artem Bityutskiy 2008-07-13 789 */ f2863c54f30ccc Artem Bityutskiy 2008-12-28 790 desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name, f2863c54f30ccc Artem Bityutskiy 2008-12-28 791 UBI_EXCLUSIVE); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 792 if (IS_ERR(desc)) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 793 err = PTR_ERR(desc); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 794 if (err == -ENODEV) f40ac9cdf69912 Artem Bityutskiy 2008-07-13 795 /* Re-naming into a non-existing volume name */ f40ac9cdf69912 Artem Bityutskiy 2008-07-13 796 continue; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 797 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 798 /* The volume exists but busy, or an error occurred */ 326087033108e7 Tanya Brokhman 2014-10-20 799 ubi_err(ubi, "cannot open volume \"%s\", error %d", f40ac9cdf69912 Artem Bityutskiy 2008-07-13 800 re->new_name, err); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 801 goto out_free; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 802 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 803 01ebc12f5f2e88 Julia Lawall 2010-08-07 804 re1 = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); 01ebc12f5f2e88 Julia Lawall 2010-08-07 805 if (!re1) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 806 err = -ENOMEM; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 807 ubi_close_volume(desc); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 808 goto out_free; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 809 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 810 01ebc12f5f2e88 Julia Lawall 2010-08-07 811 re1->remove = 1; 01ebc12f5f2e88 Julia Lawall 2010-08-07 812 re1->desc = desc; 01ebc12f5f2e88 Julia Lawall 2010-08-07 813 list_add(&re1->list, &rename_list); 719bb84017fcfc Artem Bityutskiy 2012-08-27 814 dbg_gen("will remove volume %d, name \"%s\"", 01ebc12f5f2e88 Julia Lawall 2010-08-07 815 re1->desc->vol->vol_id, re1->desc->vol->name); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 816 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 817 f089c0b28cdba1 Artem Bityutskiy 2009-05-07 818 mutex_lock(&ubi->device_mutex); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 819 err = ubi_rename_volumes(ubi, &rename_list); f089c0b28cdba1 Artem Bityutskiy 2009-05-07 820 mutex_unlock(&ubi->device_mutex); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 821 f40ac9cdf69912 Artem Bityutskiy 2008-07-13 822 out_free: f40ac9cdf69912 Artem Bityutskiy 2008-07-13 823 list_for_each_entry_safe(re, re1, &rename_list, list) { f40ac9cdf69912 Artem Bityutskiy 2008-07-13 824 ubi_close_volume(re->desc); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 825 list_del(&re->list); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 826 kfree(re); f40ac9cdf69912 Artem Bityutskiy 2008-07-13 827 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 828 return err; f40ac9cdf69912 Artem Bityutskiy 2008-07-13 829 } f40ac9cdf69912 Artem Bityutskiy 2008-07-13 830 -- 0-DAY CI Kernel Test Service https://01.org/lkp ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen 2022-08-30 20:53 ` [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen Nick Desaulniers 2022-08-31 13:13 ` kernel test robot @ 2022-08-31 19:06 ` Kees Cook 1 sibling, 0 replies; 8+ messages in thread From: Kees Cook @ 2022-08-31 19:06 UTC (permalink / raw) To: Nick Desaulniers Cc: Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada On Tue, Aug 30, 2022 at 01:53:08PM -0700, Nick Desaulniers wrote: > Two things I noticed in __compiletime_strlen: Four? :) > 1. A temporary, __p, is created+used to avoid repeated side effects from > multiple evaluation of the macro parameter, but the macro parameter > was being used accidentally in __builtin_object_size. __builtin_object_size(), like sizeof() but unlike __builtin_strlen(), will not evaluate side-effects: https://godbolt.org/z/Yaa1z7YvK And using bos on __p will sometimes mask the actual object, so p needs to stay the argument. > 2. The temporary has a curious signedness and const-less qualification. > Just use __auto_type. __auto_type is pretty rare in the kernel, but does provide the removal of "const". Even though the kernel builds with -Wno-pointer-sign, the explicit case does fix a potential warnings about signedness differences, not just const differences, for __builtin_strlen() which requires "const char *", but many arguments are "unsigned char *", "u8 *", etc. Is __auto_type more readable than the explicit cast? It does seem to work fine. > 3. (size_t)-1 is perhaps more readable as -1UL. That's true, though I kind of prefer (size_t)-1, though yes, it appears to be the extreme minority in the kernel. > 4. __p_size == -1UL when __builtin_object_size can't evaluate the > object size at compile time. We could just reuse __ret and use one > less variable here. This seems to get entire optimized away by the compiler? I think it's more readable to keep the explicit variable. -Kees > > Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> > --- > include/linux/fortify-string.h | 9 ++++----- > 1 file changed, 4 insertions(+), 5 deletions(-) > > diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h > index c5adad596a3f..aaf73575050f 100644 > --- a/include/linux/fortify-string.h > +++ b/include/linux/fortify-string.h > @@ -22,11 +22,10 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning(" > > #define __compiletime_strlen(p) \ > ({ \ > - unsigned char *__p = (unsigned char *)(p); \ > - size_t __ret = (size_t)-1; \ > - size_t __p_size = __object_size(p, 1); \ > - if (__p_size != (size_t)-1) { \ > - size_t __p_len = __p_size - 1; \ > + __auto_type __p = (p); \ > + size_t __ret = __object_size(__p, 1); \ > + if (__ret != -1UL) { \ > + size_t __p_len = __ret - 1; \ > if (__builtin_constant_p(__p[__p_len]) && \ > __p[__p_len] == '\0') \ > __ret = __builtin_strlen(__p); \ > -- > 2.37.2.672.g94769d06f0-goog > -- Kees Cook ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 3/3] HID: avoid runtime call to strlen 2022-08-30 20:53 [PATCH 0/3] Fix FORTIFY=y UBSAN_LOCAL_BOUNDS=y Nick Desaulniers 2022-08-30 20:53 ` [PATCH 1/3] fortify: use __builtin_dynamic_object_size in __compiletime_strlen Nick Desaulniers 2022-08-30 20:53 ` [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen Nick Desaulniers @ 2022-08-30 20:53 ` Nick Desaulniers 2022-08-31 6:05 ` Greg KH 2 siblings, 1 reply; 8+ messages in thread From: Nick Desaulniers @ 2022-08-30 20:53 UTC (permalink / raw) To: Kees Cook Cc: Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada, Nick Desaulniers While looking into a CONFIG_FORTIFY=y related bug, I noticed that hid_allocate calls strlen() on a local C string variable. This variable can only have literal string values. There is no benefit to having FORTIFY have this be a checked strlen call, because these are literal values. By calling strlen() explicitly in the branches of a switch, the compiler can evaluate strlen("literal value") at compile time, rather than at runtime. Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> --- drivers/hid/hid-input.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 48c1c02c69f4..9ad3cc88c26b 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1922,12 +1922,15 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, switch (application) { case HID_GD_KEYBOARD: suffix = "Keyboard"; + suffix_len = strlen(suffix); break; case HID_GD_KEYPAD: suffix = "Keypad"; + suffix_len = strlen(suffix); break; case HID_GD_MOUSE: suffix = "Mouse"; + suffix_len = strlen(suffix); break; case HID_DG_PEN: /* @@ -1938,36 +1941,44 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, * will have to change it and the test suite will not be happy. */ suffix = "Stylus"; + suffix_len = strlen(suffix); break; case HID_DG_STYLUS: suffix = "Pen"; + suffix_len = strlen(suffix); break; case HID_DG_TOUCHSCREEN: suffix = "Touchscreen"; + suffix_len = strlen(suffix); break; case HID_DG_TOUCHPAD: suffix = "Touchpad"; + suffix_len = strlen(suffix); break; case HID_GD_SYSTEM_CONTROL: suffix = "System Control"; + suffix_len = strlen(suffix); break; case HID_CP_CONSUMER_CONTROL: suffix = "Consumer Control"; + suffix_len = strlen(suffix); break; case HID_GD_WIRELESS_RADIO_CTLS: suffix = "Wireless Radio Control"; + suffix_len = strlen(suffix); break; case HID_GD_SYSTEM_MULTIAXIS: suffix = "System Multi Axis"; + suffix_len = strlen(suffix); break; default: + suffix_len = 0; break; } } if (suffix) { name_len = strlen(hid->name); - suffix_len = strlen(suffix); if ((name_len < suffix_len) || strcmp(hid->name + name_len - suffix_len, suffix)) { hidinput->name = kasprintf(GFP_KERNEL, "%s %s", -- 2.37.2.672.g94769d06f0-goog ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 3/3] HID: avoid runtime call to strlen 2022-08-30 20:53 ` [PATCH 3/3] HID: avoid runtime call to strlen Nick Desaulniers @ 2022-08-31 6:05 ` Greg KH 0 siblings, 0 replies; 8+ messages in thread From: Greg KH @ 2022-08-31 6:05 UTC (permalink / raw) To: Nick Desaulniers Cc: Kees Cook, Nathan Chancellor, Tom Rix, linux-hardening, linux-kernel, llvm, Jiri Kosina, Benjamin Tissoires, linux-input, Masahiro Yamada On Tue, Aug 30, 2022 at 01:53:09PM -0700, Nick Desaulniers wrote: > While looking into a CONFIG_FORTIFY=y related bug, I noticed that > hid_allocate calls strlen() on a local C string variable. This variable > can only have literal string values. There is no benefit to having > FORTIFY have this be a checked strlen call, because these are literal > values. By calling strlen() explicitly in the branches of a switch, the > compiler can evaluate strlen("literal value") at compile time, rather > than at runtime. > > Signed-off-by: Nick Desaulniers <ndesaulniers@google.com> > --- > drivers/hid/hid-input.c | 13 ++++++++++++- > 1 file changed, 12 insertions(+), 1 deletion(-) > > diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c > index 48c1c02c69f4..9ad3cc88c26b 100644 > --- a/drivers/hid/hid-input.c > +++ b/drivers/hid/hid-input.c > @@ -1922,12 +1922,15 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid, > switch (application) { > case HID_GD_KEYBOARD: > suffix = "Keyboard"; > + suffix_len = strlen(suffix); > break; > case HID_GD_KEYPAD: > suffix = "Keypad"; > + suffix_len = strlen(suffix); > break; > case HID_GD_MOUSE: > suffix = "Mouse"; > + suffix_len = strlen(suffix); <snip> This seems ripe for someone to come along and go "look at this cleanup patch where I move all of this duplicated code to below it in one line!" As this is a compiler bug, why not fix the compiler? Or at least put a comment in here saying why this looks so odd to prevent it from being changed in the future. thanks, greg k-h ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2022-08-31 19:06 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2022-08-30 20:53 [PATCH 0/3] Fix FORTIFY=y UBSAN_LOCAL_BOUNDS=y Nick Desaulniers 2022-08-30 20:53 ` [PATCH 1/3] fortify: use __builtin_dynamic_object_size in __compiletime_strlen Nick Desaulniers 2022-08-31 18:34 ` Kees Cook 2022-08-30 20:53 ` [PATCH 2/3] fortify: cosmetic cleanups to __compiletime_strlen Nick Desaulniers 2022-08-31 13:13 ` kernel test robot 2022-08-31 19:06 ` Kees Cook 2022-08-30 20:53 ` [PATCH 3/3] HID: avoid runtime call to strlen Nick Desaulniers 2022-08-31 6:05 ` Greg KH
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).