Merge 87caef4220 ("Merge tag 'hardening-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux") into android-mainline
Steps on the way to 6.10-rc1 Change-Id: Ic16b90c2a414259ef399577fcd12e2781c069032 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
+1
-2
@@ -8463,8 +8463,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/har
|
||||
F: include/linux/fortify-string.h
|
||||
F: lib/fortify_kunit.c
|
||||
F: lib/memcpy_kunit.c
|
||||
F: lib/strcat_kunit.c
|
||||
F: lib/strscpy_kunit.c
|
||||
F: lib/test_fortify/*
|
||||
F: scripts/test_fortify.sh
|
||||
K: \b__NO_FORTIFY\b
|
||||
@@ -22698,6 +22696,7 @@ F: include/linux/ubsan.h
|
||||
F: lib/Kconfig.ubsan
|
||||
F: lib/test_ubsan.c
|
||||
F: lib/ubsan.c
|
||||
F: lib/ubsan.h
|
||||
F: scripts/Makefile.ubsan
|
||||
K: \bARCH_HAS_UBSAN\b
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
|
||||
# Software Shadow Stack or PAC
|
||||
CONFIG_SHADOW_CALL_STACK=y
|
||||
CONFIG_UNWIND_PATCH_PAC_INTO_SCS=y
|
||||
|
||||
# Pointer authentication (ARMv8.3 and later). If hardware actually supports
|
||||
# it, one can turn off CONFIG_STACKPROTECTOR_STRONG with this enabled.
|
||||
|
||||
@@ -10,5 +10,8 @@ CONFIG_INTEL_IOMMU_DEFAULT_ON=y
|
||||
CONFIG_INTEL_IOMMU_SVM=y
|
||||
CONFIG_AMD_IOMMU=y
|
||||
|
||||
# Enforce CET Indirect Branch Tracking in the kernel.
|
||||
CONFIG_X86_KERNEL_IBT=y
|
||||
|
||||
# Enable CET Shadow Stack for userspace.
|
||||
CONFIG_X86_USER_SHADOW_STACK=y
|
||||
|
||||
@@ -2964,17 +2964,13 @@ mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
|
||||
goto out_free;
|
||||
|
||||
manufacture_reply = data_out + sizeof(struct rep_manu_request);
|
||||
strscpy(edev->vendor_id, manufacture_reply->vendor_id,
|
||||
sizeof(edev->vendor_id));
|
||||
strscpy(edev->product_id, manufacture_reply->product_id,
|
||||
sizeof(edev->product_id));
|
||||
strscpy(edev->product_rev, manufacture_reply->product_rev,
|
||||
sizeof(edev->product_rev));
|
||||
memtostr(edev->vendor_id, manufacture_reply->vendor_id);
|
||||
memtostr(edev->product_id, manufacture_reply->product_id);
|
||||
memtostr(edev->product_rev, manufacture_reply->product_rev);
|
||||
edev->level = manufacture_reply->sas_format;
|
||||
if (manufacture_reply->sas_format) {
|
||||
strscpy(edev->component_vendor_id,
|
||||
manufacture_reply->component_vendor_id,
|
||||
sizeof(edev->component_vendor_id));
|
||||
memtostr(edev->component_vendor_id,
|
||||
manufacture_reply->component_vendor_id);
|
||||
tmp = (u8 *)&manufacture_reply->component_id;
|
||||
edev->component_id = tmp[0] << 8 | tmp[1];
|
||||
edev->component_revision_id =
|
||||
|
||||
@@ -19,7 +19,7 @@ KASAN_SANITIZE_rodata.o := n
|
||||
KCSAN_SANITIZE_rodata.o := n
|
||||
KCOV_INSTRUMENT_rodata.o := n
|
||||
OBJECT_FILES_NON_STANDARD_rodata.o := y
|
||||
CFLAGS_REMOVE_rodata.o += $(CC_FLAGS_LTO) $(RETHUNK_CFLAGS)
|
||||
CFLAGS_REMOVE_rodata.o += $(CC_FLAGS_LTO) $(RETHUNK_CFLAGS) $(CC_FLAGS_CFI)
|
||||
|
||||
OBJCOPYFLAGS :=
|
||||
OBJCOPYFLAGS_rodata_objcopy.o := \
|
||||
|
||||
@@ -61,7 +61,7 @@ static void *setup_function_descriptor(func_desc_t *fdesc, void *dst)
|
||||
return fdesc;
|
||||
}
|
||||
|
||||
static noinline void execute_location(void *dst, bool write)
|
||||
static noinline __nocfi void execute_location(void *dst, bool write)
|
||||
{
|
||||
void (*func)(void);
|
||||
func_desc_t fdesc;
|
||||
|
||||
@@ -209,17 +209,13 @@ static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
|
||||
goto out;
|
||||
}
|
||||
|
||||
strscpy(edev->vendor_id, manufacture_reply->vendor_id,
|
||||
SAS_EXPANDER_VENDOR_ID_LEN);
|
||||
strscpy(edev->product_id, manufacture_reply->product_id,
|
||||
SAS_EXPANDER_PRODUCT_ID_LEN);
|
||||
strscpy(edev->product_rev, manufacture_reply->product_rev,
|
||||
SAS_EXPANDER_PRODUCT_REV_LEN);
|
||||
memtostr(edev->vendor_id, manufacture_reply->vendor_id);
|
||||
memtostr(edev->product_id, manufacture_reply->product_id);
|
||||
memtostr(edev->product_rev, manufacture_reply->product_rev);
|
||||
edev->level = manufacture_reply->sas_format & 1;
|
||||
if (edev->level) {
|
||||
strscpy(edev->component_vendor_id,
|
||||
manufacture_reply->component_vendor_id,
|
||||
SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
|
||||
memtostr(edev->component_vendor_id,
|
||||
manufacture_reply->component_vendor_id);
|
||||
tmp = (u8 *)&manufacture_reply->component_id;
|
||||
edev->component_id = tmp[0] << 8 | tmp[1];
|
||||
edev->component_revision_id =
|
||||
|
||||
@@ -1909,10 +1909,8 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
|
||||
if (fx_type == FXDISC_GET_CONFIG_INFO) {
|
||||
struct config_info_data *pinfo =
|
||||
(struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
|
||||
strscpy(vha->hw->model_number, pinfo->model_num,
|
||||
ARRAY_SIZE(vha->hw->model_number));
|
||||
strscpy(vha->hw->model_desc, pinfo->model_description,
|
||||
ARRAY_SIZE(vha->hw->model_desc));
|
||||
memtostr(vha->hw->model_number, pinfo->model_num);
|
||||
memtostr(vha->hw->model_desc, pinfo->model_description);
|
||||
memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
|
||||
sizeof(vha->hw->mr.symbolic_name));
|
||||
memcpy(&vha->hw->mr.serial_num, pinfo->serial_num,
|
||||
|
||||
@@ -433,7 +433,7 @@ struct acrn_ioreq_client *acrn_ioreq_client_create(struct acrn_vm *vm,
|
||||
client->priv = priv;
|
||||
client->is_default = is_default;
|
||||
if (name)
|
||||
strncpy(client->name, name, sizeof(client->name) - 1);
|
||||
strscpy(client->name, name);
|
||||
rwlock_init(&client->range_lock);
|
||||
INIT_LIST_HEAD(&client->range_list);
|
||||
init_waitqueue_head(&client->wq);
|
||||
|
||||
@@ -1606,9 +1606,7 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,
|
||||
goto out;
|
||||
}
|
||||
mutex_init(&tmp_tfm->key_tfm_mutex);
|
||||
strncpy(tmp_tfm->cipher_name, cipher_name,
|
||||
ECRYPTFS_MAX_CIPHER_NAME_SIZE);
|
||||
tmp_tfm->cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0';
|
||||
strscpy(tmp_tfm->cipher_name, cipher_name);
|
||||
tmp_tfm->key_size = key_size;
|
||||
rc = ecryptfs_process_key_cipher(&tmp_tfm->key_tfm,
|
||||
tmp_tfm->cipher_name,
|
||||
|
||||
+6
-20
@@ -256,11 +256,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
int token;
|
||||
char *sig_src;
|
||||
char *cipher_name_dst;
|
||||
char *cipher_name_src;
|
||||
char *fn_cipher_name_dst;
|
||||
char *fn_cipher_name_src;
|
||||
char *fnek_dst;
|
||||
char *fnek_src;
|
||||
char *cipher_key_bytes_src;
|
||||
char *fn_cipher_key_bytes_src;
|
||||
@@ -293,12 +290,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||||
case ecryptfs_opt_cipher:
|
||||
case ecryptfs_opt_ecryptfs_cipher:
|
||||
cipher_name_src = args[0].from;
|
||||
cipher_name_dst =
|
||||
mount_crypt_stat->
|
||||
global_default_cipher_name;
|
||||
strncpy(cipher_name_dst, cipher_name_src,
|
||||
ECRYPTFS_MAX_CIPHER_NAME_SIZE);
|
||||
cipher_name_dst[ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0';
|
||||
strscpy(mount_crypt_stat->global_default_cipher_name,
|
||||
cipher_name_src);
|
||||
cipher_name_set = 1;
|
||||
break;
|
||||
case ecryptfs_opt_ecryptfs_key_bytes:
|
||||
@@ -326,11 +319,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||||
break;
|
||||
case ecryptfs_opt_fnek_sig:
|
||||
fnek_src = args[0].from;
|
||||
fnek_dst =
|
||||
mount_crypt_stat->global_default_fnek_sig;
|
||||
strncpy(fnek_dst, fnek_src, ECRYPTFS_SIG_SIZE_HEX);
|
||||
mount_crypt_stat->global_default_fnek_sig[
|
||||
ECRYPTFS_SIG_SIZE_HEX] = '\0';
|
||||
strscpy(mount_crypt_stat->global_default_fnek_sig,
|
||||
fnek_src);
|
||||
rc = ecryptfs_add_global_auth_tok(
|
||||
mount_crypt_stat,
|
||||
mount_crypt_stat->global_default_fnek_sig,
|
||||
@@ -348,12 +338,8 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||||
break;
|
||||
case ecryptfs_opt_fn_cipher:
|
||||
fn_cipher_name_src = args[0].from;
|
||||
fn_cipher_name_dst =
|
||||
mount_crypt_stat->global_default_fn_cipher_name;
|
||||
strncpy(fn_cipher_name_dst, fn_cipher_name_src,
|
||||
ECRYPTFS_MAX_CIPHER_NAME_SIZE);
|
||||
mount_crypt_stat->global_default_fn_cipher_name[
|
||||
ECRYPTFS_MAX_CIPHER_NAME_SIZE] = '\0';
|
||||
strscpy(mount_crypt_stat->global_default_fn_cipher_name,
|
||||
fn_cipher_name_src);
|
||||
fn_cipher_name_set = 1;
|
||||
break;
|
||||
case ecryptfs_opt_fn_cipher_key_bytes:
|
||||
|
||||
+10
-12
@@ -400,21 +400,19 @@ static int name_len(const char *xattr_name, int xattr_name_len)
|
||||
return len;
|
||||
}
|
||||
|
||||
static int copy_name(char *buffer, const char *xattr_name, int name_len)
|
||||
static ssize_t copy_name(char *buffer, const char *xattr_name, int name_len)
|
||||
{
|
||||
int len = name_len;
|
||||
int offset = 0;
|
||||
ssize_t len;
|
||||
|
||||
if (!is_known_namespace(xattr_name)) {
|
||||
memcpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN);
|
||||
offset += XATTR_MAC_OSX_PREFIX_LEN;
|
||||
len += XATTR_MAC_OSX_PREFIX_LEN;
|
||||
}
|
||||
|
||||
strncpy(buffer + offset, xattr_name, name_len);
|
||||
memset(buffer + offset + name_len, 0, 1);
|
||||
len += 1;
|
||||
if (!is_known_namespace(xattr_name))
|
||||
len = scnprintf(buffer, name_len + XATTR_MAC_OSX_PREFIX_LEN,
|
||||
"%s%s", XATTR_MAC_OSX_PREFIX, xattr_name);
|
||||
else
|
||||
len = strscpy(buffer, xattr_name, name_len + 1);
|
||||
|
||||
/* include NUL-byte in length for non-empty name */
|
||||
if (len >= 0)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
+3
-10
@@ -389,16 +389,9 @@ static void direntry_print_item(struct item_head *ih, char *item)
|
||||
name = item + deh_location(deh);
|
||||
if (name[namelen - 1] == 0)
|
||||
namelen = strlen(name);
|
||||
namebuf[0] = '"';
|
||||
if (namelen > sizeof(namebuf) - 3) {
|
||||
strncpy(namebuf + 1, name, sizeof(namebuf) - 3);
|
||||
namebuf[sizeof(namebuf) - 2] = '"';
|
||||
namebuf[sizeof(namebuf) - 1] = 0;
|
||||
} else {
|
||||
memcpy(namebuf + 1, name, namelen);
|
||||
namebuf[namelen + 1] = '"';
|
||||
namebuf[namelen + 2] = 0;
|
||||
}
|
||||
|
||||
scnprintf(namebuf, sizeof(namebuf), "\"%.*s\"",
|
||||
(int)sizeof(namebuf)-3, name);
|
||||
|
||||
printk("%d: %-15s%-15d%-15d%-15lld%-15lld(%s)\n",
|
||||
i, namebuf,
|
||||
|
||||
@@ -15,10 +15,14 @@
|
||||
#define FORTIFY_REASON(func, write) (FIELD_PREP(BIT(0), write) | \
|
||||
FIELD_PREP(GENMASK(7, 1), func))
|
||||
|
||||
/* Overridden by KUnit tests. */
|
||||
#ifndef fortify_panic
|
||||
# define fortify_panic(func, write, avail, size, retfail) \
|
||||
__fortify_panic(FORTIFY_REASON(func, write), avail, size)
|
||||
#endif
|
||||
#ifndef fortify_warn_once
|
||||
# define fortify_warn_once(x...) WARN_ONCE(x)
|
||||
#endif
|
||||
|
||||
#define FORTIFY_READ 0
|
||||
#define FORTIFY_WRITE 1
|
||||
@@ -609,7 +613,7 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size,
|
||||
const size_t __q_size = (q_size); \
|
||||
const size_t __p_size_field = (p_size_field); \
|
||||
const size_t __q_size_field = (q_size_field); \
|
||||
WARN_ONCE(fortify_memcpy_chk(__fortify_size, __p_size, \
|
||||
fortify_warn_once(fortify_memcpy_chk(__fortify_size, __p_size, \
|
||||
__q_size, __p_size_field, \
|
||||
__q_size_field, FORTIFY_FUNC_ ##op), \
|
||||
#op ": detected field-spanning write (size %zu) of single %s (size %zu)\n", \
|
||||
@@ -734,7 +738,8 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp
|
||||
if (__compiletime_lessthan(p_size, size))
|
||||
__read_overflow();
|
||||
if (p_size < size)
|
||||
fortify_panic(FORTIFY_FUNC_kmemdup, FORTIFY_READ, p_size, size, NULL);
|
||||
fortify_panic(FORTIFY_FUNC_kmemdup, FORTIFY_READ, p_size, size,
|
||||
__real_kmemdup(p, 0, gfp));
|
||||
return __real_kmemdup(p, size, gfp);
|
||||
}
|
||||
|
||||
|
||||
+57
-5
@@ -14,8 +14,8 @@
|
||||
#include <uapi/linux/string.h>
|
||||
|
||||
extern char *strndup_user(const char __user *, long);
|
||||
extern void *memdup_user(const void __user *, size_t);
|
||||
extern void *vmemdup_user(const void __user *, size_t);
|
||||
extern void *memdup_user(const void __user *, size_t) __realloc_size(2);
|
||||
extern void *vmemdup_user(const void __user *, size_t) __realloc_size(2);
|
||||
extern void *memdup_user_nul(const void __user *, size_t);
|
||||
|
||||
/**
|
||||
@@ -27,7 +27,8 @@ extern void *memdup_user_nul(const void __user *, size_t);
|
||||
* Return: an ERR_PTR() on failure. Result is physically
|
||||
* contiguous, to be freed by kfree().
|
||||
*/
|
||||
static inline void *memdup_array_user(const void __user *src, size_t n, size_t size)
|
||||
static inline __realloc_size(2, 3)
|
||||
void *memdup_array_user(const void __user *src, size_t n, size_t size)
|
||||
{
|
||||
size_t nbytes;
|
||||
|
||||
@@ -46,7 +47,8 @@ static inline void *memdup_array_user(const void __user *src, size_t n, size_t s
|
||||
* Return: an ERR_PTR() on failure. Result may be not
|
||||
* physically contiguous. Use kvfree() to free.
|
||||
*/
|
||||
static inline void *vmemdup_array_user(const void __user *src, size_t n, size_t size)
|
||||
static inline __realloc_size(2, 3)
|
||||
void *vmemdup_array_user(const void __user *src, size_t n, size_t size)
|
||||
{
|
||||
size_t nbytes;
|
||||
|
||||
@@ -285,7 +287,8 @@ extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
|
||||
extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
|
||||
extern void *kvmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2);
|
||||
extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp);
|
||||
extern void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp);
|
||||
extern void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp)
|
||||
__realloc_size(2, 3);
|
||||
|
||||
/* lib/argv_split.c */
|
||||
extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
|
||||
@@ -422,6 +425,55 @@ void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
|
||||
memcpy(dest, src, strnlen(src, min(_src_len, _dest_len))); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* memtostr - Copy a possibly non-NUL-term string to a NUL-term string
|
||||
* @dest: Pointer to destination NUL-terminates string
|
||||
* @src: Pointer to character array (likely marked as __nonstring)
|
||||
*
|
||||
* This is a replacement for strncpy() uses where the source is not
|
||||
* a NUL-terminated string.
|
||||
*
|
||||
* Note that sizes of @dest and @src must be known at compile-time.
|
||||
*/
|
||||
#define memtostr(dest, src) do { \
|
||||
const size_t _dest_len = __builtin_object_size(dest, 1); \
|
||||
const size_t _src_len = __builtin_object_size(src, 1); \
|
||||
const size_t _src_chars = strnlen(src, _src_len); \
|
||||
const size_t _copy_len = min(_dest_len - 1, _src_chars); \
|
||||
\
|
||||
BUILD_BUG_ON(!__builtin_constant_p(_dest_len) || \
|
||||
!__builtin_constant_p(_src_len) || \
|
||||
_dest_len == 0 || _dest_len == (size_t)-1 || \
|
||||
_src_len == 0 || _src_len == (size_t)-1); \
|
||||
memcpy(dest, src, _copy_len); \
|
||||
dest[_copy_len] = '\0'; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* memtostr_pad - Copy a possibly non-NUL-term string to a NUL-term string
|
||||
* with NUL padding in the destination
|
||||
* @dest: Pointer to destination NUL-terminates string
|
||||
* @src: Pointer to character array (likely marked as __nonstring)
|
||||
*
|
||||
* This is a replacement for strncpy() uses where the source is not
|
||||
* a NUL-terminated string.
|
||||
*
|
||||
* Note that sizes of @dest and @src must be known at compile-time.
|
||||
*/
|
||||
#define memtostr_pad(dest, src) do { \
|
||||
const size_t _dest_len = __builtin_object_size(dest, 1); \
|
||||
const size_t _src_len = __builtin_object_size(src, 1); \
|
||||
const size_t _src_chars = strnlen(src, _src_len); \
|
||||
const size_t _copy_len = min(_dest_len - 1, _src_chars); \
|
||||
\
|
||||
BUILD_BUG_ON(!__builtin_constant_p(_dest_len) || \
|
||||
!__builtin_constant_p(_src_len) || \
|
||||
_dest_len == 0 || _dest_len == (size_t)-1 || \
|
||||
_src_len == 0 || _src_len == (size_t)-1); \
|
||||
memcpy(dest, src, _copy_len); \
|
||||
memset(&dest[_copy_len], 0, _dest_len - _copy_len); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* memset_after - Set a value after a struct member to the end of a struct
|
||||
*
|
||||
|
||||
@@ -55,4 +55,12 @@
|
||||
#define __counted_by(m)
|
||||
#endif
|
||||
|
||||
#ifndef __counted_by_le
|
||||
#define __counted_by_le(m)
|
||||
#endif
|
||||
|
||||
#ifndef __counted_by_be
|
||||
#define __counted_by_be(m)
|
||||
#endif
|
||||
|
||||
#endif /* _UAPI_LINUX_STDDEF_H */
|
||||
|
||||
+1
-2
@@ -159,8 +159,7 @@ static int __init do_mount_root(const char *name, const char *fs,
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
data_page = page_address(p);
|
||||
/* zero-pad. init_mount() will make sure it's terminated */
|
||||
strncpy(data_page, data, PAGE_SIZE);
|
||||
strscpy_pad(data_page, data, PAGE_SIZE);
|
||||
}
|
||||
|
||||
ret = init_mount(name, "/root", fs, flags, data_page);
|
||||
|
||||
@@ -23,6 +23,10 @@ CONFIG_SLAB_FREELIST_HARDENED=y
|
||||
CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
|
||||
CONFIG_RANDOM_KMALLOC_CACHES=y
|
||||
|
||||
# Sanity check userspace page table mappings.
|
||||
CONFIG_PAGE_TABLE_CHECK=y
|
||||
CONFIG_PAGE_TABLE_CHECK_ENFORCED=y
|
||||
|
||||
# Randomize kernel stack offset on syscall entry.
|
||||
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
|
||||
|
||||
@@ -82,6 +86,10 @@ CONFIG_SECCOMP_FILTER=y
|
||||
# Provides some protections against SYN flooding.
|
||||
CONFIG_SYN_COOKIES=y
|
||||
|
||||
# Enable Kernel Control Flow Integrity (currently Clang only).
|
||||
CONFIG_CFI_CLANG=y
|
||||
# CONFIG_CFI_PERMISSIVE is not set
|
||||
|
||||
# Attack surface reduction: do not autoload TTY line disciplines.
|
||||
# CONFIG_LDISC_AUTOLOAD is not set
|
||||
|
||||
|
||||
+3
-3
@@ -27,10 +27,10 @@ static int stack_erasing_sysctl(struct ctl_table *table, int write,
|
||||
int ret = 0;
|
||||
int state = !static_branch_unlikely(&stack_erasing_bypass);
|
||||
int prev_state = state;
|
||||
struct ctl_table table_copy = *table;
|
||||
|
||||
table->data = &state;
|
||||
table->maxlen = sizeof(int);
|
||||
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
||||
table_copy.data = &state;
|
||||
ret = proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos);
|
||||
state = !!state;
|
||||
if (ret || !write || state == prev_state)
|
||||
return ret;
|
||||
|
||||
@@ -2759,16 +2759,6 @@ config HW_BREAKPOINT_KUNIT_TEST
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config STRCAT_KUNIT_TEST
|
||||
tristate "Test strcat() family of functions at runtime" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
|
||||
config STRSCPY_KUNIT_TEST
|
||||
tristate "Test strscpy*() family of functions at runtime" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
|
||||
config SIPHASH_KUNIT_TEST
|
||||
tristate "Perform selftest on siphash functions" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
|
||||
@@ -404,8 +404,6 @@ CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread)
|
||||
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-truncation)
|
||||
CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN)
|
||||
obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
|
||||
obj-$(CONFIG_STRCAT_KUNIT_TEST) += strcat_kunit.o
|
||||
obj-$(CONFIG_STRSCPY_KUNIT_TEST) += strscpy_kunit.o
|
||||
obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
|
||||
|
||||
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
|
||||
|
||||
+167
-55
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Runtime test cases for CONFIG_FORTIFY_SOURCE. For testing memcpy(),
|
||||
* see FORTIFY_MEM_* tests in LKDTM (drivers/misc/lkdtm/fortify.c).
|
||||
* Runtime test cases for CONFIG_FORTIFY_SOURCE. For additional memcpy()
|
||||
* testing see FORTIFY_MEM_* tests in LKDTM (drivers/misc/lkdtm/fortify.c).
|
||||
*
|
||||
* For corner cases with UBSAN, try testing with:
|
||||
*
|
||||
@@ -15,14 +15,31 @@
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
/* We don't need to fill dmesg with the fortify WARNs during testing. */
|
||||
#ifdef DEBUG
|
||||
# define FORTIFY_REPORT_KUNIT(x...) __fortify_report(x)
|
||||
# define FORTIFY_WARN_KUNIT(x...) WARN_ONCE(x)
|
||||
#else
|
||||
# define FORTIFY_REPORT_KUNIT(x...) do { } while (0)
|
||||
# define FORTIFY_WARN_KUNIT(x...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Redefine fortify_panic() to track failures. */
|
||||
void fortify_add_kunit_error(int write);
|
||||
#define fortify_panic(func, write, avail, size, retfail) do { \
|
||||
__fortify_report(FORTIFY_REASON(func, write), avail, size); \
|
||||
FORTIFY_REPORT_KUNIT(FORTIFY_REASON(func, write), avail, size); \
|
||||
fortify_add_kunit_error(write); \
|
||||
return (retfail); \
|
||||
} while (0)
|
||||
|
||||
/* Redefine fortify_warn_once() to track memcpy() failures. */
|
||||
#define fortify_warn_once(chk_func, x...) do { \
|
||||
bool __result = chk_func; \
|
||||
FORTIFY_WARN_KUNIT(__result, x); \
|
||||
if (__result) \
|
||||
fortify_add_kunit_error(1); \
|
||||
} while (0)
|
||||
|
||||
#include <kunit/device.h>
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/test-bug.h>
|
||||
@@ -64,7 +81,7 @@ void fortify_add_kunit_error(int write)
|
||||
kunit_put_resource(resource);
|
||||
}
|
||||
|
||||
static void known_sizes_test(struct kunit *test)
|
||||
static void fortify_test_known_sizes(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888"), 8);
|
||||
KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_of_10), 10);
|
||||
@@ -97,7 +114,7 @@ static noinline size_t want_minus_one(int pick)
|
||||
return __compiletime_strlen(str);
|
||||
}
|
||||
|
||||
static void control_flow_split_test(struct kunit *test)
|
||||
static void fortify_test_control_flow_split(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, want_minus_one(pick), SIZE_MAX);
|
||||
}
|
||||
@@ -173,11 +190,11 @@ static volatile size_t unknown_size = 50;
|
||||
#endif
|
||||
|
||||
#define DEFINE_ALLOC_SIZE_TEST_PAIR(allocator) \
|
||||
static void alloc_size_##allocator##_const_test(struct kunit *test) \
|
||||
static void fortify_test_alloc_size_##allocator##_const(struct kunit *test) \
|
||||
{ \
|
||||
CONST_TEST_BODY(TEST_##allocator); \
|
||||
} \
|
||||
static void alloc_size_##allocator##_dynamic_test(struct kunit *test) \
|
||||
static void fortify_test_alloc_size_##allocator##_dynamic(struct kunit *test) \
|
||||
{ \
|
||||
DYNAMIC_TEST_BODY(TEST_##allocator); \
|
||||
}
|
||||
@@ -267,28 +284,28 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(vmalloc)
|
||||
\
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvmalloc((alloc_pages) * PAGE_SIZE, gfp), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvmalloc_node((alloc_pages) * PAGE_SIZE, gfp, NUMA_NO_NODE), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvzalloc((alloc_pages) * PAGE_SIZE, gfp), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvzalloc_node((alloc_pages) * PAGE_SIZE, gfp, NUMA_NO_NODE), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvcalloc(1, (alloc_pages) * PAGE_SIZE, gfp), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvcalloc((alloc_pages) * PAGE_SIZE, 1, gfp), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvmalloc_array(1, (alloc_pages) * PAGE_SIZE, gfp), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
checker((expected_pages) * PAGE_SIZE, \
|
||||
kvmalloc_array((alloc_pages) * PAGE_SIZE, 1, gfp), \
|
||||
vfree(p)); \
|
||||
kvfree(p)); \
|
||||
\
|
||||
prev_size = (expected_pages) * PAGE_SIZE; \
|
||||
orig = kvmalloc(prev_size, gfp); \
|
||||
@@ -346,6 +363,31 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc)
|
||||
} while (0)
|
||||
DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc)
|
||||
|
||||
static const char * const test_strs[] = {
|
||||
"",
|
||||
"Hello there",
|
||||
"A longer string, just for variety",
|
||||
};
|
||||
|
||||
#define TEST_realloc(checker) do { \
|
||||
gfp_t gfp = GFP_KERNEL; \
|
||||
size_t len; \
|
||||
int i; \
|
||||
\
|
||||
for (i = 0; i < ARRAY_SIZE(test_strs); i++) { \
|
||||
len = strlen(test_strs[i]); \
|
||||
KUNIT_EXPECT_EQ(test, __builtin_constant_p(len), 0); \
|
||||
checker(len, kmemdup_array(test_strs[i], len, 1, gfp), \
|
||||
kfree(p)); \
|
||||
checker(len, kmemdup(test_strs[i], len, gfp), \
|
||||
kfree(p)); \
|
||||
} \
|
||||
} while (0)
|
||||
static void fortify_test_realloc_size(struct kunit *test)
|
||||
{
|
||||
TEST_realloc(check_dynamic);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't have an array at the end of a structure or else
|
||||
* builds without -fstrict-flex-arrays=3 will report them as
|
||||
@@ -361,7 +403,7 @@ struct fortify_padding {
|
||||
/* Force compiler into not being able to resolve size at compile-time. */
|
||||
static volatile int unconst;
|
||||
|
||||
static void strlen_test(struct kunit *test)
|
||||
static void fortify_test_strlen(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
int i, end = sizeof(pad.buf) - 1;
|
||||
@@ -384,7 +426,7 @@ static void strlen_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1);
|
||||
}
|
||||
|
||||
static void strnlen_test(struct kunit *test)
|
||||
static void fortify_test_strnlen(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
int i, end = sizeof(pad.buf) - 1;
|
||||
@@ -422,7 +464,7 @@ static void strnlen_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2);
|
||||
}
|
||||
|
||||
static void strcpy_test(struct kunit *test)
|
||||
static void fortify_test_strcpy(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
char src[sizeof(pad.buf) + 1] = { };
|
||||
@@ -480,7 +522,7 @@ static void strcpy_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
|
||||
}
|
||||
|
||||
static void strncpy_test(struct kunit *test)
|
||||
static void fortify_test_strncpy(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
char src[] = "Copy me fully into a small buffer and I will overflow!";
|
||||
@@ -539,7 +581,7 @@ static void strncpy_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
|
||||
}
|
||||
|
||||
static void strscpy_test(struct kunit *test)
|
||||
static void fortify_test_strscpy(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
char src[] = "Copy me fully into a small buffer and I will overflow!";
|
||||
@@ -596,7 +638,7 @@ static void strscpy_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
|
||||
}
|
||||
|
||||
static void strcat_test(struct kunit *test)
|
||||
static void fortify_test_strcat(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
char src[sizeof(pad.buf) / 2] = { };
|
||||
@@ -653,7 +695,7 @@ static void strcat_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
|
||||
}
|
||||
|
||||
static void strncat_test(struct kunit *test)
|
||||
static void fortify_test_strncat(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
char src[sizeof(pad.buf)] = { };
|
||||
@@ -726,7 +768,7 @@ static void strncat_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
|
||||
}
|
||||
|
||||
static void strlcat_test(struct kunit *test)
|
||||
static void fortify_test_strlcat(struct kunit *test)
|
||||
{
|
||||
struct fortify_padding pad = { };
|
||||
char src[sizeof(pad.buf)] = { };
|
||||
@@ -811,7 +853,75 @@ static void strlcat_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
|
||||
}
|
||||
|
||||
static void memscan_test(struct kunit *test)
|
||||
/* Check for 0-sized arrays... */
|
||||
struct fortify_zero_sized {
|
||||
unsigned long bytes_before;
|
||||
char buf[0];
|
||||
unsigned long bytes_after;
|
||||
};
|
||||
|
||||
#define __fortify_test(memfunc) \
|
||||
static void fortify_test_##memfunc(struct kunit *test) \
|
||||
{ \
|
||||
struct fortify_zero_sized zero = { }; \
|
||||
struct fortify_padding pad = { }; \
|
||||
char srcA[sizeof(pad.buf) + 2]; \
|
||||
char srcB[sizeof(pad.buf) + 2]; \
|
||||
size_t len = sizeof(pad.buf) + unconst; \
|
||||
\
|
||||
memset(srcA, 'A', sizeof(srcA)); \
|
||||
KUNIT_ASSERT_EQ(test, srcA[0], 'A'); \
|
||||
memset(srcB, 'B', sizeof(srcB)); \
|
||||
KUNIT_ASSERT_EQ(test, srcB[0], 'B'); \
|
||||
\
|
||||
memfunc(pad.buf, srcA, 0 + unconst); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
|
||||
memfunc(pad.buf + 1, srcB, 1 + unconst); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[2], '\0'); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
|
||||
memfunc(pad.buf, srcA, 1 + unconst); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[0], 'A'); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
|
||||
memfunc(pad.buf, srcA, len - 1); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[1], 'A'); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[len - 1], '\0'); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
|
||||
memfunc(pad.buf, srcA, len); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[1], 'A'); \
|
||||
KUNIT_EXPECT_EQ(test, pad.buf[len - 1], 'A'); \
|
||||
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
|
||||
memfunc(pad.buf, srcA, len + 1); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); \
|
||||
memfunc(pad.buf + 1, srcB, len); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); \
|
||||
\
|
||||
/* Reset error counter. */ \
|
||||
fortify_write_overflows = 0; \
|
||||
/* Copy nothing into nothing: no errors. */ \
|
||||
memfunc(zero.buf, srcB, 0 + unconst); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
|
||||
/* We currently explicitly ignore zero-sized dests. */ \
|
||||
memfunc(zero.buf, srcB, 1 + unconst); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
|
||||
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
|
||||
}
|
||||
__fortify_test(memcpy)
|
||||
__fortify_test(memmove)
|
||||
|
||||
static void fortify_test_memscan(struct kunit *test)
|
||||
{
|
||||
char haystack[] = "Where oh where is my memory range?";
|
||||
char *mem = haystack + strlen("Where oh where is ");
|
||||
@@ -830,7 +940,7 @@ static void memscan_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2);
|
||||
}
|
||||
|
||||
static void memchr_test(struct kunit *test)
|
||||
static void fortify_test_memchr(struct kunit *test)
|
||||
{
|
||||
char haystack[] = "Where oh where is my memory range?";
|
||||
char *mem = haystack + strlen("Where oh where is ");
|
||||
@@ -849,7 +959,7 @@ static void memchr_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2);
|
||||
}
|
||||
|
||||
static void memchr_inv_test(struct kunit *test)
|
||||
static void fortify_test_memchr_inv(struct kunit *test)
|
||||
{
|
||||
char haystack[] = "Where oh where is my memory range?";
|
||||
char *mem = haystack + 1;
|
||||
@@ -869,7 +979,7 @@ static void memchr_inv_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2);
|
||||
}
|
||||
|
||||
static void memcmp_test(struct kunit *test)
|
||||
static void fortify_test_memcmp(struct kunit *test)
|
||||
{
|
||||
char one[] = "My mind is going ...";
|
||||
char two[] = "My mind is going ... I can feel it.";
|
||||
@@ -891,7 +1001,7 @@ static void memcmp_test(struct kunit *test)
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2);
|
||||
}
|
||||
|
||||
static void kmemdup_test(struct kunit *test)
|
||||
static void fortify_test_kmemdup(struct kunit *test)
|
||||
{
|
||||
char src[] = "I got Doom running on it!";
|
||||
char *copy;
|
||||
@@ -917,19 +1027,19 @@ static void kmemdup_test(struct kunit *test)
|
||||
|
||||
/* Out of bounds by 1 byte. */
|
||||
copy = kmemdup(src, len + 1, GFP_KERNEL);
|
||||
KUNIT_EXPECT_NULL(test, copy);
|
||||
KUNIT_EXPECT_PTR_EQ(test, copy, ZERO_SIZE_PTR);
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 1);
|
||||
kfree(copy);
|
||||
|
||||
/* Way out of bounds. */
|
||||
copy = kmemdup(src, len * 2, GFP_KERNEL);
|
||||
KUNIT_EXPECT_NULL(test, copy);
|
||||
KUNIT_EXPECT_PTR_EQ(test, copy, ZERO_SIZE_PTR);
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 2);
|
||||
kfree(copy);
|
||||
|
||||
/* Starting offset causing out of bounds. */
|
||||
copy = kmemdup(src + 1, len, GFP_KERNEL);
|
||||
KUNIT_EXPECT_NULL(test, copy);
|
||||
KUNIT_EXPECT_PTR_EQ(test, copy, ZERO_SIZE_PTR);
|
||||
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 3);
|
||||
kfree(copy);
|
||||
}
|
||||
@@ -951,31 +1061,33 @@ static int fortify_test_init(struct kunit *test)
|
||||
}
|
||||
|
||||
static struct kunit_case fortify_test_cases[] = {
|
||||
KUNIT_CASE(known_sizes_test),
|
||||
KUNIT_CASE(control_flow_split_test),
|
||||
KUNIT_CASE(alloc_size_kmalloc_const_test),
|
||||
KUNIT_CASE(alloc_size_kmalloc_dynamic_test),
|
||||
KUNIT_CASE(alloc_size_vmalloc_const_test),
|
||||
KUNIT_CASE(alloc_size_vmalloc_dynamic_test),
|
||||
KUNIT_CASE(alloc_size_kvmalloc_const_test),
|
||||
KUNIT_CASE(alloc_size_kvmalloc_dynamic_test),
|
||||
KUNIT_CASE(alloc_size_devm_kmalloc_const_test),
|
||||
KUNIT_CASE(alloc_size_devm_kmalloc_dynamic_test),
|
||||
KUNIT_CASE(strlen_test),
|
||||
KUNIT_CASE(strnlen_test),
|
||||
KUNIT_CASE(strcpy_test),
|
||||
KUNIT_CASE(strncpy_test),
|
||||
KUNIT_CASE(strscpy_test),
|
||||
KUNIT_CASE(strcat_test),
|
||||
KUNIT_CASE(strncat_test),
|
||||
KUNIT_CASE(strlcat_test),
|
||||
KUNIT_CASE(fortify_test_known_sizes),
|
||||
KUNIT_CASE(fortify_test_control_flow_split),
|
||||
KUNIT_CASE(fortify_test_alloc_size_kmalloc_const),
|
||||
KUNIT_CASE(fortify_test_alloc_size_kmalloc_dynamic),
|
||||
KUNIT_CASE(fortify_test_alloc_size_vmalloc_const),
|
||||
KUNIT_CASE(fortify_test_alloc_size_vmalloc_dynamic),
|
||||
KUNIT_CASE(fortify_test_alloc_size_kvmalloc_const),
|
||||
KUNIT_CASE(fortify_test_alloc_size_kvmalloc_dynamic),
|
||||
KUNIT_CASE(fortify_test_alloc_size_devm_kmalloc_const),
|
||||
KUNIT_CASE(fortify_test_alloc_size_devm_kmalloc_dynamic),
|
||||
KUNIT_CASE(fortify_test_realloc_size),
|
||||
KUNIT_CASE(fortify_test_strlen),
|
||||
KUNIT_CASE(fortify_test_strnlen),
|
||||
KUNIT_CASE(fortify_test_strcpy),
|
||||
KUNIT_CASE(fortify_test_strncpy),
|
||||
KUNIT_CASE(fortify_test_strscpy),
|
||||
KUNIT_CASE(fortify_test_strcat),
|
||||
KUNIT_CASE(fortify_test_strncat),
|
||||
KUNIT_CASE(fortify_test_strlcat),
|
||||
/* skip memset: performs bounds checking on whole structs */
|
||||
/* skip memcpy: still using warn-and-overwrite instead of hard-fail */
|
||||
KUNIT_CASE(memscan_test),
|
||||
KUNIT_CASE(memchr_test),
|
||||
KUNIT_CASE(memchr_inv_test),
|
||||
KUNIT_CASE(memcmp_test),
|
||||
KUNIT_CASE(kmemdup_test),
|
||||
KUNIT_CASE(fortify_test_memcpy),
|
||||
KUNIT_CASE(fortify_test_memmove),
|
||||
KUNIT_CASE(fortify_test_memscan),
|
||||
KUNIT_CASE(fortify_test_memchr),
|
||||
KUNIT_CASE(fortify_test_memchr_inv),
|
||||
KUNIT_CASE(fortify_test_memcmp),
|
||||
KUNIT_CASE(fortify_test_kmemdup),
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -493,58 +493,6 @@ static void memmove_overlap_test(struct kunit *test)
|
||||
}
|
||||
}
|
||||
|
||||
static void strtomem_test(struct kunit *test)
|
||||
{
|
||||
static const char input[sizeof(unsigned long)] = "hi";
|
||||
static const char truncate[] = "this is too long";
|
||||
struct {
|
||||
unsigned long canary1;
|
||||
unsigned char output[sizeof(unsigned long)] __nonstring;
|
||||
unsigned long canary2;
|
||||
} wrap;
|
||||
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
KUNIT_EXPECT_EQ_MSG(test, wrap.canary1, ULONG_MAX,
|
||||
"bad initial canary value");
|
||||
KUNIT_EXPECT_EQ_MSG(test, wrap.canary2, ULONG_MAX,
|
||||
"bad initial canary value");
|
||||
|
||||
/* Check unpadded copy leaves surroundings untouched. */
|
||||
strtomem(wrap.output, input);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[0], input[0]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[1], input[1]);
|
||||
for (size_t i = 2; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], 0xFF);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
|
||||
/* Check truncated copy leaves surroundings untouched. */
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
strtomem(wrap.output, truncate);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
for (size_t i = 0; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], truncate[i]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
|
||||
/* Check padded copy leaves only string padded. */
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
strtomem_pad(wrap.output, input, 0xAA);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[0], input[0]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[1], input[1]);
|
||||
for (size_t i = 2; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], 0xAA);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
|
||||
/* Check truncated padded copy has no padding. */
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
strtomem(wrap.output, truncate);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
for (size_t i = 0; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], truncate[i]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
}
|
||||
|
||||
static struct kunit_case memcpy_test_cases[] = {
|
||||
KUNIT_CASE(memset_test),
|
||||
KUNIT_CASE(memcpy_test),
|
||||
@@ -552,7 +500,6 @@ static struct kunit_case memcpy_test_cases[] = {
|
||||
KUNIT_CASE_SLOW(memmove_test),
|
||||
KUNIT_CASE_SLOW(memmove_large_test),
|
||||
KUNIT_CASE_SLOW(memmove_overlap_test),
|
||||
KUNIT_CASE(strtomem_test),
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Kernel module for testing 'strcat' family of functions.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
static volatile int unconst;
|
||||
|
||||
static void strcat_test(struct kunit *test)
|
||||
{
|
||||
char dest[8];
|
||||
|
||||
/* Destination is terminated. */
|
||||
memset(dest, 0, sizeof(dest));
|
||||
KUNIT_EXPECT_EQ(test, strlen(dest), 0);
|
||||
/* Empty copy does nothing. */
|
||||
KUNIT_EXPECT_TRUE(test, strcat(dest, "") == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* 4 characters copied in, stops at %NUL. */
|
||||
KUNIT_EXPECT_TRUE(test, strcat(dest, "four\000123") == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "four");
|
||||
KUNIT_EXPECT_EQ(test, dest[5], '\0');
|
||||
/* 2 more characters copied in okay. */
|
||||
KUNIT_EXPECT_TRUE(test, strcat(dest, "AB") == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
}
|
||||
|
||||
static void strncat_test(struct kunit *test)
|
||||
{
|
||||
char dest[8];
|
||||
|
||||
/* Destination is terminated. */
|
||||
memset(dest, 0, sizeof(dest));
|
||||
KUNIT_EXPECT_EQ(test, strlen(dest), 0);
|
||||
/* Empty copy of size 0 does nothing. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "", 0 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* Empty copy of size 1 does nothing too. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "", 1 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* Copy of max 0 characters should do nothing. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "asdf", 0 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
|
||||
/* 4 characters copied in, even if max is 8. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "four\000123", 8 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "four");
|
||||
KUNIT_EXPECT_EQ(test, dest[5], '\0');
|
||||
KUNIT_EXPECT_EQ(test, dest[6], '\0');
|
||||
/* 2 characters copied in okay, 2 ignored. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "ABCD", 2 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
}
|
||||
|
||||
static void strlcat_test(struct kunit *test)
|
||||
{
|
||||
char dest[8] = "";
|
||||
int len = sizeof(dest) + unconst;
|
||||
|
||||
/* Destination is terminated. */
|
||||
KUNIT_EXPECT_EQ(test, strlen(dest), 0);
|
||||
/* Empty copy is size 0. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "", len), 0);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* Size 1 should keep buffer terminated, report size of source only. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "four", 1 + unconst), 4);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
|
||||
/* 4 characters copied in. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "four", len), 4);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "four");
|
||||
/* 2 characters copied in okay, gets to 6 total. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "AB", len), 6);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
/* 2 characters ignored if max size (7) reached. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "CD", 7 + unconst), 8);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
/* 1 of 2 characters skipped, now at true max size. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "EFG", len), 9);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourABE");
|
||||
/* Everything else ignored, now at full size. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "1234", len), 11);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourABE");
|
||||
}
|
||||
|
||||
static struct kunit_case strcat_test_cases[] = {
|
||||
KUNIT_CASE(strcat_test),
|
||||
KUNIT_CASE(strncat_test),
|
||||
KUNIT_CASE(strlcat_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite strcat_test_suite = {
|
||||
.name = "strcat",
|
||||
.test_cases = strcat_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(strcat_test_suite);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
+449
-12
@@ -11,7 +11,13 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
static void test_memset16(struct kunit *test)
|
||||
#define STRCMP_LARGE_BUF_LEN 2048
|
||||
#define STRCMP_CHANGE_POINT 1337
|
||||
#define STRCMP_TEST_EXPECT_EQUAL(test, fn, ...) KUNIT_EXPECT_EQ(test, fn(__VA_ARGS__), 0)
|
||||
#define STRCMP_TEST_EXPECT_LOWER(test, fn, ...) KUNIT_EXPECT_LT(test, fn(__VA_ARGS__), 0)
|
||||
#define STRCMP_TEST_EXPECT_GREATER(test, fn, ...) KUNIT_EXPECT_GT(test, fn(__VA_ARGS__), 0)
|
||||
|
||||
static void string_test_memset16(struct kunit *test)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
u16 v, *p;
|
||||
@@ -40,7 +46,7 @@ static void test_memset16(struct kunit *test)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_memset32(struct kunit *test)
|
||||
static void string_test_memset32(struct kunit *test)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
u32 v, *p;
|
||||
@@ -69,7 +75,7 @@ static void test_memset32(struct kunit *test)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_memset64(struct kunit *test)
|
||||
static void string_test_memset64(struct kunit *test)
|
||||
{
|
||||
unsigned i, j, k;
|
||||
u64 v, *p;
|
||||
@@ -98,7 +104,7 @@ static void test_memset64(struct kunit *test)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_strchr(struct kunit *test)
|
||||
static void string_test_strchr(struct kunit *test)
|
||||
{
|
||||
const char *test_string = "abcdefghijkl";
|
||||
const char *empty_string = "";
|
||||
@@ -121,7 +127,7 @@ static void test_strchr(struct kunit *test)
|
||||
KUNIT_ASSERT_NULL(test, result);
|
||||
}
|
||||
|
||||
static void test_strnchr(struct kunit *test)
|
||||
static void string_test_strnchr(struct kunit *test)
|
||||
{
|
||||
const char *test_string = "abcdefghijkl";
|
||||
const char *empty_string = "";
|
||||
@@ -154,7 +160,7 @@ static void test_strnchr(struct kunit *test)
|
||||
KUNIT_ASSERT_NULL(test, result);
|
||||
}
|
||||
|
||||
static void test_strspn(struct kunit *test)
|
||||
static void string_test_strspn(struct kunit *test)
|
||||
{
|
||||
static const struct strspn_test {
|
||||
const char str[16];
|
||||
@@ -179,13 +185,444 @@ static void test_strspn(struct kunit *test)
|
||||
}
|
||||
}
|
||||
|
||||
static char strcmp_buffer1[STRCMP_LARGE_BUF_LEN];
|
||||
static char strcmp_buffer2[STRCMP_LARGE_BUF_LEN];
|
||||
|
||||
static void strcmp_fill_buffers(char fill1, char fill2)
|
||||
{
|
||||
memset(strcmp_buffer1, fill1, STRCMP_LARGE_BUF_LEN);
|
||||
memset(strcmp_buffer2, fill2, STRCMP_LARGE_BUF_LEN);
|
||||
strcmp_buffer1[STRCMP_LARGE_BUF_LEN - 1] = 0;
|
||||
strcmp_buffer2[STRCMP_LARGE_BUF_LEN - 1] = 0;
|
||||
}
|
||||
|
||||
static void string_test_strcmp(struct kunit *test)
|
||||
{
|
||||
/* Equal strings */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strcmp, "Hello, Kernel!", "Hello, Kernel!");
|
||||
/* First string is lexicographically less than the second */
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strcmp, "Hello, KUnit!", "Hello, Kernel!");
|
||||
/* First string is lexicographically larger than the second */
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strcmp, "Hello, Kernel!", "Hello, KUnit!");
|
||||
/* Empty string is always lexicographically less than any non-empty string */
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strcmp, "", "Non-empty string");
|
||||
/* Two empty strings should be equal */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strcmp, "", "");
|
||||
/* Compare two strings which have only one char difference */
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strcmp, "Abacaba", "Abadaba");
|
||||
/* Compare two strings which have the same prefix*/
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strcmp, "Just a string", "Just a string and something else");
|
||||
}
|
||||
|
||||
static void string_test_strcmp_long_strings(struct kunit *test)
|
||||
{
|
||||
strcmp_fill_buffers('B', 'B');
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strcmp, strcmp_buffer1, strcmp_buffer2);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'A';
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strcmp, strcmp_buffer1, strcmp_buffer2);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'C';
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strcmp, strcmp_buffer1, strcmp_buffer2);
|
||||
}
|
||||
|
||||
static void string_test_strncmp(struct kunit *test)
|
||||
{
|
||||
/* Equal strings */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncmp, "Hello, KUnit!", "Hello, KUnit!", 13);
|
||||
/* First string is lexicographically less than the second */
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strncmp, "Hello, KUnit!", "Hello, Kernel!", 13);
|
||||
/* Result is always 'equal' when count = 0 */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncmp, "Hello, Kernel!", "Hello, KUnit!", 0);
|
||||
/* Strings with common prefix are equal if count = length of prefix */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncmp, "Abacaba", "Abadaba", 3);
|
||||
/* Strings with common prefix are not equal when count = length of prefix + 1 */
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strncmp, "Abacaba", "Abadaba", 4);
|
||||
/* If one string is a prefix of another, the shorter string is lexicographically smaller */
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strncmp, "Just a string", "Just a string and something else",
|
||||
strlen("Just a string and something else"));
|
||||
/*
|
||||
* If one string is a prefix of another, and we check first length
|
||||
* of prefix chars, the result is 'equal'
|
||||
*/
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncmp, "Just a string", "Just a string and something else",
|
||||
strlen("Just a string"));
|
||||
}
|
||||
|
||||
static void string_test_strncmp_long_strings(struct kunit *test)
|
||||
{
|
||||
strcmp_fill_buffers('B', 'B');
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_LARGE_BUF_LEN);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'A';
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strncmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_LARGE_BUF_LEN);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'C';
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strncmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_LARGE_BUF_LEN);
|
||||
/* the strings are equal up to STRCMP_CHANGE_POINT */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_CHANGE_POINT);
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strncmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_CHANGE_POINT + 1);
|
||||
}
|
||||
|
||||
static void string_test_strcasecmp(struct kunit *test)
|
||||
{
|
||||
/* Same strings in different case should be equal */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strcasecmp, "Hello, Kernel!", "HeLLO, KErNeL!");
|
||||
/* Empty strings should be equal */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strcasecmp, "", "");
|
||||
/* Despite ascii code for 'a' is larger than ascii code for 'B', 'a' < 'B' */
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strcasecmp, "a", "B");
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strcasecmp, "B", "a");
|
||||
/* Special symbols and numbers should be processed correctly */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strcasecmp, "-+**.1230ghTTT~^", "-+**.1230Ghttt~^");
|
||||
}
|
||||
|
||||
static void string_test_strcasecmp_long_strings(struct kunit *test)
|
||||
{
|
||||
strcmp_fill_buffers('b', 'B');
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strcasecmp, strcmp_buffer1, strcmp_buffer2);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'a';
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strcasecmp, strcmp_buffer1, strcmp_buffer2);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'C';
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strcasecmp, strcmp_buffer1, strcmp_buffer2);
|
||||
}
|
||||
|
||||
static void string_test_strncasecmp(struct kunit *test)
|
||||
{
|
||||
/* Same strings in different case should be equal */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncasecmp, "AbAcAbA", "Abacaba", strlen("Abacaba"));
|
||||
/* strncasecmp should check 'count' chars only */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncasecmp, "AbaCaBa", "abaCaDa", 5);
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strncasecmp, "a", "B", 1);
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strncasecmp, "B", "a", 1);
|
||||
/* Result is always 'equal' when count = 0 */
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncasecmp, "Abacaba", "Not abacaba", 0);
|
||||
}
|
||||
|
||||
static void string_test_strncasecmp_long_strings(struct kunit *test)
|
||||
{
|
||||
strcmp_fill_buffers('b', 'B');
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncasecmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_LARGE_BUF_LEN);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'a';
|
||||
STRCMP_TEST_EXPECT_LOWER(test, strncasecmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_LARGE_BUF_LEN);
|
||||
|
||||
strcmp_buffer1[STRCMP_CHANGE_POINT] = 'C';
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strncasecmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_LARGE_BUF_LEN);
|
||||
|
||||
STRCMP_TEST_EXPECT_EQUAL(test, strncasecmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_CHANGE_POINT);
|
||||
STRCMP_TEST_EXPECT_GREATER(test, strncasecmp, strcmp_buffer1,
|
||||
strcmp_buffer2, STRCMP_CHANGE_POINT + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* strscpy_check() - Run a specific test case.
|
||||
* @test: KUnit test context pointer
|
||||
* @src: Source string, argument to strscpy_pad()
|
||||
* @count: Size of destination buffer, argument to strscpy_pad()
|
||||
* @expected: Expected return value from call to strscpy_pad()
|
||||
* @chars: Number of characters from the src string expected to be
|
||||
* written to the dst buffer.
|
||||
* @terminator: 1 if there should be a terminating null byte 0 otherwise.
|
||||
* @pad: Number of pad characters expected (in the tail of dst buffer).
|
||||
* (@pad does not include the null terminator byte.)
|
||||
*
|
||||
* Calls strscpy_pad() and verifies the return value and state of the
|
||||
* destination buffer after the call returns.
|
||||
*/
|
||||
static void strscpy_check(struct kunit *test, char *src, int count,
|
||||
int expected, int chars, int terminator, int pad)
|
||||
{
|
||||
int nr_bytes_poison;
|
||||
int max_expected;
|
||||
int max_count;
|
||||
int written;
|
||||
char buf[6];
|
||||
int index, i;
|
||||
const char POISON = 'z';
|
||||
|
||||
KUNIT_ASSERT_TRUE_MSG(test, src != NULL,
|
||||
"null source string not supported");
|
||||
|
||||
memset(buf, POISON, sizeof(buf));
|
||||
/* Future proofing test suite, validate args */
|
||||
max_count = sizeof(buf) - 2; /* Space for null and to verify overflow */
|
||||
max_expected = count - 1; /* Space for the null */
|
||||
|
||||
KUNIT_ASSERT_LE_MSG(test, count, max_count,
|
||||
"count (%d) is too big (%d) ... aborting", count, max_count);
|
||||
KUNIT_EXPECT_LE_MSG(test, expected, max_expected,
|
||||
"expected (%d) is bigger than can possibly be returned (%d)",
|
||||
expected, max_expected);
|
||||
|
||||
written = strscpy_pad(buf, src, count);
|
||||
KUNIT_ASSERT_EQ(test, written, expected);
|
||||
|
||||
if (count && written == -E2BIG) {
|
||||
KUNIT_ASSERT_EQ_MSG(test, 0, strncmp(buf, src, count - 1),
|
||||
"buffer state invalid for -E2BIG");
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[count - 1], '\0',
|
||||
"too big string is not null terminated correctly");
|
||||
}
|
||||
|
||||
for (i = 0; i < chars; i++)
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[i], src[i],
|
||||
"buf[i]==%c != src[i]==%c", buf[i], src[i]);
|
||||
|
||||
if (terminator)
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[count - 1], '\0',
|
||||
"string is not null terminated correctly");
|
||||
|
||||
for (i = 0; i < pad; i++) {
|
||||
index = chars + terminator + i;
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[index], '\0',
|
||||
"padding missing at index: %d", i);
|
||||
}
|
||||
|
||||
nr_bytes_poison = sizeof(buf) - chars - terminator - pad;
|
||||
for (i = 0; i < nr_bytes_poison; i++) {
|
||||
index = sizeof(buf) - 1 - i; /* Check from the end back */
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[index], POISON,
|
||||
"poison value missing at index: %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
static void string_test_strscpy(struct kunit *test)
|
||||
{
|
||||
char dest[8];
|
||||
|
||||
/*
|
||||
* strscpy_check() uses a destination buffer of size 6 and needs at
|
||||
* least 2 characters spare (one for null and one to check for
|
||||
* overflow). This means we should only call tc() with
|
||||
* strings up to a maximum of 4 characters long and 'count'
|
||||
* should not exceed 4. To test with longer strings increase
|
||||
* the buffer size in tc().
|
||||
*/
|
||||
|
||||
/* strscpy_check(test, src, count, expected, chars, terminator, pad) */
|
||||
strscpy_check(test, "a", 0, -E2BIG, 0, 0, 0);
|
||||
strscpy_check(test, "", 0, -E2BIG, 0, 0, 0);
|
||||
|
||||
strscpy_check(test, "a", 1, -E2BIG, 0, 1, 0);
|
||||
strscpy_check(test, "", 1, 0, 0, 1, 0);
|
||||
|
||||
strscpy_check(test, "ab", 2, -E2BIG, 1, 1, 0);
|
||||
strscpy_check(test, "a", 2, 1, 1, 1, 0);
|
||||
strscpy_check(test, "", 2, 0, 0, 1, 1);
|
||||
|
||||
strscpy_check(test, "abc", 3, -E2BIG, 2, 1, 0);
|
||||
strscpy_check(test, "ab", 3, 2, 2, 1, 0);
|
||||
strscpy_check(test, "a", 3, 1, 1, 1, 1);
|
||||
strscpy_check(test, "", 3, 0, 0, 1, 2);
|
||||
|
||||
strscpy_check(test, "abcd", 4, -E2BIG, 3, 1, 0);
|
||||
strscpy_check(test, "abc", 4, 3, 3, 1, 0);
|
||||
strscpy_check(test, "ab", 4, 2, 2, 1, 1);
|
||||
strscpy_check(test, "a", 4, 1, 1, 1, 2);
|
||||
strscpy_check(test, "", 4, 0, 0, 1, 3);
|
||||
|
||||
/* Compile-time-known source strings. */
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", ARRAY_SIZE(dest)), 0);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 3), 0);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 1), 0);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 0), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", ARRAY_SIZE(dest)), 5);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 3), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 1), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 0), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "This is too long", ARRAY_SIZE(dest)), -E2BIG);
|
||||
}
|
||||
|
||||
static volatile int unconst;
|
||||
|
||||
static void string_test_strcat(struct kunit *test)
|
||||
{
|
||||
char dest[8];
|
||||
|
||||
/* Destination is terminated. */
|
||||
memset(dest, 0, sizeof(dest));
|
||||
KUNIT_EXPECT_EQ(test, strlen(dest), 0);
|
||||
/* Empty copy does nothing. */
|
||||
KUNIT_EXPECT_TRUE(test, strcat(dest, "") == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* 4 characters copied in, stops at %NUL. */
|
||||
KUNIT_EXPECT_TRUE(test, strcat(dest, "four\000123") == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "four");
|
||||
KUNIT_EXPECT_EQ(test, dest[5], '\0');
|
||||
/* 2 more characters copied in okay. */
|
||||
KUNIT_EXPECT_TRUE(test, strcat(dest, "AB") == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
}
|
||||
|
||||
static void string_test_strncat(struct kunit *test)
|
||||
{
|
||||
char dest[8];
|
||||
|
||||
/* Destination is terminated. */
|
||||
memset(dest, 0, sizeof(dest));
|
||||
KUNIT_EXPECT_EQ(test, strlen(dest), 0);
|
||||
/* Empty copy of size 0 does nothing. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "", 0 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* Empty copy of size 1 does nothing too. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "", 1 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* Copy of max 0 characters should do nothing. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "asdf", 0 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
|
||||
/* 4 characters copied in, even if max is 8. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "four\000123", 8 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "four");
|
||||
KUNIT_EXPECT_EQ(test, dest[5], '\0');
|
||||
KUNIT_EXPECT_EQ(test, dest[6], '\0');
|
||||
/* 2 characters copied in okay, 2 ignored. */
|
||||
KUNIT_EXPECT_TRUE(test, strncat(dest, "ABCD", 2 + unconst) == dest);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
}
|
||||
|
||||
static void string_test_strlcat(struct kunit *test)
|
||||
{
|
||||
char dest[8] = "";
|
||||
int len = sizeof(dest) + unconst;
|
||||
|
||||
/* Destination is terminated. */
|
||||
KUNIT_EXPECT_EQ(test, strlen(dest), 0);
|
||||
/* Empty copy is size 0. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "", len), 0);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
/* Size 1 should keep buffer terminated, report size of source only. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "four", 1 + unconst), 4);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "");
|
||||
|
||||
/* 4 characters copied in. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "four", len), 4);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "four");
|
||||
/* 2 characters copied in okay, gets to 6 total. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "AB", len), 6);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
/* 2 characters ignored if max size (7) reached. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "CD", 7 + unconst), 8);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourAB");
|
||||
/* 1 of 2 characters skipped, now at true max size. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "EFG", len), 9);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourABE");
|
||||
/* Everything else ignored, now at full size. */
|
||||
KUNIT_EXPECT_EQ(test, strlcat(dest, "1234", len), 11);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "fourABE");
|
||||
}
|
||||
|
||||
static void string_test_strtomem(struct kunit *test)
|
||||
{
|
||||
static const char input[sizeof(unsigned long)] = "hi";
|
||||
static const char truncate[] = "this is too long";
|
||||
struct {
|
||||
unsigned long canary1;
|
||||
unsigned char output[sizeof(unsigned long)] __nonstring;
|
||||
unsigned long canary2;
|
||||
} wrap;
|
||||
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
KUNIT_EXPECT_EQ_MSG(test, wrap.canary1, ULONG_MAX,
|
||||
"bad initial canary value");
|
||||
KUNIT_EXPECT_EQ_MSG(test, wrap.canary2, ULONG_MAX,
|
||||
"bad initial canary value");
|
||||
|
||||
/* Check unpadded copy leaves surroundings untouched. */
|
||||
strtomem(wrap.output, input);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[0], input[0]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[1], input[1]);
|
||||
for (size_t i = 2; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], 0xFF);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
|
||||
/* Check truncated copy leaves surroundings untouched. */
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
strtomem(wrap.output, truncate);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
for (size_t i = 0; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], truncate[i]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
|
||||
/* Check padded copy leaves only string padded. */
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
strtomem_pad(wrap.output, input, 0xAA);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[0], input[0]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[1], input[1]);
|
||||
for (size_t i = 2; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], 0xAA);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
|
||||
/* Check truncated padded copy has no padding. */
|
||||
memset(&wrap, 0xFF, sizeof(wrap));
|
||||
strtomem(wrap.output, truncate);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
|
||||
for (size_t i = 0; i < sizeof(wrap.output); i++)
|
||||
KUNIT_EXPECT_EQ(test, wrap.output[i], truncate[i]);
|
||||
KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
|
||||
}
|
||||
|
||||
|
||||
static void string_test_memtostr(struct kunit *test)
|
||||
{
|
||||
char nonstring[7] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
|
||||
char nonstring_small[3] = { 'a', 'b', 'c' };
|
||||
char dest[sizeof(nonstring) + 1];
|
||||
|
||||
/* Copy in a non-NUL-terminated string into exactly right-sized dest. */
|
||||
KUNIT_EXPECT_EQ(test, sizeof(dest), sizeof(nonstring) + 1);
|
||||
memset(dest, 'X', sizeof(dest));
|
||||
memtostr(dest, nonstring);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "abcdefg");
|
||||
memset(dest, 'X', sizeof(dest));
|
||||
memtostr(dest, nonstring_small);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "abc");
|
||||
KUNIT_EXPECT_EQ(test, dest[7], 'X');
|
||||
|
||||
memset(dest, 'X', sizeof(dest));
|
||||
memtostr_pad(dest, nonstring);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "abcdefg");
|
||||
memset(dest, 'X', sizeof(dest));
|
||||
memtostr_pad(dest, nonstring_small);
|
||||
KUNIT_EXPECT_STREQ(test, dest, "abc");
|
||||
KUNIT_EXPECT_EQ(test, dest[7], '\0');
|
||||
}
|
||||
|
||||
static struct kunit_case string_test_cases[] = {
|
||||
KUNIT_CASE(test_memset16),
|
||||
KUNIT_CASE(test_memset32),
|
||||
KUNIT_CASE(test_memset64),
|
||||
KUNIT_CASE(test_strchr),
|
||||
KUNIT_CASE(test_strnchr),
|
||||
KUNIT_CASE(test_strspn),
|
||||
KUNIT_CASE(string_test_memset16),
|
||||
KUNIT_CASE(string_test_memset32),
|
||||
KUNIT_CASE(string_test_memset64),
|
||||
KUNIT_CASE(string_test_strchr),
|
||||
KUNIT_CASE(string_test_strnchr),
|
||||
KUNIT_CASE(string_test_strspn),
|
||||
KUNIT_CASE(string_test_strcmp),
|
||||
KUNIT_CASE(string_test_strcmp_long_strings),
|
||||
KUNIT_CASE(string_test_strncmp),
|
||||
KUNIT_CASE(string_test_strncmp_long_strings),
|
||||
KUNIT_CASE(string_test_strcasecmp),
|
||||
KUNIT_CASE(string_test_strcasecmp_long_strings),
|
||||
KUNIT_CASE(string_test_strncasecmp),
|
||||
KUNIT_CASE(string_test_strncasecmp_long_strings),
|
||||
KUNIT_CASE(string_test_strscpy),
|
||||
KUNIT_CASE(string_test_strcat),
|
||||
KUNIT_CASE(string_test_strncat),
|
||||
KUNIT_CASE(string_test_strlcat),
|
||||
KUNIT_CASE(string_test_strtomem),
|
||||
KUNIT_CASE(string_test_memtostr),
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Kernel module for testing 'strscpy' family of functions.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
/*
|
||||
* tc() - Run a specific test case.
|
||||
* @src: Source string, argument to strscpy_pad()
|
||||
* @count: Size of destination buffer, argument to strscpy_pad()
|
||||
* @expected: Expected return value from call to strscpy_pad()
|
||||
* @terminator: 1 if there should be a terminating null byte 0 otherwise.
|
||||
* @chars: Number of characters from the src string expected to be
|
||||
* written to the dst buffer.
|
||||
* @pad: Number of pad characters expected (in the tail of dst buffer).
|
||||
* (@pad does not include the null terminator byte.)
|
||||
*
|
||||
* Calls strscpy_pad() and verifies the return value and state of the
|
||||
* destination buffer after the call returns.
|
||||
*/
|
||||
static void tc(struct kunit *test, char *src, int count, int expected,
|
||||
int chars, int terminator, int pad)
|
||||
{
|
||||
int nr_bytes_poison;
|
||||
int max_expected;
|
||||
int max_count;
|
||||
int written;
|
||||
char buf[6];
|
||||
int index, i;
|
||||
const char POISON = 'z';
|
||||
|
||||
KUNIT_ASSERT_TRUE_MSG(test, src != NULL,
|
||||
"null source string not supported");
|
||||
|
||||
memset(buf, POISON, sizeof(buf));
|
||||
/* Future proofing test suite, validate args */
|
||||
max_count = sizeof(buf) - 2; /* Space for null and to verify overflow */
|
||||
max_expected = count - 1; /* Space for the null */
|
||||
|
||||
KUNIT_ASSERT_LE_MSG(test, count, max_count,
|
||||
"count (%d) is too big (%d) ... aborting", count, max_count);
|
||||
KUNIT_EXPECT_LE_MSG(test, expected, max_expected,
|
||||
"expected (%d) is bigger than can possibly be returned (%d)",
|
||||
expected, max_expected);
|
||||
|
||||
written = strscpy_pad(buf, src, count);
|
||||
KUNIT_ASSERT_EQ(test, written, expected);
|
||||
|
||||
if (count && written == -E2BIG) {
|
||||
KUNIT_ASSERT_EQ_MSG(test, 0, strncmp(buf, src, count - 1),
|
||||
"buffer state invalid for -E2BIG");
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[count - 1], '\0',
|
||||
"too big string is not null terminated correctly");
|
||||
}
|
||||
|
||||
for (i = 0; i < chars; i++)
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[i], src[i],
|
||||
"buf[i]==%c != src[i]==%c", buf[i], src[i]);
|
||||
|
||||
if (terminator)
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[count - 1], '\0',
|
||||
"string is not null terminated correctly");
|
||||
|
||||
for (i = 0; i < pad; i++) {
|
||||
index = chars + terminator + i;
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[index], '\0',
|
||||
"padding missing at index: %d", i);
|
||||
}
|
||||
|
||||
nr_bytes_poison = sizeof(buf) - chars - terminator - pad;
|
||||
for (i = 0; i < nr_bytes_poison; i++) {
|
||||
index = sizeof(buf) - 1 - i; /* Check from the end back */
|
||||
KUNIT_ASSERT_EQ_MSG(test, buf[index], POISON,
|
||||
"poison value missing at index: %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
static void strscpy_test(struct kunit *test)
|
||||
{
|
||||
char dest[8];
|
||||
|
||||
/*
|
||||
* tc() uses a destination buffer of size 6 and needs at
|
||||
* least 2 characters spare (one for null and one to check for
|
||||
* overflow). This means we should only call tc() with
|
||||
* strings up to a maximum of 4 characters long and 'count'
|
||||
* should not exceed 4. To test with longer strings increase
|
||||
* the buffer size in tc().
|
||||
*/
|
||||
|
||||
/* tc(test, src, count, expected, chars, terminator, pad) */
|
||||
tc(test, "a", 0, -E2BIG, 0, 0, 0);
|
||||
tc(test, "", 0, -E2BIG, 0, 0, 0);
|
||||
|
||||
tc(test, "a", 1, -E2BIG, 0, 1, 0);
|
||||
tc(test, "", 1, 0, 0, 1, 0);
|
||||
|
||||
tc(test, "ab", 2, -E2BIG, 1, 1, 0);
|
||||
tc(test, "a", 2, 1, 1, 1, 0);
|
||||
tc(test, "", 2, 0, 0, 1, 1);
|
||||
|
||||
tc(test, "abc", 3, -E2BIG, 2, 1, 0);
|
||||
tc(test, "ab", 3, 2, 2, 1, 0);
|
||||
tc(test, "a", 3, 1, 1, 1, 1);
|
||||
tc(test, "", 3, 0, 0, 1, 2);
|
||||
|
||||
tc(test, "abcd", 4, -E2BIG, 3, 1, 0);
|
||||
tc(test, "abc", 4, 3, 3, 1, 0);
|
||||
tc(test, "ab", 4, 2, 2, 1, 1);
|
||||
tc(test, "a", 4, 1, 1, 1, 2);
|
||||
tc(test, "", 4, 0, 0, 1, 3);
|
||||
|
||||
/* Compile-time-known source strings. */
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", ARRAY_SIZE(dest)), 0);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 3), 0);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 1), 0);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "", 0), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", ARRAY_SIZE(dest)), 5);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 3), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 1), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 0), -E2BIG);
|
||||
KUNIT_EXPECT_EQ(test, strscpy(dest, "This is too long", ARRAY_SIZE(dest)), -E2BIG);
|
||||
}
|
||||
|
||||
static struct kunit_case strscpy_test_cases[] = {
|
||||
KUNIT_CASE(strscpy_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite strscpy_test_suite = {
|
||||
.name = "strscpy",
|
||||
.test_cases = strscpy_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(strscpy_test_suite);
|
||||
|
||||
MODULE_AUTHOR("Tobin C. Harding <tobin@kernel.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
+28
-15
@@ -43,7 +43,7 @@ enum {
|
||||
struct type_descriptor {
|
||||
u16 type_kind;
|
||||
u16 type_info;
|
||||
char type_name[1];
|
||||
char type_name[];
|
||||
};
|
||||
|
||||
struct source_location {
|
||||
@@ -124,19 +124,32 @@ typedef s64 s_max;
|
||||
typedef u64 u_max;
|
||||
#endif
|
||||
|
||||
void __ubsan_handle_add_overflow(void *data, void *lhs, void *rhs);
|
||||
void __ubsan_handle_sub_overflow(void *data, void *lhs, void *rhs);
|
||||
void __ubsan_handle_mul_overflow(void *data, void *lhs, void *rhs);
|
||||
void __ubsan_handle_negate_overflow(void *_data, void *old_val);
|
||||
void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs);
|
||||
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr);
|
||||
void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr);
|
||||
void __ubsan_handle_out_of_bounds(void *_data, void *index);
|
||||
void __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs);
|
||||
void __ubsan_handle_builtin_unreachable(void *_data);
|
||||
void __ubsan_handle_load_invalid_value(void *_data, void *val);
|
||||
void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
|
||||
unsigned long align,
|
||||
unsigned long offset);
|
||||
/*
|
||||
* When generating Runtime Calls, Clang doesn't respect the -mregparm=3
|
||||
* option used on i386: https://github.com/llvm/llvm-project/issues/89670
|
||||
* Fix this for earlier Clang versions by forcing the calling convention
|
||||
* to use non-register arguments.
|
||||
*/
|
||||
#if defined(CONFIG_X86_32) && \
|
||||
defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 190000
|
||||
# define ubsan_linkage asmlinkage
|
||||
#else
|
||||
# define ubsan_linkage
|
||||
#endif
|
||||
|
||||
void ubsan_linkage __ubsan_handle_add_overflow(void *data, void *lhs, void *rhs);
|
||||
void ubsan_linkage __ubsan_handle_sub_overflow(void *data, void *lhs, void *rhs);
|
||||
void ubsan_linkage __ubsan_handle_mul_overflow(void *data, void *lhs, void *rhs);
|
||||
void ubsan_linkage __ubsan_handle_negate_overflow(void *_data, void *old_val);
|
||||
void ubsan_linkage __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs);
|
||||
void ubsan_linkage __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr);
|
||||
void ubsan_linkage __ubsan_handle_type_mismatch_v1(void *_data, void *ptr);
|
||||
void ubsan_linkage __ubsan_handle_out_of_bounds(void *_data, void *index);
|
||||
void ubsan_linkage __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs);
|
||||
void ubsan_linkage __ubsan_handle_builtin_unreachable(void *_data);
|
||||
void ubsan_linkage __ubsan_handle_load_invalid_value(void *_data, void *val);
|
||||
void ubsan_linkage __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
|
||||
unsigned long align,
|
||||
unsigned long offset);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user