From ce6616724fb425d6043d0dad6af996cd7c79bcc4 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Wed, 5 Jul 2023 23:51:27 +0200 Subject: [PATCH 1/6] ubsan: Clarify Kconfig text for CONFIG_UBSAN_TRAP Make it clearer in the one-line description and the verbose description text that CONFIG_UBSAN_TRAP as currently implemented involves a tradeoff of much less helpful oops messages in exchange for a smaller kernel image. (With the additional effect of turning UBSAN warnings into crashes, which may or may not be desired.) Signed-off-by: Jann Horn Link: https://lore.kernel.org/r/20230705215128.486054-1-jannh@google.com Signed-off-by: Kees Cook --- lib/Kconfig.ubsan | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index efae7e0119565..59e21bfec188c 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -13,7 +13,7 @@ menuconfig UBSAN if UBSAN config UBSAN_TRAP - bool "On Sanitizer warnings, abort the running kernel code" + bool "Abort on Sanitizer warnings (smaller kernel but less verbose)" depends on !COMPILE_TEST help Building kernels with Sanitizer features enabled tends to grow @@ -26,6 +26,14 @@ config UBSAN_TRAP the system. For some system builders this is an acceptable trade-off. + Also note that selecting Y will cause your kernel to Oops + with an "illegal instruction" error with no further details + when a UBSAN violation occurs. (Except on arm64, which will + report which Sanitizer failed.) This may make it hard to + determine whether an Oops was caused by UBSAN or to figure + out the details of a UBSAN violation. It makes the kernel log + output less useful for bug reports. + config CC_HAS_UBSAN_BOUNDS_STRICT def_bool $(cc-option,-fsanitize=bounds-strict) help From 8453e7924a1a9130f2b4d2c507de2cdc3892a5b5 Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Tue, 23 May 2023 02:14:25 +0000 Subject: [PATCH 2/6] soc: fsl: qe: Replace all non-returning strlcpy with strscpy strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. In an effort to remove strlcpy() completely [2], replace strlcpy() here with strscpy(). No return values were used, so direct replacement is safe. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230523021425.2406309-1-azeemshaikh38@gmail.com Signed-off-by: Kees Cook --- drivers/soc/fsl/qe/qe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c index b3c226eb5292f..58746e570d14c 100644 --- a/drivers/soc/fsl/qe/qe.c +++ b/drivers/soc/fsl/qe/qe.c @@ -524,7 +524,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) * saved microcode information and put in the new. */ memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); - strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id)); + strscpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id)); qe_firmware_info.extended_modes = be64_to_cpu(firmware->extended_modes); memcpy(qe_firmware_info.vtraps, firmware->vtraps, sizeof(firmware->vtraps)); @@ -599,7 +599,7 @@ struct qe_firmware_info *qe_get_firmware_info(void) /* Copy the data into qe_firmware_info*/ sprop = of_get_property(fw, "id", NULL); if (sprop) - strlcpy(qe_firmware_info.id, sprop, + strscpy(qe_firmware_info.id, sprop, sizeof(qe_firmware_info.id)); of_property_read_u64(fw, "extended-modes", From 630fdd592912614a72d00026fdadad72d9ef62eb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 26 Jul 2023 14:59:57 -0700 Subject: [PATCH 3/6] seq_file: seq_show_option_n() is used for precise sizes When seq_show_option_n() is used, it is for non-string memory that happens to be printable bytes. As such, we must use memcpy() to copy the bytes and then explicitly NUL-terminate the result. Cc: Andy Shevchenko Cc: Andrew Morton Cc: Al Viro Cc: Muchun Song Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230726215957.never.619-kees@kernel.org Signed-off-by: Kees Cook --- include/linux/seq_file.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index bd023dd38ae6f..386ab580b839b 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -249,18 +249,19 @@ static inline void seq_show_option(struct seq_file *m, const char *name, /** * seq_show_option_n - display mount options with appropriate escapes - * where @value must be a specific length. + * where @value must be a specific length (i.e. + * not NUL-terminated). * @m: the seq_file handle * @name: the mount option name * @value: the mount option name's value, cannot be NULL - * @length: the length of @value to display + * @length: the exact length of @value to display, must be constant expression * * This is a macro since this uses "length" to define the size of the * stack buffer. */ #define seq_show_option_n(m, name, value, length) { \ char val_buf[length + 1]; \ - strncpy(val_buf, value, length); \ + memcpy(val_buf, value, length); \ val_buf[length] = '\0'; \ seq_show_option(m, name, val_buf); \ } From 61ce78f29a694772c3b2c5c749589682dbdfec2d Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Mon, 3 Jul 2023 16:06:41 +0000 Subject: [PATCH 4/6] um: Remove strlcpy declaration strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. In an effort to remove strlcpy() completely [2], replace strlcpy() here with strscpy(). No return values were used, so direct replacement is safe. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230703160641.1790935-1-azeemshaikh38@gmail.com Signed-off-by: Kees Cook --- arch/um/include/shared/user.h | 1 - arch/um/os-Linux/umid.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/um/include/shared/user.h b/arch/um/include/shared/user.h index 0347a190429cd..981e11d8e0254 100644 --- a/arch/um/include/shared/user.h +++ b/arch/um/include/shared/user.h @@ -50,7 +50,6 @@ static inline int printk(const char *fmt, ...) #endif extern int in_aton(char *str); -extern size_t strlcpy(char *, const char *, size_t); extern size_t strlcat(char *, const char *, size_t); extern size_t strscpy(char *, const char *, size_t); diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 7a1abb8299307..288c422bfa964 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -40,7 +40,7 @@ static int __init make_uml_dir(void) __func__); goto err; } - strlcpy(dir, home, sizeof(dir)); + strscpy(dir, home, sizeof(dir)); uml_dir++; } strlcat(dir, uml_dir, sizeof(dir)); @@ -243,7 +243,7 @@ int __init set_umid(char *name) if (strlen(name) > UMID_LEN - 1) return -E2BIG; - strlcpy(umid, name, sizeof(umid)); + strscpy(umid, name, sizeof(umid)); return 0; } @@ -262,7 +262,7 @@ static int __init make_umid(void) make_uml_dir(); if (*umid == '\0') { - strlcpy(tmp, uml_dir, sizeof(tmp)); + strscpy(tmp, uml_dir, sizeof(tmp)); strlcat(tmp, "XXXXXX", sizeof(tmp)); fd = mkstemp(tmp); if (fd < 0) { From c9732f1461f947429f8ee9289792c5ffea793350 Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Mon, 3 Jul 2023 16:58:16 +0000 Subject: [PATCH 5/6] perf: Replace strlcpy with strscpy strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. In an effort to remove strlcpy() completely [2], replace strlcpy() here with strscpy(). No return values were used, so direct replacement is safe. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230703165817.2840457-1-azeemshaikh38@gmail.com Signed-off-by: Kees Cook --- kernel/events/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 78ae7b6f90fdb..2554f5fc70dcd 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -8249,7 +8249,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) unsigned int size; memset(comm, 0, sizeof(comm)); - strlcpy(comm, comm_event->task->comm, sizeof(comm)); + strscpy(comm, comm_event->task->comm, sizeof(comm)); size = ALIGN(strlen(comm)+1, sizeof(u64)); comm_event->comm = comm; @@ -8704,7 +8704,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) } cpy_name: - strlcpy(tmp, name, sizeof(tmp)); + strscpy(tmp, name, sizeof(tmp)); name = tmp; got_name: /* @@ -9128,7 +9128,7 @@ void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, bool unregister, ksym_type == PERF_RECORD_KSYMBOL_TYPE_UNKNOWN) goto err; - strlcpy(name, sym, KSYM_NAME_LEN); + strscpy(name, sym, KSYM_NAME_LEN); name_len = strlen(name) + 1; while (!IS_ALIGNED(name_len, sizeof(u64))) name[name_len++] = '\0'; From b6ed2f7758a558485ff889b4a3912fcb6abcf689 Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Thu, 6 Jul 2023 17:58:04 +0000 Subject: [PATCH 6/6] EISA: Replace all non-returning strlcpy with strscpy strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. In an effort to remove strlcpy() completely [2], replace strlcpy() here with strscpy(). No return values were used, so direct replacement is safe. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230706175804.2249018-1-azeemshaikh38@gmail.com Signed-off-by: Kees Cook # diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c # index 713582cc27d1..33f0ba11c6ad 100644 # --- a/drivers/eisa/eisa-bus.c # +++ b/drivers/eisa/eisa-bus.c # @@ -60,7 +60,7 @@ static void __init eisa_name_device(struct eisa_device *edev) # int i; # for (i = 0; i < EISA_INFOS; i++) { # if (!strcmp(edev->id.sig, eisa_table[i].id.sig)) { # - strlcpy(edev->pretty_name, # + strscpy(edev->pretty_name, # eisa_table[i].name, # sizeof(edev->pretty_name)); # return; --- drivers/eisa/eisa-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 713582cc27d1f..33f0ba11c6adf 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -60,7 +60,7 @@ static void __init eisa_name_device(struct eisa_device *edev) int i; for (i = 0; i < EISA_INFOS; i++) { if (!strcmp(edev->id.sig, eisa_table[i].id.sig)) { - strlcpy(edev->pretty_name, + strscpy(edev->pretty_name, eisa_table[i].name, sizeof(edev->pretty_name)); return;