c4f92aff87
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmFLBPMACgkQONu9yGCS aT6BIQ//Wb4ZQJtEVvaKnda7vFwe8BoZzPGYZA4Imn9KERDRgHuavEuRfMQtKc2y YHwe/PD2JreuDHcd+Wz32xsdMe045xNvgiE1oGcxq0jNBvhJqANSmVTWpdqAquON cTmwsK3roa7ELC2g1WjrYZDv6CrCggqvbuM9AJ/cLITtd8zerhLdZo+CCDG/28cH EosrWvkBcaGmX+r/IBC86Rt6K2OFQ/3LLbb79L4vjKi5lopsm5CTAmfOfIk8p1gB mGB3PkQZnIqphBfqGXLGuljl4e+zb1SONrugUh78Egom393Ex34oo+RjWEGe9dV2 Stkuqo0GTi85X7JA7SGCA/xgF8A8yvaaLjQBsJsL9+2ji+GW+J7hfn4mE5h8H3Di UBjeLMFJA8Mge8Ng9xUSttvjRdwSTm0jWTS9SOl07w24b0pKYbMrQdWt2eI6CT+/ ytq3nCxNJZKeVcAVH+OJNrbSLYvMy/PgYvGTbzASkNmpAeyNiHOyBz1sRcoiAM9U QCWDdZyaqDKktqEyKHxK3opqPzbnHfZFFlCxR7Gw7vvR+itIGJEh/50RNv2F6vnu wzowrVxe+Bf1h7JiNEqLLVHdiuygRqjH1ygepGM4+3TVF4jYHzDISyrqlA/Se3Pg Hhvlzsbv7PH+KiApwBFjSeHTs5WOrokGMFQ7ZYFDpPkleWiywS0= =50Hk -----END PGP SIGNATURE----- Merge 5.4.148 into android11-5.4-lts Changes in 5.4.148 rtc: tps65910: Correct driver module alias btrfs: wake up async_delalloc_pages waiters after submit btrfs: reset replace target device to allocation state on close blk-zoned: allow zone management send operations without CAP_SYS_ADMIN blk-zoned: allow BLKREPORTZONE without CAP_SYS_ADMIN PCI/MSI: Skip masking MSI-X on Xen PV powerpc/perf/hv-gpci: Fix counter value parsing xen: fix setting of max_pfn in shared_info include/linux/list.h: add a macro to test if entry is pointing to the head 9p/xen: Fix end of loop tests for list_for_each_entry tools/thermal/tmon: Add cross compiling support pinctrl: stmfx: Fix hazardous u8[] to unsigned long cast pinctrl: ingenic: Fix incorrect pull up/down info soc: qcom: aoss: Fix the out of bound usage of cooling_devs soc: aspeed: lpc-ctrl: Fix boundary check for mmap soc: aspeed: p2a-ctrl: Fix boundary check for mmap arm64: head: avoid over-mapping in map_memory crypto: public_key: fix overflow during implicit conversion block: bfq: fix bfq_set_next_ioprio_data() power: supply: max17042: handle fails of reading status register dm crypt: Avoid percpu_counter spinlock contention in crypt_page_alloc() VMCI: fix NULL pointer dereference when unmapping queue pair media: uvc: don't do DMA on stack media: rc-loopback: return number of emitters rather than error Revert "dmaengine: imx-sdma: refine to load context only once" dmaengine: imx-sdma: remove duplicated sdma_load_context libata: add ATA_HORKAGE_NO_NCQ_TRIM for Samsung 860 and 870 SSDs ARM: 9105/1: atags_to_fdt: don't warn about stack size PCI/portdrv: Enable Bandwidth Notification only if port supports it PCI: Restrict ASMedia ASM1062 SATA Max Payload Size Supported PCI: Return ~0 data on pciconfig_read() CAP_SYS_ADMIN failure PCI: xilinx-nwl: Enable the clock through CCF PCI: aardvark: Fix checking for PIO status PCI: aardvark: Increase polling delay to 1.5s while waiting for PIO response PCI: aardvark: Fix masking and unmasking legacy INTx interrupts HID: input: do not report stylus battery state as "full" f2fs: quota: fix potential deadlock scsi: bsg: Remove support for SCSI_IOCTL_SEND_COMMAND IB/hfi1: Adjust pkey entry in index 0 RDMA/iwcm: Release resources if iw_cm module initialization fails docs: Fix infiniband uverbs minor number pinctrl: samsung: Fix pinctrl bank pin count vfio: Use config not menuconfig for VFIO_NOIOMMU powerpc/stacktrace: Include linux/delay.h RDMA/efa: Remove double QP type assignment f2fs: show f2fs instance in printk_ratelimited f2fs: reduce the scope of setting fsck tag when de->name_len is zero openrisc: don't printk() unconditionally dma-debug: fix debugfs initialization order SUNRPC: Fix potential memory corruption scsi: fdomain: Fix error return code in fdomain_probe() pinctrl: single: Fix error return code in pcs_parse_bits_in_pinctrl_entry() scsi: smartpqi: Fix an error code in pqi_get_raid_map() scsi: qedi: Fix error codes in qedi_alloc_global_queues() scsi: qedf: Fix error codes in qedf_alloc_global_queues() powerpc/config: Renable MTD_PHYSMAP_OF scsi: target: avoid per-loop XCOPY buffer allocations HID: i2c-hid: Fix Elan touchpad regression KVM: PPC: Book3S HV Nested: Reflect guest PMU in-use to L0 when guest SPRs are live platform/x86: dell-smbios-wmi: Add missing kfree in error-exit from run_smbios_call fscache: Fix cookie key hashing clk: at91: sam9x60: Don't use audio PLL clk: at91: clk-generated: pass the id of changeable parent at registration clk: at91: clk-generated: Limit the requested rate to our range KVM: PPC: Fix clearing never mapped TCEs in realmode f2fs: fix to account missing .skipped_gc_rwsem f2fs: fix unexpected ENOENT comes from f2fs_map_blocks() f2fs: fix to unmap pages from userspace process in punch_hole() MIPS: Malta: fix alignment of the devicetree buffer kbuild: Fix 'no symbols' warning when CONFIG_TRIM_UNUSD_KSYMS=y userfaultfd: prevent concurrent API initialization drm/amdgpu: Fix amdgpu_ras_eeprom_init() ASoC: atmel: ATMEL drivers don't need HAS_DMA media: dib8000: rewrite the init prbs logic crypto: mxs-dcp - Use sg_mapping_iter to copy data PCI: Use pci_update_current_state() in pci_enable_device_flags() tipc: keep the skb in rcv queue until the whole data is read iio: dac: ad5624r: Fix incorrect handling of an optional regulator. iavf: do not override the adapter state in the watchdog task iavf: fix locking of critical sections ARM: dts: qcom: apq8064: correct clock names video: fbdev: kyro: fix a DoS bug by restricting user input netlink: Deal with ESRCH error in nlmsg_notify() Smack: Fix wrong semantics in smk_access_entry() drm: avoid blocking in drm_clients_info's rcu section igc: Check if num of q_vectors is smaller than max before array access usb: host: fotg210: fix the endpoint's transactional opportunities calculation usb: host: fotg210: fix the actual_length of an iso packet usb: gadget: u_ether: fix a potential null pointer dereference USB: EHCI: ehci-mv: improve error handling in mv_ehci_enable() usb: gadget: composite: Allow bMaxPower=0 if self-powered staging: board: Fix uninitialized spinlock when attaching genpd tty: serial: jsm: hold port lock when reporting modem line changes drm/amd/display: Fix timer_per_pixel unit error drm/amd/amdgpu: Update debugfs link_settings output link_rate field in hex bpf/tests: Fix copy-and-paste error in double word test bpf/tests: Do not PASS tests without actually testing the result video: fbdev: asiliantfb: Error out if 'pixclock' equals zero video: fbdev: kyro: Error out if 'pixclock' equals zero video: fbdev: riva: Error out if 'pixclock' equals zero ipv4: ip_output.c: Fix out-of-bounds warning in ip_copy_addrs() flow_dissector: Fix out-of-bounds warnings s390/jump_label: print real address in a case of a jump label bug s390: make PCI mio support a machine flag serial: 8250: Define RX trigger levels for OxSemi 950 devices xtensa: ISS: don't panic in rs_init hvsi: don't panic on tty_register_driver failure serial: 8250_pci: make setup_port() parameters explicitly unsigned staging: ks7010: Fix the initialization of the 'sleep_status' structure samples: bpf: Fix tracex7 error raised on the missing argument ata: sata_dwc_460ex: No need to call phy_exit() befre phy_init() Bluetooth: skip invalid hci_sync_conn_complete_evt workqueue: Fix possible memory leaks in wq_numa_init() bonding: 3ad: fix the concurrency between __bond_release_one() and bond_3ad_state_machine_handler() arm64: tegra: Fix Tegra194 PCIe EP compatible string ASoC: Intel: bytcr_rt5640: Move "Platform Clock" routes to the maps for the matching in-/output media: imx258: Rectify mismatch of VTS value media: imx258: Limit the max analogue gain to 480 media: v4l2-dv-timings.c: fix wrong condition in two for-loops media: TDA1997x: fix tda1997x_query_dv_timings() return value media: tegra-cec: Handle errors of clk_prepare_enable() ARM: dts: imx53-ppd: Fix ACHC entry arm64: dts: qcom: sdm660: use reg value for memory node net: ethernet: stmmac: Do not use unreachable() in ipq806x_gmac_probe() drm/msm: mdp4: drop vblank get/put from prepare/complete_commit selftests/bpf: Fix xdp_tx.c prog section name Bluetooth: schedule SCO timeouts with delayed_work Bluetooth: avoid circular locks in sco_sock_connect net/mlx5: Fix variable type to match 64bit gpu: drm: amd: amdgpu: amdgpu_i2c: fix possible uninitialized-variable access in amdgpu_i2c_router_select_ddc_port() drm/display: fix possible null-pointer dereference in dcn10_set_clock() mac80211: Fix monitor MTU limit so that A-MSDUs get through ARM: tegra: tamonten: Fix UART pad setting arm64: tegra: Fix compatible string for Tegra132 CPUs arm64: dts: ls1046a: fix eeprom entries nvme-tcp: don't check blk_mq_tag_to_rq when receiving pdu data Bluetooth: Fix handling of LE Enhanced Connection Complete opp: Don't print an error if required-opps is missing serial: sh-sci: fix break handling for sysrq tcp: enable data-less, empty-cookie SYN with TFO_SERVER_COOKIE_NOT_REQD rpc: fix gss_svc_init cleanup on failure staging: rts5208: Fix get_ms_information() heap buffer size gfs2: Don't call dlm after protocol is unmounted usb: chipidea: host: fix port index underflow and UBSAN complains lockd: lockd server-side shouldn't set fl_ops drm/exynos: Always initialize mapping in exynos_drm_register_dma() m68knommu: only set CONFIG_ISA_DMA_API for ColdFire sub-arch btrfs: tree-log: check btrfs_lookup_data_extent return value ASoC: Intel: Skylake: Fix module configuration for KPB and MIXER ASoC: Intel: Skylake: Fix passing loadable flag for module of: Don't allow __of_attached_node_sysfs() without CONFIG_SYSFS mmc: sdhci-of-arasan: Check return value of non-void funtions mmc: rtsx_pci: Fix long reads when clock is prescaled selftests/bpf: Enlarge select() timeout for test_maps mmc: core: Return correct emmc response in case of ioctl error cifs: fix wrong release in sess_alloc_buffer() failed path Revert "USB: xhci: fix U1/U2 handling for hardware with XHCI_INTEL_HOST quirk set" usb: musb: musb_dsps: request_irq() after initializing musb usbip: give back URBs for unsent unlink requests during cleanup usbip:vhci_hcd USB port can get stuck in the disabled state ASoC: rockchip: i2s: Fix regmap_ops hang ASoC: rockchip: i2s: Fixup config for DAIFMT_DSP_A/B drm/amdkfd: Account for SH/SE count when setting up cu masks. iwlwifi: mvm: fix a memory leak in iwl_mvm_mac_ctxt_beacon_changed iwlwifi: mvm: avoid static queue number aliasing iwlwifi: mvm: fix access to BSS elements net/mlx5: DR, Enable QP retransmission parport: remove non-zero check on count ath9k: fix OOB read ar9300_eeprom_restore_internal ath9k: fix sleeping in atomic context net: fix NULL pointer reference in cipso_v4_doi_free fix array-index-out-of-bounds in taprio_change net: w5100: check return value after calling platform_get_resource() parisc: fix crash with signals and alloca ovl: fix BUG_ON() in may_delete() when called from ovl_cleanup() scsi: BusLogic: Fix missing pr_cont() use scsi: qla2xxx: Changes to support kdump kernel scsi: qla2xxx: Sync queue idx with queue_pair_map idx cpufreq: powernv: Fix init_chip_info initialization in numa=off s390/pv: fix the forcing of the swiotlb mm/hugetlb: initialize hugetlb_usage in mm_init mm,vmscan: fix divide by zero in get_scan_count memcg: enable accounting for pids in nested pid namespaces platform/chrome: cros_ec_proto: Send command again when timeout occurs lib/test_stackinit: Fix static initializer test net: dsa: lantiq_gswip: fix maximum frame length drm/msi/mdp4: populate priv->kms in mdp4_kms_init drm/amdgpu: Fix BUG_ON assert drm/panfrost: Simplify lock_region calculation drm/panfrost: Use u64 for size in lock_region drm/panfrost: Clamp lock region to Bifrost minimum btrfs: fix upper limit for max_inline for page size 64K xen: reset legacy rtc flag for PV domU bnx2x: Fix enabling network interfaces without VFs arm64/sve: Use correct size when reinitialising SVE state PM: base: power: don't try to use non-existing RTC for storing data PCI: Add AMD GPU multi-function power dependencies drm/amd/amdgpu: Increase HWIP_MAX_INSTANCE to 10 drm/etnaviv: return context from etnaviv_iommu_context_get drm/etnaviv: put submit prev MMU context when it exists drm/etnaviv: stop abusing mmu_context as FE running marker drm/etnaviv: keep MMU context across runtime suspend/resume drm/etnaviv: exec and MMU state is lost when resetting the GPU drm/etnaviv: fix MMU context leak on GPU reset drm/etnaviv: reference MMU context when setting up hardware state drm/etnaviv: add missing MMU context put when reaping MMU mapping s390/sclp: fix Secure-IPL facility detection x86/mm: Fix kern_addr_valid() to cope with existing but not present entries tipc: fix an use-after-free issue in tipc_recvmsg net-caif: avoid user-triggerable WARN_ON(1) ptp: dp83640: don't define PAGE0 dccp: don't duplicate ccid when cloning dccp sock net/l2tp: Fix reference count leak in l2tp_udp_recv_core r6040: Restore MDIO clock frequency after MAC reset tipc: increase timeout in tipc_sk_enqueue() perf machine: Initialize srcline string member in add_location struct net/mlx5: FWTrace, cancel work on alloc pd error flow net/mlx5: Fix potential sleeping in atomic context events: Reuse value read using READ_ONCE instead of re-reading it vhost_net: fix OoB on sendmsg() failure. net/af_unix: fix a data-race in unix_dgram_poll net: dsa: destroy the phylink instance on any error in dsa_slave_phy_setup tcp: fix tp->undo_retrans accounting in tcp_sacktag_one() qed: Handle management FW error dt-bindings: arm: Fix Toradex compatible typo ibmvnic: check failover_pending in login response KVM: PPC: Book3S HV: Tolerate treclaim. in fake-suspend mode changing registers net: hns3: pad the short tunnel frame before sending to hardware net: hns3: change affinity_mask to numa node range net: hns3: disable mac in flr process net: hns3: fix the timing issue of VF clearing interrupt sources mm/memory_hotplug: use "unsigned long" for PFN in zone_for_pfn_range() dt-bindings: mtd: gpmc: Fix the ECC bytes vs. OOB bytes equation mfd: db8500-prcmu: Adjust map to reality PCI: Add ACS quirks for NXP LX2xx0 and LX2xx2 platforms fuse: fix use after free in fuse_read_interrupt() mfd: Don't use irq_create_mapping() to resolve a mapping tracing/probes: Reject events which have the same name of existing one PCI: Add ACS quirks for Cavium multi-function devices Set fc_nlinfo in nh_create_ipv4, nh_create_ipv6 net: usb: cdc_mbim: avoid altsetting toggling for Telit LN920 block, bfq: honor already-setup queue merges PCI: ibmphp: Fix double unmap of io_mem ethtool: Fix an error code in cxgb2.c NTB: Fix an error code in ntb_msit_probe() NTB: perf: Fix an error code in perf_setup_inbuf() mfd: axp20x: Update AXP288 volatile ranges PCI: Fix pci_dev_str_match_path() alloc while atomic bug mfd: tqmx86: Clear GPIO IRQ resource when no IRQ is set KVM: arm64: Handle PSCI resets before userspace touches vCPU state PCI: Sync __pci_register_driver() stub for CONFIG_PCI=n mtd: rawnand: cafe: Fix a resource leak in the error handling path of 'cafe_nand_probe()' ARC: export clear_user_page() for modules perf unwind: Do not overwrite FEATURE_CHECK_LDFLAGS-libunwind-{x86,aarch64} net: dsa: b53: Fix calculating number of switch ports netfilter: socket: icmp6: fix use-after-scope fq_codel: reject silly quantum parameters qlcnic: Remove redundant unlock in qlcnic_pinit_from_rom ip_gre: validate csum_start only on pull net: renesas: sh_eth: Fix freeing wrong tx descriptor s390/bpf: Fix optimizing out zero-extensions s390/bpf: Fix 64-bit subtraction of the -0x80000000 constant Linux 5.4.148 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I8613b511cb543a7ce0d1623663fc1306aaa45af1
390 lines
11 KiB
C
390 lines
11 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Test cases for compiler-based stack variable zeroing via future
|
|
* compiler flags or CONFIG_GCC_PLUGIN_STRUCTLEAK*.
|
|
*/
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/string.h>
|
|
|
|
/* Exfiltration buffer. */
|
|
#define MAX_VAR_SIZE 128
|
|
static u8 check_buf[MAX_VAR_SIZE];
|
|
|
|
/* Character array to trigger stack protector in all functions. */
|
|
#define VAR_BUFFER 32
|
|
|
|
/* Volatile mask to convince compiler to copy memory with 0xff. */
|
|
static volatile u8 forced_mask = 0xff;
|
|
|
|
/* Location and size tracking to validate fill and test are colocated. */
|
|
static void *fill_start, *target_start;
|
|
static size_t fill_size, target_size;
|
|
|
|
static bool range_contains(char *haystack_start, size_t haystack_size,
|
|
char *needle_start, size_t needle_size)
|
|
{
|
|
if (needle_start >= haystack_start &&
|
|
needle_start + needle_size <= haystack_start + haystack_size)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
#define DO_NOTHING_TYPE_SCALAR(var_type) var_type
|
|
#define DO_NOTHING_TYPE_STRING(var_type) void
|
|
#define DO_NOTHING_TYPE_STRUCT(var_type) void
|
|
|
|
#define DO_NOTHING_RETURN_SCALAR(ptr) *(ptr)
|
|
#define DO_NOTHING_RETURN_STRING(ptr) /**/
|
|
#define DO_NOTHING_RETURN_STRUCT(ptr) /**/
|
|
|
|
#define DO_NOTHING_CALL_SCALAR(var, name) \
|
|
(var) = do_nothing_ ## name(&(var))
|
|
#define DO_NOTHING_CALL_STRING(var, name) \
|
|
do_nothing_ ## name(var)
|
|
#define DO_NOTHING_CALL_STRUCT(var, name) \
|
|
do_nothing_ ## name(&(var))
|
|
|
|
#define FETCH_ARG_SCALAR(var) &var
|
|
#define FETCH_ARG_STRING(var) var
|
|
#define FETCH_ARG_STRUCT(var) &var
|
|
|
|
#define FILL_SIZE_STRING 16
|
|
|
|
#define INIT_CLONE_SCALAR /**/
|
|
#define INIT_CLONE_STRING [FILL_SIZE_STRING]
|
|
#define INIT_CLONE_STRUCT /**/
|
|
|
|
#define INIT_SCALAR_none /**/
|
|
#define INIT_SCALAR_zero = 0
|
|
|
|
#define INIT_STRING_none [FILL_SIZE_STRING] /**/
|
|
#define INIT_STRING_zero [FILL_SIZE_STRING] = { }
|
|
|
|
#define INIT_STRUCT_none /**/
|
|
#define INIT_STRUCT_zero = { }
|
|
#define INIT_STRUCT_static_partial = { .two = 0, }
|
|
#define INIT_STRUCT_static_all = { .one = 0, \
|
|
.two = 0, \
|
|
.three = 0, \
|
|
.four = 0, \
|
|
}
|
|
#define INIT_STRUCT_dynamic_partial = { .two = arg->two, }
|
|
#define INIT_STRUCT_dynamic_all = { .one = arg->one, \
|
|
.two = arg->two, \
|
|
.three = arg->three, \
|
|
.four = arg->four, \
|
|
}
|
|
#define INIT_STRUCT_runtime_partial ; \
|
|
var.two = 0
|
|
#define INIT_STRUCT_runtime_all ; \
|
|
var.one = 0; \
|
|
var.two = 0; \
|
|
var.three = 0; \
|
|
var.four = 0
|
|
|
|
/*
|
|
* @name: unique string name for the test
|
|
* @var_type: type to be tested for zeroing initialization
|
|
* @which: is this a SCALAR, STRING, or STRUCT type?
|
|
* @init_level: what kind of initialization is performed
|
|
* @xfail: is this test expected to fail?
|
|
*/
|
|
#define DEFINE_TEST_DRIVER(name, var_type, which, xfail) \
|
|
/* Returns 0 on success, 1 on failure. */ \
|
|
static noinline __init int test_ ## name (void) \
|
|
{ \
|
|
var_type zero INIT_CLONE_ ## which; \
|
|
int ignored; \
|
|
u8 sum = 0, i; \
|
|
\
|
|
/* Notice when a new test is larger than expected. */ \
|
|
BUILD_BUG_ON(sizeof(zero) > MAX_VAR_SIZE); \
|
|
\
|
|
/* Fill clone type with zero for per-field init. */ \
|
|
memset(&zero, 0x00, sizeof(zero)); \
|
|
/* Clear entire check buffer for 0xFF overlap test. */ \
|
|
memset(check_buf, 0x00, sizeof(check_buf)); \
|
|
/* Fill stack with 0xFF. */ \
|
|
ignored = leaf_ ##name((unsigned long)&ignored, 1, \
|
|
FETCH_ARG_ ## which(zero)); \
|
|
/* Verify all bytes overwritten with 0xFF. */ \
|
|
for (sum = 0, i = 0; i < target_size; i++) \
|
|
sum += (check_buf[i] != 0xFF); \
|
|
if (sum) { \
|
|
pr_err(#name ": leaf fill was not 0xFF!?\n"); \
|
|
return 1; \
|
|
} \
|
|
/* Clear entire check buffer for later bit tests. */ \
|
|
memset(check_buf, 0x00, sizeof(check_buf)); \
|
|
/* Extract stack-defined variable contents. */ \
|
|
ignored = leaf_ ##name((unsigned long)&ignored, 0, \
|
|
FETCH_ARG_ ## which(zero)); \
|
|
\
|
|
/* Validate that compiler lined up fill and target. */ \
|
|
if (!range_contains(fill_start, fill_size, \
|
|
target_start, target_size)) { \
|
|
pr_err(#name ": stack fill missed target!?\n"); \
|
|
pr_err(#name ": fill %zu wide\n", fill_size); \
|
|
pr_err(#name ": target offset by %d\n", \
|
|
(int)((ssize_t)(uintptr_t)fill_start - \
|
|
(ssize_t)(uintptr_t)target_start)); \
|
|
return 1; \
|
|
} \
|
|
\
|
|
/* Look for any bytes still 0xFF in check region. */ \
|
|
for (sum = 0, i = 0; i < target_size; i++) \
|
|
sum += (check_buf[i] == 0xFF); \
|
|
\
|
|
if (sum == 0) { \
|
|
pr_info(#name " ok\n"); \
|
|
return 0; \
|
|
} else { \
|
|
pr_warn(#name " %sFAIL (uninit bytes: %d)\n", \
|
|
(xfail) ? "X" : "", sum); \
|
|
return (xfail) ? 0 : 1; \
|
|
} \
|
|
}
|
|
#define DEFINE_TEST(name, var_type, which, init_level) \
|
|
/* no-op to force compiler into ignoring "uninitialized" vars */\
|
|
static noinline __init DO_NOTHING_TYPE_ ## which(var_type) \
|
|
do_nothing_ ## name(var_type *ptr) \
|
|
{ \
|
|
/* Will always be true, but compiler doesn't know. */ \
|
|
if ((unsigned long)ptr > 0x2) \
|
|
return DO_NOTHING_RETURN_ ## which(ptr); \
|
|
else \
|
|
return DO_NOTHING_RETURN_ ## which(ptr + 1); \
|
|
} \
|
|
static noinline __init int leaf_ ## name(unsigned long sp, \
|
|
bool fill, \
|
|
var_type *arg) \
|
|
{ \
|
|
char buf[VAR_BUFFER]; \
|
|
var_type var INIT_ ## which ## _ ## init_level; \
|
|
\
|
|
target_start = &var; \
|
|
target_size = sizeof(var); \
|
|
/* \
|
|
* Keep this buffer around to make sure we've got a \
|
|
* stack frame of SOME kind... \
|
|
*/ \
|
|
memset(buf, (char)(sp & 0xff), sizeof(buf)); \
|
|
/* Fill variable with 0xFF. */ \
|
|
if (fill) { \
|
|
fill_start = &var; \
|
|
fill_size = sizeof(var); \
|
|
memset(fill_start, \
|
|
(char)((sp & 0xff) | forced_mask), \
|
|
fill_size); \
|
|
} \
|
|
\
|
|
/* Silence "never initialized" warnings. */ \
|
|
DO_NOTHING_CALL_ ## which(var, name); \
|
|
\
|
|
/* Exfiltrate "var". */ \
|
|
memcpy(check_buf, target_start, target_size); \
|
|
\
|
|
return (int)buf[0] | (int)buf[sizeof(buf) - 1]; \
|
|
} \
|
|
DEFINE_TEST_DRIVER(name, var_type, which, 0)
|
|
|
|
/* Structure with no padding. */
|
|
struct test_packed {
|
|
unsigned long one;
|
|
unsigned long two;
|
|
unsigned long three;
|
|
unsigned long four;
|
|
};
|
|
|
|
/* Simple structure with padding likely to be covered by compiler. */
|
|
struct test_small_hole {
|
|
size_t one;
|
|
char two;
|
|
/* 3 byte padding hole here. */
|
|
int three;
|
|
unsigned long four;
|
|
};
|
|
|
|
/* Trigger unhandled padding in a structure. */
|
|
struct test_big_hole {
|
|
u8 one;
|
|
u8 two;
|
|
u8 three;
|
|
/* 61 byte padding hole here. */
|
|
u8 four __aligned(64);
|
|
} __aligned(64);
|
|
|
|
struct test_trailing_hole {
|
|
char *one;
|
|
char *two;
|
|
char *three;
|
|
char four;
|
|
/* "sizeof(unsigned long) - 1" byte padding hole here. */
|
|
};
|
|
|
|
/* Test if STRUCTLEAK is clearing structs with __user fields. */
|
|
struct test_user {
|
|
u8 one;
|
|
unsigned long two;
|
|
char __user *three;
|
|
unsigned long four;
|
|
};
|
|
|
|
#define DEFINE_SCALAR_TEST(name, init) \
|
|
DEFINE_TEST(name ## _ ## init, name, SCALAR, init)
|
|
|
|
#define DEFINE_SCALAR_TESTS(init) \
|
|
DEFINE_SCALAR_TEST(u8, init); \
|
|
DEFINE_SCALAR_TEST(u16, init); \
|
|
DEFINE_SCALAR_TEST(u32, init); \
|
|
DEFINE_SCALAR_TEST(u64, init); \
|
|
DEFINE_TEST(char_array_ ## init, unsigned char, STRING, init)
|
|
|
|
#define DEFINE_STRUCT_TEST(name, init) \
|
|
DEFINE_TEST(name ## _ ## init, \
|
|
struct test_ ## name, STRUCT, init)
|
|
|
|
#define DEFINE_STRUCT_TESTS(init) \
|
|
DEFINE_STRUCT_TEST(small_hole, init); \
|
|
DEFINE_STRUCT_TEST(big_hole, init); \
|
|
DEFINE_STRUCT_TEST(trailing_hole, init); \
|
|
DEFINE_STRUCT_TEST(packed, init)
|
|
|
|
/* These should be fully initialized all the time! */
|
|
DEFINE_SCALAR_TESTS(zero);
|
|
DEFINE_STRUCT_TESTS(zero);
|
|
/* Static initialization: padding may be left uninitialized. */
|
|
DEFINE_STRUCT_TESTS(static_partial);
|
|
DEFINE_STRUCT_TESTS(static_all);
|
|
/* Dynamic initialization: padding may be left uninitialized. */
|
|
DEFINE_STRUCT_TESTS(dynamic_partial);
|
|
DEFINE_STRUCT_TESTS(dynamic_all);
|
|
/* Runtime initialization: padding may be left uninitialized. */
|
|
DEFINE_STRUCT_TESTS(runtime_partial);
|
|
DEFINE_STRUCT_TESTS(runtime_all);
|
|
/* No initialization without compiler instrumentation. */
|
|
DEFINE_SCALAR_TESTS(none);
|
|
DEFINE_STRUCT_TESTS(none);
|
|
DEFINE_TEST(user, struct test_user, STRUCT, none);
|
|
|
|
/*
|
|
* Check two uses through a variable declaration outside either path,
|
|
* which was noticed as a special case in porting earlier stack init
|
|
* compiler logic.
|
|
*/
|
|
static int noinline __leaf_switch_none(int path, bool fill)
|
|
{
|
|
switch (path) {
|
|
uint64_t var;
|
|
|
|
case 1:
|
|
target_start = &var;
|
|
target_size = sizeof(var);
|
|
if (fill) {
|
|
fill_start = &var;
|
|
fill_size = sizeof(var);
|
|
|
|
memset(fill_start, forced_mask | 0x55, fill_size);
|
|
}
|
|
memcpy(check_buf, target_start, target_size);
|
|
break;
|
|
case 2:
|
|
target_start = &var;
|
|
target_size = sizeof(var);
|
|
if (fill) {
|
|
fill_start = &var;
|
|
fill_size = sizeof(var);
|
|
|
|
memset(fill_start, forced_mask | 0xaa, fill_size);
|
|
}
|
|
memcpy(check_buf, target_start, target_size);
|
|
break;
|
|
default:
|
|
var = 5;
|
|
return var & forced_mask;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static noinline __init int leaf_switch_1_none(unsigned long sp, bool fill,
|
|
uint64_t *arg)
|
|
{
|
|
return __leaf_switch_none(1, fill);
|
|
}
|
|
|
|
static noinline __init int leaf_switch_2_none(unsigned long sp, bool fill,
|
|
uint64_t *arg)
|
|
{
|
|
return __leaf_switch_none(2, fill);
|
|
}
|
|
|
|
/*
|
|
* These are expected to fail for most configurations because neither
|
|
* GCC nor Clang have a way to perform initialization of variables in
|
|
* non-code areas (i.e. in a switch statement before the first "case").
|
|
* https://bugs.llvm.org/show_bug.cgi?id=44916
|
|
*/
|
|
DEFINE_TEST_DRIVER(switch_1_none, uint64_t, SCALAR, 1);
|
|
DEFINE_TEST_DRIVER(switch_2_none, uint64_t, SCALAR, 1);
|
|
|
|
static int __init test_stackinit_init(void)
|
|
{
|
|
unsigned int failures = 0;
|
|
|
|
#define test_scalars(init) do { \
|
|
failures += test_u8_ ## init (); \
|
|
failures += test_u16_ ## init (); \
|
|
failures += test_u32_ ## init (); \
|
|
failures += test_u64_ ## init (); \
|
|
failures += test_char_array_ ## init (); \
|
|
} while (0)
|
|
|
|
#define test_structs(init) do { \
|
|
failures += test_small_hole_ ## init (); \
|
|
failures += test_big_hole_ ## init (); \
|
|
failures += test_trailing_hole_ ## init (); \
|
|
failures += test_packed_ ## init (); \
|
|
} while (0)
|
|
|
|
/* These are explicitly initialized and should always pass. */
|
|
test_scalars(zero);
|
|
test_structs(zero);
|
|
/* Padding here appears to be accidentally always initialized? */
|
|
test_structs(dynamic_partial);
|
|
/* Padding initialization depends on compiler behaviors. */
|
|
test_structs(static_partial);
|
|
test_structs(static_all);
|
|
test_structs(dynamic_all);
|
|
test_structs(runtime_partial);
|
|
test_structs(runtime_all);
|
|
|
|
/* STRUCTLEAK_BYREF_ALL should cover everything from here down. */
|
|
test_scalars(none);
|
|
failures += test_switch_1_none();
|
|
failures += test_switch_2_none();
|
|
|
|
/* STRUCTLEAK_BYREF should cover from here down. */
|
|
test_structs(none);
|
|
|
|
/* STRUCTLEAK will only cover this. */
|
|
failures += test_user();
|
|
|
|
if (failures == 0)
|
|
pr_info("all tests passed!\n");
|
|
else
|
|
pr_err("failures: %u\n", failures);
|
|
|
|
return failures ? -EINVAL : 0;
|
|
}
|
|
module_init(test_stackinit_init);
|
|
|
|
static void __exit test_stackinit_exit(void)
|
|
{ }
|
|
module_exit(test_stackinit_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|