/* "An issue was discovered in drivers/scsi/aacraid/commctrl.c in the Linux kernel before 4.13. There is potential exposure of kernel stack memory because aac_get_hba_info does not initialize the hbainfo structure." Fixed e.g. by 342ffc26693b528648bdc9377e51e4f2450b4860 on linux-4.13.y in linux-stable. This is a simplified version of that code (before and after the fix). */ /* { dg-do compile } */ /* { dg-options "-fanalyzer" } */ /* { dg-require-effective-target analyzer } */ /* { dg-skip-if "structure layout assumption not met" { default_packed } } */ #include typedef unsigned int __u32; typedef unsigned int u32; typedef unsigned char u8; #include "test-uaccess.h" /* Adapted from include/uapi/linux/types.h */ #define __bitwise typedef __u32 __bitwise __le32; /* Adapted from drivers/scsi/aacraid/aacraid.h */ struct aac_hba_info { u8 driver_name[50]; /* { dg-message "field 'driver_name' is uninitialized \\(50 bytes\\)" } */ u8 adapter_number; u8 system_io_bus_number; u8 device_number; /* { dg-message "padding after field 'device_number' is uninitialized \\(3 bytes\\)" } */ u32 function_number; u32 vendor_id; u32 device_id; u32 sub_vendor_id; u32 sub_system_id; u32 mapped_base_address_size; /* { dg-message "field 'mapped_base_address_size' is uninitialized \\(4 bytes\\)" } */ u32 base_physical_address_high_part; u32 base_physical_address_low_part; u32 max_command_size; u32 max_fib_size; u32 max_scatter_gather_from_os; u32 max_scatter_gather_to_fw; u32 max_outstanding_fibs; u32 queue_start_threshold; u32 queue_dump_threshold; u32 max_io_size_queued; u32 outstanding_io; u32 firmware_build_number; u32 bios_build_number; u32 driver_build_number; u32 serial_number_high_part; u32 serial_number_low_part; u32 supported_options; u32 feature_bits; u32 currentnumber_ports; u8 new_comm_interface:1; /* { dg-message "field 'new_comm_interface' is uninitialized \\(1 bit\\)" } */ u8 new_commands_supported:1; u8 disable_passthrough:1; u8 expose_non_dasd:1; u8 queue_allowed:1; u8 bled_check_enabled:1; u8 reserved1:1; u8 reserted2:1; u32 reserved3[10]; /* { dg-message "field 'reserved3' is uninitialized \\(40 bytes\\)" } */ }; struct aac_dev { /* [...snip...] */ int id; /* [...snip...] */ struct pci_dev *pdev; /* Our PCI interface */ /* [...snip...] */ }; /* Adapted from include/linux/pci.h */ struct pci_dev { /* [...snip...] */ struct pci_bus *bus; /* bus this device is on */ /* [...snip...] */ unsigned int devfn; /* encoded device & function index */ unsigned short vendor; unsigned short device; unsigned short subsystem_vendor; unsigned short subsystem_device; /* [...snip...] */ }; struct pci_bus { /* [...snip...] */ unsigned char number; /* bus number */ /* [...snip...] */ }; /* Adapted from drivers/scsi/aacraid/commctrl.c */ static int aac_get_hba_info(struct aac_dev *dev, void __user *arg) { struct aac_hba_info hbainfo; /* { dg-message "region created on stack here" "memspace message" } */ /* { dg-message "capacity: 200 bytes" "capacity message" { target *-*-* } .-1 } */ hbainfo.adapter_number = (u8) dev->id; hbainfo.system_io_bus_number = dev->pdev->bus->number; hbainfo.device_number = (dev->pdev->devfn >> 3); hbainfo.function_number = (dev->pdev->devfn & 0x0007); hbainfo.vendor_id = dev->pdev->vendor; hbainfo.device_id = dev->pdev->device; hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; hbainfo.sub_system_id = dev->pdev->subsystem_device; if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { /* { dg-warning "potential exposure of sensitive information by copying uninitialized data from stack" "warning" } */ /* { dg-message "177 bytes are uninitialized" "how much" { target *-*-* } .-1 } */ /* [...snip...] */ } return 0; } static int aac_get_hba_info_fixed(struct aac_dev *dev, void __user *arg) { struct aac_hba_info hbainfo; memset(&hbainfo, 0, sizeof(hbainfo)); hbainfo.adapter_number = (u8) dev->id; hbainfo.system_io_bus_number = dev->pdev->bus->number; hbainfo.device_number = (dev->pdev->devfn >> 3); hbainfo.function_number = (dev->pdev->devfn & 0x0007); hbainfo.vendor_id = dev->pdev->vendor; hbainfo.device_id = dev->pdev->device; hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; hbainfo.sub_system_id = dev->pdev->subsystem_device; if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { /* { dg-bogus "" } */ /* [...snip...] */ } return 0; } /* An alternate fix using "= {0}" rather than memset. */ static int aac_get_hba_info_fixed_alt(struct aac_dev *dev, void __user *arg) { struct aac_hba_info hbainfo = {0}; memset(&hbainfo, 0, sizeof(hbainfo)); hbainfo.adapter_number = (u8) dev->id; hbainfo.system_io_bus_number = dev->pdev->bus->number; hbainfo.device_number = (dev->pdev->devfn >> 3); hbainfo.function_number = (dev->pdev->devfn & 0x0007); hbainfo.vendor_id = dev->pdev->vendor; hbainfo.device_id = dev->pdev->device; hbainfo.sub_vendor_id = dev->pdev->subsystem_vendor; hbainfo.sub_system_id = dev->pdev->subsystem_device; if (copy_to_user(arg, &hbainfo, sizeof(struct aac_hba_info))) { /* { dg-bogus "" } */ /* [...snip...] */ } return 0; }