* remotes/origin/tmp-4716ccc :
UPSTREAM: media: rc: Fix use-after-free bugs caused by ene_tx_irqsim()
ANDROID: incremental fs: Evict inodes before freeing mount data
UPSTREAM: ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
UPSTREAM: hid: bigben_probe(): validate report count
UPSTREAM: HID: bigben: use spinlock to safely schedule workers
BACKPORT: of: base: Skip CPU nodes with "fail"/"fail-..." status
UPSTREAM: HID: bigben_worker() remove unneeded check on report_field
UPSTREAM: HID: bigben: use spinlock to protect concurrent accesses
UPSTREAM: hwrng: virtio - add an internal buffer
UPSTREAM: ext4: fix another off-by-one fsmap error on 1k block filesystems
UPSTREAM: ext4: refuse to create ea block when umounted
UPSTREAM: ext4: optimize ea_inode block expansion
UPSTREAM: ext4: allocate extended attribute value in vmalloc area
BACKPORT: FROMGIT: cgroup: Use separate src/dst nodes when preloading css_sets for migration
ANDROID: fs/f2fs: fixup __f2fs_cluster_blocks with F2FS_FS_COMPRESSION
UPSTREAM: usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
UPSTREAM: KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS
Revert "iommu: Add gfp parameter to iommu_ops::map"
Revert "iommu/amd: Pass gfp flags to iommu_map_page() in amd_iommu_map()"
Revert "RDMA/usnic: use iommu_map_atomic() under spin_lock()"
Linux 5.4.233
bpf: add missing header file include
Revert "net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo child qdiscs"
ext4: Fix function prototype mismatch for ext4_feat_ktype
wifi: mwifiex: Add missing compatible string for SD8787
uaccess: Add speculation barrier to copy_from_user()
mac80211: mesh: embedd mesh_paths and mpp_paths into ieee80211_if_mesh
drm/i915/gvt: fix double free bug in split_2MB_gtt_entry
alarmtimer: Prevent starvation by small intervals and SIG_IGN
powerpc: dts: t208x: Disable 10G on MAC1 and MAC2
can: kvaser_usb: hydra: help gcc-13 to figure out cmd_len
KVM: VMX: Execute IBPB on emulated VM-exit when guest has IBRS
KVM: x86: Fail emulation during EMULTYPE_SKIP on any exception
random: always mix cycle counter in add_latent_entropy()
powerpc: dts: t208x: Mark MAC1 and MAC2 as 10G
wifi: rtl8xxxu: gen2: Turn on the rate control
drm/etnaviv: don't truncate physical page address
drm: etnaviv: fix common struct sg_table related issues
scatterlist: add generic wrappers for iterating over sgtable objects
dma-mapping: add generic helpers for mapping sgtable objects
Linux 5.4.232
iommu/amd: Pass gfp flags to iommu_map_page() in amd_iommu_map()
net: sched: sch: Fix off by one in htb_activate_prios()
ASoC: SOF: Intel: hda-dai: fix possible stream_tag leak
nilfs2: fix underflow in second superblock position calculations
kvm: initialize all of the kvm_debugregs structure before sending it to userspace
i40e: Add checking for null for nlmsg_find_attr()
ipv6: Fix tcp socket connection with DSCP.
ipv6: Fix datagram socket connection with DSCP.
ixgbe: add double of VLAN header when computing the max MTU
net: mpls: fix stale pointer if allocation fails during device rename
net: stmmac: Restrict warning on disabling DMA store and fwd mode
bnxt_en: Fix mqprio and XDP ring checking logic
net: stmmac: fix order of dwmac5 FlexPPS parametrization sequence
net/usb: kalmia: Don't pass act_len in usb_bulk_msg error path
dccp/tcp: Avoid negative sk_forward_alloc by ipv6_pinfo.pktoptions.
sctp: sctp_sock_filter(): avoid list_entry() on possibly empty list
net: bgmac: fix BCM5358 support by setting correct flags
i40e: add double of VLAN header when computing the max MTU
ixgbe: allow to increase MTU to 3K with XDP enabled
revert "squashfs: harden sanity check in squashfs_read_xattr_id_table"
net: Fix unwanted sign extension in netdev_stats_to_stats64()
Revert "mm: Always release pages to the buddy allocator in memblock_free_late()."
hugetlb: check for undefined shift on 32 bit architectures
sched/psi: Fix use-after-free in ep_remove_wait_queue()
ALSA: hda/realtek - fixed wrong gpio assigned
ALSA: hda/conexant: add a new hda codec SN6180
mmc: mmc_spi: fix error handling in mmc_spi_probe()
mmc: sdio: fix possible resource leaks in some error paths
ipv4: Fix incorrect route flushing when source address is deleted
Revert "ipv4: Fix incorrect route flushing when source address is deleted"
xfs: sync lazy sb accounting on quiesce of read-only mounts
xfs: prevent UAF in xfs_log_item_in_current_chkpt
xfs: fix the forward progress assertion in xfs_iwalk_run_callbacks
xfs: ensure inobt record walks always make forward progress
xfs: fix missing CoW blocks writeback conversion retry
xfs: only relog deferred intent items if free space in the log gets low
xfs: expose the log push threshold
xfs: periodically relog deferred intent items
xfs: change the order in which child and parent defer ops are finished
xfs: fix an incore inode UAF in xfs_bui_recover
xfs: clean up xfs_bui_item_recover iget/trans_alloc/ilock ordering
xfs: clean up bmap intent item recovery checking
xfs: xfs_defer_capture should absorb remaining transaction reservation
xfs: xfs_defer_capture should absorb remaining block reservations
xfs: proper replay of deferred ops queued during log recovery
xfs: fix finobt btree block recovery ordering
xfs: log new intent items created as part of finishing recovered intent items
xfs: refactor xfs_defer_finish_noroll
xfs: turn dfp_intent into a xfs_log_item
xfs: merge the ->diff_items defer op into ->create_intent
xfs: merge the ->log_item defer op into ->create_intent
xfs: factor out a xfs_defer_create_intent helper
xfs: remove the xfs_inode_log_item_t typedef
xfs: remove the xfs_efd_log_item_t typedef
xfs: remove the xfs_efi_log_item_t typedef
netfilter: nft_tproxy: restrict to prerouting hook
btrfs: free device in btrfs_close_devices for a single device filesystem
aio: fix mremap after fork null-deref
nvme-fc: fix a missing queue put in nvmet_fc_ls_create_association
s390/decompressor: specify __decompress() buf len to avoid overflow
net: sched: sch: Bounds check priority
net: stmmac: do not stop RX_CLK in Rx LPI state for qcs404 SoC
net/rose: Fix to not accept on connected socket
tools/virtio: fix the vringh test for virtio ring changes
ASoC: cs42l56: fix DT probe
selftests/bpf: Verify copy_register_state() preserves parent/live fields
migrate: hugetlb: check for hugetlb shared PMD in node migration
bpf: Always return target ifindex in bpf_fib_lookup
nvme-pci: Move enumeration by class to be last in the table
arm64: dts: meson-axg: Make mmc host controller interrupts level-sensitive
arm64: dts: meson-g12-common: Make mmc host controller interrupts level-sensitive
arm64: dts: meson-gx: Make mmc host controller interrupts level-sensitive
riscv: Fixup race condition on PG_dcache_clean in flush_icache_pte
ceph: flush cap releases when the session is flushed
usb: typec: altmodes/displayport: Fix probe pin assign check
usb: core: add quirk for Alcor Link AK9563 smartcard reader
net: USB: Fix wrong-direction WARNING in plusb.c
pinctrl: intel: Restore the pins that used to be in Direct IRQ mode
pinctrl: single: fix potential NULL dereference
pinctrl: aspeed: Fix confusing types in return value
ALSA: pci: lx6464es: fix a debug loop
selftests: forwarding: lib: quote the sysctl values
rds: rds_rm_zerocopy_callback() use list_first_entry()
ice: Do not use WQ_MEM_RECLAIM flag for workqueue
ionic: clean interrupt before enabling queue to avoid credit race
net: phy: meson-gxl: use MMD access dummy stubs for GXL, internal PHY
bonding: fix error checking in bond_debug_reregister()
xfrm: fix bug with DSCP copy to v6 from v4 tunnel
RDMA/usnic: use iommu_map_atomic() under spin_lock()
iommu: Add gfp parameter to iommu_ops::map
IB/IPoIB: Fix legacy IPoIB due to wrong number of queues
IB/hfi1: Restore allocated resources on failed copyout
can: j1939: do not wait 250 ms if the same addr was already claimed
tracing: Fix poll() and select() do not work on per_cpu trace_pipe and trace_pipe_raw
ALSA: emux: Avoid potential array out-of-bound in snd_emux_xg_control()
btrfs: zlib: zero-initialize zlib workspace
btrfs: limit device extents to the device size
iio:adc:twl6030: Enable measurement of VAC
wifi: brcmfmac: Check the count value of channel spec to prevent out-of-bounds reads
f2fs: fix to do sanity check on i_extra_isize in is_alive()
fbdev: smscufx: fix error handling code in ufx_usb_probe
powerpc/imc-pmu: Revert nest_init_lock to being a mutex
serial: 8250_dma: Fix DMA Rx rearm race
serial: 8250_dma: Fix DMA Rx completion race
xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
mm: swap: properly update readahead statistics in unuse_pte_range()
nvmem: core: fix cell removal on error
Squashfs: fix handling and sanity checking of xattr_ids count
mm/swapfile: add cond_resched() in get_swap_pages()
fpga: stratix10-soc: Fix return value check in s10_ops_write_init()
mm: hugetlb: proc: check for hugetlb shared PMD in /proc/PID/smaps
riscv: disable generation of unwind tables
parisc: Wire up PTRACE_GETREGS/PTRACE_SETREGS for compat case
parisc: Fix return code of pdc_iodc_print()
iio:adc:twl6030: Enable measurements of VUSB, VBAT and others
iio: adc: berlin2-adc: Add missing of_node_put() in error path
iio: hid: fix the retval in accel_3d_capture_sample
efi: Accept version 2 of memory attributes table
watchdog: diag288_wdt: fix __diag288() inline assembly
watchdog: diag288_wdt: do not use stack buffers for hardware data
fbcon: Check font dimension limits
Input: i8042 - add Clevo PCX0DX to i8042 quirk table
Input: i8042 - add TUXEDO devices to i8042 quirk tables
Input: i8042 - merge quirk tables
Input: i8042 - move __initconst to fix code styling warning
vc_screen: move load of struct vc_data pointer in vcs_read() to avoid UAF
usb: gadget: f_fs: Fix unbalanced spinlock in __ffs_ep0_queue_wait
usb: dwc3: qcom: enable vbus override when in OTG dr-mode
usb: dwc3: dwc3-qcom: Fix typo in the dwc3 vbus override API
iio: adc: stm32-dfsdm: fill module aliases
net/x25: Fix to not accept on connected socket
i2c: rk3x: fix a bunch of kernel-doc warnings
scsi: iscsi_tcp: Fix UAF during login when accessing the shost ipaddress
scsi: target: core: Fix warning on RT kernels
efi: fix potential NULL deref in efi_mem_reserve_persistent
net: openvswitch: fix flow memory leak in ovs_flow_cmd_new
virtio-net: Keep stop() to follow mirror sequence of open()
selftests: net: udpgso_bench_tx: Cater for pending datagrams zerocopy benchmarking
selftests: net: udpgso_bench: Fix racing bug between the rx/tx programs
selftests: net: udpgso_bench_rx/tx: Stop when wrong CLI args are provided
selftests: net: udpgso_bench_rx: Fix 'used uninitialized' compiler warning
ata: libata: Fix sata_down_spd_limit() when no link speed is reported
can: j1939: fix errant WARN_ON_ONCE in j1939_session_deactivate
net: phy: meson-gxl: Add generic dummy stubs for MMD register access
squashfs: harden sanity check in squashfs_read_xattr_id_table
netfilter: br_netfilter: disable sabotage_in hook after first suppression
netrom: Fix use-after-free caused by accept on already connected socket
fix "direction" argument of iov_iter_kvec()
fix iov_iter_bvec() "direction" argument
WRITE is "data source", not destination...
scsi: Revert "scsi: core: map PQ=1, PDT=other values to SCSI_SCAN_TARGET_PRESENT"
arm64: dts: imx8mm: Fix pad control for UART1_DTE_RX
ALSA: hda/via: Avoid potential array out-of-bound in add_secret_dac_path()
ASoC: Intel: bytcr_rt5651: Drop reference count of ACPI device after use
bus: sunxi-rsb: Fix error handling in sunxi_rsb_init()
firewire: fix memory leak for payload of request subaction to IEC 61883-1 FCP region
Linux 5.4.231
Revert "xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()"
usb: host: xhci-plat: add wakeup entry at sysfs
Bluetooth: fix null ptr deref on hci_sync_conn_complete_evt
ipv6: ensure sane device mtu in tunnels
exit: Use READ_ONCE() for all oops/warn limit reads
docs: Fix path paste-o for /sys/kernel/warn_count
panic: Expose "warn_count" to sysfs
panic: Introduce warn_limit
panic: Consolidate open-coded panic_on_warn checks
exit: Allow oops_limit to be disabled
exit: Expose "oops_count" to sysfs
exit: Put an upper limit on how often we can oops
ia64: make IA64_MCA_RECOVERY bool instead of tristate
csky: Fix function name in csky_alignment() and die()
h8300: Fix build errors from do_exit() to make_task_dead() transition
hexagon: Fix function name in die()
objtool: Add a missing comma to avoid string concatenation
exit: Add and use make_task_dead.
mm: kasan: do not panic if both panic_on_warn and kasan_multishot set
panic: unset panic_on_warn inside panic()
sysctl: add a new register_sysctl_init() interface
dmaengine: imx-sdma: Fix a possible memory leak in sdma_transfer_init
blk-cgroup: fix missing pd_online_fn() while activating policy
bpf: Skip task with pid=1 in send_signal_common()
ARM: dts: imx: Fix pca9547 i2c-mux node name
x86/asm: Fix an assembler warning with current binutils
clk: Fix pointer casting to prevent oops in devm_clk_release()
perf/x86/amd: fix potential integer overflow on shift of a int
netfilter: conntrack: unify established states for SCTP paths
x86/i8259: Mark legacy PIC interrupts with IRQ_LEVEL
block: fix and cleanup bio_check_ro
nfsd: Ensure knfsd shuts down when the "nfsd" pseudofs is unmounted
Revert "Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode"
net: mdio-mux-meson-g12a: force internal PHY off on mux switch
net: xgene: Move shared header file into include/linux
net/phy/mdio-i2c: Move header file to include/linux/mdio
net/tg3: resolve deadlock in tg3_reset_task() during EEH
thermal: intel: int340x: Add locking to int340x_thermal_get_trip_type()
net: ravb: Fix possible hang if RIS2_QFF1 happen
sctp: fail if no bound addresses can be used for a given scope
net/sched: sch_taprio: do not schedule in taprio_reset()
netrom: Fix use-after-free of a listening socket.
netfilter: conntrack: fix vtag checks for ABORT/SHUTDOWN_COMPLETE
ipv4: prevent potential spectre v1 gadget in fib_metrics_match()
ipv4: prevent potential spectre v1 gadget in ip_metrics_convert()
netlink: annotate data races around sk_state
netlink: annotate data races around dst_portid and dst_group
netlink: annotate data races around nlk->portid
netfilter: nft_set_rbtree: skip elements in transaction from garbage collection
net: fix UaF in netns ops registration error path
netlink: prevent potential spectre v1 gadgets
EDAC/qcom: Do not pass llcc_driv_data as edac_device_ctl_info's pvt_info
EDAC/device: Respect any driver-supplied workqueue polling value
ARM: 9280/1: mm: fix warning on phys_addr_t to void pointer assignment
thermal: intel: int340x: Protect trip temperature from concurrent updates
KVM: x86/vmx: Do not skip segment attributes if unusable bit is set
cifs: Fix oops due to uncleared server->smbd_conn in reconnect
ftrace/scripts: Update the instructions for ftrace-bisect.sh
trace_events_hist: add check for return value of 'create_hist_field'
tracing: Make sure trace_printk() can output as soon as it can be used
module: Don't wait for GOING modules
scsi: hpsa: Fix allocation size for scsi_host_alloc()
Bluetooth: hci_sync: cancel cmd_timer if hci_open failed
Revert "Revert "xhci: Set HCD flag to defer primary roothub registration""
fs: reiserfs: remove useless new_opts in reiserfs_remount
netfilter: conntrack: do not renew entry stuck in tcp SYN_SENT state
Revert "selftests/bpf: check null propagation only neither reg is PTR_TO_BTF_ID"
mmc: sdhci-esdhc-imx: correct the tuning start tap and step setting
mmc: sdhci-esdhc-imx: disable the CMD CRC check for standard tuning
mmc: sdhci-esdhc-imx: clear pending interrupt and halt cqhci
lockref: stop doing cpu_relax in the cmpxchg loop
platform/x86: asus-nb-wmi: Add alternate mapping for KEY_SCREENLOCK
platform/x86: touchscreen_dmi: Add info for the CSL Panther Tab HD
scsi: hisi_sas: Set a port invalid only if there are no devices attached when refreshing port id
KVM: s390: interrupt: use READ_ONCE() before cmpxchg()
spi: spidev: remove debug messages that access spidev->spi without locking
ASoC: fsl-asoc-card: Fix naming of AC'97 CODEC widgets
ASoC: fsl_ssi: Rename AC'97 streams to avoid collisions with AC'97 CODEC
cpufreq: armada-37xx: stop using 0 as NULL pointer
s390/debug: add _ASM_S390_ prefix to header guard
drm: Add orientation quirk for Lenovo ideapad D330-10IGL
ASoC: fsl_micfil: Correct the number of steps on SX controls
cpufreq: Add Tegra234 to cpufreq-dt-platdev blocklist
tcp: fix rate_app_limited to default to 1
net: dsa: microchip: ksz9477: port map correction in ALU table entry register
driver core: Fix test_async_probe_init saves device in wrong array
w1: fix WARNING after calling w1_process()
w1: fix deadloop in __w1_remove_master_device()
tcp: avoid the lookup process failing to get sk in ehash table
dmaengine: xilinx_dma: call of_node_put() when breaking out of for_each_child_of_node()
dmaengine: xilinx_dma: Fix devm_platform_ioremap_resource error handling
dmaengine: xilinx_dma: use devm_platform_ioremap_resource()
HID: betop: check shape of output reports
net: macb: fix PTP TX timestamp failure due to packet padding
dmaengine: Fix double increment of client_count in dma_chan_get()
drm/panfrost: fix GENERIC_ATOMIC64 dependency
net: mlx5: eliminate anonymous module_init & module_exit
usb: gadget: f_fs: Ensure ep0req is dequeued before free_request
usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
HID: revert CHERRY_MOUSE_000C quirk
net: stmmac: fix invalid call to mdiobus_get_phy()
HID: check empty report_list in bigben_probe()
HID: check empty report_list in hid_validate_values()
net: mdio: validate parameter addr in mdiobus_get_phy()
net: usb: sr9700: Handle negative len
l2tp: Don't sleep and disable BH under writer-side sk_callback_lock
l2tp: Serialize access to sk_user_data with sk_callback_lock
net: fix a concurrency bug in l2tp_tunnel_register()
net/sched: sch_taprio: fix possible use-after-free
wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid
gpio: mxc: Always set GPIOs used as interrupt source to INPUT mode
net: wan: Add checks for NULL for utdm in undo_uhdlc_init and unmap_si_regs
net: nfc: Fix use-after-free in local_cleanup()
phy: rockchip-inno-usb2: Fix missing clk_disable_unprepare() in rockchip_usb2phy_power_on()
bpf: Fix pointer-leak due to insufficient speculative store bypass mitigation
amd-xgbe: Delay AN timeout during KR training
amd-xgbe: TX Flow Ctrl Registers are h/w ver dependent
affs: initialize fsdata in affs_truncate()
IB/hfi1: Fix expected receive setup error exit issues
IB/hfi1: Reserve user expected TIDs
IB/hfi1: Reject a zero-length user expected buffer
RDMA/core: Fix ib block iterator counter overflow
tomoyo: fix broken dependency on *.conf.default
EDAC/highbank: Fix memory leak in highbank_mc_probe()
HID: intel_ish-hid: Add check for ishtp_dma_tx_map
ARM: imx: add missing of_node_put()
ARM: imx35: Retrieve the IIM base address from devicetree
ARM: imx31: Retrieve the IIM base address from devicetree
ARM: imx27: Retrieve the SYSCTRL base address from devicetree
ARM: dts: imx6qdl-gw560x: Remove incorrect 'uart-has-rtscts'
memory: mvebu-devbus: Fix missing clk_disable_unprepare in mvebu_devbus_probe()
memory: atmel-sdramc: Fix missing clk_disable_unprepare in atmel_ramc_probe()
clk: Provide new devm_clk helpers for prepared and enabled clocks
clk: generalize devm_clk_get() a bit
Linux 5.4.230
mm/khugepaged: fix collapse_pte_mapped_thp() to allow anon_vma
x86/fpu: Use _Alignof to avoid undefined behavior in TYPE_ALIGN
drm/amd/display: Fix COLOR_SPACE_YCBCR2020_TYPE matrix
drm/amd/display: Fix set scaling doesn's work
drm/i915: re-disable RC6p on Sandy Bridge
gsmi: fix null-deref in gsmi_get_variable
serial: atmel: fix incorrect baudrate setup
dmaengine: tegra210-adma: fix global intr clear
serial: pch_uart: Pass correct sg to dma_unmap_sg()
dt-bindings: phy: g12a-usb3-pcie-phy: fix compatible string documentation
usb-storage: apply IGNORE_UAS only for HIKSEMI MD202 on RTL9210
usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate()
usb: gadget: g_webcam: Send color matching descriptor per frame
usb: typec: altmodes/displayport: Fix pin assignment calculation
usb: typec: altmodes/displayport: Add pin assignment helper
usb: host: ehci-fsl: Fix module alias
USB: serial: cp210x: add SCALANCE LPE-9000 device id
USB: gadgetfs: Fix race between mounting and unmounting
cifs: do not include page data when checking signature
btrfs: fix race between quota rescan and disable leading to NULL pointer deref
mmc: sunxi-mmc: Fix clock refcount imbalance during unbind
comedi: adv_pci1760: Fix PWM instruction handling
usb: core: hub: disable autosuspend for TI TUSB8041
misc: fastrpc: Fix use-after-free race condition for maps
misc: fastrpc: Don't remove map on creater_process and device_release
USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100
USB: serial: option: add Quectel EM05CN modem
USB: serial: option: add Quectel EM05CN (SG) modem
USB: serial: option: add Quectel EC200U modem
USB: serial: option: add Quectel EM05-G (RS) modem
USB: serial: option: add Quectel EM05-G (CS) modem
USB: serial: option: add Quectel EM05-G (GR) modem
prlimit: do_prlimit needs to have a speculation check
xhci: Detect lpm incapable xHC USB3 roothub ports from ACPI tables
usb: acpi: add helper to check port lpm capability using acpi _DSM
xhci: Add a flag to disable USB3 lpm on a xhci root port level.
xhci: Add update_hub_device override for PCI xHCI hosts
xhci: Fix null pointer dereference when host dies
usb: xhci: Check endpoint is valid before dereferencing it
xhci-pci: set the dma max_seg_size
ALSA: hda/realtek - Turn on power early
drm/i915/gt: Reset twice
efi: fix userspace infinite retry read efivars after EFI runtime services page fault
nilfs2: fix general protection fault in nilfs_btree_insert()
Add exception protection processing for vd in axi_chan_handle_err function
wifi: brcmfmac: fix regression for Broadcom PCIe wifi devices
f2fs: let's avoid panic if extent_tree is not created
RDMA/srp: Move large values to a new enum for gcc13
net/ethtool/ioctl: return -EOPNOTSUPP if we have no phy stats
selftests/bpf: check null propagation only neither reg is PTR_TO_BTF_ID
pNFS/filelayout: Fix coalescing test for single DS
Revert "net: add atomic_long_t to net_device_stats fields"
Revert "PM/devfreq: governor: Add a private governor_data for governor"
Linux 5.4.229
tipc: call tipc_lxc_xmit without holding node_read_lock
ocfs2: fix freeing uninitialized resource on ocfs2_dlm_shutdown
tipc: Add a missing case of TIPC_DIRECT_MSG type
tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started
tipc: fix use-after-free in tipc_disc_rcv()
Revert "usb: ulpi: defer ulpi_register on ulpi_read_id timeout"
mm: Always release pages to the buddy allocator in memblock_free_late().
efi: fix NULL-deref in init error path
arm64: cmpxchg_double*: hazard against entire exchange variable
arm64: atomics: remove LL/SC trampolines
arm64: atomics: format whitespace consistently
drm/virtio: Fix GEM handle creation UAF
x86/resctrl: Fix task CLOSID/RMID update race
x86/resctrl: Use task_curr() instead of task_struct->on_cpu to prevent unnecessary IPI
iommu/mediatek-v1: Fix an error handling path in mtk_iommu_v1_probe()
iommu/mediatek-v1: Add error handle for mtk_iommu_probe
net/mlx5: Fix ptp max frequency adjustment range
net/mlx5: Rename ptp clock info
net/sched: act_mpls: Fix warning during failed attribute validation
nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame()
hvc/xen: lock console list traversal
tipc: fix unexpected link reset due to discovery messages
tipc: eliminate checking netns if node established
tipc: improve throughput between nodes in netns
regulator: da9211: Use irq handler when ready
EDAC/device: Fix period calculation in edac_device_reset_delay_period()
x86/boot: Avoid using Intel mnemonics in AT&T syntax asm
powerpc/imc-pmu: Fix use of mutex in IRQs disabled section
netfilter: ipset: Fix overflow before widen in the bitmap_ip_create() function.
ext4: fix uninititialized value in 'ext4_evict_inode'
ext4: fix use-after-free in ext4_orphan_cleanup
ext4: lost matching-pair of trace in ext4_truncate
ext4: fix bug_on in __es_tree_search caused by bad quota inode
quota: Factor out setup of quota inode
jbd2: use the correct print format
usb: ulpi: defer ulpi_register on ulpi_read_id timeout
wifi: wilc1000: sdio: fix module autoloading
ipv6: raw: Deduct extension header length in rawv6_push_pending_frames
ixgbe: fix pci device refcount leak
platform/x86: sony-laptop: Don't turn off 0x153 keyboard backlight during probe
drm/msm/adreno: Make adreno quirks not overwrite each other
cifs: Fix uninitialized memory read for smb311 posix symlink create
ALSA: hda/hdmi: Add a HP device 0x8715 to force connect list
ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
net/ulp: prevent ULP without clone op from entering the LISTEN status
s390/percpu: add READ_ONCE() to arch_this_cpu_to_op_simple()
s390/kexec: fix ipl report address for kdump
perf auxtrace: Fix address filter duplicate symbol selection
docs: Fix the docs build with Sphinx 6.0
efi: tpm: Avoid READ_ONCE() for accessing the event log
KVM: arm64: Fix S1PTW handling on RO memslots
net: sched: disallow noqueue for qdisc classes
driver core: Fix bus_type.match() error handling in __driver_attach()
selftests: set the BUILD variable to absolute path
selftests: Fix kselftest O=objdir build from cluttering top level objdir
parisc: Align parisc MADV_XXX constants with all other architectures
mbcache: Avoid nesting of cache->c_list_lock under bit locks
hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling
hfs/hfsplus: use WARN_ON for sanity check
ext4: don't allow journal inode to have encrypt flag
riscv: uaccess: fix type of 0 variable on error in get_user()
nfsd: fix handling of readdir in v4root vs. mount upcall timeout
x86/bugs: Flush IBP in ib_prctl_set()
ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet
udf: Fix extension of the last extent in the file
caif: fix memory leak in cfctrl_linkup_request()
drm/i915: unpin on error in intel_vgpu_shadow_mm_pin()
usb: rndis_host: Secure rndis_query check against int overflow
drivers/net/bonding/bond_3ad: return when there's no aggregator
perf tools: Fix resources leak in perf_data__open_dir()
net: sched: cbq: dont intepret cls results when asked to drop
net: sched: atm: dont intepret cls results when asked to drop
RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
RDMA/uverbs: Silence shiftTooManyBitsSigned warning
net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
net: amd-xgbe: add missed tasklet_kill
vhost: fix range used in translate_desc()
nfc: Fix potential resource leaks
qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
net: sched: fix memory leak in tcindex_set_parms
net: hns3: add interrupts re-initialization while doing VF FLR
nfsd: shut down the NFSv4 state objects before the filecache
bpf: pull before calling skb_postpull_rcsum()
SUNRPC: ensure the matching upcall is in-flight upon downcall
ext4: fix deadlock due to mbcache entry corruption
mbcache: automatically delete entries from cache on freeing
ext4: fix race when reusing xattr blocks
ext4: unindent codeblock in ext4_xattr_block_set()
ext4: remove EA inode entry from mbcache on inode eviction
mbcache: add functions to delete entry if unused
mbcache: don't reclaim used entries
ext4: use kmemdup() to replace kmalloc + memcpy
fs: ext4: initialize fsdata in pagecache_write()
ext4: use memcpy_to_page() in pagecache_write()
mm/highmem: Lift memcpy_[to|from]_page to core
ext4: correct inconsistent error msg in nojournal mode
ext4: goto right label 'failed_mount3a'
ravb: Fix "failed to switch device to config mode" message during unbind
KVM: nVMX: Properly expose ENABLE_USR_WAIT_PAUSE control to L1
KVM: VMX: Fix the spelling of CPU_BASED_USE_TSC_OFFSETTING
KVM: VMX: Rename NMI_PENDING to NMI_WINDOW
KVM: VMX: Rename INTERRUPT_PENDING to INTERRUPT_WINDOW
KVM: retpolines: x86: eliminate retpoline from vmx.c exit handlers
KVM: x86: optimize more exit handlers in vmx.c
perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data
perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
dm thin: resume even if in FAIL mode
media: s5p-mfc: Fix in register read and write for H264
media: s5p-mfc: Clear workbit to handle error condition
media: s5p-mfc: Fix to handle reference queue during finishing
PM/devfreq: governor: Add a private governor_data for governor
btrfs: replace strncpy() with strscpy()
ext4: allocate extended attribute value in vmalloc area
ext4: avoid unaccounted block allocation when expanding inode
ext4: initialize quota before expanding inode in setproject ioctl
ext4: fix inode leak in ext4_xattr_inode_create() on an error path
ext4: avoid BUG_ON when creating xattrs
ext4: fix error code return to user-space in ext4_get_branch()
ext4: fix corruption when online resizing a 1K bigalloc fs
ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline
ext4: init quota for 'old.inode' in 'ext4_rename'
ext4: fix bug_on in __es_tree_search caused by bad boot loader inode
ext4: fix reserved cluster accounting in __es_remove_extent()
ext4: add helper to check quota inums
ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode
ext4: fix undefined behavior in bit shift for ext4_check_flag_values
ext4: add inode table check in __ext4_get_inode_loc to aovid possible infinite loop
drm/vmwgfx: Validate the box size for the snooped cursor
drm/connector: send hotplug uevent on connector cleanup
device_cgroup: Roll back to original exceptions after copy failure
parisc: led: Fix potential null-ptr-deref in start_task()
iommu/amd: Fix ivrs_acpihid cmdline parsing code
crypto: n2 - add missing hash statesize
PCI/sysfs: Fix double free in error path
PCI: Fix pci_device_is_present() for VFs by checking PF
ipmi: fix use after free in _ipmi_destroy_user()
ima: Fix a potential NULL pointer access in ima_restore_measurement_list
mtd: spi-nor: Check for zero erase size in spi_nor_find_best_erase_type()
ipmi: fix long wait in unload when IPMI disconnect
efi: Add iMac Pro 2017 to uefi skip cert quirk
md/bitmap: Fix bitmap chunk size overflow issues
cifs: fix missing display of three mount options
cifs: fix confusing debug message
media: dvb-core: Fix UAF due to refcount races at releasing
media: dvb-core: Fix double free in dvb_register_device()
ARM: 9256/1: NWFPE: avoid compiler-generated __aeabi_uldivmod
tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line
tracing/hist: Fix wrong return value in parse_action_params()
x86/microcode/intel: Do not retry microcode reloading on the APs
tracing/hist: Fix out-of-bound write on 'action_data.var_ref_idx'
dm cache: set needs_check flag after aborting metadata
dm cache: Fix UAF in destroy()
dm clone: Fix UAF in clone_dtr()
dm integrity: Fix UAF in dm_integrity_dtr()
dm thin: Fix UAF in run_timer_softirq()
dm thin: Use last transaction's pmd->root when commit failed
dm thin: Fix ABBA deadlock between shrink_slab and dm_pool_abort_metadata
dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort
binfmt: Fix error return code in load_elf_fdpic_binary()
binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf
cpufreq: Init completion before kobject_init_and_add()
selftests: Use optional USERCFLAGS and USERLDFLAGS
arm64: dts: qcom: sdm850-lenovo-yoga-c630: correct I2C12 pins drive strength
ARM: ux500: do not directly dereference __iomem
btrfs: fix resolving backrefs for inline extent followed by prealloc
mmc: sdhci-sprd: Disable CLK_AUTO when the clock is less than 400K
ktest.pl minconfig: Unset configs instead of just removing them
kest.pl: Fix grub2 menu handling for rebooting
soc: qcom: Select REMAP_MMIO for LLCC driver
media: stv0288: use explicitly signed char
net/af_packet: make sure to pull mac header
net/af_packet: add VLAN support for AF_PACKET SOCK_RAW GSO
SUNRPC: Don't leak netobj memory when gss_read_proxy_verf() fails
tpm: tpm_tis: Add the missed acpi_put_table() to fix memory leak
tpm: tpm_crb: Add the missed acpi_put_table() to fix memory leak
mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING
f2fs: should put a page when checking the summary info
mm, compaction: fix fast_isolate_around() to stay within boundaries
md: fix a crash in mempool_free
pnode: terminate at peers of source
ALSA: line6: fix stack overflow in line6_midi_transmit
ALSA: line6: correct midi status byte when receiving data from podxt
ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
hfsplus: fix bug causing custom uid and gid being unable to be assigned with mount
HID: plantronics: Additional PIDs for double volume key presses quirk
HID: multitouch: fix Asus ExpertBook P2 P2451FA trackpoint
powerpc/rtas: avoid scheduling in rtas_os_term()
powerpc/rtas: avoid device tree lookups in rtas_os_term()
objtool: Fix SEGFAULT
nvme: fix the NVME_CMD_EFFECTS_CSE_MASK definition
nvme: resync include/linux/nvme.h with nvmecli
ata: ahci: Fix PCS quirk application for suspend
nvme-pci: fix doorbell buffer value endianness
cifs: fix oops during encryption
media: dvbdev: fix refcnt bug
media: dvbdev: fix build warning due to comments
gcov: add support for checksum field
regulator: core: fix deadlock on regulator enable
iio: adc128s052: add proper .data members in adc128_of_match table
iio: adc: ad_sigma_delta: do not use internal iio_dev lock
reiserfs: Add missing calls to reiserfs_security_free()
HID: wacom: Ensure bootloader PID is usable in hidraw mode
usb: dwc3: core: defer probe on ulpi_read_id timeout
ALSA: hda/hdmi: Add HP Device 0x8711 to force connect list
ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES
pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion
ASoC: rt5670: Remove unbalanced pm_runtime_put()
ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume()
ASoC: wm8994: Fix potential deadlock
ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume()
ASoC: audio-graph-card: fix refcount leak of cpu_ep in __graph_for_each_link()
ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe()
ASoC: Intel: Skylake: Fix driver hang during shutdown
ALSA: hda: add snd_hdac_stop_streams() helper
ALSA/ASoC: hda: move/rename snd_hdac_ext_stop_streams to hdac_stream.c
orangefs: Fix kmemleak in orangefs_{kernel,client}_debug_init()
orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string()
drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid()
drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid()
hugetlbfs: fix null-ptr-deref in hugetlbfs_parse_param()
clk: st: Fix memory leak in st_of_quadfs_setup()
media: si470x: Fix use-after-free in si470x_int_in_callback()
mmc: f-sdh30: Add quirks for broken timeout clock capability
regulator: core: fix use_count leakage when handling boot-on
blk-mq: fix possible memleak when register 'hctx' failed
media: dvb-usb: fix memory leak in dvb_usb_adapter_init()
media: dvbdev: adopts refcnt to avoid UAF
media: dvb-frontends: fix leak of memory fw
bpf: Prevent decl_tag from being referenced in func_proto arg
ppp: associate skb with a device at tx
mrp: introduce active flags to prevent UAF when applicant uninit
net: add atomic_long_t to net_device_stats fields
md/raid1: stop mdx_raid1 thread when raid1 array run failed
drivers/md/md-bitmap: check the return value of md_bitmap_get_counter()
drm/sti: Use drm_mode_copy()
drm/rockchip: Use drm_mode_copy()
s390/lcs: Fix return type of lcs_start_xmit()
s390/netiucv: Fix return type of netiucv_tx()
s390/ctcm: Fix return type of ctc{mp,}m_tx()
igb: Do not free q_vector unless new one was allocated
wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request()
hamradio: baycom_epp: Fix return type of baycom_send_packet()
net: ethernet: ti: Fix return type of netcp_ndo_start_xmit()
bpf: make sure skb->len != 0 when redirecting to a tunneling device
ipmi: fix memleak when unload ipmi driver
ASoC: codecs: rt298: Add quirk for KBL-R RVP platform
wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out
wifi: ath9k: verify the expected usb_endpoints are present
brcmfmac: return error when getting invalid max_flowrings from dongle
drm/etnaviv: add missing quirks for GC300
hfs: fix OOB Read in __hfs_brec_find
acct: fix potential integer overflow in encode_comp_t()
nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset()
ACPICA: Fix error code path in acpi_ds_call_control_method()
fs: jfs: fix shift-out-of-bounds in dbDiscardAG
udf: Avoid double brelse() in udf_rename()
fs: jfs: fix shift-out-of-bounds in dbAllocAG
binfmt_misc: fix shift-out-of-bounds in check_special_flags
rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state()
net: stream: purge sk_error_queue in sk_stream_kill_queues()
myri10ge: Fix an error handling path in myri10ge_probe()
rxrpc: Fix missing unlock in rxrpc_do_sendmsg()
net_sched: reject TCF_EM_SIMPLE case for complex ematch module
mailbox: zynq-ipi: fix error handling while device_register() fails
skbuff: Account for tail adjustment during pull operations
openvswitch: Fix flow lookup to use unmasked key
rtc: mxc_v2: Add missing clk_disable_unprepare()
r6040: Fix kmemleak in probe and remove
nfc: pn533: Clear nfc_target before being used
mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave()
nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure
NFSD: Add tracepoints to NFSD's duplicate reply cache
nfsd: Define the file access mode enum for tracing
rtc: pic32: Move devm_rtc_allocate_device earlier in pic32_rtc_probe()
rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe()
remoteproc: qcom_q6v5_pas: Fix missing of_node_put() in adsp_alloc_memory_region()
remoteproc: sysmon: fix memory leak in qcom_add_sysmon_subdev()
pwm: sifive: Call pwm_sifive_update_clock() while mutex is held
selftests/powerpc: Fix resource leaks
powerpc/hv-gpci: Fix hv_gpci event list
powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe()
powerpc/perf: callchain validate kernel stack pointer bounds
powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data()
cxl: Fix refcount leak in cxl_calc_capp_routing
powerpc/52xx: Fix a resource leak in an error handling path
macintosh/macio-adb: check the return value of ioremap()
macintosh: fix possible memory leak in macio_add_one_device()
iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe()
iommu/amd: Fix pci device refcount leak in ppr_notifier()
rtc: pcf85063: Fix reading alarm
rtc: snvs: Allow a time difference on clock register read
include/uapi/linux/swab: Fix potentially missing __always_inline
RDMA/siw: Fix pointer cast warning
power: supply: fix null pointer dereferencing in power_supply_get_battery_info
HSI: omap_ssi_core: Fix error handling in ssi_init()
perf symbol: correction while adjusting symbol
perf trace: Handle failure when trace point folder is missed
perf trace: Use macro RAW_SYSCALL_ARGS_NUM to replace number
perf trace: Add a strtoul() method to 'struct syscall_arg_fmt'
perf trace: Allow associating scnprintf routines with well known arg names
perf trace: Add the syscall_arg_fmt pointer to syscall_arg
perf trace: Factor out the initialization of syscal_arg_fmt->scnprintf
perf trace: Separate 'struct syscall_fmt' definition from syscall_fmts variable
perf trace: Return error if a system call doesn't exist
power: supply: fix residue sysfs file in error handle route of __power_supply_register()
HSI: omap_ssi_core: fix possible memory leak in ssi_probe()
HSI: omap_ssi_core: fix unbalanced pm_runtime_disable()
fbdev: uvesafb: Fixes an error handling path in uvesafb_probe()
fbdev: vermilion: decrease reference count in error path
fbdev: via: Fix error in via_core_init()
fbdev: pm2fb: fix missing pci_disable_device()
fbdev: ssd1307fb: Drop optional dependency
samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe()
tracing/hist: Fix issue of losting command info in error_log
usb: storage: Add check for kcalloc
i2c: ismt: Fix an out-of-bounds bug in ismt_access()
vme: Fix error not catched in fake_init()
staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor()
staging: rtl8192u: Fix use after free in ieee80211_rx()
i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe
chardev: fix error handling in cdev_device_add()
mcb: mcb-parse: fix error handing in chameleon_parse_gdd()
drivers: mcb: fix resource leak in mcb_probe()
usb: gadget: f_hid: fix refcount leak on error path
usb: gadget: f_hid: fix f_hidg lifetime vs cdev
usb: gadget: f_hid: optional SETUP/SET_REPORT mode
usb: roles: fix of node refcount leak in usb_role_switch_is_parent()
counter: stm32-lptimer-cnt: fix the check on arr and cmp registers update
cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter()
cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter()
misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os
misc: tifm: fix possible memory leak in tifm_7xx1_switch_media()
misc: ocxl: fix possible name leak in ocxl_file_register_afu()
test_firmware: fix memory leak in test_firmware_init()
serial: sunsab: Fix error handling in sunsab_init()
serial: altera_uart: fix locking in polling mode
tty: serial: altera_uart_{r,t}x_chars() need only uart_port
tty: serial: clean up stop-tx part in altera_uart_tx_chars()
serial: pch: Fix PCI device refcount leak in pch_request_dma()
serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle.
serial: amba-pl011: avoid SBSA UART accessing DMACR register
usb: typec: tcpci: fix of node refcount leak in tcpci_register_port()
usb: typec: Check for ops->exit instead of ops->enter in altmode_exit
staging: vme_user: Fix possible UAF in tsi148_dma_list_add
usb: fotg210-udc: Fix ages old endianness issues
uio: uio_dmem_genirq: Fix deadlock between irq config and handling
uio: uio_dmem_genirq: Fix missing unlock in irq configuration
vfio: platform: Do not pass return buffer to ACPI _RST method
class: fix possible memory leak in __class_register()
serial: tegra: Read DMA status before terminating
tty: serial: tegra: Activate RX DMA transfer by request
drivers: dio: fix possible memory leak in dio_init()
IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces
hwrng: geode - Fix PCI device refcount leak
hwrng: amd - Fix PCI device refcount leak
crypto: img-hash - Fix variable dereferenced before check 'hdev->req'
orangefs: Fix sysfs not cleanup when dev init failed
RDMA/hfi1: Fix error return code in parse_platform_config()
crypto: omap-sham - Use pm_runtime_resume_and_get() in omap_sham_probe()
f2fs: avoid victim selection from previous victim section
RDMA/nldev: Add checks for nla_nest_start() in fill_stat_counter_qps()
scsi: snic: Fix possible UAF in snic_tgt_create()
scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails
scsi: ipr: Fix WARNING in ipr_init()
scsi: fcoe: Fix possible name leak when device_register() fails
scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device()
scsi: hpsa: Fix error handling in hpsa_add_sas_host()
scsi: mpt3sas: Fix possible resource leaks in mpt3sas_transport_port_add()
crypto: tcrypt - Fix multibuffer skcipher speed test mem leak
scsi: hpsa: Fix possible memory leak in hpsa_init_one()
RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed
crypto: ccree - Make cc_debugfs_global_fini() available for module init function
RDMA/hfi: Decrease PCI device reference count in error path
PCI: Check for alloc failure in pci_request_irq()
crypto: ccree - Remove debugfs when platform_driver_register failed
crypto: ccree - swap SHA384 and SHA512 larval hashes at build time
scsi: scsi_debug: Fix a warning in resp_write_scat()
RDMA/siw: Set defined status for work completion with undefined status
RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port
RDMA/siw: Fix immediate work request flush to completion queue
f2fs: fix normal discard process
RDMA/core: Fix order of nldev_exit call
apparmor: Use pointer to struct aa_label for lbs_cred
apparmor: Fix abi check to include v8 abi
apparmor: fix lockdep warning when removing a namespace
apparmor: fix a memleak in multi_transaction_new()
stmmac: fix potential division by 0
Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_ll: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave()
Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave()
ntb_netdev: Use dev_kfree_skb_any() in interrupt context
net: lan9303: Fix read error execution path
can: tcan4x5x: Remove invalid write in clear_interrupts
net: amd-xgbe: Check only the minimum speed for active/passive cables
net: amd-xgbe: Fix logic around active and passive cables
net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave()
hamradio: don't call dev_kfree_skb() under spin_lock_irqsave()
net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave()
net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave()
net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave()
net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave()
net/tunnel: wait until all sk_user_data reader finish before releasing the sock
net: farsync: Fix kmemleak when rmmods farsync
ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave()
of: overlay: fix null pointer dereferencing in find_dup_cset_node_entry() and find_dup_cset_prop()
drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init()
net: stmmac: selftests: fix potential memleak in stmmac_test_arpoffload()
net: defxx: Fix missing err handling in dfx_init()
net: vmw_vsock: vmci: Check memcpy_from_msg()
clk: socfpga: Fix memory leak in socfpga_gate_init()
clk: socfpga: use clk_hw_register for a5/c5
clk: socfpga: clk-pll: Remove unused variable 'rc'
blktrace: Fix output non-blktrace event when blk_classic option enabled
wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware()
wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h
spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode
clk: samsung: Fix memory leak in _samsung_clk_register_pll()
media: coda: Add check for kmalloc
media: coda: Add check for dcoda_iram_alloc
media: c8sectpfe: Add of_node_put() when breaking out of loop
mmc: mmci: fix return value check of mmc_add_host()
mmc: wbsd: fix return value check of mmc_add_host()
mmc: via-sdmmc: fix return value check of mmc_add_host()
mmc: meson-gx: fix return value check of mmc_add_host()
mmc: omap_hsmmc: fix return value check of mmc_add_host()
mmc: atmel-mci: fix return value check of mmc_add_host()
mmc: wmt-sdmmc: fix return value check of mmc_add_host()
mmc: vub300: fix return value check of mmc_add_host()
mmc: toshsd: fix return value check of mmc_add_host()
mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host()
mmc: pxamci: fix return value check of mmc_add_host()
mmc: mxcmmc: fix return value check of mmc_add_host()
mmc: moxart: fix return value check of mmc_add_host()
mmc: alcor: fix return value check of mmc_add_host()
NFSv4.x: Fail client initialisation if state manager thread can't run
SUNRPC: Fix missing release socket in rpc_sockname()
xprtrdma: Fix regbuf data not freed in rpcrdma_req_create()
ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
media: saa7164: fix missing pci_disable_device()
bpf, sockmap: fix race in sock_map_free()
regulator: core: fix resource leak in regulator_register()
configfs: fix possible memory leak in configfs_create_dir()
hsr: Avoid double remove of a node.
clk: qcom: clk-krait: fix wrong div2 functions
regulator: core: fix module refcount leak in set_supply()
wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails
spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE
bonding: uninitialized variable in bond_miimon_inspect()
bpf, sockmap: Fix data loss caused by using apply_bytes on ingress redirect
bpf, sockmap: Fix repeated calls to sock_put() when msg has more_data
netfilter: conntrack: set icmpv6 redirects as RELATED
ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe
drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios()
drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios()
ASoC: mediatek: mt8173: Enable IRQ when pdata is ready
wifi: iwlwifi: mvm: fix double free on tx path.
ALSA: asihpi: fix missing pci_disable_device()
NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn
NFSv4.2: Fix initialisation of struct nfs4_label
NFSv4.2: Fix a memory stomp in decode_attr_security_label
NFSv4.2: Clear FATTR4_WORD2_SECURITY_LABEL when done decoding
ASoC: mediatek: mtk-btcvsd: Add checks for write and read of mtk_btcvsd_snd
ASoC: dt-bindings: wcd9335: fix reset line polarity in example
drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe()
media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC
media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer()
media: dvb-core: Fix ignored return value in dvb_register_frontend()
pinctrl: pinconf-generic: add missing of_node_put()
clk: imx: replace osc_hdmi with dummy
clk: imx8mn: correct the usb1_ctrl parent to be usb_bus
media: imon: fix a race condition in send_packet()
mtd: maps: pxa2xx-flash: fix memory leak in probe
bonding: fix link recovery in mode 2 when updelay is nonzero
bonding: Rename slave_arr to usable_slaves
bonding: Export skip slave logic to function
clk: rockchip: Fix memory leak in rockchip_clk_register_pll()
regulator: core: use kfree_const() to free space conditionally
ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT
ALSA: pcm: fix undefined behavior in bit shift for SNDRV_PCM_RATE_KNOT
HID: hid-sensor-custom: set fixed size for custom attributes
bpf: Move skb->len == 0 checks into __bpf_redirect
media: videobuf-dma-contig: use dma_mmap_coherent
media: platform: exynos4-is: Fix error handling in fimc_md_init()
media: solo6x10: fix possible memory leak in solo_sysfs_init()
Input: elants_i2c - properly handle the reset GPIO when power is off
mtd: lpddr2_nvm: Fix possible null-ptr-deref
wifi: ath10k: Fix return value in ath10k_pci_init()
ima: Fix misuse of dereference of pointer in template_desc_init_fields()
integrity: Fix memory leakage in keyring allocation error path
amdgpu/pm: prevent array underflow in vega20_odn_edit_dpm_table()
regulator: core: fix unbalanced of node refcount in regulator_dev_lookup()
ASoC: pxa: fix null-pointer dereference in filter()
drm/mediatek: Modify dpi power on/off sequence.
drm/radeon: Add the missed acpi_put_table() to fix memory leak
rxrpc: Fix ack.bufferSize to be 0 when generating an ack
net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write()
media: camss: Clean up received buffers on failed start of streaming
wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port
mtd: Fix device name leak when register device failed in add_mtd_device()
bpf: propagate precision in ALU/ALU64 operations
media: vivid: fix compose size exceed boundary
ima: Handle -ESTALE returned by ima_filter_rule_match()
ima: Fix fall-through warnings for Clang
ima: Rename internal filter rule functions
drm/panel/panel-sitronix-st7701: Remove panel on DSI attach failure
spi: Update reference to struct spi_controller
clk: renesas: r9a06g032: Repair grave increment error
can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming
can: kvaser_usb: Add struct kvaser_usb_busparams
can: kvaser_usb_leaf: Fix bogus restart events
can: kvaser_usb_leaf: Fix wrong CAN state after stopping
can: kvaser_usb_leaf: Fix improved state not being reported
can: kvaser_usb_leaf: Set Warning state even without bus errors
can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT
can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event
can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device
can: kvaser_usb: do not increase tx statistics when sending error message frames
media: i2c: ad5820: Fix error path
pata_ipx4xx_cf: Fix unsigned comparison with less than zero
wifi: rtl8xxxu: Fix reading the vendor of combo chips
wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb()
wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs()
rapidio: devices: fix missing put_device in mport_cdev_open
hfs: Fix OOB Write in hfs_asc2mac
relay: fix type mismatch when allocating memory in relay_create_buf()
eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD
rapidio: fix possible UAF when kfifo_alloc() fails
fs: sysv: Fix sysv_nblocks() returns wrong value
MIPS: OCTEON: warn only once if deprecated link status is being used
MIPS: BCM63xx: Add check for NULL for clk in clk_enable
platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]()
PM: runtime: Do not call __rpm_callback() from rpm_idle()
PM: runtime: Improve path in rpm_idle() when no callback
xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource()
x86/xen: Fix memory leak in xen_init_lock_cpu()
x86/xen: Fix memory leak in xen_smp_intr_init{_pv}()
xen/events: only register debug interrupt for 2-level events
uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix
ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage()
clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled
rapidio: rio: fix possible name leak in rio_register_mport()
rapidio: fix possible name leaks when rio_add_device() fails
ocfs2: fix memory leak in ocfs2_mount_volume()
ocfs2: rewrite error handling of ocfs2_fill_super
ocfs2: ocfs2_mount_volume does cleanup job before return error
debugfs: fix error when writing negative value to atomic_t debugfs file
docs: fault-injection: fix non-working usage of negative values
lib/notifier-error-inject: fix error when writing -errno to debugfs file
libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value
cpufreq: amd_freq_sensitivity: Add missing pci_dev_put()
genirq/irqdesc: Don't try to remove non-existing sysfs files
nfsd: don't call nfsd_file_put from client states seqfile display
EDAC/i10nm: fix refcount leak in pci_get_dev_wrapper()
irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe()
perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox()
PNP: fix name memory leak in pnp_alloc_dev()
selftests/efivarfs: Add checking of the test return value
MIPS: vpe-cmp: fix possible memory leak while module exiting
MIPS: vpe-mt: fix possible memory leak while module exiting
ocfs2: fix memory leak in ocfs2_stack_glue_init()
lib/fonts: fix undefined behavior in bit shift for get_default_font
proc: fixup uptime selftest
timerqueue: Use rb_entry_safe() in timerqueue_getnext()
perf: Fix possible memleak in pmu_dev_alloc()
selftests/ftrace: event_triggers: wait longer for test_event_enable
fs: don't audit the capability check in simple_xattr_list()
PM: hibernate: Fix mistake in kerneldoc comment
alpha: fix syscall entry in !AUDUT_SYSCALL case
cpuidle: dt: Return the correct numbers of parsed idle states
tpm/tpm_crb: Fix error message in __crb_relinquish_locality()
pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
ARM: mmp: fix timer_read delay
pstore/ram: Fix error return code in ramoops_probe()
arm64: dts: armada-3720-turris-mox: Add missing interrupt for RTC
ARM: dts: turris-omnia: Add switch port 6 node
ARM: dts: turris-omnia: Add ethernet aliases
ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port
ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port
ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port
arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name
arm64: dts: mt2712-evb: Fix usb vbus regulators unit names
arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names
arm64: dts: mt2712e: Fix unit address for pinctrl node
arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators
perf/smmuv3: Fix hotplug callback leak in arm_smmu_pmu_init()
perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init()
soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe
soc: ti: knav_qmss_queue: Fix PM disable depth imbalance in knav_queue_probe
soc: ti: knav_qmss_queue: Use pm_runtime_resume_and_get instead of pm_runtime_get_sync
arm: dts: spear600: Fix clcd interrupt
drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static
arm64: dts: qcom: sdm845-cheza: fix AP suspend pin bias
ARM: dts: qcom: apq8064: fix coresight compatible
usb: musb: remove extra check in musb_gadget_vbus_draw
net: loopback: use NET_NAME_PREDICTABLE for name_assign_type
Bluetooth: L2CAP: Fix u8 overflow
HID: uclogic: Add HID_QUIRK_HIDINPUT_FORCE quirk
HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch V 10
HID: ite: Enable QUIRK_TOUCHPAD_ON_OFF_REPORT on Acer Aspire Switch 10E
HID: ite: Add support for Acer S1002 keyboard-dock
xen-netback: move removal of "hotplug-status" to the right place
igb: Initialize mailbox message for VF reset
USB: serial: f81534: fix division by zero on line-speed change
USB: serial: f81232: fix division by zero on line-speed change
USB: serial: cp210x: add Kamstrup RF sniffer PIDs
USB: serial: option: add Quectel EM05-G modem
usb: gadget: uvc: Prevent buffer overflow in setup handler
udf: Fix extending file within last block
udf: Do not bother looking for prealloc extents if i_lenExtents matches i_size
udf: Fix preallocation discarding at indirect extent boundary
udf: Discard preallocation before extending file with a hole
tracing/ring-buffer: Only do full wait when cpu != RING_BUFFER_ALL_CPUS
ANDROID: Add more hvc devices for virtio-console.
Revert "can: af_can: fix NULL pointer dereference in can_rcv_filter"
ANDROID: Revert "tracing/ring-buffer: Have polling block on watermark"
Linux 5.4.228
ASoC: ops: Correct bounds check for second channel on SX controls
can: mcba_usb: Fix termination command argument
can: sja1000: fix size of OCR_MODE_MASK define
pinctrl: meditatek: Startup with the IRQs disabled
ASoC: ops: Check bounds for second channel in snd_soc_put_volsw_sx()
nfp: fix use-after-free in area_cache_get()
block: unhash blkdev part inode when the part is deleted
mm/hugetlb: fix races when looking up a CONT-PTE/PMD size hugetlb page
x86/smpboot: Move rcu_cpu_starting() earlier
net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
Linux 5.4.227
can: esd_usb: Allow REC and TEC to return to zero
net: mvneta: Fix an out of bounds check
ipv6: avoid use-after-free in ip6_fragment()
net: plip: don't call kfree_skb/dev_kfree_skb() under spin_lock_irq()
xen/netback: fix build warning
ethernet: aeroflex: fix potential skb leak in greth_init_rings()
ipv4: Fix incorrect route flushing when table ID 0 is used
ipv4: Fix incorrect route flushing when source address is deleted
tipc: Fix potential OOB in tipc_link_proto_rcv()
net: hisilicon: Fix potential use-after-free in hix5hd2_rx()
net: hisilicon: Fix potential use-after-free in hisi_femac_rx()
net: thunderx: Fix missing destroy_workqueue of nicvf_rx_mode_wq
net: stmmac: fix "snps,axi-config" node property parsing
nvme initialize core quirks before calling nvme_init_subsystem
NFC: nci: Bounds check struct nfc_target arrays
i40e: Disallow ip4 and ip6 l4_4_bytes
i40e: Fix for VF MAC address 0
i40e: Fix not setting default xps_cpus after reset
net: mvneta: Prevent out of bounds read in mvneta_config_rss()
xen-netfront: Fix NULL sring after live migration
net: encx24j600: Fix invalid logic in reading of MISTAT register
net: encx24j600: Add parentheses to fix precedence
mac802154: fix missing INIT_LIST_HEAD in ieee802154_if_add()
selftests: rtnetlink: correct xfrm policy rule in kci_test_ipsec_offload
net: dsa: ksz: Check return value
Bluetooth: Fix not cleanup led when bt_init fails
Bluetooth: 6LoWPAN: add missing hci_dev_put() in get_l2cap_conn()
af_unix: Get user_ns from in_skb in unix_diag_get_exact().
igb: Allocate MSI-X vector when testing
e1000e: Fix TX dispatch condition
gpio: amd8111: Fix PCI device reference count leak
drm/bridge: ti-sn65dsi86: Fix output polarity setting bug
ca8210: Fix crash by zero initializing data
ieee802154: cc2520: Fix error return code in cc2520_hw_init()
can: af_can: fix NULL pointer dereference in can_rcv_filter
HID: core: fix shift-out-of-bounds in hid_report_raw_event
HID: hid-lg4ff: Add check for empty lbuf
HID: usbhid: Add ALWAYS_POLL quirk for some mice
drm/shmem-helper: Remove errant put in error path
KVM: s390: vsie: Fix the initialization of the epoch extension (epdx) field
mm/gup: fix gup_pud_range() for dax
memcg: fix possible use-after-free in memcg_write_event_control()
media: v4l2-dv-timings.c: fix too strict blanking sanity checks
Revert "net: dsa: b53: Fix valid setting for MDB entries"
xen/netback: don't call kfree_skb() with interrupts disabled
xen/netback: do some code cleanup
xen/netback: Ensure protocol headers don't fall in the non-linear area
mm/khugepaged: invoke MMU notifiers in shmem/file collapse paths
mm/khugepaged: fix GUP-fast interaction by sending IPI
mm/khugepaged: take the right locks for page table retraction
net: usb: qmi_wwan: add u-blox 0x1342 composition
9p/xen: check logical size for buffer size
fbcon: Use kzalloc() in fbcon_prepare_logo()
regulator: twl6030: fix get status of twl6032 regulators
ASoC: soc-pcm: Add NULL check in BE reparenting
btrfs: send: avoid unaligned encoded writes when attempting to clone range
ALSA: seq: Fix function prototype mismatch in snd_seq_expand_var_event
regulator: slg51000: Wait after asserting CS pin
9p/fd: Use P9_HDRSZ for header size
ARM: dts: rockchip: disable arm_global_timer on rk3066 and rk3188
ARM: 9266/1: mm: fix no-MMU ZERO_PAGE() implementation
ARM: 9251/1: perf: Fix stacktraces for tracepoint events in THUMB2 kernels
ARM: dts: rockchip: rk3188: fix lcdc1-rgb24 node name
ARM: dts: rockchip: fix ir-receiver node names
arm: dts: rockchip: fix node name for hym8563 rtc
arm64: dts: rockchip: keep I2S1 disabled for GPIO function on ROCK Pi 4 series
Change-Id: I6a643eaa2ee55257328d881f5b860200719e981e
Signed-off-by: kamasali Satyanarayan <quic_kamasali@quicinc.com>
4759 lines
121 KiB
C
4759 lines
121 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
Copyright (C) 2002 Richard Henderson
|
|
Copyright (C) 2001 Rusty Russell, 2002, 2010 Rusty Russell IBM.
|
|
|
|
*/
|
|
#include <linux/export.h>
|
|
#include <linux/extable.h>
|
|
#include <linux/moduleloader.h>
|
|
#include <linux/module_signature.h>
|
|
#include <linux/trace_events.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kallsyms.h>
|
|
#include <linux/file.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/elf.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/security.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/rcupdate.h>
|
|
#include <linux/capability.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/err.h>
|
|
#include <linux/vermagic.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/device.h>
|
|
#include <linux/string.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/rculist.h>
|
|
#include <linux/uaccess.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <linux/set_memory.h>
|
|
#include <asm/mmu_context.h>
|
|
#include <linux/license.h>
|
|
#include <asm/sections.h>
|
|
#include <linux/tracepoint.h>
|
|
#include <linux/ftrace.h>
|
|
#include <linux/livepatch.h>
|
|
#include <linux/async.h>
|
|
#include <linux/percpu.h>
|
|
#include <linux/kmemleak.h>
|
|
#include <linux/jump_label.h>
|
|
#include <linux/pfn.h>
|
|
#include <linux/bsearch.h>
|
|
#include <linux/dynamic_debug.h>
|
|
#include <linux/audit.h>
|
|
#include <uapi/linux/module.h>
|
|
#include "module-internal.h"
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/module.h>
|
|
|
|
#ifndef ARCH_SHF_SMALL
|
|
#define ARCH_SHF_SMALL 0
|
|
#endif
|
|
|
|
/*
|
|
* Modules' sections will be aligned on page boundaries
|
|
* to ensure complete separation of code and data, but
|
|
* only when CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
|
*/
|
|
#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
|
|
# define debug_align(X) ALIGN(X, PAGE_SIZE)
|
|
#else
|
|
# define debug_align(X) (X)
|
|
#endif
|
|
|
|
/* If this is set, the section belongs in the init part of the module */
|
|
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
|
|
|
|
/*
|
|
* Mutex protects:
|
|
* 1) List of modules (also safely readable with preempt_disable),
|
|
* 2) module_use links,
|
|
* 3) module_addr_min/module_addr_max.
|
|
* (delete and add uses RCU list operations). */
|
|
DEFINE_MUTEX(module_mutex);
|
|
EXPORT_SYMBOL_GPL(module_mutex);
|
|
static LIST_HEAD(modules);
|
|
|
|
/* Work queue for freeing init sections in success case */
|
|
static void do_free_init(struct work_struct *w);
|
|
static DECLARE_WORK(init_free_wq, do_free_init);
|
|
static LLIST_HEAD(init_free_list);
|
|
|
|
#ifdef CONFIG_MODULES_TREE_LOOKUP
|
|
|
|
/*
|
|
* Use a latched RB-tree for __module_address(); this allows us to use
|
|
* RCU-sched lookups of the address from any context.
|
|
*
|
|
* This is conditional on PERF_EVENTS || TRACING because those can really hit
|
|
* __module_address() hard by doing a lot of stack unwinding; potentially from
|
|
* NMI context.
|
|
*/
|
|
|
|
static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n)
|
|
{
|
|
struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
|
|
|
|
return (unsigned long)layout->base;
|
|
}
|
|
|
|
static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n)
|
|
{
|
|
struct module_layout *layout = container_of(n, struct module_layout, mtn.node);
|
|
|
|
return (unsigned long)layout->size;
|
|
}
|
|
|
|
static __always_inline bool
|
|
mod_tree_less(struct latch_tree_node *a, struct latch_tree_node *b)
|
|
{
|
|
return __mod_tree_val(a) < __mod_tree_val(b);
|
|
}
|
|
|
|
static __always_inline int
|
|
mod_tree_comp(void *key, struct latch_tree_node *n)
|
|
{
|
|
unsigned long val = (unsigned long)key;
|
|
unsigned long start, end;
|
|
|
|
start = __mod_tree_val(n);
|
|
if (val < start)
|
|
return -1;
|
|
|
|
end = start + __mod_tree_size(n);
|
|
if (val >= end)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct latch_tree_ops mod_tree_ops = {
|
|
.less = mod_tree_less,
|
|
.comp = mod_tree_comp,
|
|
};
|
|
|
|
static struct mod_tree_root {
|
|
struct latch_tree_root root;
|
|
unsigned long addr_min;
|
|
unsigned long addr_max;
|
|
} mod_tree __cacheline_aligned = {
|
|
.addr_min = -1UL,
|
|
};
|
|
|
|
#define module_addr_min mod_tree.addr_min
|
|
#define module_addr_max mod_tree.addr_max
|
|
|
|
static noinline void __mod_tree_insert(struct mod_tree_node *node)
|
|
{
|
|
latch_tree_insert(&node->node, &mod_tree.root, &mod_tree_ops);
|
|
}
|
|
|
|
static void __mod_tree_remove(struct mod_tree_node *node)
|
|
{
|
|
latch_tree_erase(&node->node, &mod_tree.root, &mod_tree_ops);
|
|
}
|
|
|
|
/*
|
|
* These modifications: insert, remove_init and remove; are serialized by the
|
|
* module_mutex.
|
|
*/
|
|
static void mod_tree_insert(struct module *mod)
|
|
{
|
|
mod->core_layout.mtn.mod = mod;
|
|
mod->init_layout.mtn.mod = mod;
|
|
|
|
__mod_tree_insert(&mod->core_layout.mtn);
|
|
if (mod->init_layout.size)
|
|
__mod_tree_insert(&mod->init_layout.mtn);
|
|
}
|
|
|
|
static void mod_tree_remove_init(struct module *mod)
|
|
{
|
|
if (mod->init_layout.size)
|
|
__mod_tree_remove(&mod->init_layout.mtn);
|
|
}
|
|
|
|
static void mod_tree_remove(struct module *mod)
|
|
{
|
|
__mod_tree_remove(&mod->core_layout.mtn);
|
|
mod_tree_remove_init(mod);
|
|
}
|
|
|
|
static struct module *mod_find(unsigned long addr)
|
|
{
|
|
struct latch_tree_node *ltn;
|
|
|
|
ltn = latch_tree_find((void *)addr, &mod_tree.root, &mod_tree_ops);
|
|
if (!ltn)
|
|
return NULL;
|
|
|
|
return container_of(ltn, struct mod_tree_node, node)->mod;
|
|
}
|
|
|
|
#else /* MODULES_TREE_LOOKUP */
|
|
|
|
static unsigned long module_addr_min = -1UL, module_addr_max = 0;
|
|
|
|
static void mod_tree_insert(struct module *mod) { }
|
|
static void mod_tree_remove_init(struct module *mod) { }
|
|
static void mod_tree_remove(struct module *mod) { }
|
|
|
|
static struct module *mod_find(unsigned long addr)
|
|
{
|
|
struct module *mod;
|
|
|
|
list_for_each_entry_rcu(mod, &modules, list,
|
|
lockdep_is_held(&module_mutex)) {
|
|
if (within_module(addr, mod))
|
|
return mod;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#endif /* MODULES_TREE_LOOKUP */
|
|
|
|
/*
|
|
* Bounds of module text, for speeding up __module_address.
|
|
* Protected by module_mutex.
|
|
*/
|
|
static void __mod_update_bounds(void *base, unsigned int size)
|
|
{
|
|
unsigned long min = (unsigned long)base;
|
|
unsigned long max = min + size;
|
|
|
|
if (min < module_addr_min)
|
|
module_addr_min = min;
|
|
if (max > module_addr_max)
|
|
module_addr_max = max;
|
|
}
|
|
|
|
static void mod_update_bounds(struct module *mod)
|
|
{
|
|
__mod_update_bounds(mod->core_layout.base, mod->core_layout.size);
|
|
if (mod->init_layout.size)
|
|
__mod_update_bounds(mod->init_layout.base, mod->init_layout.size);
|
|
}
|
|
|
|
#ifdef CONFIG_KGDB_KDB
|
|
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
|
|
#endif /* CONFIG_KGDB_KDB */
|
|
|
|
static void module_assert_mutex(void)
|
|
{
|
|
lockdep_assert_held(&module_mutex);
|
|
}
|
|
|
|
static void module_assert_mutex_or_preempt(void)
|
|
{
|
|
#ifdef CONFIG_LOCKDEP
|
|
if (unlikely(!debug_locks))
|
|
return;
|
|
|
|
WARN_ON_ONCE(!rcu_read_lock_sched_held() &&
|
|
!lockdep_is_held(&module_mutex));
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_MODULE_SIG
|
|
static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE);
|
|
module_param(sig_enforce, bool_enable_only, 0644);
|
|
|
|
void set_module_sig_enforced(void)
|
|
{
|
|
sig_enforce = true;
|
|
}
|
|
#else
|
|
#define sig_enforce false
|
|
#endif
|
|
|
|
/*
|
|
* Export sig_enforce kernel cmdline parameter to allow other subsystems rely
|
|
* on that instead of directly to CONFIG_MODULE_SIG_FORCE config.
|
|
*/
|
|
bool is_module_sig_enforced(void)
|
|
{
|
|
return sig_enforce;
|
|
}
|
|
EXPORT_SYMBOL(is_module_sig_enforced);
|
|
|
|
/* Block module loading/unloading? */
|
|
int modules_disabled = 0;
|
|
core_param(nomodule, modules_disabled, bint, 0);
|
|
|
|
/* Waiting for a module to finish initializing? */
|
|
static DECLARE_WAIT_QUEUE_HEAD(module_wq);
|
|
|
|
static BLOCKING_NOTIFIER_HEAD(module_notify_list);
|
|
|
|
int register_module_notifier(struct notifier_block *nb)
|
|
{
|
|
return blocking_notifier_chain_register(&module_notify_list, nb);
|
|
}
|
|
EXPORT_SYMBOL(register_module_notifier);
|
|
|
|
int unregister_module_notifier(struct notifier_block *nb)
|
|
{
|
|
return blocking_notifier_chain_unregister(&module_notify_list, nb);
|
|
}
|
|
EXPORT_SYMBOL(unregister_module_notifier);
|
|
|
|
/*
|
|
* We require a truly strong try_module_get(): 0 means success.
|
|
* Otherwise an error is returned due to ongoing or failed
|
|
* initialization etc.
|
|
*/
|
|
static inline int strong_try_module_get(struct module *mod)
|
|
{
|
|
BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);
|
|
if (mod && mod->state == MODULE_STATE_COMING)
|
|
return -EBUSY;
|
|
if (try_module_get(mod))
|
|
return 0;
|
|
else
|
|
return -ENOENT;
|
|
}
|
|
|
|
static inline void add_taint_module(struct module *mod, unsigned flag,
|
|
enum lockdep_ok lockdep_ok)
|
|
{
|
|
add_taint(flag, lockdep_ok);
|
|
set_bit(flag, &mod->taints);
|
|
}
|
|
|
|
/*
|
|
* A thread that wants to hold a reference to a module only while it
|
|
* is running can call this to safely exit. nfsd and lockd use this.
|
|
*/
|
|
void __noreturn __module_put_and_exit(struct module *mod, long code)
|
|
{
|
|
module_put(mod);
|
|
do_exit(code);
|
|
}
|
|
EXPORT_SYMBOL(__module_put_and_exit);
|
|
|
|
/* Find a module section: 0 means not found. */
|
|
static unsigned int find_sec(const struct load_info *info, const char *name)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 1; i < info->hdr->e_shnum; i++) {
|
|
Elf_Shdr *shdr = &info->sechdrs[i];
|
|
/* Alloc bit cleared means "ignore it." */
|
|
if ((shdr->sh_flags & SHF_ALLOC)
|
|
&& strcmp(info->secstrings + shdr->sh_name, name) == 0)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Find a module section, or NULL. */
|
|
static void *section_addr(const struct load_info *info, const char *name)
|
|
{
|
|
/* Section 0 has sh_addr 0. */
|
|
return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
|
|
}
|
|
|
|
/* Find a module section, or NULL. Fill in number of "objects" in section. */
|
|
static void *section_objs(const struct load_info *info,
|
|
const char *name,
|
|
size_t object_size,
|
|
unsigned int *num)
|
|
{
|
|
unsigned int sec = find_sec(info, name);
|
|
|
|
/* Section 0 has sh_addr 0 and sh_size 0. */
|
|
*num = info->sechdrs[sec].sh_size / object_size;
|
|
return (void *)info->sechdrs[sec].sh_addr;
|
|
}
|
|
|
|
/* Provided by the linker */
|
|
extern const struct kernel_symbol __start___ksymtab[];
|
|
extern const struct kernel_symbol __stop___ksymtab[];
|
|
extern const struct kernel_symbol __start___ksymtab_gpl[];
|
|
extern const struct kernel_symbol __stop___ksymtab_gpl[];
|
|
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
|
|
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
|
|
extern const s32 __start___kcrctab[];
|
|
extern const s32 __start___kcrctab_gpl[];
|
|
extern const s32 __start___kcrctab_gpl_future[];
|
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
extern const struct kernel_symbol __start___ksymtab_unused[];
|
|
extern const struct kernel_symbol __stop___ksymtab_unused[];
|
|
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
|
|
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
|
|
extern const s32 __start___kcrctab_unused[];
|
|
extern const s32 __start___kcrctab_unused_gpl[];
|
|
#endif
|
|
|
|
#ifndef CONFIG_MODVERSIONS
|
|
#define symversion(base, idx) NULL
|
|
#else
|
|
#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
|
|
#endif
|
|
|
|
static bool each_symbol_in_section(const struct symsearch *arr,
|
|
unsigned int arrsize,
|
|
struct module *owner,
|
|
bool (*fn)(const struct symsearch *syms,
|
|
struct module *owner,
|
|
void *data),
|
|
void *data)
|
|
{
|
|
unsigned int j;
|
|
|
|
for (j = 0; j < arrsize; j++) {
|
|
if (fn(&arr[j], owner, data))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Returns true as soon as fn returns true, otherwise false. */
|
|
static bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
|
|
struct module *owner,
|
|
void *data),
|
|
void *data)
|
|
{
|
|
struct module *mod;
|
|
static const struct symsearch arr[] = {
|
|
{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
|
|
NOT_GPL_ONLY, false },
|
|
{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
|
|
__start___kcrctab_gpl,
|
|
GPL_ONLY, false },
|
|
{ __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
|
|
__start___kcrctab_gpl_future,
|
|
WILL_BE_GPL_ONLY, false },
|
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
{ __start___ksymtab_unused, __stop___ksymtab_unused,
|
|
__start___kcrctab_unused,
|
|
NOT_GPL_ONLY, true },
|
|
{ __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
|
|
__start___kcrctab_unused_gpl,
|
|
GPL_ONLY, true },
|
|
#endif
|
|
};
|
|
|
|
module_assert_mutex_or_preempt();
|
|
|
|
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
|
|
return true;
|
|
|
|
list_for_each_entry_rcu(mod, &modules, list,
|
|
lockdep_is_held(&module_mutex)) {
|
|
struct symsearch arr[] = {
|
|
{ mod->syms, mod->syms + mod->num_syms, mod->crcs,
|
|
NOT_GPL_ONLY, false },
|
|
{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
|
|
mod->gpl_crcs,
|
|
GPL_ONLY, false },
|
|
{ mod->gpl_future_syms,
|
|
mod->gpl_future_syms + mod->num_gpl_future_syms,
|
|
mod->gpl_future_crcs,
|
|
WILL_BE_GPL_ONLY, false },
|
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
{ mod->unused_syms,
|
|
mod->unused_syms + mod->num_unused_syms,
|
|
mod->unused_crcs,
|
|
NOT_GPL_ONLY, true },
|
|
{ mod->unused_gpl_syms,
|
|
mod->unused_gpl_syms + mod->num_unused_gpl_syms,
|
|
mod->unused_gpl_crcs,
|
|
GPL_ONLY, true },
|
|
#endif
|
|
};
|
|
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
|
|
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
struct find_symbol_arg {
|
|
/* Input */
|
|
const char *name;
|
|
bool gplok;
|
|
bool warn;
|
|
|
|
/* Output */
|
|
struct module *owner;
|
|
const s32 *crc;
|
|
const struct kernel_symbol *sym;
|
|
enum mod_license license;
|
|
};
|
|
|
|
static bool check_exported_symbol(const struct symsearch *syms,
|
|
struct module *owner,
|
|
unsigned int symnum, void *data)
|
|
{
|
|
struct find_symbol_arg *fsa = data;
|
|
|
|
if (!fsa->gplok) {
|
|
if (syms->license == GPL_ONLY)
|
|
return false;
|
|
if (syms->license == WILL_BE_GPL_ONLY && fsa->warn) {
|
|
pr_warn("Symbol %s is being used by a non-GPL module, "
|
|
"which will not be allowed in the future\n",
|
|
fsa->name);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
if (syms->unused && fsa->warn) {
|
|
pr_warn("Symbol %s is marked as UNUSED, however this module is "
|
|
"using it.\n", fsa->name);
|
|
pr_warn("This symbol will go away in the future.\n");
|
|
pr_warn("Please evaluate if this is the right api to use and "
|
|
"if it really is, submit a report to the linux kernel "
|
|
"mailing list together with submitting your code for "
|
|
"inclusion.\n");
|
|
}
|
|
#endif
|
|
|
|
fsa->owner = owner;
|
|
fsa->crc = symversion(syms->crcs, symnum);
|
|
fsa->sym = &syms->start[symnum];
|
|
fsa->license = syms->license;
|
|
return true;
|
|
}
|
|
|
|
static unsigned long kernel_symbol_value(const struct kernel_symbol *sym)
|
|
{
|
|
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
|
return (unsigned long)offset_to_ptr(&sym->value_offset);
|
|
#else
|
|
return sym->value;
|
|
#endif
|
|
}
|
|
|
|
static const char *kernel_symbol_name(const struct kernel_symbol *sym)
|
|
{
|
|
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
|
return offset_to_ptr(&sym->name_offset);
|
|
#else
|
|
return sym->name;
|
|
#endif
|
|
}
|
|
|
|
static const char *kernel_symbol_namespace(const struct kernel_symbol *sym)
|
|
{
|
|
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
|
if (!sym->namespace_offset)
|
|
return NULL;
|
|
return offset_to_ptr(&sym->namespace_offset);
|
|
#else
|
|
return sym->namespace;
|
|
#endif
|
|
}
|
|
|
|
static int cmp_name(const void *name, const void *sym)
|
|
{
|
|
return strcmp(name, kernel_symbol_name(sym));
|
|
}
|
|
|
|
static bool find_exported_symbol_in_section(const struct symsearch *syms,
|
|
struct module *owner,
|
|
void *data)
|
|
{
|
|
struct find_symbol_arg *fsa = data;
|
|
struct kernel_symbol *sym;
|
|
|
|
sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
|
|
sizeof(struct kernel_symbol), cmp_name);
|
|
|
|
if (sym != NULL && check_exported_symbol(syms, owner,
|
|
sym - syms->start, data))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/* Find an exported symbol and return it, along with, (optional) crc and
|
|
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
|
|
static const struct kernel_symbol *find_symbol(const char *name,
|
|
struct module **owner,
|
|
const s32 **crc,
|
|
enum mod_license *license,
|
|
bool gplok,
|
|
bool warn)
|
|
{
|
|
struct find_symbol_arg fsa;
|
|
|
|
fsa.name = name;
|
|
fsa.gplok = gplok;
|
|
fsa.warn = warn;
|
|
|
|
if (each_symbol_section(find_exported_symbol_in_section, &fsa)) {
|
|
if (owner)
|
|
*owner = fsa.owner;
|
|
if (crc)
|
|
*crc = fsa.crc;
|
|
if (license)
|
|
*license = fsa.license;
|
|
return fsa.sym;
|
|
}
|
|
|
|
pr_debug("Failed to find symbol %s\n", name);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Search for module by name: must hold module_mutex (or preempt disabled
|
|
* for read-only access).
|
|
*/
|
|
static struct module *find_module_all(const char *name, size_t len,
|
|
bool even_unformed)
|
|
{
|
|
struct module *mod;
|
|
|
|
module_assert_mutex_or_preempt();
|
|
|
|
list_for_each_entry_rcu(mod, &modules, list,
|
|
lockdep_is_held(&module_mutex)) {
|
|
if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
|
|
return mod;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct module *find_module(const char *name)
|
|
{
|
|
module_assert_mutex();
|
|
return find_module_all(name, strlen(name), false);
|
|
}
|
|
EXPORT_SYMBOL_GPL(find_module);
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
static inline void __percpu *mod_percpu(struct module *mod)
|
|
{
|
|
return mod->percpu;
|
|
}
|
|
|
|
static int percpu_modalloc(struct module *mod, struct load_info *info)
|
|
{
|
|
Elf_Shdr *pcpusec = &info->sechdrs[info->index.pcpu];
|
|
unsigned long align = pcpusec->sh_addralign;
|
|
|
|
if (!pcpusec->sh_size)
|
|
return 0;
|
|
|
|
if (align > PAGE_SIZE) {
|
|
pr_warn("%s: per-cpu alignment %li > %li\n",
|
|
mod->name, align, PAGE_SIZE);
|
|
align = PAGE_SIZE;
|
|
}
|
|
|
|
mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align);
|
|
if (!mod->percpu) {
|
|
pr_warn("%s: Could not allocate %lu bytes percpu data\n",
|
|
mod->name, (unsigned long)pcpusec->sh_size);
|
|
return -ENOMEM;
|
|
}
|
|
mod->percpu_size = pcpusec->sh_size;
|
|
return 0;
|
|
}
|
|
|
|
static void percpu_modfree(struct module *mod)
|
|
{
|
|
free_percpu(mod->percpu);
|
|
}
|
|
|
|
static unsigned int find_pcpusec(struct load_info *info)
|
|
{
|
|
return find_sec(info, ".data..percpu");
|
|
}
|
|
|
|
static void percpu_modcopy(struct module *mod,
|
|
const void *from, unsigned long size)
|
|
{
|
|
int cpu;
|
|
|
|
for_each_possible_cpu(cpu)
|
|
memcpy(per_cpu_ptr(mod->percpu, cpu), from, size);
|
|
}
|
|
|
|
bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr)
|
|
{
|
|
struct module *mod;
|
|
unsigned int cpu;
|
|
|
|
preempt_disable();
|
|
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
if (!mod->percpu_size)
|
|
continue;
|
|
for_each_possible_cpu(cpu) {
|
|
void *start = per_cpu_ptr(mod->percpu, cpu);
|
|
void *va = (void *)addr;
|
|
|
|
if (va >= start && va < start + mod->percpu_size) {
|
|
if (can_addr) {
|
|
*can_addr = (unsigned long) (va - start);
|
|
*can_addr += (unsigned long)
|
|
per_cpu_ptr(mod->percpu,
|
|
get_boot_cpu_id());
|
|
}
|
|
preempt_enable();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
preempt_enable();
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* is_module_percpu_address - test whether address is from module static percpu
|
|
* @addr: address to test
|
|
*
|
|
* Test whether @addr belongs to module static percpu area.
|
|
*
|
|
* RETURNS:
|
|
* %true if @addr is from module static percpu area
|
|
*/
|
|
bool is_module_percpu_address(unsigned long addr)
|
|
{
|
|
return __is_module_percpu_address(addr, NULL);
|
|
}
|
|
|
|
#else /* ... !CONFIG_SMP */
|
|
|
|
static inline void __percpu *mod_percpu(struct module *mod)
|
|
{
|
|
return NULL;
|
|
}
|
|
static int percpu_modalloc(struct module *mod, struct load_info *info)
|
|
{
|
|
/* UP modules shouldn't have this section: ENOMEM isn't quite right */
|
|
if (info->sechdrs[info->index.pcpu].sh_size != 0)
|
|
return -ENOMEM;
|
|
return 0;
|
|
}
|
|
static inline void percpu_modfree(struct module *mod)
|
|
{
|
|
}
|
|
static unsigned int find_pcpusec(struct load_info *info)
|
|
{
|
|
return 0;
|
|
}
|
|
static inline void percpu_modcopy(struct module *mod,
|
|
const void *from, unsigned long size)
|
|
{
|
|
/* pcpusec should be 0, and size of that section should be 0. */
|
|
BUG_ON(size != 0);
|
|
}
|
|
bool is_module_percpu_address(unsigned long addr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
#define MODINFO_ATTR(field) \
|
|
static void setup_modinfo_##field(struct module *mod, const char *s) \
|
|
{ \
|
|
mod->field = kstrdup(s, GFP_KERNEL); \
|
|
} \
|
|
static ssize_t show_modinfo_##field(struct module_attribute *mattr, \
|
|
struct module_kobject *mk, char *buffer) \
|
|
{ \
|
|
return scnprintf(buffer, PAGE_SIZE, "%s\n", mk->mod->field); \
|
|
} \
|
|
static int modinfo_##field##_exists(struct module *mod) \
|
|
{ \
|
|
return mod->field != NULL; \
|
|
} \
|
|
static void free_modinfo_##field(struct module *mod) \
|
|
{ \
|
|
kfree(mod->field); \
|
|
mod->field = NULL; \
|
|
} \
|
|
static struct module_attribute modinfo_##field = { \
|
|
.attr = { .name = __stringify(field), .mode = 0444 }, \
|
|
.show = show_modinfo_##field, \
|
|
.setup = setup_modinfo_##field, \
|
|
.test = modinfo_##field##_exists, \
|
|
.free = free_modinfo_##field, \
|
|
};
|
|
|
|
MODINFO_ATTR(version);
|
|
MODINFO_ATTR(srcversion);
|
|
|
|
static char last_unloaded_module[MODULE_NAME_LEN+1];
|
|
|
|
#ifdef CONFIG_MODULE_UNLOAD
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL(module_get);
|
|
|
|
/* MODULE_REF_BASE is the base reference count by kmodule loader. */
|
|
#define MODULE_REF_BASE 1
|
|
|
|
/* Init the unload section of the module. */
|
|
static int module_unload_init(struct module *mod)
|
|
{
|
|
/*
|
|
* Initialize reference counter to MODULE_REF_BASE.
|
|
* refcnt == 0 means module is going.
|
|
*/
|
|
atomic_set(&mod->refcnt, MODULE_REF_BASE);
|
|
|
|
INIT_LIST_HEAD(&mod->source_list);
|
|
INIT_LIST_HEAD(&mod->target_list);
|
|
|
|
/* Hold reference count during initialization. */
|
|
atomic_inc(&mod->refcnt);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Does a already use b? */
|
|
static int already_uses(struct module *a, struct module *b)
|
|
{
|
|
struct module_use *use;
|
|
|
|
list_for_each_entry(use, &b->source_list, source_list) {
|
|
if (use->source == a) {
|
|
pr_debug("%s uses %s!\n", a->name, b->name);
|
|
return 1;
|
|
}
|
|
}
|
|
pr_debug("%s does not use %s!\n", a->name, b->name);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Module a uses b
|
|
* - we add 'a' as a "source", 'b' as a "target" of module use
|
|
* - the module_use is added to the list of 'b' sources (so
|
|
* 'b' can walk the list to see who sourced them), and of 'a'
|
|
* targets (so 'a' can see what modules it targets).
|
|
*/
|
|
static int add_module_usage(struct module *a, struct module *b)
|
|
{
|
|
struct module_use *use;
|
|
|
|
pr_debug("Allocating new usage for %s.\n", a->name);
|
|
use = kmalloc(sizeof(*use), GFP_ATOMIC);
|
|
if (!use)
|
|
return -ENOMEM;
|
|
|
|
use->source = a;
|
|
use->target = b;
|
|
list_add(&use->source_list, &b->source_list);
|
|
list_add(&use->target_list, &a->target_list);
|
|
return 0;
|
|
}
|
|
|
|
/* Module a uses b: caller needs module_mutex() */
|
|
static int ref_module(struct module *a, struct module *b)
|
|
{
|
|
int err;
|
|
|
|
if (b == NULL || already_uses(a, b))
|
|
return 0;
|
|
|
|
/* If module isn't available, we fail. */
|
|
err = strong_try_module_get(b);
|
|
if (err)
|
|
return err;
|
|
|
|
err = add_module_usage(a, b);
|
|
if (err) {
|
|
module_put(b);
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Clear the unload stuff of the module. */
|
|
static void module_unload_free(struct module *mod)
|
|
{
|
|
struct module_use *use, *tmp;
|
|
|
|
mutex_lock(&module_mutex);
|
|
list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
|
|
struct module *i = use->target;
|
|
pr_debug("%s unusing %s\n", mod->name, i->name);
|
|
module_put(i);
|
|
list_del(&use->source_list);
|
|
list_del(&use->target_list);
|
|
kfree(use);
|
|
}
|
|
mutex_unlock(&module_mutex);
|
|
}
|
|
|
|
#ifdef CONFIG_MODULE_FORCE_UNLOAD
|
|
static inline int try_force_unload(unsigned int flags)
|
|
{
|
|
int ret = (flags & O_TRUNC);
|
|
if (ret)
|
|
add_taint(TAINT_FORCED_RMMOD, LOCKDEP_NOW_UNRELIABLE);
|
|
return ret;
|
|
}
|
|
#else
|
|
static inline int try_force_unload(unsigned int flags)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_MODULE_FORCE_UNLOAD */
|
|
|
|
/* Try to release refcount of module, 0 means success. */
|
|
static int try_release_module_ref(struct module *mod)
|
|
{
|
|
int ret;
|
|
|
|
/* Try to decrement refcnt which we set at loading */
|
|
ret = atomic_sub_return(MODULE_REF_BASE, &mod->refcnt);
|
|
BUG_ON(ret < 0);
|
|
if (ret)
|
|
/* Someone can put this right now, recover with checking */
|
|
ret = atomic_add_unless(&mod->refcnt, MODULE_REF_BASE, 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int try_stop_module(struct module *mod, int flags, int *forced)
|
|
{
|
|
/* If it's not unused, quit unless we're forcing. */
|
|
if (try_release_module_ref(mod) != 0) {
|
|
*forced = try_force_unload(flags);
|
|
if (!(*forced))
|
|
return -EWOULDBLOCK;
|
|
}
|
|
|
|
/* Mark it as dying. */
|
|
mod->state = MODULE_STATE_GOING;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* module_refcount - return the refcount or -1 if unloading
|
|
*
|
|
* @mod: the module we're checking
|
|
*
|
|
* Returns:
|
|
* -1 if the module is in the process of unloading
|
|
* otherwise the number of references in the kernel to the module
|
|
*/
|
|
int module_refcount(struct module *mod)
|
|
{
|
|
return atomic_read(&mod->refcnt) - MODULE_REF_BASE;
|
|
}
|
|
EXPORT_SYMBOL(module_refcount);
|
|
|
|
/* This exists whether we can unload or not */
|
|
static void free_module(struct module *mod);
|
|
|
|
SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
|
|
unsigned int, flags)
|
|
{
|
|
struct module *mod;
|
|
char name[MODULE_NAME_LEN];
|
|
int ret, forced = 0;
|
|
|
|
if (!capable(CAP_SYS_MODULE) || modules_disabled)
|
|
return -EPERM;
|
|
|
|
if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
|
|
return -EFAULT;
|
|
name[MODULE_NAME_LEN-1] = '\0';
|
|
|
|
audit_log_kern_module(name);
|
|
|
|
if (mutex_lock_interruptible(&module_mutex) != 0)
|
|
return -EINTR;
|
|
|
|
mod = find_module(name);
|
|
if (!mod) {
|
|
ret = -ENOENT;
|
|
goto out;
|
|
}
|
|
|
|
if (!list_empty(&mod->source_list)) {
|
|
/* Other modules depend on us: get rid of them first. */
|
|
ret = -EWOULDBLOCK;
|
|
goto out;
|
|
}
|
|
|
|
/* Doing init or already dying? */
|
|
if (mod->state != MODULE_STATE_LIVE) {
|
|
/* FIXME: if (force), slam module count damn the torpedoes */
|
|
pr_debug("%s already dying\n", mod->name);
|
|
ret = -EBUSY;
|
|
goto out;
|
|
}
|
|
|
|
/* If it has an init func, it must have an exit func to unload */
|
|
if (mod->init && !mod->exit) {
|
|
forced = try_force_unload(flags);
|
|
if (!forced) {
|
|
/* This module can't be removed */
|
|
ret = -EBUSY;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* Stop the machine so refcounts can't move and disable module. */
|
|
ret = try_stop_module(mod, flags, &forced);
|
|
if (ret != 0)
|
|
goto out;
|
|
|
|
mutex_unlock(&module_mutex);
|
|
/* Final destruction now no one is using it. */
|
|
if (mod->exit != NULL)
|
|
mod->exit();
|
|
blocking_notifier_call_chain(&module_notify_list,
|
|
MODULE_STATE_GOING, mod);
|
|
klp_module_going(mod);
|
|
ftrace_release_mod(mod);
|
|
|
|
async_synchronize_full();
|
|
|
|
/* Store the name of the last unloaded module for diagnostic purposes */
|
|
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
|
|
|
|
free_module(mod);
|
|
/* someone could wait for the module in add_unformed_module() */
|
|
wake_up_all(&module_wq);
|
|
return 0;
|
|
out:
|
|
mutex_unlock(&module_mutex);
|
|
return ret;
|
|
}
|
|
|
|
static inline void print_unload_info(struct seq_file *m, struct module *mod)
|
|
{
|
|
struct module_use *use;
|
|
int printed_something = 0;
|
|
|
|
seq_printf(m, " %i ", module_refcount(mod));
|
|
|
|
/*
|
|
* Always include a trailing , so userspace can differentiate
|
|
* between this and the old multi-field proc format.
|
|
*/
|
|
list_for_each_entry(use, &mod->source_list, source_list) {
|
|
printed_something = 1;
|
|
seq_printf(m, "%s,", use->source->name);
|
|
}
|
|
|
|
if (mod->init != NULL && mod->exit == NULL) {
|
|
printed_something = 1;
|
|
seq_puts(m, "[permanent],");
|
|
}
|
|
|
|
if (!printed_something)
|
|
seq_puts(m, "-");
|
|
}
|
|
|
|
void __symbol_put(const char *symbol)
|
|
{
|
|
struct module *owner;
|
|
|
|
preempt_disable();
|
|
if (!find_symbol(symbol, &owner, NULL, NULL, true, false))
|
|
BUG();
|
|
module_put(owner);
|
|
preempt_enable();
|
|
}
|
|
|
|
/* Note this assumes addr is a function, which it currently always is. */
|
|
void symbol_put_addr(void *addr)
|
|
{
|
|
struct module *modaddr;
|
|
unsigned long a = (unsigned long)dereference_function_descriptor(addr);
|
|
|
|
if (core_kernel_text(a))
|
|
return;
|
|
|
|
/*
|
|
* Even though we hold a reference on the module; we still need to
|
|
* disable preemption in order to safely traverse the data structure.
|
|
*/
|
|
preempt_disable();
|
|
modaddr = __module_text_address(a);
|
|
BUG_ON(!modaddr);
|
|
module_put(modaddr);
|
|
preempt_enable();
|
|
}
|
|
EXPORT_SYMBOL_GPL(symbol_put_addr);
|
|
|
|
static ssize_t show_refcnt(struct module_attribute *mattr,
|
|
struct module_kobject *mk, char *buffer)
|
|
{
|
|
return sprintf(buffer, "%i\n", module_refcount(mk->mod));
|
|
}
|
|
|
|
static struct module_attribute modinfo_refcnt =
|
|
__ATTR(refcnt, 0444, show_refcnt, NULL);
|
|
|
|
void __module_get(struct module *module)
|
|
{
|
|
if (module) {
|
|
preempt_disable();
|
|
atomic_inc(&module->refcnt);
|
|
trace_module_get(module, _RET_IP_);
|
|
preempt_enable();
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(__module_get);
|
|
|
|
bool try_module_get(struct module *module)
|
|
{
|
|
bool ret = true;
|
|
|
|
if (module) {
|
|
preempt_disable();
|
|
/* Note: here, we can fail to get a reference */
|
|
if (likely(module_is_live(module) &&
|
|
atomic_inc_not_zero(&module->refcnt) != 0))
|
|
trace_module_get(module, _RET_IP_);
|
|
else
|
|
ret = false;
|
|
|
|
preempt_enable();
|
|
}
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(try_module_get);
|
|
|
|
void module_put(struct module *module)
|
|
{
|
|
int ret;
|
|
|
|
if (module) {
|
|
preempt_disable();
|
|
ret = atomic_dec_if_positive(&module->refcnt);
|
|
WARN_ON(ret < 0); /* Failed to put refcount */
|
|
trace_module_put(module, _RET_IP_);
|
|
preempt_enable();
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(module_put);
|
|
|
|
#else /* !CONFIG_MODULE_UNLOAD */
|
|
static inline void print_unload_info(struct seq_file *m, struct module *mod)
|
|
{
|
|
/* We don't know the usage count, or what modules are using. */
|
|
seq_puts(m, " - -");
|
|
}
|
|
|
|
static inline void module_unload_free(struct module *mod)
|
|
{
|
|
}
|
|
|
|
static int ref_module(struct module *a, struct module *b)
|
|
{
|
|
return strong_try_module_get(b);
|
|
}
|
|
|
|
static inline int module_unload_init(struct module *mod)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_MODULE_UNLOAD */
|
|
|
|
static size_t module_flags_taint(struct module *mod, char *buf)
|
|
{
|
|
size_t l = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
|
|
if (taint_flags[i].module && test_bit(i, &mod->taints))
|
|
buf[l++] = taint_flags[i].c_true;
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
static ssize_t show_initstate(struct module_attribute *mattr,
|
|
struct module_kobject *mk, char *buffer)
|
|
{
|
|
const char *state = "unknown";
|
|
|
|
switch (mk->mod->state) {
|
|
case MODULE_STATE_LIVE:
|
|
state = "live";
|
|
break;
|
|
case MODULE_STATE_COMING:
|
|
state = "coming";
|
|
break;
|
|
case MODULE_STATE_GOING:
|
|
state = "going";
|
|
break;
|
|
default:
|
|
BUG();
|
|
}
|
|
return sprintf(buffer, "%s\n", state);
|
|
}
|
|
|
|
static struct module_attribute modinfo_initstate =
|
|
__ATTR(initstate, 0444, show_initstate, NULL);
|
|
|
|
static ssize_t store_uevent(struct module_attribute *mattr,
|
|
struct module_kobject *mk,
|
|
const char *buffer, size_t count)
|
|
{
|
|
int rc;
|
|
|
|
rc = kobject_synth_uevent(&mk->kobj, buffer, count);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
struct module_attribute module_uevent =
|
|
__ATTR(uevent, 0200, NULL, store_uevent);
|
|
|
|
static ssize_t show_coresize(struct module_attribute *mattr,
|
|
struct module_kobject *mk, char *buffer)
|
|
{
|
|
return sprintf(buffer, "%u\n", mk->mod->core_layout.size);
|
|
}
|
|
|
|
static struct module_attribute modinfo_coresize =
|
|
__ATTR(coresize, 0444, show_coresize, NULL);
|
|
|
|
static ssize_t show_initsize(struct module_attribute *mattr,
|
|
struct module_kobject *mk, char *buffer)
|
|
{
|
|
return sprintf(buffer, "%u\n", mk->mod->init_layout.size);
|
|
}
|
|
|
|
static struct module_attribute modinfo_initsize =
|
|
__ATTR(initsize, 0444, show_initsize, NULL);
|
|
|
|
static ssize_t show_taint(struct module_attribute *mattr,
|
|
struct module_kobject *mk, char *buffer)
|
|
{
|
|
size_t l;
|
|
|
|
l = module_flags_taint(mk->mod, buffer);
|
|
buffer[l++] = '\n';
|
|
return l;
|
|
}
|
|
|
|
static struct module_attribute modinfo_taint =
|
|
__ATTR(taint, 0444, show_taint, NULL);
|
|
|
|
static struct module_attribute *modinfo_attrs[] = {
|
|
&module_uevent,
|
|
&modinfo_version,
|
|
&modinfo_srcversion,
|
|
&modinfo_initstate,
|
|
&modinfo_coresize,
|
|
&modinfo_initsize,
|
|
&modinfo_taint,
|
|
#ifdef CONFIG_MODULE_UNLOAD
|
|
&modinfo_refcnt,
|
|
#endif
|
|
NULL,
|
|
};
|
|
|
|
static const char vermagic[] = VERMAGIC_STRING;
|
|
|
|
static int try_to_force_load(struct module *mod, const char *reason)
|
|
{
|
|
#ifdef CONFIG_MODULE_FORCE_LOAD
|
|
if (!test_taint(TAINT_FORCED_MODULE))
|
|
pr_warn("%s: %s: kernel tainted.\n", mod->name, reason);
|
|
add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_NOW_UNRELIABLE);
|
|
return 0;
|
|
#else
|
|
return -ENOEXEC;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_MODVERSIONS
|
|
|
|
static u32 resolve_rel_crc(const s32 *crc)
|
|
{
|
|
return *(u32 *)((void *)crc + *crc);
|
|
}
|
|
|
|
static int check_version(const struct load_info *info,
|
|
const char *symname,
|
|
struct module *mod,
|
|
const s32 *crc)
|
|
{
|
|
Elf_Shdr *sechdrs = info->sechdrs;
|
|
unsigned int versindex = info->index.vers;
|
|
unsigned int i, num_versions;
|
|
struct modversion_info *versions;
|
|
|
|
/* Exporting module didn't supply crcs? OK, we're already tainted. */
|
|
if (!crc)
|
|
return 1;
|
|
|
|
/* No versions at all? modprobe --force does this. */
|
|
if (versindex == 0)
|
|
return try_to_force_load(mod, symname) == 0;
|
|
|
|
versions = (void *) sechdrs[versindex].sh_addr;
|
|
num_versions = sechdrs[versindex].sh_size
|
|
/ sizeof(struct modversion_info);
|
|
|
|
for (i = 0; i < num_versions; i++) {
|
|
u32 crcval;
|
|
|
|
if (strcmp(versions[i].name, symname) != 0)
|
|
continue;
|
|
|
|
if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
|
|
crcval = resolve_rel_crc(crc);
|
|
else
|
|
crcval = *crc;
|
|
if (versions[i].crc == crcval)
|
|
return 1;
|
|
pr_debug("Found checksum %X vs module %lX\n",
|
|
crcval, versions[i].crc);
|
|
goto bad_version;
|
|
}
|
|
|
|
/* Broken toolchain. Warn once, then let it go.. */
|
|
pr_warn_once("%s: no symbol version for %s\n", info->name, symname);
|
|
return 1;
|
|
|
|
bad_version:
|
|
pr_warn("%s: disagrees about version of symbol %s\n",
|
|
info->name, symname);
|
|
return 0;
|
|
}
|
|
|
|
static inline int check_modstruct_version(const struct load_info *info,
|
|
struct module *mod)
|
|
{
|
|
const s32 *crc;
|
|
|
|
/*
|
|
* Since this should be found in kernel (which can't be removed), no
|
|
* locking is necessary -- use preempt_disable() to placate lockdep.
|
|
*/
|
|
preempt_disable();
|
|
if (!find_symbol("module_layout", NULL, &crc, NULL, true, false)) {
|
|
preempt_enable();
|
|
BUG();
|
|
}
|
|
preempt_enable();
|
|
return check_version(info, "module_layout", mod, crc);
|
|
}
|
|
|
|
/* First part is kernel version, which we ignore if module has crcs. */
|
|
static inline int same_magic(const char *amagic, const char *bmagic,
|
|
bool has_crcs)
|
|
{
|
|
if (has_crcs) {
|
|
amagic += strcspn(amagic, " ");
|
|
bmagic += strcspn(bmagic, " ");
|
|
}
|
|
return strcmp(amagic, bmagic) == 0;
|
|
}
|
|
#else
|
|
static inline int check_version(const struct load_info *info,
|
|
const char *symname,
|
|
struct module *mod,
|
|
const s32 *crc)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static inline int check_modstruct_version(const struct load_info *info,
|
|
struct module *mod)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static inline int same_magic(const char *amagic, const char *bmagic,
|
|
bool has_crcs)
|
|
{
|
|
return strcmp(amagic, bmagic) == 0;
|
|
}
|
|
#endif /* CONFIG_MODVERSIONS */
|
|
|
|
static char *get_modinfo(const struct load_info *info, const char *tag);
|
|
static char *get_next_modinfo(const struct load_info *info, const char *tag,
|
|
char *prev);
|
|
|
|
static int verify_namespace_is_imported(const struct load_info *info,
|
|
const struct kernel_symbol *sym,
|
|
struct module *mod)
|
|
{
|
|
const char *namespace;
|
|
char *imported_namespace;
|
|
|
|
namespace = kernel_symbol_namespace(sym);
|
|
if (namespace) {
|
|
imported_namespace = get_modinfo(info, "import_ns");
|
|
while (imported_namespace) {
|
|
if (strcmp(namespace, imported_namespace) == 0)
|
|
return 0;
|
|
imported_namespace = get_next_modinfo(
|
|
info, "import_ns", imported_namespace);
|
|
}
|
|
#ifdef CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
|
|
pr_warn(
|
|
#else
|
|
pr_err(
|
|
#endif
|
|
"%s: module uses symbol (%s) from namespace %s, but does not import it.\n",
|
|
mod->name, kernel_symbol_name(sym), namespace);
|
|
#ifndef CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
|
|
return -EINVAL;
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool inherit_taint(struct module *mod, struct module *owner)
|
|
{
|
|
if (!owner || !test_bit(TAINT_PROPRIETARY_MODULE, &owner->taints))
|
|
return true;
|
|
|
|
if (mod->using_gplonly_symbols) {
|
|
pr_err("%s: module using GPL-only symbols uses symbols from proprietary module %s.\n",
|
|
mod->name, owner->name);
|
|
return false;
|
|
}
|
|
|
|
if (!test_bit(TAINT_PROPRIETARY_MODULE, &mod->taints)) {
|
|
pr_warn("%s: module uses symbols from proprietary module %s, inheriting taint.\n",
|
|
mod->name, owner->name);
|
|
set_bit(TAINT_PROPRIETARY_MODULE, &mod->taints);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* Resolve a symbol for this module. I.e. if we find one, record usage. */
|
|
static const struct kernel_symbol *resolve_symbol(struct module *mod,
|
|
const struct load_info *info,
|
|
const char *name,
|
|
char ownername[])
|
|
{
|
|
struct module *owner;
|
|
const struct kernel_symbol *sym;
|
|
const s32 *crc;
|
|
enum mod_license license;
|
|
int err;
|
|
|
|
/*
|
|
* The module_mutex should not be a heavily contended lock;
|
|
* if we get the occasional sleep here, we'll go an extra iteration
|
|
* in the wait_event_interruptible(), which is harmless.
|
|
*/
|
|
sched_annotate_sleep();
|
|
mutex_lock(&module_mutex);
|
|
sym = find_symbol(name, &owner, &crc, &license,
|
|
!(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
|
|
if (!sym)
|
|
goto unlock;
|
|
|
|
if (license == GPL_ONLY)
|
|
mod->using_gplonly_symbols = true;
|
|
|
|
if (!inherit_taint(mod, owner)) {
|
|
sym = NULL;
|
|
goto getname;
|
|
}
|
|
|
|
if (!check_version(info, name, mod, crc)) {
|
|
sym = ERR_PTR(-EINVAL);
|
|
goto getname;
|
|
}
|
|
|
|
err = verify_namespace_is_imported(info, sym, mod);
|
|
if (err) {
|
|
sym = ERR_PTR(err);
|
|
goto getname;
|
|
}
|
|
|
|
err = ref_module(mod, owner);
|
|
if (err) {
|
|
sym = ERR_PTR(err);
|
|
goto getname;
|
|
}
|
|
|
|
getname:
|
|
/* We must make copy under the lock if we failed to get ref. */
|
|
strncpy(ownername, module_name(owner), MODULE_NAME_LEN);
|
|
unlock:
|
|
mutex_unlock(&module_mutex);
|
|
return sym;
|
|
}
|
|
|
|
static const struct kernel_symbol *
|
|
resolve_symbol_wait(struct module *mod,
|
|
const struct load_info *info,
|
|
const char *name)
|
|
{
|
|
const struct kernel_symbol *ksym;
|
|
char owner[MODULE_NAME_LEN];
|
|
|
|
if (wait_event_interruptible_timeout(module_wq,
|
|
!IS_ERR(ksym = resolve_symbol(mod, info, name, owner))
|
|
|| PTR_ERR(ksym) != -EBUSY,
|
|
30 * HZ) <= 0) {
|
|
pr_warn("%s: gave up waiting for init of module %s.\n",
|
|
mod->name, owner);
|
|
}
|
|
return ksym;
|
|
}
|
|
|
|
/*
|
|
* /sys/module/foo/sections stuff
|
|
* J. Corbet <corbet@lwn.net>
|
|
*/
|
|
#ifdef CONFIG_SYSFS
|
|
|
|
#ifdef CONFIG_KALLSYMS
|
|
static inline bool sect_empty(const Elf_Shdr *sect)
|
|
{
|
|
return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
|
|
}
|
|
|
|
struct module_sect_attr {
|
|
struct bin_attribute battr;
|
|
unsigned long address;
|
|
};
|
|
|
|
struct module_sect_attrs {
|
|
struct attribute_group grp;
|
|
unsigned int nsections;
|
|
struct module_sect_attr attrs[0];
|
|
};
|
|
|
|
#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
|
|
static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
|
|
struct bin_attribute *battr,
|
|
char *buf, loff_t pos, size_t count)
|
|
{
|
|
struct module_sect_attr *sattr =
|
|
container_of(battr, struct module_sect_attr, battr);
|
|
char bounce[MODULE_SECT_READ_SIZE + 1];
|
|
size_t wrote;
|
|
|
|
if (pos != 0)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* Since we're a binary read handler, we must account for the
|
|
* trailing NUL byte that sprintf will write: if "buf" is
|
|
* too small to hold the NUL, or the NUL is exactly the last
|
|
* byte, the read will look like it got truncated by one byte.
|
|
* Since there is no way to ask sprintf nicely to not write
|
|
* the NUL, we have to use a bounce buffer.
|
|
*/
|
|
wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
|
|
kallsyms_show_value(file->f_cred)
|
|
? (void *)sattr->address : NULL);
|
|
count = min(count, wrote);
|
|
memcpy(buf, bounce, count);
|
|
|
|
return count;
|
|
}
|
|
|
|
static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
|
|
{
|
|
unsigned int section;
|
|
|
|
for (section = 0; section < sect_attrs->nsections; section++)
|
|
kfree(sect_attrs->attrs[section].battr.attr.name);
|
|
kfree(sect_attrs);
|
|
}
|
|
|
|
static void add_sect_attrs(struct module *mod, const struct load_info *info)
|
|
{
|
|
unsigned int nloaded = 0, i, size[2];
|
|
struct module_sect_attrs *sect_attrs;
|
|
struct module_sect_attr *sattr;
|
|
struct bin_attribute **gattr;
|
|
|
|
/* Count loaded sections and allocate structures */
|
|
for (i = 0; i < info->hdr->e_shnum; i++)
|
|
if (!sect_empty(&info->sechdrs[i]))
|
|
nloaded++;
|
|
size[0] = ALIGN(struct_size(sect_attrs, attrs, nloaded),
|
|
sizeof(sect_attrs->grp.bin_attrs[0]));
|
|
size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.bin_attrs[0]);
|
|
sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
|
|
if (sect_attrs == NULL)
|
|
return;
|
|
|
|
/* Setup section attributes. */
|
|
sect_attrs->grp.name = "sections";
|
|
sect_attrs->grp.bin_attrs = (void *)sect_attrs + size[0];
|
|
|
|
sect_attrs->nsections = 0;
|
|
sattr = §_attrs->attrs[0];
|
|
gattr = §_attrs->grp.bin_attrs[0];
|
|
for (i = 0; i < info->hdr->e_shnum; i++) {
|
|
Elf_Shdr *sec = &info->sechdrs[i];
|
|
if (sect_empty(sec))
|
|
continue;
|
|
sysfs_bin_attr_init(&sattr->battr);
|
|
sattr->address = sec->sh_addr;
|
|
sattr->battr.attr.name =
|
|
kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL);
|
|
if (sattr->battr.attr.name == NULL)
|
|
goto out;
|
|
sect_attrs->nsections++;
|
|
sattr->battr.read = module_sect_read;
|
|
sattr->battr.size = MODULE_SECT_READ_SIZE;
|
|
sattr->battr.attr.mode = 0400;
|
|
*(gattr++) = &(sattr++)->battr;
|
|
}
|
|
*gattr = NULL;
|
|
|
|
if (sysfs_create_group(&mod->mkobj.kobj, §_attrs->grp))
|
|
goto out;
|
|
|
|
mod->sect_attrs = sect_attrs;
|
|
return;
|
|
out:
|
|
free_sect_attrs(sect_attrs);
|
|
}
|
|
|
|
static void remove_sect_attrs(struct module *mod)
|
|
{
|
|
if (mod->sect_attrs) {
|
|
sysfs_remove_group(&mod->mkobj.kobj,
|
|
&mod->sect_attrs->grp);
|
|
/* We are positive that no one is using any sect attrs
|
|
* at this point. Deallocate immediately. */
|
|
free_sect_attrs(mod->sect_attrs);
|
|
mod->sect_attrs = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
|
|
*/
|
|
|
|
struct module_notes_attrs {
|
|
struct kobject *dir;
|
|
unsigned int notes;
|
|
struct bin_attribute attrs[0];
|
|
};
|
|
|
|
static ssize_t module_notes_read(struct file *filp, struct kobject *kobj,
|
|
struct bin_attribute *bin_attr,
|
|
char *buf, loff_t pos, size_t count)
|
|
{
|
|
/*
|
|
* The caller checked the pos and count against our size.
|
|
*/
|
|
memcpy(buf, bin_attr->private + pos, count);
|
|
return count;
|
|
}
|
|
|
|
static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
|
|
unsigned int i)
|
|
{
|
|
if (notes_attrs->dir) {
|
|
while (i-- > 0)
|
|
sysfs_remove_bin_file(notes_attrs->dir,
|
|
¬es_attrs->attrs[i]);
|
|
kobject_put(notes_attrs->dir);
|
|
}
|
|
kfree(notes_attrs);
|
|
}
|
|
|
|
static void add_notes_attrs(struct module *mod, const struct load_info *info)
|
|
{
|
|
unsigned int notes, loaded, i;
|
|
struct module_notes_attrs *notes_attrs;
|
|
struct bin_attribute *nattr;
|
|
|
|
/* failed to create section attributes, so can't create notes */
|
|
if (!mod->sect_attrs)
|
|
return;
|
|
|
|
/* Count notes sections and allocate structures. */
|
|
notes = 0;
|
|
for (i = 0; i < info->hdr->e_shnum; i++)
|
|
if (!sect_empty(&info->sechdrs[i]) &&
|
|
(info->sechdrs[i].sh_type == SHT_NOTE))
|
|
++notes;
|
|
|
|
if (notes == 0)
|
|
return;
|
|
|
|
notes_attrs = kzalloc(struct_size(notes_attrs, attrs, notes),
|
|
GFP_KERNEL);
|
|
if (notes_attrs == NULL)
|
|
return;
|
|
|
|
notes_attrs->notes = notes;
|
|
nattr = ¬es_attrs->attrs[0];
|
|
for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
|
|
if (sect_empty(&info->sechdrs[i]))
|
|
continue;
|
|
if (info->sechdrs[i].sh_type == SHT_NOTE) {
|
|
sysfs_bin_attr_init(nattr);
|
|
nattr->attr.name = mod->sect_attrs->attrs[loaded].battr.attr.name;
|
|
nattr->attr.mode = S_IRUGO;
|
|
nattr->size = info->sechdrs[i].sh_size;
|
|
nattr->private = (void *) info->sechdrs[i].sh_addr;
|
|
nattr->read = module_notes_read;
|
|
++nattr;
|
|
}
|
|
++loaded;
|
|
}
|
|
|
|
notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
|
|
if (!notes_attrs->dir)
|
|
goto out;
|
|
|
|
for (i = 0; i < notes; ++i)
|
|
if (sysfs_create_bin_file(notes_attrs->dir,
|
|
¬es_attrs->attrs[i]))
|
|
goto out;
|
|
|
|
mod->notes_attrs = notes_attrs;
|
|
return;
|
|
|
|
out:
|
|
free_notes_attrs(notes_attrs, i);
|
|
}
|
|
|
|
static void remove_notes_attrs(struct module *mod)
|
|
{
|
|
if (mod->notes_attrs)
|
|
free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void add_sect_attrs(struct module *mod,
|
|
const struct load_info *info)
|
|
{
|
|
}
|
|
|
|
static inline void remove_sect_attrs(struct module *mod)
|
|
{
|
|
}
|
|
|
|
static inline void add_notes_attrs(struct module *mod,
|
|
const struct load_info *info)
|
|
{
|
|
}
|
|
|
|
static inline void remove_notes_attrs(struct module *mod)
|
|
{
|
|
}
|
|
#endif /* CONFIG_KALLSYMS */
|
|
|
|
static void del_usage_links(struct module *mod)
|
|
{
|
|
#ifdef CONFIG_MODULE_UNLOAD
|
|
struct module_use *use;
|
|
|
|
mutex_lock(&module_mutex);
|
|
list_for_each_entry(use, &mod->target_list, target_list)
|
|
sysfs_remove_link(use->target->holders_dir, mod->name);
|
|
mutex_unlock(&module_mutex);
|
|
#endif
|
|
}
|
|
|
|
static int add_usage_links(struct module *mod)
|
|
{
|
|
int ret = 0;
|
|
#ifdef CONFIG_MODULE_UNLOAD
|
|
struct module_use *use;
|
|
|
|
mutex_lock(&module_mutex);
|
|
list_for_each_entry(use, &mod->target_list, target_list) {
|
|
ret = sysfs_create_link(use->target->holders_dir,
|
|
&mod->mkobj.kobj, mod->name);
|
|
if (ret)
|
|
break;
|
|
}
|
|
mutex_unlock(&module_mutex);
|
|
if (ret)
|
|
del_usage_links(mod);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static void module_remove_modinfo_attrs(struct module *mod, int end);
|
|
|
|
static int module_add_modinfo_attrs(struct module *mod)
|
|
{
|
|
struct module_attribute *attr;
|
|
struct module_attribute *temp_attr;
|
|
int error = 0;
|
|
int i;
|
|
|
|
mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
|
|
(ARRAY_SIZE(modinfo_attrs) + 1)),
|
|
GFP_KERNEL);
|
|
if (!mod->modinfo_attrs)
|
|
return -ENOMEM;
|
|
|
|
temp_attr = mod->modinfo_attrs;
|
|
for (i = 0; (attr = modinfo_attrs[i]); i++) {
|
|
if (!attr->test || attr->test(mod)) {
|
|
memcpy(temp_attr, attr, sizeof(*temp_attr));
|
|
sysfs_attr_init(&temp_attr->attr);
|
|
error = sysfs_create_file(&mod->mkobj.kobj,
|
|
&temp_attr->attr);
|
|
if (error)
|
|
goto error_out;
|
|
++temp_attr;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_out:
|
|
if (i > 0)
|
|
module_remove_modinfo_attrs(mod, --i);
|
|
else
|
|
kfree(mod->modinfo_attrs);
|
|
return error;
|
|
}
|
|
|
|
static void module_remove_modinfo_attrs(struct module *mod, int end)
|
|
{
|
|
struct module_attribute *attr;
|
|
int i;
|
|
|
|
for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
|
|
if (end >= 0 && i > end)
|
|
break;
|
|
/* pick a field to test for end of list */
|
|
if (!attr->attr.name)
|
|
break;
|
|
sysfs_remove_file(&mod->mkobj.kobj, &attr->attr);
|
|
if (attr->free)
|
|
attr->free(mod);
|
|
}
|
|
kfree(mod->modinfo_attrs);
|
|
}
|
|
|
|
static void mod_kobject_put(struct module *mod)
|
|
{
|
|
DECLARE_COMPLETION_ONSTACK(c);
|
|
mod->mkobj.kobj_completion = &c;
|
|
kobject_put(&mod->mkobj.kobj);
|
|
wait_for_completion(&c);
|
|
}
|
|
|
|
static int mod_sysfs_init(struct module *mod)
|
|
{
|
|
int err;
|
|
struct kobject *kobj;
|
|
|
|
if (!module_sysfs_initialized) {
|
|
pr_err("%s: module sysfs not initialized\n", mod->name);
|
|
err = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
kobj = kset_find_obj(module_kset, mod->name);
|
|
if (kobj) {
|
|
pr_err("%s: module is already loaded\n", mod->name);
|
|
kobject_put(kobj);
|
|
err = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
mod->mkobj.mod = mod;
|
|
|
|
memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
|
|
mod->mkobj.kobj.kset = module_kset;
|
|
err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
|
|
"%s", mod->name);
|
|
if (err)
|
|
mod_kobject_put(mod);
|
|
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
static int mod_sysfs_setup(struct module *mod,
|
|
const struct load_info *info,
|
|
struct kernel_param *kparam,
|
|
unsigned int num_params)
|
|
{
|
|
int err;
|
|
|
|
err = mod_sysfs_init(mod);
|
|
if (err)
|
|
goto out;
|
|
|
|
mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
|
|
if (!mod->holders_dir) {
|
|
err = -ENOMEM;
|
|
goto out_unreg;
|
|
}
|
|
|
|
err = module_param_sysfs_setup(mod, kparam, num_params);
|
|
if (err)
|
|
goto out_unreg_holders;
|
|
|
|
err = module_add_modinfo_attrs(mod);
|
|
if (err)
|
|
goto out_unreg_param;
|
|
|
|
err = add_usage_links(mod);
|
|
if (err)
|
|
goto out_unreg_modinfo_attrs;
|
|
|
|
add_sect_attrs(mod, info);
|
|
add_notes_attrs(mod, info);
|
|
|
|
return 0;
|
|
|
|
out_unreg_modinfo_attrs:
|
|
module_remove_modinfo_attrs(mod, -1);
|
|
out_unreg_param:
|
|
module_param_sysfs_remove(mod);
|
|
out_unreg_holders:
|
|
kobject_put(mod->holders_dir);
|
|
out_unreg:
|
|
mod_kobject_put(mod);
|
|
out:
|
|
return err;
|
|
}
|
|
|
|
static void mod_sysfs_fini(struct module *mod)
|
|
{
|
|
remove_notes_attrs(mod);
|
|
remove_sect_attrs(mod);
|
|
mod_kobject_put(mod);
|
|
}
|
|
|
|
static void init_param_lock(struct module *mod)
|
|
{
|
|
mutex_init(&mod->param_lock);
|
|
}
|
|
#else /* !CONFIG_SYSFS */
|
|
|
|
static int mod_sysfs_setup(struct module *mod,
|
|
const struct load_info *info,
|
|
struct kernel_param *kparam,
|
|
unsigned int num_params)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void mod_sysfs_fini(struct module *mod)
|
|
{
|
|
}
|
|
|
|
static void module_remove_modinfo_attrs(struct module *mod, int end)
|
|
{
|
|
}
|
|
|
|
static void del_usage_links(struct module *mod)
|
|
{
|
|
}
|
|
|
|
static void init_param_lock(struct module *mod)
|
|
{
|
|
}
|
|
#endif /* CONFIG_SYSFS */
|
|
|
|
static void mod_sysfs_teardown(struct module *mod)
|
|
{
|
|
del_usage_links(mod);
|
|
module_remove_modinfo_attrs(mod, -1);
|
|
module_param_sysfs_remove(mod);
|
|
kobject_put(mod->mkobj.drivers_dir);
|
|
kobject_put(mod->holders_dir);
|
|
mod_sysfs_fini(mod);
|
|
}
|
|
|
|
#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
|
|
/*
|
|
* LKM RO/NX protection: protect module's text/ro-data
|
|
* from modification and any data from execution.
|
|
*
|
|
* General layout of module is:
|
|
* [text] [read-only-data] [ro-after-init] [writable data]
|
|
* text_size -----^ ^ ^ ^
|
|
* ro_size ------------------------| | |
|
|
* ro_after_init_size -----------------------------| |
|
|
* size -----------------------------------------------------------|
|
|
*
|
|
* These values are always page-aligned (as is base)
|
|
*/
|
|
static void frob_text(const struct module_layout *layout,
|
|
int (*set_memory)(unsigned long start, int num_pages))
|
|
{
|
|
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
|
|
BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
|
|
set_memory((unsigned long)layout->base,
|
|
layout->text_size >> PAGE_SHIFT);
|
|
}
|
|
|
|
#ifdef CONFIG_STRICT_MODULE_RWX
|
|
static void frob_rodata(const struct module_layout *layout,
|
|
int (*set_memory)(unsigned long start, int num_pages))
|
|
{
|
|
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
|
|
BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1));
|
|
BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
|
|
set_memory((unsigned long)layout->base + layout->text_size,
|
|
(layout->ro_size - layout->text_size) >> PAGE_SHIFT);
|
|
}
|
|
|
|
static void frob_ro_after_init(const struct module_layout *layout,
|
|
int (*set_memory)(unsigned long start, int num_pages))
|
|
{
|
|
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
|
|
BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1));
|
|
BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
|
|
set_memory((unsigned long)layout->base + layout->ro_size,
|
|
(layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT);
|
|
}
|
|
|
|
static void frob_writable_data(const struct module_layout *layout,
|
|
int (*set_memory)(unsigned long start, int num_pages))
|
|
{
|
|
BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1));
|
|
BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1));
|
|
BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1));
|
|
set_memory((unsigned long)layout->base + layout->ro_after_init_size,
|
|
(layout->size - layout->ro_after_init_size) >> PAGE_SHIFT);
|
|
}
|
|
|
|
/* livepatching wants to disable read-only so it can frob module. */
|
|
void module_disable_ro(const struct module *mod)
|
|
{
|
|
if (!rodata_enabled)
|
|
return;
|
|
|
|
frob_text(&mod->core_layout, set_memory_rw);
|
|
frob_rodata(&mod->core_layout, set_memory_rw);
|
|
frob_ro_after_init(&mod->core_layout, set_memory_rw);
|
|
frob_text(&mod->init_layout, set_memory_rw);
|
|
frob_rodata(&mod->init_layout, set_memory_rw);
|
|
}
|
|
|
|
void module_enable_ro(const struct module *mod, bool after_init)
|
|
{
|
|
if (!rodata_enabled)
|
|
return;
|
|
|
|
set_vm_flush_reset_perms(mod->core_layout.base);
|
|
set_vm_flush_reset_perms(mod->init_layout.base);
|
|
frob_text(&mod->core_layout, set_memory_ro);
|
|
|
|
frob_rodata(&mod->core_layout, set_memory_ro);
|
|
frob_text(&mod->init_layout, set_memory_ro);
|
|
frob_rodata(&mod->init_layout, set_memory_ro);
|
|
|
|
if (after_init)
|
|
frob_ro_after_init(&mod->core_layout, set_memory_ro);
|
|
}
|
|
|
|
static void module_enable_nx(const struct module *mod)
|
|
{
|
|
frob_rodata(&mod->core_layout, set_memory_nx);
|
|
frob_ro_after_init(&mod->core_layout, set_memory_nx);
|
|
frob_writable_data(&mod->core_layout, set_memory_nx);
|
|
frob_rodata(&mod->init_layout, set_memory_nx);
|
|
frob_writable_data(&mod->init_layout, set_memory_nx);
|
|
}
|
|
|
|
/* Iterate through all modules and set each module's text as RW */
|
|
void set_all_modules_text_rw(void)
|
|
{
|
|
struct module *mod;
|
|
|
|
if (!rodata_enabled)
|
|
return;
|
|
|
|
mutex_lock(&module_mutex);
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
|
|
frob_text(&mod->core_layout, set_memory_rw);
|
|
frob_text(&mod->init_layout, set_memory_rw);
|
|
}
|
|
mutex_unlock(&module_mutex);
|
|
}
|
|
|
|
/* Iterate through all modules and set each module's text as RO */
|
|
void set_all_modules_text_ro(void)
|
|
{
|
|
struct module *mod;
|
|
|
|
if (!rodata_enabled)
|
|
return;
|
|
|
|
mutex_lock(&module_mutex);
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
/*
|
|
* Ignore going modules since it's possible that ro
|
|
* protection has already been disabled, otherwise we'll
|
|
* run into protection faults at module deallocation.
|
|
*/
|
|
if (mod->state == MODULE_STATE_UNFORMED ||
|
|
mod->state == MODULE_STATE_GOING)
|
|
continue;
|
|
|
|
frob_text(&mod->core_layout, set_memory_ro);
|
|
frob_text(&mod->init_layout, set_memory_ro);
|
|
}
|
|
mutex_unlock(&module_mutex);
|
|
}
|
|
#else /* !CONFIG_STRICT_MODULE_RWX */
|
|
static void module_enable_nx(const struct module *mod) { }
|
|
#endif /* CONFIG_STRICT_MODULE_RWX */
|
|
static void module_enable_x(const struct module *mod)
|
|
{
|
|
frob_text(&mod->core_layout, set_memory_x);
|
|
frob_text(&mod->init_layout, set_memory_x);
|
|
}
|
|
#else /* !CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
|
|
static void module_enable_nx(const struct module *mod) { }
|
|
static void module_enable_x(const struct module *mod) { }
|
|
#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
|
|
|
|
|
|
#ifdef CONFIG_LIVEPATCH
|
|
/*
|
|
* Persist Elf information about a module. Copy the Elf header,
|
|
* section header table, section string table, and symtab section
|
|
* index from info to mod->klp_info.
|
|
*/
|
|
static int copy_module_elf(struct module *mod, struct load_info *info)
|
|
{
|
|
unsigned int size, symndx;
|
|
int ret;
|
|
|
|
size = sizeof(*mod->klp_info);
|
|
mod->klp_info = kmalloc(size, GFP_KERNEL);
|
|
if (mod->klp_info == NULL)
|
|
return -ENOMEM;
|
|
|
|
/* Elf header */
|
|
size = sizeof(mod->klp_info->hdr);
|
|
memcpy(&mod->klp_info->hdr, info->hdr, size);
|
|
|
|
/* Elf section header table */
|
|
size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
|
|
mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
|
|
if (mod->klp_info->sechdrs == NULL) {
|
|
ret = -ENOMEM;
|
|
goto free_info;
|
|
}
|
|
|
|
/* Elf section name string table */
|
|
size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
|
|
mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
|
|
if (mod->klp_info->secstrings == NULL) {
|
|
ret = -ENOMEM;
|
|
goto free_sechdrs;
|
|
}
|
|
|
|
/* Elf symbol section index */
|
|
symndx = info->index.sym;
|
|
mod->klp_info->symndx = symndx;
|
|
|
|
/*
|
|
* For livepatch modules, core_kallsyms.symtab is a complete
|
|
* copy of the original symbol table. Adjust sh_addr to point
|
|
* to core_kallsyms.symtab since the copy of the symtab in module
|
|
* init memory is freed at the end of do_init_module().
|
|
*/
|
|
mod->klp_info->sechdrs[symndx].sh_addr = \
|
|
(unsigned long) mod->core_kallsyms.symtab;
|
|
|
|
return 0;
|
|
|
|
free_sechdrs:
|
|
kfree(mod->klp_info->sechdrs);
|
|
free_info:
|
|
kfree(mod->klp_info);
|
|
return ret;
|
|
}
|
|
|
|
static void free_module_elf(struct module *mod)
|
|
{
|
|
kfree(mod->klp_info->sechdrs);
|
|
kfree(mod->klp_info->secstrings);
|
|
kfree(mod->klp_info);
|
|
}
|
|
#else /* !CONFIG_LIVEPATCH */
|
|
static int copy_module_elf(struct module *mod, struct load_info *info)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void free_module_elf(struct module *mod)
|
|
{
|
|
}
|
|
#endif /* CONFIG_LIVEPATCH */
|
|
|
|
void __weak module_memfree(void *module_region)
|
|
{
|
|
/*
|
|
* This memory may be RO, and freeing RO memory in an interrupt is not
|
|
* supported by vmalloc.
|
|
*/
|
|
WARN_ON(in_interrupt());
|
|
vfree(module_region);
|
|
}
|
|
|
|
void __weak module_arch_cleanup(struct module *mod)
|
|
{
|
|
}
|
|
|
|
void __weak module_arch_freeing_init(struct module *mod)
|
|
{
|
|
}
|
|
|
|
static void cfi_cleanup(struct module *mod);
|
|
|
|
/* Free a module, remove from lists, etc. */
|
|
static void free_module(struct module *mod)
|
|
{
|
|
trace_module_free(mod);
|
|
|
|
mod_sysfs_teardown(mod);
|
|
|
|
/* We leave it in list to prevent duplicate loads, but make sure
|
|
* that noone uses it while it's being deconstructed. */
|
|
mutex_lock(&module_mutex);
|
|
mod->state = MODULE_STATE_UNFORMED;
|
|
mutex_unlock(&module_mutex);
|
|
|
|
/* Remove dynamic debug info */
|
|
ddebug_remove_module(mod->name);
|
|
|
|
/* Arch-specific cleanup. */
|
|
module_arch_cleanup(mod);
|
|
|
|
/* Module unload stuff */
|
|
module_unload_free(mod);
|
|
|
|
/* Free any allocated parameters. */
|
|
destroy_params(mod->kp, mod->num_kp);
|
|
|
|
if (is_livepatch_module(mod))
|
|
free_module_elf(mod);
|
|
|
|
/* Now we can delete it from the lists */
|
|
mutex_lock(&module_mutex);
|
|
/* Unlink carefully: kallsyms could be walking list. */
|
|
list_del_rcu(&mod->list);
|
|
mod_tree_remove(mod);
|
|
/* Remove this module from bug list, this uses list_del_rcu */
|
|
module_bug_cleanup(mod);
|
|
/* Wait for RCU-sched synchronizing before releasing mod->list and buglist. */
|
|
synchronize_rcu();
|
|
mutex_unlock(&module_mutex);
|
|
|
|
/* Clean up CFI for the module. */
|
|
cfi_cleanup(mod);
|
|
|
|
/* This may be empty, but that's OK */
|
|
module_arch_freeing_init(mod);
|
|
module_memfree(mod->init_layout.base);
|
|
kfree(mod->args);
|
|
percpu_modfree(mod);
|
|
|
|
/* Free lock-classes; relies on the preceding sync_rcu(). */
|
|
lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
|
|
|
|
#ifdef CONFIG_DEBUG_MODULE_LOAD_INFO
|
|
pr_info("Unloaded %s: module core layout, start: 0x%pK size: 0x%x\n",
|
|
mod->name, mod->core_layout.base, mod->core_layout.size);
|
|
#endif
|
|
/* Finally, free the core (containing the module structure) */
|
|
module_memfree(mod->core_layout.base);
|
|
}
|
|
|
|
void *__symbol_get(const char *symbol)
|
|
{
|
|
struct module *owner;
|
|
const struct kernel_symbol *sym;
|
|
|
|
preempt_disable();
|
|
sym = find_symbol(symbol, &owner, NULL, NULL, true, true);
|
|
if (sym && strong_try_module_get(owner))
|
|
sym = NULL;
|
|
preempt_enable();
|
|
|
|
return sym ? (void *)kernel_symbol_value(sym) : NULL;
|
|
}
|
|
|
|
/*
|
|
* Ensure that an exported symbol [global namespace] does not already exist
|
|
* in the kernel or in some other module's exported symbol table.
|
|
*
|
|
* You must hold the module_mutex.
|
|
*/
|
|
static int verify_exported_symbols(struct module *mod)
|
|
{
|
|
unsigned int i;
|
|
struct module *owner;
|
|
const struct kernel_symbol *s;
|
|
struct {
|
|
const struct kernel_symbol *sym;
|
|
unsigned int num;
|
|
} arr[] = {
|
|
{ mod->syms, mod->num_syms },
|
|
{ mod->gpl_syms, mod->num_gpl_syms },
|
|
{ mod->gpl_future_syms, mod->num_gpl_future_syms },
|
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
{ mod->unused_syms, mod->num_unused_syms },
|
|
{ mod->unused_gpl_syms, mod->num_unused_gpl_syms },
|
|
#endif
|
|
};
|
|
|
|
for (i = 0; i < ARRAY_SIZE(arr); i++) {
|
|
for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
|
|
if (find_symbol(kernel_symbol_name(s), &owner, NULL,
|
|
NULL, true, false)) {
|
|
pr_err("%s: exports duplicate symbol %s"
|
|
" (owned by %s)\n",
|
|
mod->name, kernel_symbol_name(s),
|
|
module_name(owner));
|
|
return -ENOEXEC;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool ignore_undef_symbol(Elf_Half emachine, const char *name)
|
|
{
|
|
/*
|
|
* On x86, PIC code and Clang non-PIC code may have call foo@PLT. GNU as
|
|
* before 2.37 produces an unreferenced _GLOBAL_OFFSET_TABLE_ on x86-64.
|
|
* i386 has a similar problem but may not deserve a fix.
|
|
*
|
|
* If we ever have to ignore many symbols, consider refactoring the code to
|
|
* only warn if referenced by a relocation.
|
|
*/
|
|
if (emachine == EM_386 || emachine == EM_X86_64)
|
|
return !strcmp(name, "_GLOBAL_OFFSET_TABLE_");
|
|
return false;
|
|
}
|
|
|
|
/* Change all symbols so that st_value encodes the pointer directly. */
|
|
static int simplify_symbols(struct module *mod, const struct load_info *info)
|
|
{
|
|
Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
|
|
Elf_Sym *sym = (void *)symsec->sh_addr;
|
|
unsigned long secbase;
|
|
unsigned int i;
|
|
int ret = 0;
|
|
const struct kernel_symbol *ksym;
|
|
|
|
for (i = 1; i < symsec->sh_size / sizeof(Elf_Sym); i++) {
|
|
const char *name = info->strtab + sym[i].st_name;
|
|
|
|
switch (sym[i].st_shndx) {
|
|
case SHN_COMMON:
|
|
/* Ignore common symbols */
|
|
if (!strncmp(name, "__gnu_lto", 9))
|
|
break;
|
|
|
|
/* We compiled with -fno-common. These are not
|
|
supposed to happen. */
|
|
pr_debug("Common symbol: %s\n", name);
|
|
pr_warn("%s: please compile with -fno-common\n",
|
|
mod->name);
|
|
ret = -ENOEXEC;
|
|
break;
|
|
|
|
case SHN_ABS:
|
|
/* Don't need to do anything */
|
|
pr_debug("Absolute symbol: 0x%08lx\n",
|
|
(long)sym[i].st_value);
|
|
break;
|
|
|
|
case SHN_LIVEPATCH:
|
|
/* Livepatch symbols are resolved by livepatch */
|
|
break;
|
|
|
|
case SHN_UNDEF:
|
|
ksym = resolve_symbol_wait(mod, info, name);
|
|
/* Ok if resolved. */
|
|
if (ksym && !IS_ERR(ksym)) {
|
|
sym[i].st_value = kernel_symbol_value(ksym);
|
|
break;
|
|
}
|
|
|
|
/* Ok if weak or ignored. */
|
|
if (!ksym &&
|
|
(ELF_ST_BIND(sym[i].st_info) == STB_WEAK ||
|
|
ignore_undef_symbol(info->hdr->e_machine, name)))
|
|
break;
|
|
|
|
ret = PTR_ERR(ksym) ?: -ENOENT;
|
|
pr_warn("%s: Unknown symbol %s (err %d)\n",
|
|
mod->name, name, ret);
|
|
break;
|
|
|
|
default:
|
|
/* Divert to percpu allocation if a percpu var. */
|
|
if (sym[i].st_shndx == info->index.pcpu)
|
|
secbase = (unsigned long)mod_percpu(mod);
|
|
else
|
|
secbase = info->sechdrs[sym[i].st_shndx].sh_addr;
|
|
sym[i].st_value += secbase;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int apply_relocations(struct module *mod, const struct load_info *info)
|
|
{
|
|
unsigned int i;
|
|
int err = 0;
|
|
|
|
/* Now do relocations. */
|
|
for (i = 1; i < info->hdr->e_shnum; i++) {
|
|
unsigned int infosec = info->sechdrs[i].sh_info;
|
|
|
|
/* Not a valid relocation section? */
|
|
if (infosec >= info->hdr->e_shnum)
|
|
continue;
|
|
|
|
/* Don't bother with non-allocated sections */
|
|
if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))
|
|
continue;
|
|
|
|
/* Livepatch relocation sections are applied by livepatch */
|
|
if (info->sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH)
|
|
continue;
|
|
|
|
if (info->sechdrs[i].sh_type == SHT_REL)
|
|
err = apply_relocate(info->sechdrs, info->strtab,
|
|
info->index.sym, i, mod);
|
|
else if (info->sechdrs[i].sh_type == SHT_RELA)
|
|
err = apply_relocate_add(info->sechdrs, info->strtab,
|
|
info->index.sym, i, mod);
|
|
if (err < 0)
|
|
break;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/* Additional bytes needed by arch in front of individual sections */
|
|
unsigned int __weak arch_mod_section_prepend(struct module *mod,
|
|
unsigned int section)
|
|
{
|
|
/* default implementation just returns zero */
|
|
return 0;
|
|
}
|
|
|
|
/* Update size with this section: return offset. */
|
|
static long get_offset(struct module *mod, unsigned int *size,
|
|
Elf_Shdr *sechdr, unsigned int section)
|
|
{
|
|
long ret;
|
|
|
|
*size += arch_mod_section_prepend(mod, section);
|
|
ret = ALIGN(*size, sechdr->sh_addralign ?: 1);
|
|
*size = ret + sechdr->sh_size;
|
|
return ret;
|
|
}
|
|
|
|
/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
|
|
might -- code, read-only data, read-write data, small data. Tally
|
|
sizes, and place the offsets into sh_entsize fields: high bit means it
|
|
belongs in init. */
|
|
static void layout_sections(struct module *mod, struct load_info *info)
|
|
{
|
|
static unsigned long const masks[][2] = {
|
|
/* NOTE: all executable code must be the first section
|
|
* in this array; otherwise modify the text_size
|
|
* finder in the two loops below */
|
|
{ SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL },
|
|
{ SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL },
|
|
{ SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL },
|
|
{ SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL },
|
|
{ ARCH_SHF_SMALL | SHF_ALLOC, 0 }
|
|
};
|
|
unsigned int m, i;
|
|
|
|
for (i = 0; i < info->hdr->e_shnum; i++)
|
|
info->sechdrs[i].sh_entsize = ~0UL;
|
|
|
|
pr_debug("Core section allocation order:\n");
|
|
for (m = 0; m < ARRAY_SIZE(masks); ++m) {
|
|
for (i = 0; i < info->hdr->e_shnum; ++i) {
|
|
Elf_Shdr *s = &info->sechdrs[i];
|
|
const char *sname = info->secstrings + s->sh_name;
|
|
|
|
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|
|
|| (s->sh_flags & masks[m][1])
|
|
|| s->sh_entsize != ~0UL
|
|
|| strstarts(sname, ".init"))
|
|
continue;
|
|
s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i);
|
|
pr_debug("\t%s\n", sname);
|
|
}
|
|
switch (m) {
|
|
case 0: /* executable */
|
|
mod->core_layout.size = debug_align(mod->core_layout.size);
|
|
mod->core_layout.text_size = mod->core_layout.size;
|
|
break;
|
|
case 1: /* RO: text and ro-data */
|
|
mod->core_layout.size = debug_align(mod->core_layout.size);
|
|
mod->core_layout.ro_size = mod->core_layout.size;
|
|
break;
|
|
case 2: /* RO after init */
|
|
mod->core_layout.size = debug_align(mod->core_layout.size);
|
|
mod->core_layout.ro_after_init_size = mod->core_layout.size;
|
|
break;
|
|
case 4: /* whole core */
|
|
mod->core_layout.size = debug_align(mod->core_layout.size);
|
|
break;
|
|
}
|
|
}
|
|
|
|
pr_debug("Init section allocation order:\n");
|
|
for (m = 0; m < ARRAY_SIZE(masks); ++m) {
|
|
for (i = 0; i < info->hdr->e_shnum; ++i) {
|
|
Elf_Shdr *s = &info->sechdrs[i];
|
|
const char *sname = info->secstrings + s->sh_name;
|
|
|
|
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|
|
|| (s->sh_flags & masks[m][1])
|
|
|| s->sh_entsize != ~0UL
|
|
|| !strstarts(sname, ".init"))
|
|
continue;
|
|
s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i)
|
|
| INIT_OFFSET_MASK);
|
|
pr_debug("\t%s\n", sname);
|
|
}
|
|
switch (m) {
|
|
case 0: /* executable */
|
|
mod->init_layout.size = debug_align(mod->init_layout.size);
|
|
mod->init_layout.text_size = mod->init_layout.size;
|
|
break;
|
|
case 1: /* RO: text and ro-data */
|
|
mod->init_layout.size = debug_align(mod->init_layout.size);
|
|
mod->init_layout.ro_size = mod->init_layout.size;
|
|
break;
|
|
case 2:
|
|
/*
|
|
* RO after init doesn't apply to init_layout (only
|
|
* core_layout), so it just takes the value of ro_size.
|
|
*/
|
|
mod->init_layout.ro_after_init_size = mod->init_layout.ro_size;
|
|
break;
|
|
case 4: /* whole init */
|
|
mod->init_layout.size = debug_align(mod->init_layout.size);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void set_license(struct module *mod, const char *license)
|
|
{
|
|
if (!license)
|
|
license = "unspecified";
|
|
|
|
if (!license_is_gpl_compatible(license)) {
|
|
if (!test_taint(TAINT_PROPRIETARY_MODULE))
|
|
pr_warn("%s: module license '%s' taints kernel.\n",
|
|
mod->name, license);
|
|
add_taint_module(mod, TAINT_PROPRIETARY_MODULE,
|
|
LOCKDEP_NOW_UNRELIABLE);
|
|
}
|
|
}
|
|
|
|
/* Parse tag=value strings from .modinfo section */
|
|
static char *next_string(char *string, unsigned long *secsize)
|
|
{
|
|
/* Skip non-zero chars */
|
|
while (string[0]) {
|
|
string++;
|
|
if ((*secsize)-- <= 1)
|
|
return NULL;
|
|
}
|
|
|
|
/* Skip any zero padding. */
|
|
while (!string[0]) {
|
|
string++;
|
|
if ((*secsize)-- <= 1)
|
|
return NULL;
|
|
}
|
|
return string;
|
|
}
|
|
|
|
static char *get_next_modinfo(const struct load_info *info, const char *tag,
|
|
char *prev)
|
|
{
|
|
char *p;
|
|
unsigned int taglen = strlen(tag);
|
|
Elf_Shdr *infosec = &info->sechdrs[info->index.info];
|
|
unsigned long size = infosec->sh_size;
|
|
|
|
/*
|
|
* get_modinfo() calls made before rewrite_section_headers()
|
|
* must use sh_offset, as sh_addr isn't set!
|
|
*/
|
|
char *modinfo = (char *)info->hdr + infosec->sh_offset;
|
|
|
|
if (prev) {
|
|
size -= prev - modinfo;
|
|
modinfo = next_string(prev, &size);
|
|
}
|
|
|
|
for (p = modinfo; p; p = next_string(p, &size)) {
|
|
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
|
|
return p + taglen + 1;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static char *get_modinfo(const struct load_info *info, const char *tag)
|
|
{
|
|
return get_next_modinfo(info, tag, NULL);
|
|
}
|
|
|
|
static void setup_modinfo(struct module *mod, struct load_info *info)
|
|
{
|
|
struct module_attribute *attr;
|
|
int i;
|
|
|
|
for (i = 0; (attr = modinfo_attrs[i]); i++) {
|
|
if (attr->setup)
|
|
attr->setup(mod, get_modinfo(info, attr->attr.name));
|
|
}
|
|
}
|
|
|
|
static void free_modinfo(struct module *mod)
|
|
{
|
|
struct module_attribute *attr;
|
|
int i;
|
|
|
|
for (i = 0; (attr = modinfo_attrs[i]); i++) {
|
|
if (attr->free)
|
|
attr->free(mod);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_KALLSYMS
|
|
|
|
/* Lookup exported symbol in given range of kernel_symbols */
|
|
static const struct kernel_symbol *lookup_exported_symbol(const char *name,
|
|
const struct kernel_symbol *start,
|
|
const struct kernel_symbol *stop)
|
|
{
|
|
return bsearch(name, start, stop - start,
|
|
sizeof(struct kernel_symbol), cmp_name);
|
|
}
|
|
|
|
static int is_exported(const char *name, unsigned long value,
|
|
const struct module *mod)
|
|
{
|
|
const struct kernel_symbol *ks;
|
|
if (!mod)
|
|
ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
|
|
else
|
|
ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
|
|
|
|
return ks != NULL && kernel_symbol_value(ks) == value;
|
|
}
|
|
|
|
/* As per nm */
|
|
static char elf_type(const Elf_Sym *sym, const struct load_info *info)
|
|
{
|
|
const Elf_Shdr *sechdrs = info->sechdrs;
|
|
|
|
if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
|
|
if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
|
|
return 'v';
|
|
else
|
|
return 'w';
|
|
}
|
|
if (sym->st_shndx == SHN_UNDEF)
|
|
return 'U';
|
|
if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu)
|
|
return 'a';
|
|
if (sym->st_shndx >= SHN_LORESERVE)
|
|
return '?';
|
|
if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
|
|
return 't';
|
|
if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC
|
|
&& sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
|
|
if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
|
|
return 'r';
|
|
else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
|
|
return 'g';
|
|
else
|
|
return 'd';
|
|
}
|
|
if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
|
|
if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
|
|
return 's';
|
|
else
|
|
return 'b';
|
|
}
|
|
if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
|
|
".debug")) {
|
|
return 'n';
|
|
}
|
|
return '?';
|
|
}
|
|
|
|
static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
|
|
unsigned int shnum, unsigned int pcpundx)
|
|
{
|
|
const Elf_Shdr *sec;
|
|
|
|
if (src->st_shndx == SHN_UNDEF
|
|
|| src->st_shndx >= shnum
|
|
|| !src->st_name)
|
|
return false;
|
|
|
|
#ifdef CONFIG_KALLSYMS_ALL
|
|
if (src->st_shndx == pcpundx)
|
|
return true;
|
|
#endif
|
|
|
|
sec = sechdrs + src->st_shndx;
|
|
if (!(sec->sh_flags & SHF_ALLOC)
|
|
#ifndef CONFIG_KALLSYMS_ALL
|
|
|| !(sec->sh_flags & SHF_EXECINSTR)
|
|
#endif
|
|
|| (sec->sh_entsize & INIT_OFFSET_MASK))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* We only allocate and copy the strings needed by the parts of symtab
|
|
* we keep. This is simple, but has the effect of making multiple
|
|
* copies of duplicates. We could be more sophisticated, see
|
|
* linux-kernel thread starting with
|
|
* <73defb5e4bca04a6431392cc341112b1@localhost>.
|
|
*/
|
|
static void layout_symtab(struct module *mod, struct load_info *info)
|
|
{
|
|
Elf_Shdr *symsect = info->sechdrs + info->index.sym;
|
|
Elf_Shdr *strsect = info->sechdrs + info->index.str;
|
|
const Elf_Sym *src;
|
|
unsigned int i, nsrc, ndst, strtab_size = 0;
|
|
|
|
/* Put symbol section at end of init part of module. */
|
|
symsect->sh_flags |= SHF_ALLOC;
|
|
symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect,
|
|
info->index.sym) | INIT_OFFSET_MASK;
|
|
pr_debug("\t%s\n", info->secstrings + symsect->sh_name);
|
|
|
|
src = (void *)info->hdr + symsect->sh_offset;
|
|
nsrc = symsect->sh_size / sizeof(*src);
|
|
|
|
/* Compute total space required for the core symbols' strtab. */
|
|
for (ndst = i = 0; i < nsrc; i++) {
|
|
if (i == 0 || is_livepatch_module(mod) ||
|
|
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
|
|
info->index.pcpu)) {
|
|
strtab_size += strlen(&info->strtab[src[i].st_name])+1;
|
|
ndst++;
|
|
}
|
|
}
|
|
|
|
/* Append room for core symbols at end of core part. */
|
|
info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1);
|
|
info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
|
|
mod->core_layout.size += strtab_size;
|
|
info->core_typeoffs = mod->core_layout.size;
|
|
mod->core_layout.size += ndst * sizeof(char);
|
|
mod->core_layout.size = debug_align(mod->core_layout.size);
|
|
|
|
/* Put string table section at end of init part of module. */
|
|
strsect->sh_flags |= SHF_ALLOC;
|
|
strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
|
|
info->index.str) | INIT_OFFSET_MASK;
|
|
pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
|
|
|
|
/* We'll tack temporary mod_kallsyms on the end. */
|
|
mod->init_layout.size = ALIGN(mod->init_layout.size,
|
|
__alignof__(struct mod_kallsyms));
|
|
info->mod_kallsyms_init_off = mod->init_layout.size;
|
|
mod->init_layout.size += sizeof(struct mod_kallsyms);
|
|
info->init_typeoffs = mod->init_layout.size;
|
|
mod->init_layout.size += nsrc * sizeof(char);
|
|
mod->init_layout.size = debug_align(mod->init_layout.size);
|
|
}
|
|
|
|
/*
|
|
* We use the full symtab and strtab which layout_symtab arranged to
|
|
* be appended to the init section. Later we switch to the cut-down
|
|
* core-only ones.
|
|
*/
|
|
static void add_kallsyms(struct module *mod, const struct load_info *info)
|
|
{
|
|
unsigned int i, ndst;
|
|
const Elf_Sym *src;
|
|
Elf_Sym *dst;
|
|
char *s;
|
|
Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
|
|
|
|
/* Set up to point into init section. */
|
|
mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off;
|
|
|
|
mod->kallsyms->symtab = (void *)symsec->sh_addr;
|
|
mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
|
|
/* Make sure we get permanent strtab: don't use info->strtab. */
|
|
mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
|
|
mod->kallsyms->typetab = mod->init_layout.base + info->init_typeoffs;
|
|
|
|
/*
|
|
* Now populate the cut down core kallsyms for after init
|
|
* and set types up while we still have access to sections.
|
|
*/
|
|
mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
|
|
mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
|
|
mod->core_kallsyms.typetab = mod->core_layout.base + info->core_typeoffs;
|
|
src = mod->kallsyms->symtab;
|
|
for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
|
|
mod->kallsyms->typetab[i] = elf_type(src + i, info);
|
|
if (i == 0 || is_livepatch_module(mod) ||
|
|
is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
|
|
info->index.pcpu)) {
|
|
mod->core_kallsyms.typetab[ndst] =
|
|
mod->kallsyms->typetab[i];
|
|
dst[ndst] = src[i];
|
|
dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
|
|
s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
|
|
KSYM_NAME_LEN) + 1;
|
|
}
|
|
}
|
|
mod->core_kallsyms.num_symtab = ndst;
|
|
}
|
|
#else
|
|
static inline void layout_symtab(struct module *mod, struct load_info *info)
|
|
{
|
|
}
|
|
|
|
static void add_kallsyms(struct module *mod, const struct load_info *info)
|
|
{
|
|
}
|
|
#endif /* CONFIG_KALLSYMS */
|
|
|
|
static void dynamic_debug_setup(struct module *mod, struct _ddebug *debug, unsigned int num)
|
|
{
|
|
if (!debug)
|
|
return;
|
|
ddebug_add_module(debug, num, mod->name);
|
|
}
|
|
|
|
static void dynamic_debug_remove(struct module *mod, struct _ddebug *debug)
|
|
{
|
|
if (debug)
|
|
ddebug_remove_module(mod->name);
|
|
}
|
|
|
|
void * __weak module_alloc(unsigned long size)
|
|
{
|
|
return vmalloc_exec(size);
|
|
}
|
|
|
|
bool __weak module_exit_section(const char *name)
|
|
{
|
|
return strstarts(name, ".exit");
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_KMEMLEAK
|
|
static void kmemleak_load_module(const struct module *mod,
|
|
const struct load_info *info)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* only scan the sections containing data */
|
|
kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
|
|
|
|
for (i = 1; i < info->hdr->e_shnum; i++) {
|
|
/* Scan all writable sections that's not executable */
|
|
if (!(info->sechdrs[i].sh_flags & SHF_ALLOC) ||
|
|
!(info->sechdrs[i].sh_flags & SHF_WRITE) ||
|
|
(info->sechdrs[i].sh_flags & SHF_EXECINSTR))
|
|
continue;
|
|
|
|
kmemleak_scan_area((void *)info->sechdrs[i].sh_addr,
|
|
info->sechdrs[i].sh_size, GFP_KERNEL);
|
|
}
|
|
}
|
|
#else
|
|
static inline void kmemleak_load_module(const struct module *mod,
|
|
const struct load_info *info)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_MODULE_SIG
|
|
static int module_sig_check(struct load_info *info, int flags)
|
|
{
|
|
int err = -ENODATA;
|
|
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
|
|
const char *reason;
|
|
const void *mod = info->hdr;
|
|
|
|
/*
|
|
* Require flags == 0, as a module with version information
|
|
* removed is no longer the module that was signed
|
|
*/
|
|
if (flags == 0 &&
|
|
info->len > markerlen &&
|
|
memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
|
|
/* We truncate the module to discard the signature */
|
|
info->len -= markerlen;
|
|
err = mod_verify_sig(mod, info);
|
|
}
|
|
|
|
switch (err) {
|
|
case 0:
|
|
info->sig_ok = true;
|
|
return 0;
|
|
|
|
/* We don't permit modules to be loaded into trusted kernels
|
|
* without a valid signature on them, but if we're not
|
|
* enforcing, certain errors are non-fatal.
|
|
*/
|
|
case -ENODATA:
|
|
reason = "unsigned module";
|
|
break;
|
|
case -ENOPKG:
|
|
reason = "module with unsupported crypto";
|
|
break;
|
|
case -ENOKEY:
|
|
reason = "module with unavailable key";
|
|
break;
|
|
|
|
/* All other errors are fatal, including nomem, unparseable
|
|
* signatures and signature check failures - even if signatures
|
|
* aren't required.
|
|
*/
|
|
default:
|
|
return err;
|
|
}
|
|
|
|
if (is_module_sig_enforced()) {
|
|
pr_notice("Loading of %s is rejected\n", reason);
|
|
return -EKEYREJECTED;
|
|
}
|
|
|
|
return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
|
|
}
|
|
#else /* !CONFIG_MODULE_SIG */
|
|
static int module_sig_check(struct load_info *info, int flags)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* !CONFIG_MODULE_SIG */
|
|
|
|
static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
|
|
{
|
|
unsigned long secend;
|
|
|
|
/*
|
|
* Check for both overflow and offset/size being
|
|
* too large.
|
|
*/
|
|
secend = shdr->sh_offset + shdr->sh_size;
|
|
if (secend < shdr->sh_offset || secend > info->len)
|
|
return -ENOEXEC;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Sanity checks against invalid binaries, wrong arch, weird elf version.
|
|
*
|
|
* Also do basic validity checks against section offsets and sizes, the
|
|
* section name string table, and the indices used for it (sh_name).
|
|
*/
|
|
static int elf_validity_check(struct load_info *info)
|
|
{
|
|
unsigned int i;
|
|
Elf_Shdr *shdr, *strhdr;
|
|
int err;
|
|
|
|
if (info->len < sizeof(*(info->hdr)))
|
|
return -ENOEXEC;
|
|
|
|
if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
|
|
|| info->hdr->e_type != ET_REL
|
|
|| !elf_check_arch(info->hdr)
|
|
|| info->hdr->e_shentsize != sizeof(Elf_Shdr))
|
|
return -ENOEXEC;
|
|
|
|
/*
|
|
* e_shnum is 16 bits, and sizeof(Elf_Shdr) is
|
|
* known and small. So e_shnum * sizeof(Elf_Shdr)
|
|
* will not overflow unsigned long on any platform.
|
|
*/
|
|
if (info->hdr->e_shoff >= info->len
|
|
|| (info->hdr->e_shnum * sizeof(Elf_Shdr) >
|
|
info->len - info->hdr->e_shoff))
|
|
return -ENOEXEC;
|
|
|
|
info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
|
|
|
|
/*
|
|
* Verify if the section name table index is valid.
|
|
*/
|
|
if (info->hdr->e_shstrndx == SHN_UNDEF
|
|
|| info->hdr->e_shstrndx >= info->hdr->e_shnum)
|
|
return -ENOEXEC;
|
|
|
|
strhdr = &info->sechdrs[info->hdr->e_shstrndx];
|
|
err = validate_section_offset(info, strhdr);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
/*
|
|
* The section name table must be NUL-terminated, as required
|
|
* by the spec. This makes strcmp and pr_* calls that access
|
|
* strings in the section safe.
|
|
*/
|
|
info->secstrings = (void *)info->hdr + strhdr->sh_offset;
|
|
if (info->secstrings[strhdr->sh_size - 1] != '\0')
|
|
return -ENOEXEC;
|
|
|
|
/*
|
|
* The code assumes that section 0 has a length of zero and
|
|
* an addr of zero, so check for it.
|
|
*/
|
|
if (info->sechdrs[0].sh_type != SHT_NULL
|
|
|| info->sechdrs[0].sh_size != 0
|
|
|| info->sechdrs[0].sh_addr != 0)
|
|
return -ENOEXEC;
|
|
|
|
for (i = 1; i < info->hdr->e_shnum; i++) {
|
|
shdr = &info->sechdrs[i];
|
|
switch (shdr->sh_type) {
|
|
case SHT_NULL:
|
|
case SHT_NOBITS:
|
|
continue;
|
|
case SHT_SYMTAB:
|
|
if (shdr->sh_link == SHN_UNDEF
|
|
|| shdr->sh_link >= info->hdr->e_shnum)
|
|
return -ENOEXEC;
|
|
fallthrough;
|
|
default:
|
|
err = validate_section_offset(info, shdr);
|
|
if (err < 0) {
|
|
pr_err("Invalid ELF section in module (section %u type %u)\n",
|
|
i, shdr->sh_type);
|
|
return err;
|
|
}
|
|
|
|
if (shdr->sh_flags & SHF_ALLOC) {
|
|
if (shdr->sh_name >= strhdr->sh_size) {
|
|
pr_err("Invalid ELF section name in module (section %u type %u)\n",
|
|
i, shdr->sh_type);
|
|
return -ENOEXEC;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define COPY_CHUNK_SIZE (16*PAGE_SIZE)
|
|
|
|
static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned long len)
|
|
{
|
|
do {
|
|
unsigned long n = min(len, COPY_CHUNK_SIZE);
|
|
|
|
if (copy_from_user(dst, usrc, n) != 0)
|
|
return -EFAULT;
|
|
cond_resched();
|
|
dst += n;
|
|
usrc += n;
|
|
len -= n;
|
|
} while (len);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_LIVEPATCH
|
|
static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
|
|
{
|
|
if (get_modinfo(info, "livepatch")) {
|
|
mod->klp = true;
|
|
add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
|
|
pr_notice_once("%s: tainting kernel with TAINT_LIVEPATCH\n",
|
|
mod->name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#else /* !CONFIG_LIVEPATCH */
|
|
static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
|
|
{
|
|
if (get_modinfo(info, "livepatch")) {
|
|
pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
|
|
mod->name);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_LIVEPATCH */
|
|
|
|
static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
|
|
{
|
|
if (retpoline_module_ok(get_modinfo(info, "retpoline")))
|
|
return;
|
|
|
|
pr_warn("%s: loading module not compiled with retpoline compiler.\n",
|
|
mod->name);
|
|
}
|
|
|
|
/* Sets info->hdr and info->len. */
|
|
static int copy_module_from_user(const void __user *umod, unsigned long len,
|
|
struct load_info *info)
|
|
{
|
|
int err;
|
|
|
|
info->len = len;
|
|
if (info->len < sizeof(*(info->hdr)))
|
|
return -ENOEXEC;
|
|
|
|
err = security_kernel_load_data(LOADING_MODULE);
|
|
if (err)
|
|
return err;
|
|
|
|
/* Suck in entire file: we'll want most of it. */
|
|
info->hdr = __vmalloc(info->len,
|
|
GFP_KERNEL | __GFP_NOWARN, PAGE_KERNEL);
|
|
if (!info->hdr)
|
|
return -ENOMEM;
|
|
|
|
if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) {
|
|
vfree(info->hdr);
|
|
return -EFAULT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void free_copy(struct load_info *info)
|
|
{
|
|
vfree(info->hdr);
|
|
}
|
|
|
|
static int rewrite_section_headers(struct load_info *info, int flags)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* This should always be true, but let's be sure. */
|
|
info->sechdrs[0].sh_addr = 0;
|
|
|
|
for (i = 1; i < info->hdr->e_shnum; i++) {
|
|
Elf_Shdr *shdr = &info->sechdrs[i];
|
|
|
|
/* Mark all sections sh_addr with their address in the
|
|
temporary image. */
|
|
shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset;
|
|
|
|
#ifndef CONFIG_MODULE_UNLOAD
|
|
/* Don't load .exit sections */
|
|
if (module_exit_section(info->secstrings+shdr->sh_name))
|
|
shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
#endif
|
|
}
|
|
|
|
/* Track but don't keep modinfo and version sections. */
|
|
info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Set up our basic convenience variables (pointers to section headers,
|
|
* search for module section index etc), and do some basic section
|
|
* verification.
|
|
*
|
|
* Set info->mod to the temporary copy of the module in info->hdr. The final one
|
|
* will be allocated in move_module().
|
|
*/
|
|
static int setup_load_info(struct load_info *info, int flags)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* Try to find a name early so we can log errors with a module name */
|
|
info->index.info = find_sec(info, ".modinfo");
|
|
if (info->index.info)
|
|
info->name = get_modinfo(info, "name");
|
|
|
|
/* Find internal symbols and strings. */
|
|
for (i = 1; i < info->hdr->e_shnum; i++) {
|
|
if (info->sechdrs[i].sh_type == SHT_SYMTAB) {
|
|
info->index.sym = i;
|
|
info->index.str = info->sechdrs[i].sh_link;
|
|
info->strtab = (char *)info->hdr
|
|
+ info->sechdrs[info->index.str].sh_offset;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (info->index.sym == 0) {
|
|
pr_warn("%s: module has no symbols (stripped?)\n",
|
|
info->name ?: "(missing .modinfo section or name field)");
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
|
|
if (!info->index.mod) {
|
|
pr_warn("%s: No module found in object\n",
|
|
info->name ?: "(missing .modinfo section or name field)");
|
|
return -ENOEXEC;
|
|
}
|
|
/* This is temporary: point mod into copy of data. */
|
|
info->mod = (void *)info->hdr + info->sechdrs[info->index.mod].sh_offset;
|
|
|
|
/*
|
|
* If we didn't load the .modinfo 'name' field earlier, fall back to
|
|
* on-disk struct mod 'name' field.
|
|
*/
|
|
if (!info->name)
|
|
info->name = info->mod->name;
|
|
|
|
if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
|
|
info->index.vers = 0; /* Pretend no __versions section! */
|
|
else
|
|
info->index.vers = find_sec(info, "__versions");
|
|
|
|
info->index.pcpu = find_pcpusec(info);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_modinfo(struct module *mod, struct load_info *info, int flags)
|
|
{
|
|
const char *modmagic = get_modinfo(info, "vermagic");
|
|
int err;
|
|
|
|
if (flags & MODULE_INIT_IGNORE_VERMAGIC)
|
|
modmagic = NULL;
|
|
|
|
/* This is allowed: modprobe --force will invalidate it. */
|
|
if (!modmagic) {
|
|
err = try_to_force_load(mod, "bad vermagic");
|
|
if (err)
|
|
return err;
|
|
} else if (!same_magic(modmagic, vermagic, info->index.vers)) {
|
|
pr_err("%s: version magic '%s' should be '%s'\n",
|
|
info->name, modmagic, vermagic);
|
|
return -ENOEXEC;
|
|
}
|
|
|
|
if (!get_modinfo(info, "intree")) {
|
|
if (!test_taint(TAINT_OOT_MODULE))
|
|
pr_warn("%s: loading out-of-tree module taints kernel.\n",
|
|
mod->name);
|
|
add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
|
|
}
|
|
|
|
check_modinfo_retpoline(mod, info);
|
|
|
|
if (get_modinfo(info, "staging")) {
|
|
add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
|
|
pr_warn("%s: module is from the staging directory, the quality "
|
|
"is unknown, you have been warned.\n", mod->name);
|
|
}
|
|
|
|
err = check_modinfo_livepatch(mod, info);
|
|
if (err)
|
|
return err;
|
|
|
|
/* Set up license info based on the info section */
|
|
set_license(mod, get_modinfo(info, "license"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int find_module_sections(struct module *mod, struct load_info *info)
|
|
{
|
|
mod->kp = section_objs(info, "__param",
|
|
sizeof(*mod->kp), &mod->num_kp);
|
|
mod->syms = section_objs(info, "__ksymtab",
|
|
sizeof(*mod->syms), &mod->num_syms);
|
|
mod->crcs = section_addr(info, "__kcrctab");
|
|
mod->gpl_syms = section_objs(info, "__ksymtab_gpl",
|
|
sizeof(*mod->gpl_syms),
|
|
&mod->num_gpl_syms);
|
|
mod->gpl_crcs = section_addr(info, "__kcrctab_gpl");
|
|
mod->gpl_future_syms = section_objs(info,
|
|
"__ksymtab_gpl_future",
|
|
sizeof(*mod->gpl_future_syms),
|
|
&mod->num_gpl_future_syms);
|
|
mod->gpl_future_crcs = section_addr(info, "__kcrctab_gpl_future");
|
|
|
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
mod->unused_syms = section_objs(info, "__ksymtab_unused",
|
|
sizeof(*mod->unused_syms),
|
|
&mod->num_unused_syms);
|
|
mod->unused_crcs = section_addr(info, "__kcrctab_unused");
|
|
mod->unused_gpl_syms = section_objs(info, "__ksymtab_unused_gpl",
|
|
sizeof(*mod->unused_gpl_syms),
|
|
&mod->num_unused_gpl_syms);
|
|
mod->unused_gpl_crcs = section_addr(info, "__kcrctab_unused_gpl");
|
|
#endif
|
|
#ifdef CONFIG_CONSTRUCTORS
|
|
mod->ctors = section_objs(info, ".ctors",
|
|
sizeof(*mod->ctors), &mod->num_ctors);
|
|
if (!mod->ctors)
|
|
mod->ctors = section_objs(info, ".init_array",
|
|
sizeof(*mod->ctors), &mod->num_ctors);
|
|
else if (find_sec(info, ".init_array")) {
|
|
/*
|
|
* This shouldn't happen with same compiler and binutils
|
|
* building all parts of the module.
|
|
*/
|
|
pr_warn("%s: has both .ctors and .init_array.\n",
|
|
mod->name);
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_TRACEPOINTS
|
|
mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs",
|
|
sizeof(*mod->tracepoints_ptrs),
|
|
&mod->num_tracepoints);
|
|
#endif
|
|
#ifdef CONFIG_TREE_SRCU
|
|
mod->srcu_struct_ptrs = section_objs(info, "___srcu_struct_ptrs",
|
|
sizeof(*mod->srcu_struct_ptrs),
|
|
&mod->num_srcu_structs);
|
|
#endif
|
|
#ifdef CONFIG_BPF_EVENTS
|
|
mod->bpf_raw_events = section_objs(info, "__bpf_raw_tp_map",
|
|
sizeof(*mod->bpf_raw_events),
|
|
&mod->num_bpf_raw_events);
|
|
#endif
|
|
#ifdef CONFIG_JUMP_LABEL
|
|
mod->jump_entries = section_objs(info, "__jump_table",
|
|
sizeof(*mod->jump_entries),
|
|
&mod->num_jump_entries);
|
|
#endif
|
|
#ifdef CONFIG_EVENT_TRACING
|
|
mod->trace_events = section_objs(info, "_ftrace_events",
|
|
sizeof(*mod->trace_events),
|
|
&mod->num_trace_events);
|
|
mod->trace_evals = section_objs(info, "_ftrace_eval_map",
|
|
sizeof(*mod->trace_evals),
|
|
&mod->num_trace_evals);
|
|
#endif
|
|
#ifdef CONFIG_TRACING
|
|
mod->trace_bprintk_fmt_start = section_objs(info, "__trace_printk_fmt",
|
|
sizeof(*mod->trace_bprintk_fmt_start),
|
|
&mod->num_trace_bprintk_fmt);
|
|
#endif
|
|
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
|
/* sechdrs[0].sh_size is always zero */
|
|
mod->ftrace_callsites = section_objs(info, FTRACE_CALLSITE_SECTION,
|
|
sizeof(*mod->ftrace_callsites),
|
|
&mod->num_ftrace_callsites);
|
|
#endif
|
|
#ifdef CONFIG_FUNCTION_ERROR_INJECTION
|
|
mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
|
|
sizeof(*mod->ei_funcs),
|
|
&mod->num_ei_funcs);
|
|
#endif
|
|
mod->extable = section_objs(info, "__ex_table",
|
|
sizeof(*mod->extable), &mod->num_exentries);
|
|
|
|
if (section_addr(info, "__obsparm"))
|
|
pr_warn("%s: Ignoring obsolete parameters\n", mod->name);
|
|
|
|
info->debug = section_objs(info, "__verbose",
|
|
sizeof(*info->debug), &info->num_debug);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int move_module(struct module *mod, struct load_info *info)
|
|
{
|
|
int i;
|
|
void *ptr;
|
|
|
|
/* Do the allocs. */
|
|
ptr = module_alloc(mod->core_layout.size);
|
|
/*
|
|
* The pointer to this block is stored in the module structure
|
|
* which is inside the block. Just mark it as not being a
|
|
* leak.
|
|
*/
|
|
kmemleak_not_leak(ptr);
|
|
if (!ptr)
|
|
return -ENOMEM;
|
|
|
|
memset(ptr, 0, mod->core_layout.size);
|
|
mod->core_layout.base = ptr;
|
|
|
|
if (mod->init_layout.size) {
|
|
ptr = module_alloc(mod->init_layout.size);
|
|
/*
|
|
* The pointer to this block is stored in the module structure
|
|
* which is inside the block. This block doesn't need to be
|
|
* scanned as it contains data and code that will be freed
|
|
* after the module is initialized.
|
|
*/
|
|
kmemleak_ignore(ptr);
|
|
if (!ptr) {
|
|
module_memfree(mod->core_layout.base);
|
|
return -ENOMEM;
|
|
}
|
|
memset(ptr, 0, mod->init_layout.size);
|
|
mod->init_layout.base = ptr;
|
|
} else
|
|
mod->init_layout.base = NULL;
|
|
|
|
/* Transfer each section which specifies SHF_ALLOC */
|
|
pr_debug("final section addresses:\n");
|
|
for (i = 0; i < info->hdr->e_shnum; i++) {
|
|
void *dest;
|
|
Elf_Shdr *shdr = &info->sechdrs[i];
|
|
|
|
if (!(shdr->sh_flags & SHF_ALLOC))
|
|
continue;
|
|
|
|
if (shdr->sh_entsize & INIT_OFFSET_MASK)
|
|
dest = mod->init_layout.base
|
|
+ (shdr->sh_entsize & ~INIT_OFFSET_MASK);
|
|
else
|
|
dest = mod->core_layout.base + shdr->sh_entsize;
|
|
|
|
if (shdr->sh_type != SHT_NOBITS)
|
|
memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
|
|
/* Update sh_addr to point to copy in image. */
|
|
shdr->sh_addr = (unsigned long)dest;
|
|
pr_debug("\t0x%lx %s\n",
|
|
(long)shdr->sh_addr, info->secstrings + shdr->sh_name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_module_license_and_versions(struct module *mod)
|
|
{
|
|
int prev_taint = test_taint(TAINT_PROPRIETARY_MODULE);
|
|
|
|
/*
|
|
* ndiswrapper is under GPL by itself, but loads proprietary modules.
|
|
* Don't use add_taint_module(), as it would prevent ndiswrapper from
|
|
* using GPL-only symbols it needs.
|
|
*/
|
|
if (strcmp(mod->name, "ndiswrapper") == 0)
|
|
add_taint(TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE);
|
|
|
|
/* driverloader was caught wrongly pretending to be under GPL */
|
|
if (strcmp(mod->name, "driverloader") == 0)
|
|
add_taint_module(mod, TAINT_PROPRIETARY_MODULE,
|
|
LOCKDEP_NOW_UNRELIABLE);
|
|
|
|
/* lve claims to be GPL but upstream won't provide source */
|
|
if (strcmp(mod->name, "lve") == 0)
|
|
add_taint_module(mod, TAINT_PROPRIETARY_MODULE,
|
|
LOCKDEP_NOW_UNRELIABLE);
|
|
|
|
if (!prev_taint && test_taint(TAINT_PROPRIETARY_MODULE))
|
|
pr_warn("%s: module license taints kernel.\n", mod->name);
|
|
|
|
#ifdef CONFIG_MODVERSIONS
|
|
if ((mod->num_syms && !mod->crcs)
|
|
|| (mod->num_gpl_syms && !mod->gpl_crcs)
|
|
|| (mod->num_gpl_future_syms && !mod->gpl_future_crcs)
|
|
#ifdef CONFIG_UNUSED_SYMBOLS
|
|
|| (mod->num_unused_syms && !mod->unused_crcs)
|
|
|| (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
|
|
#endif
|
|
) {
|
|
return try_to_force_load(mod,
|
|
"no versions for exported symbols");
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void flush_module_icache(const struct module *mod)
|
|
{
|
|
mm_segment_t old_fs;
|
|
|
|
/* flush the icache in correct context */
|
|
old_fs = get_fs();
|
|
set_fs(KERNEL_DS);
|
|
|
|
/*
|
|
* Flush the instruction cache, since we've played with text.
|
|
* Do it before processing of module parameters, so the module
|
|
* can provide parameter accessor functions of its own.
|
|
*/
|
|
if (mod->init_layout.base)
|
|
flush_icache_range((unsigned long)mod->init_layout.base,
|
|
(unsigned long)mod->init_layout.base
|
|
+ mod->init_layout.size);
|
|
flush_icache_range((unsigned long)mod->core_layout.base,
|
|
(unsigned long)mod->core_layout.base + mod->core_layout.size);
|
|
|
|
set_fs(old_fs);
|
|
}
|
|
|
|
int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
|
|
Elf_Shdr *sechdrs,
|
|
char *secstrings,
|
|
struct module *mod)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* module_blacklist is a comma-separated list of module names */
|
|
static char *module_blacklist;
|
|
static bool blacklisted(const char *module_name)
|
|
{
|
|
const char *p;
|
|
size_t len;
|
|
|
|
if (!module_blacklist)
|
|
return false;
|
|
|
|
for (p = module_blacklist; *p; p += len) {
|
|
len = strcspn(p, ",");
|
|
if (strlen(module_name) == len && !memcmp(module_name, p, len))
|
|
return true;
|
|
if (p[len] == ',')
|
|
len++;
|
|
}
|
|
return false;
|
|
}
|
|
core_param(module_blacklist, module_blacklist, charp, 0400);
|
|
|
|
static struct module *layout_and_allocate(struct load_info *info, int flags)
|
|
{
|
|
struct module *mod;
|
|
unsigned int ndx;
|
|
int err;
|
|
|
|
err = check_modinfo(info->mod, info, flags);
|
|
if (err)
|
|
return ERR_PTR(err);
|
|
|
|
/* Allow arches to frob section contents and sizes. */
|
|
err = module_frob_arch_sections(info->hdr, info->sechdrs,
|
|
info->secstrings, info->mod);
|
|
if (err < 0)
|
|
return ERR_PTR(err);
|
|
|
|
/* We will do a special allocation for per-cpu sections later. */
|
|
info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
|
|
|
|
/*
|
|
* Mark ro_after_init section with SHF_RO_AFTER_INIT so that
|
|
* layout_sections() can put it in the right place.
|
|
* Note: ro_after_init sections also have SHF_{WRITE,ALLOC} set.
|
|
*/
|
|
ndx = find_sec(info, ".data..ro_after_init");
|
|
if (ndx)
|
|
info->sechdrs[ndx].sh_flags |= SHF_RO_AFTER_INIT;
|
|
/*
|
|
* Mark the __jump_table section as ro_after_init as well: these data
|
|
* structures are never modified, with the exception of entries that
|
|
* refer to code in the __init section, which are annotated as such
|
|
* at module load time.
|
|
*/
|
|
ndx = find_sec(info, "__jump_table");
|
|
if (ndx)
|
|
info->sechdrs[ndx].sh_flags |= SHF_RO_AFTER_INIT;
|
|
|
|
/* Determine total sizes, and put offsets in sh_entsize. For now
|
|
this is done generically; there doesn't appear to be any
|
|
special cases for the architectures. */
|
|
layout_sections(info->mod, info);
|
|
layout_symtab(info->mod, info);
|
|
|
|
/* Allocate and move to the final place */
|
|
err = move_module(info->mod, info);
|
|
if (err)
|
|
return ERR_PTR(err);
|
|
|
|
/* Module has been copied to its final place now: return it. */
|
|
mod = (void *)info->sechdrs[info->index.mod].sh_addr;
|
|
kmemleak_load_module(mod, info);
|
|
return mod;
|
|
}
|
|
|
|
/* mod is no longer valid after this! */
|
|
static void module_deallocate(struct module *mod, struct load_info *info)
|
|
{
|
|
percpu_modfree(mod);
|
|
module_arch_freeing_init(mod);
|
|
module_memfree(mod->init_layout.base);
|
|
module_memfree(mod->core_layout.base);
|
|
}
|
|
|
|
int __weak module_finalize(const Elf_Ehdr *hdr,
|
|
const Elf_Shdr *sechdrs,
|
|
struct module *me)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void cfi_init(struct module *mod);
|
|
|
|
static int post_relocation(struct module *mod, const struct load_info *info)
|
|
{
|
|
/* Sort exception table now relocations are done. */
|
|
sort_extable(mod->extable, mod->extable + mod->num_exentries);
|
|
|
|
/* Copy relocated percpu area over. */
|
|
percpu_modcopy(mod, (void *)info->sechdrs[info->index.pcpu].sh_addr,
|
|
info->sechdrs[info->index.pcpu].sh_size);
|
|
|
|
/* Setup kallsyms-specific fields. */
|
|
add_kallsyms(mod, info);
|
|
|
|
/* Setup CFI for the module. */
|
|
cfi_init(mod);
|
|
|
|
/* Arch-specific module finalizing. */
|
|
return module_finalize(info->hdr, info->sechdrs, mod);
|
|
}
|
|
|
|
/* Is this module of this name done loading? No locks held. */
|
|
static bool finished_loading(const char *name)
|
|
{
|
|
struct module *mod;
|
|
bool ret;
|
|
|
|
/*
|
|
* The module_mutex should not be a heavily contended lock;
|
|
* if we get the occasional sleep here, we'll go an extra iteration
|
|
* in the wait_event_interruptible(), which is harmless.
|
|
*/
|
|
sched_annotate_sleep();
|
|
mutex_lock(&module_mutex);
|
|
mod = find_module_all(name, strlen(name), true);
|
|
ret = !mod || mod->state == MODULE_STATE_LIVE
|
|
|| mod->state == MODULE_STATE_GOING;
|
|
mutex_unlock(&module_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Call module constructors. */
|
|
static void do_mod_ctors(struct module *mod)
|
|
{
|
|
#ifdef CONFIG_CONSTRUCTORS
|
|
unsigned long i;
|
|
|
|
for (i = 0; i < mod->num_ctors; i++)
|
|
mod->ctors[i]();
|
|
#endif
|
|
}
|
|
|
|
/* For freeing module_init on success, in case kallsyms traversing */
|
|
struct mod_initfree {
|
|
struct llist_node node;
|
|
void *module_init;
|
|
};
|
|
|
|
static void do_free_init(struct work_struct *w)
|
|
{
|
|
struct llist_node *pos, *n, *list;
|
|
struct mod_initfree *initfree;
|
|
|
|
list = llist_del_all(&init_free_list);
|
|
|
|
synchronize_rcu();
|
|
|
|
llist_for_each_safe(pos, n, list) {
|
|
initfree = container_of(pos, struct mod_initfree, node);
|
|
module_memfree(initfree->module_init);
|
|
kfree(initfree);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This is where the real work happens.
|
|
*
|
|
* Keep it uninlined to provide a reliable breakpoint target, e.g. for the gdb
|
|
* helper command 'lx-symbols'.
|
|
*/
|
|
static noinline int do_init_module(struct module *mod)
|
|
{
|
|
int ret = 0;
|
|
struct mod_initfree *freeinit;
|
|
|
|
freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
|
|
if (!freeinit) {
|
|
ret = -ENOMEM;
|
|
goto fail;
|
|
}
|
|
freeinit->module_init = mod->init_layout.base;
|
|
|
|
do_mod_ctors(mod);
|
|
/* Start the module */
|
|
if (mod->init != NULL)
|
|
ret = do_one_initcall(mod->init);
|
|
if (ret < 0) {
|
|
goto fail_free_freeinit;
|
|
}
|
|
if (ret > 0) {
|
|
pr_warn("%s: '%s'->init suspiciously returned %d, it should "
|
|
"follow 0/-E convention\n"
|
|
"%s: loading module anyway...\n",
|
|
__func__, mod->name, ret, __func__);
|
|
dump_stack();
|
|
}
|
|
|
|
/* Now it's a first class citizen! */
|
|
mod->state = MODULE_STATE_LIVE;
|
|
blocking_notifier_call_chain(&module_notify_list,
|
|
MODULE_STATE_LIVE, mod);
|
|
|
|
/* Delay uevent until module has finished its init routine */
|
|
kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
|
|
|
|
/*
|
|
* We need to finish all async code before the module init sequence
|
|
* is done. This has potential to deadlock if synchronous module
|
|
* loading is requested from async (which is not allowed!).
|
|
*
|
|
* See commit 0fdff3ec6d87 ("async, kmod: warn on synchronous
|
|
* request_module() from async workers") for more details.
|
|
*/
|
|
if (!mod->async_probe_requested)
|
|
async_synchronize_full();
|
|
|
|
ftrace_free_mem(mod, mod->init_layout.base, mod->init_layout.base +
|
|
mod->init_layout.size);
|
|
mutex_lock(&module_mutex);
|
|
/* Drop initial reference. */
|
|
module_put(mod);
|
|
trim_init_extable(mod);
|
|
#ifdef CONFIG_KALLSYMS
|
|
/* Switch to core kallsyms now init is done: kallsyms may be walking! */
|
|
rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
|
|
#endif
|
|
module_enable_ro(mod, true);
|
|
mod_tree_remove_init(mod);
|
|
module_arch_freeing_init(mod);
|
|
mod->init_layout.base = NULL;
|
|
mod->init_layout.size = 0;
|
|
mod->init_layout.ro_size = 0;
|
|
mod->init_layout.ro_after_init_size = 0;
|
|
mod->init_layout.text_size = 0;
|
|
/*
|
|
* We want to free module_init, but be aware that kallsyms may be
|
|
* walking this with preempt disabled. In all the failure paths, we
|
|
* call synchronize_rcu(), but we don't want to slow down the success
|
|
* path. module_memfree() cannot be called in an interrupt, so do the
|
|
* work and call synchronize_rcu() in a work queue.
|
|
*
|
|
* Note that module_alloc() on most architectures creates W+X page
|
|
* mappings which won't be cleaned up until do_free_init() runs. Any
|
|
* code such as mark_rodata_ro() which depends on those mappings to
|
|
* be cleaned up needs to sync with the queued work - ie
|
|
* rcu_barrier()
|
|
*/
|
|
if (llist_add(&freeinit->node, &init_free_list))
|
|
schedule_work(&init_free_wq);
|
|
|
|
mutex_unlock(&module_mutex);
|
|
wake_up_all(&module_wq);
|
|
|
|
return 0;
|
|
|
|
fail_free_freeinit:
|
|
kfree(freeinit);
|
|
fail:
|
|
/* Try to protect us from buggy refcounters. */
|
|
mod->state = MODULE_STATE_GOING;
|
|
synchronize_rcu();
|
|
module_put(mod);
|
|
blocking_notifier_call_chain(&module_notify_list,
|
|
MODULE_STATE_GOING, mod);
|
|
klp_module_going(mod);
|
|
ftrace_release_mod(mod);
|
|
free_module(mod);
|
|
wake_up_all(&module_wq);
|
|
return ret;
|
|
}
|
|
|
|
static int may_init_module(void)
|
|
{
|
|
if (!capable(CAP_SYS_MODULE) || modules_disabled)
|
|
return -EPERM;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We try to place it in the list now to make sure it's unique before
|
|
* we dedicate too many resources. In particular, temporary percpu
|
|
* memory exhaustion.
|
|
*/
|
|
static int add_unformed_module(struct module *mod)
|
|
{
|
|
int err;
|
|
struct module *old;
|
|
|
|
mod->state = MODULE_STATE_UNFORMED;
|
|
|
|
mutex_lock(&module_mutex);
|
|
old = find_module_all(mod->name, strlen(mod->name), true);
|
|
if (old != NULL) {
|
|
if (old->state == MODULE_STATE_COMING
|
|
|| old->state == MODULE_STATE_UNFORMED) {
|
|
/* Wait in case it fails to load. */
|
|
mutex_unlock(&module_mutex);
|
|
err = wait_event_interruptible(module_wq,
|
|
finished_loading(mod->name));
|
|
if (err)
|
|
goto out_unlocked;
|
|
|
|
/* The module might have gone in the meantime. */
|
|
mutex_lock(&module_mutex);
|
|
old = find_module_all(mod->name, strlen(mod->name),
|
|
true);
|
|
}
|
|
|
|
/*
|
|
* We are here only when the same module was being loaded. Do
|
|
* not try to load it again right now. It prevents long delays
|
|
* caused by serialized module load failures. It might happen
|
|
* when more devices of the same type trigger load of
|
|
* a particular module.
|
|
*/
|
|
if (old && old->state == MODULE_STATE_LIVE)
|
|
err = -EEXIST;
|
|
else
|
|
err = -EBUSY;
|
|
goto out;
|
|
}
|
|
mod_update_bounds(mod);
|
|
list_add_rcu(&mod->list, &modules);
|
|
mod_tree_insert(mod);
|
|
err = 0;
|
|
|
|
out:
|
|
mutex_unlock(&module_mutex);
|
|
out_unlocked:
|
|
return err;
|
|
}
|
|
|
|
static int complete_formation(struct module *mod, struct load_info *info)
|
|
{
|
|
int err;
|
|
|
|
mutex_lock(&module_mutex);
|
|
|
|
/* Find duplicate symbols (must be called under lock). */
|
|
err = verify_exported_symbols(mod);
|
|
if (err < 0)
|
|
goto out;
|
|
|
|
/* This relies on module_mutex for list integrity. */
|
|
module_bug_finalize(info->hdr, info->sechdrs, mod);
|
|
|
|
module_enable_ro(mod, false);
|
|
module_enable_nx(mod);
|
|
module_enable_x(mod);
|
|
|
|
/* Mark state as coming so strong_try_module_get() ignores us,
|
|
* but kallsyms etc. can see us. */
|
|
mod->state = MODULE_STATE_COMING;
|
|
mutex_unlock(&module_mutex);
|
|
|
|
return 0;
|
|
|
|
out:
|
|
mutex_unlock(&module_mutex);
|
|
return err;
|
|
}
|
|
|
|
static int prepare_coming_module(struct module *mod)
|
|
{
|
|
int err;
|
|
|
|
ftrace_module_enable(mod);
|
|
err = klp_module_coming(mod);
|
|
if (err)
|
|
return err;
|
|
|
|
blocking_notifier_call_chain(&module_notify_list,
|
|
MODULE_STATE_COMING, mod);
|
|
return 0;
|
|
}
|
|
|
|
static int unknown_module_param_cb(char *param, char *val, const char *modname,
|
|
void *arg)
|
|
{
|
|
struct module *mod = arg;
|
|
int ret;
|
|
|
|
if (strcmp(param, "async_probe") == 0) {
|
|
mod->async_probe_requested = true;
|
|
return 0;
|
|
}
|
|
|
|
/* Check for magic 'dyndbg' arg */
|
|
ret = ddebug_dyndbg_module_param_cb(param, val, modname);
|
|
if (ret != 0)
|
|
pr_warn("%s: unknown parameter '%s' ignored\n", modname, param);
|
|
return 0;
|
|
}
|
|
|
|
/* Allocate and load the module: note that size of section 0 is always
|
|
zero, and we rely on this for optional sections. */
|
|
static int load_module(struct load_info *info, const char __user *uargs,
|
|
int flags)
|
|
{
|
|
struct module *mod;
|
|
long err = 0;
|
|
char *after_dashes;
|
|
|
|
/*
|
|
* Do the signature check (if any) first. All that
|
|
* the signature check needs is info->len, it does
|
|
* not need any of the section info. That can be
|
|
* set up later. This will minimize the chances
|
|
* of a corrupt module causing problems before
|
|
* we even get to the signature check.
|
|
*
|
|
* The check will also adjust info->len by stripping
|
|
* off the sig length at the end of the module, making
|
|
* checks against info->len more correct.
|
|
*/
|
|
err = module_sig_check(info, flags);
|
|
if (err)
|
|
goto free_copy;
|
|
|
|
/*
|
|
* Do basic sanity checks against the ELF header and
|
|
* sections.
|
|
*/
|
|
err = elf_validity_check(info);
|
|
if (err) {
|
|
pr_err("Module has invalid ELF structures\n");
|
|
goto free_copy;
|
|
}
|
|
|
|
/*
|
|
* Everything checks out, so set up the section info
|
|
* in the info structure.
|
|
*/
|
|
err = setup_load_info(info, flags);
|
|
if (err)
|
|
goto free_copy;
|
|
|
|
/*
|
|
* Now that we know we have the correct module name, check
|
|
* if it's blacklisted.
|
|
*/
|
|
if (blacklisted(info->name)) {
|
|
err = -EPERM;
|
|
goto free_copy;
|
|
}
|
|
|
|
err = rewrite_section_headers(info, flags);
|
|
if (err)
|
|
goto free_copy;
|
|
|
|
/* Check module struct version now, before we try to use module. */
|
|
if (!check_modstruct_version(info, info->mod)) {
|
|
err = -ENOEXEC;
|
|
goto free_copy;
|
|
}
|
|
|
|
/* Figure out module layout, and allocate all the memory. */
|
|
mod = layout_and_allocate(info, flags);
|
|
if (IS_ERR(mod)) {
|
|
err = PTR_ERR(mod);
|
|
goto free_copy;
|
|
}
|
|
|
|
audit_log_kern_module(mod->name);
|
|
|
|
/* Reserve our place in the list. */
|
|
err = add_unformed_module(mod);
|
|
if (err)
|
|
goto free_module;
|
|
|
|
#ifdef CONFIG_MODULE_SIG
|
|
mod->sig_ok = info->sig_ok;
|
|
if (!mod->sig_ok) {
|
|
pr_notice_once("%s: module verification failed: signature "
|
|
"and/or required key missing - tainting "
|
|
"kernel\n", mod->name);
|
|
add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK);
|
|
}
|
|
#endif
|
|
|
|
/* To avoid stressing percpu allocator, do this once we're unique. */
|
|
err = percpu_modalloc(mod, info);
|
|
if (err)
|
|
goto unlink_mod;
|
|
|
|
/* Now module is in final location, initialize linked lists, etc. */
|
|
err = module_unload_init(mod);
|
|
if (err)
|
|
goto unlink_mod;
|
|
|
|
init_param_lock(mod);
|
|
|
|
/* Now we've got everything in the final locations, we can
|
|
* find optional sections. */
|
|
err = find_module_sections(mod, info);
|
|
if (err)
|
|
goto free_unload;
|
|
|
|
err = check_module_license_and_versions(mod);
|
|
if (err)
|
|
goto free_unload;
|
|
|
|
/* Set up MODINFO_ATTR fields */
|
|
setup_modinfo(mod, info);
|
|
|
|
/* Fix up syms, so that st_value is a pointer to location. */
|
|
err = simplify_symbols(mod, info);
|
|
if (err < 0)
|
|
goto free_modinfo;
|
|
|
|
err = apply_relocations(mod, info);
|
|
if (err < 0)
|
|
goto free_modinfo;
|
|
|
|
err = post_relocation(mod, info);
|
|
if (err < 0)
|
|
goto free_modinfo;
|
|
|
|
flush_module_icache(mod);
|
|
|
|
/* Now copy in args */
|
|
mod->args = strndup_user(uargs, ~0UL >> 1);
|
|
if (IS_ERR(mod->args)) {
|
|
err = PTR_ERR(mod->args);
|
|
goto free_arch_cleanup;
|
|
}
|
|
|
|
dynamic_debug_setup(mod, info->debug, info->num_debug);
|
|
|
|
/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
|
|
ftrace_module_init(mod);
|
|
|
|
/* Finally it's fully formed, ready to start executing. */
|
|
err = complete_formation(mod, info);
|
|
if (err)
|
|
goto ddebug_cleanup;
|
|
|
|
err = prepare_coming_module(mod);
|
|
if (err)
|
|
goto bug_cleanup;
|
|
|
|
/* Module is ready to execute: parsing args may do that. */
|
|
after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
|
|
-32768, 32767, mod,
|
|
unknown_module_param_cb);
|
|
if (IS_ERR(after_dashes)) {
|
|
err = PTR_ERR(after_dashes);
|
|
goto coming_cleanup;
|
|
} else if (after_dashes) {
|
|
pr_warn("%s: parameters '%s' after `--' ignored\n",
|
|
mod->name, after_dashes);
|
|
}
|
|
|
|
/* Link in to sysfs. */
|
|
err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
|
|
if (err < 0)
|
|
goto coming_cleanup;
|
|
|
|
if (is_livepatch_module(mod)) {
|
|
err = copy_module_elf(mod, info);
|
|
if (err < 0)
|
|
goto sysfs_cleanup;
|
|
}
|
|
|
|
/* Get rid of temporary copy. */
|
|
free_copy(info);
|
|
|
|
/* Done! */
|
|
trace_module_load(mod);
|
|
|
|
return do_init_module(mod);
|
|
|
|
sysfs_cleanup:
|
|
mod_sysfs_teardown(mod);
|
|
coming_cleanup:
|
|
mod->state = MODULE_STATE_GOING;
|
|
destroy_params(mod->kp, mod->num_kp);
|
|
blocking_notifier_call_chain(&module_notify_list,
|
|
MODULE_STATE_GOING, mod);
|
|
klp_module_going(mod);
|
|
bug_cleanup:
|
|
mod->state = MODULE_STATE_GOING;
|
|
/* module_bug_cleanup needs module_mutex protection */
|
|
mutex_lock(&module_mutex);
|
|
module_bug_cleanup(mod);
|
|
mutex_unlock(&module_mutex);
|
|
|
|
ddebug_cleanup:
|
|
/* Clean up CFI for the module. */
|
|
cfi_cleanup(mod);
|
|
ftrace_release_mod(mod);
|
|
dynamic_debug_remove(mod, info->debug);
|
|
synchronize_rcu();
|
|
kfree(mod->args);
|
|
free_arch_cleanup:
|
|
module_arch_cleanup(mod);
|
|
free_modinfo:
|
|
free_modinfo(mod);
|
|
free_unload:
|
|
module_unload_free(mod);
|
|
unlink_mod:
|
|
mutex_lock(&module_mutex);
|
|
/* Unlink carefully: kallsyms could be walking list. */
|
|
list_del_rcu(&mod->list);
|
|
mod_tree_remove(mod);
|
|
wake_up_all(&module_wq);
|
|
/* Wait for RCU-sched synchronizing before releasing mod->list. */
|
|
synchronize_rcu();
|
|
mutex_unlock(&module_mutex);
|
|
free_module:
|
|
/* Free lock-classes; relies on the preceding sync_rcu() */
|
|
lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size);
|
|
|
|
module_deallocate(mod, info);
|
|
free_copy:
|
|
free_copy(info);
|
|
return err;
|
|
}
|
|
|
|
SYSCALL_DEFINE3(init_module, void __user *, umod,
|
|
unsigned long, len, const char __user *, uargs)
|
|
{
|
|
int err;
|
|
struct load_info info = { };
|
|
|
|
err = may_init_module();
|
|
if (err)
|
|
return err;
|
|
|
|
pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
|
|
umod, len, uargs);
|
|
|
|
err = copy_module_from_user(umod, len, &info);
|
|
if (err)
|
|
return err;
|
|
|
|
return load_module(&info, uargs, 0);
|
|
}
|
|
|
|
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
|
|
{
|
|
struct load_info info = { };
|
|
loff_t size;
|
|
void *hdr;
|
|
int err;
|
|
|
|
err = may_init_module();
|
|
if (err)
|
|
return err;
|
|
|
|
pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
|
|
|
|
if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
|
|
|MODULE_INIT_IGNORE_VERMAGIC))
|
|
return -EINVAL;
|
|
|
|
err = kernel_read_file_from_fd(fd, &hdr, &size, INT_MAX,
|
|
READING_MODULE);
|
|
if (err)
|
|
return err;
|
|
info.hdr = hdr;
|
|
info.len = size;
|
|
|
|
return load_module(&info, uargs, flags);
|
|
}
|
|
|
|
static inline int within(unsigned long addr, void *start, unsigned long size)
|
|
{
|
|
return ((void *)addr >= start && (void *)addr < start + size);
|
|
}
|
|
|
|
#ifdef CONFIG_KALLSYMS
|
|
/*
|
|
* This ignores the intensely annoying "mapping symbols" found
|
|
* in ARM ELF files: $a, $t and $d.
|
|
*/
|
|
static inline int is_arm_mapping_symbol(const char *str)
|
|
{
|
|
if (str[0] == '.' && str[1] == 'L')
|
|
return true;
|
|
return str[0] == '$' && strchr("axtd", str[1])
|
|
&& (str[2] == '\0' || str[2] == '.');
|
|
}
|
|
|
|
static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
|
|
{
|
|
return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
|
|
}
|
|
|
|
/*
|
|
* Given a module and address, find the corresponding symbol and return its name
|
|
* while providing its size and offset if needed.
|
|
*/
|
|
static const char *find_kallsyms_symbol(struct module *mod,
|
|
unsigned long addr,
|
|
unsigned long *size,
|
|
unsigned long *offset)
|
|
{
|
|
unsigned int i, best = 0;
|
|
unsigned long nextval, bestval;
|
|
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
|
|
|
|
/* At worse, next value is at end of module */
|
|
if (within_module_init(addr, mod))
|
|
nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size;
|
|
else
|
|
nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
|
|
|
|
bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
|
|
|
|
/* Scan for closest preceding symbol, and next symbol. (ELF
|
|
starts real symbols at 1). */
|
|
for (i = 1; i < kallsyms->num_symtab; i++) {
|
|
const Elf_Sym *sym = &kallsyms->symtab[i];
|
|
unsigned long thisval = kallsyms_symbol_value(sym);
|
|
|
|
if (sym->st_shndx == SHN_UNDEF)
|
|
continue;
|
|
|
|
/* We ignore unnamed symbols: they're uninformative
|
|
* and inserted at a whim. */
|
|
if (*kallsyms_symbol_name(kallsyms, i) == '\0'
|
|
|| is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
|
|
continue;
|
|
|
|
if (thisval <= addr && thisval > bestval) {
|
|
best = i;
|
|
bestval = thisval;
|
|
}
|
|
if (thisval > addr && thisval < nextval)
|
|
nextval = thisval;
|
|
}
|
|
|
|
if (!best)
|
|
return NULL;
|
|
|
|
if (size)
|
|
*size = nextval - bestval;
|
|
if (offset)
|
|
*offset = addr - bestval;
|
|
|
|
return kallsyms_symbol_name(kallsyms, best);
|
|
}
|
|
|
|
void * __weak dereference_module_function_descriptor(struct module *mod,
|
|
void *ptr)
|
|
{
|
|
return ptr;
|
|
}
|
|
|
|
/* For kallsyms to ask for address resolution. NULL means not found. Careful
|
|
* not to lock to avoid deadlock on oopses, simply disable preemption. */
|
|
const char *module_address_lookup(unsigned long addr,
|
|
unsigned long *size,
|
|
unsigned long *offset,
|
|
char **modname,
|
|
char *namebuf)
|
|
{
|
|
const char *ret = NULL;
|
|
struct module *mod;
|
|
|
|
preempt_disable();
|
|
mod = __module_address(addr);
|
|
if (mod) {
|
|
if (modname)
|
|
*modname = mod->name;
|
|
|
|
ret = find_kallsyms_symbol(mod, addr, size, offset);
|
|
}
|
|
/* Make a copy in here where it's safe */
|
|
if (ret) {
|
|
strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
|
|
ret = namebuf;
|
|
}
|
|
preempt_enable();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int lookup_module_symbol_name(unsigned long addr, char *symname)
|
|
{
|
|
struct module *mod;
|
|
|
|
preempt_disable();
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
if (within_module(addr, mod)) {
|
|
const char *sym;
|
|
|
|
sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
|
|
if (!sym)
|
|
goto out;
|
|
|
|
strlcpy(symname, sym, KSYM_NAME_LEN);
|
|
preempt_enable();
|
|
return 0;
|
|
}
|
|
}
|
|
out:
|
|
preempt_enable();
|
|
return -ERANGE;
|
|
}
|
|
|
|
int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
|
|
unsigned long *offset, char *modname, char *name)
|
|
{
|
|
struct module *mod;
|
|
|
|
preempt_disable();
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
if (within_module(addr, mod)) {
|
|
const char *sym;
|
|
|
|
sym = find_kallsyms_symbol(mod, addr, size, offset);
|
|
if (!sym)
|
|
goto out;
|
|
if (modname)
|
|
strlcpy(modname, mod->name, MODULE_NAME_LEN);
|
|
if (name)
|
|
strlcpy(name, sym, KSYM_NAME_LEN);
|
|
preempt_enable();
|
|
return 0;
|
|
}
|
|
}
|
|
out:
|
|
preempt_enable();
|
|
return -ERANGE;
|
|
}
|
|
|
|
int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
|
char *name, char *module_name, int *exported)
|
|
{
|
|
struct module *mod;
|
|
|
|
preempt_disable();
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
struct mod_kallsyms *kallsyms;
|
|
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
kallsyms = rcu_dereference_sched(mod->kallsyms);
|
|
if (symnum < kallsyms->num_symtab) {
|
|
const Elf_Sym *sym = &kallsyms->symtab[symnum];
|
|
|
|
*value = kallsyms_symbol_value(sym);
|
|
*type = kallsyms->typetab[symnum];
|
|
strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
|
|
strlcpy(module_name, mod->name, MODULE_NAME_LEN);
|
|
*exported = is_exported(name, *value, mod);
|
|
preempt_enable();
|
|
return 0;
|
|
}
|
|
symnum -= kallsyms->num_symtab;
|
|
}
|
|
preempt_enable();
|
|
return -ERANGE;
|
|
}
|
|
|
|
/* Given a module and name of symbol, find and return the symbol's value */
|
|
static unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
|
|
{
|
|
unsigned int i;
|
|
struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
|
|
|
|
for (i = 0; i < kallsyms->num_symtab; i++) {
|
|
const Elf_Sym *sym = &kallsyms->symtab[i];
|
|
|
|
if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
|
|
sym->st_shndx != SHN_UNDEF)
|
|
return kallsyms_symbol_value(sym);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Look for this name: can be of form module:name. */
|
|
unsigned long module_kallsyms_lookup_name(const char *name)
|
|
{
|
|
struct module *mod;
|
|
char *colon;
|
|
unsigned long ret = 0;
|
|
|
|
/* Don't lock: we're in enough trouble already. */
|
|
preempt_disable();
|
|
if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
|
|
if ((mod = find_module_all(name, colon - name, false)) != NULL)
|
|
ret = find_kallsyms_symbol_value(mod, colon+1);
|
|
} else {
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
|
|
break;
|
|
}
|
|
}
|
|
preempt_enable();
|
|
return ret;
|
|
}
|
|
|
|
int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
|
|
struct module *, unsigned long),
|
|
void *data)
|
|
{
|
|
struct module *mod;
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
module_assert_mutex();
|
|
|
|
list_for_each_entry(mod, &modules, list) {
|
|
/* We hold module_mutex: no need for rcu_dereference_sched */
|
|
struct mod_kallsyms *kallsyms = mod->kallsyms;
|
|
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
for (i = 0; i < kallsyms->num_symtab; i++) {
|
|
const Elf_Sym *sym = &kallsyms->symtab[i];
|
|
|
|
if (sym->st_shndx == SHN_UNDEF)
|
|
continue;
|
|
|
|
ret = fn(data, kallsyms_symbol_name(kallsyms, i),
|
|
mod, kallsyms_symbol_value(sym));
|
|
if (ret != 0)
|
|
return ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_KALLSYMS */
|
|
|
|
static void cfi_init(struct module *mod)
|
|
{
|
|
#ifdef CONFIG_CFI_CLANG
|
|
rcu_read_lock_sched();
|
|
mod->cfi_check = (cfi_check_fn)find_kallsyms_symbol_value(mod,
|
|
CFI_CHECK_FN_NAME);
|
|
rcu_read_unlock_sched();
|
|
cfi_module_add(mod, module_addr_min, module_addr_max);
|
|
#endif
|
|
}
|
|
|
|
static void cfi_cleanup(struct module *mod)
|
|
{
|
|
#ifdef CONFIG_CFI_CLANG
|
|
cfi_module_remove(mod, module_addr_min, module_addr_max);
|
|
#endif
|
|
}
|
|
|
|
/* Maximum number of characters written by module_flags() */
|
|
#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
|
|
|
|
/* Keep in sync with MODULE_FLAGS_BUF_SIZE !!! */
|
|
static char *module_flags(struct module *mod, char *buf)
|
|
{
|
|
int bx = 0;
|
|
|
|
BUG_ON(mod->state == MODULE_STATE_UNFORMED);
|
|
if (mod->taints ||
|
|
mod->state == MODULE_STATE_GOING ||
|
|
mod->state == MODULE_STATE_COMING) {
|
|
buf[bx++] = '(';
|
|
bx += module_flags_taint(mod, buf + bx);
|
|
/* Show a - for module-is-being-unloaded */
|
|
if (mod->state == MODULE_STATE_GOING)
|
|
buf[bx++] = '-';
|
|
/* Show a + for module-is-being-loaded */
|
|
if (mod->state == MODULE_STATE_COMING)
|
|
buf[bx++] = '+';
|
|
buf[bx++] = ')';
|
|
}
|
|
buf[bx] = '\0';
|
|
|
|
return buf;
|
|
}
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
/* Called by the /proc file system to return a list of modules. */
|
|
static void *m_start(struct seq_file *m, loff_t *pos)
|
|
{
|
|
mutex_lock(&module_mutex);
|
|
return seq_list_start(&modules, *pos);
|
|
}
|
|
|
|
static void *m_next(struct seq_file *m, void *p, loff_t *pos)
|
|
{
|
|
return seq_list_next(p, &modules, pos);
|
|
}
|
|
|
|
static void m_stop(struct seq_file *m, void *p)
|
|
{
|
|
mutex_unlock(&module_mutex);
|
|
}
|
|
|
|
static int m_show(struct seq_file *m, void *p)
|
|
{
|
|
struct module *mod = list_entry(p, struct module, list);
|
|
char buf[MODULE_FLAGS_BUF_SIZE];
|
|
void *value;
|
|
|
|
/* We always ignore unformed modules. */
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
return 0;
|
|
|
|
seq_printf(m, "%s %u",
|
|
mod->name, mod->init_layout.size + mod->core_layout.size);
|
|
print_unload_info(m, mod);
|
|
|
|
/* Informative for users. */
|
|
seq_printf(m, " %s",
|
|
mod->state == MODULE_STATE_GOING ? "Unloading" :
|
|
mod->state == MODULE_STATE_COMING ? "Loading" :
|
|
"Live");
|
|
/* Used by oprofile and other similar tools. */
|
|
value = m->private ? NULL : mod->core_layout.base;
|
|
seq_printf(m, " 0x%px", value);
|
|
|
|
/* Taints info */
|
|
if (mod->taints)
|
|
seq_printf(m, " %s", module_flags(mod, buf));
|
|
|
|
seq_puts(m, "\n");
|
|
return 0;
|
|
}
|
|
|
|
/* Format: modulename size refcount deps address
|
|
|
|
Where refcount is a number or -, and deps is a comma-separated list
|
|
of depends or -.
|
|
*/
|
|
static const struct seq_operations modules_op = {
|
|
.start = m_start,
|
|
.next = m_next,
|
|
.stop = m_stop,
|
|
.show = m_show
|
|
};
|
|
|
|
/*
|
|
* This also sets the "private" pointer to non-NULL if the
|
|
* kernel pointers should be hidden (so you can just test
|
|
* "m->private" to see if you should keep the values private).
|
|
*
|
|
* We use the same logic as for /proc/kallsyms.
|
|
*/
|
|
static int modules_open(struct inode *inode, struct file *file)
|
|
{
|
|
int err = seq_open(file, &modules_op);
|
|
|
|
if (!err) {
|
|
struct seq_file *m = file->private_data;
|
|
m->private = kallsyms_show_value(file->f_cred) ? NULL : (void *)8ul;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static const struct file_operations proc_modules_operations = {
|
|
.open = modules_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = seq_release,
|
|
};
|
|
|
|
static int __init proc_modules_init(void)
|
|
{
|
|
proc_create("modules", 0, NULL, &proc_modules_operations);
|
|
return 0;
|
|
}
|
|
module_init(proc_modules_init);
|
|
#endif
|
|
|
|
/* Given an address, look for it in the module exception tables. */
|
|
const struct exception_table_entry *search_module_extables(unsigned long addr)
|
|
{
|
|
const struct exception_table_entry *e = NULL;
|
|
struct module *mod;
|
|
|
|
preempt_disable();
|
|
mod = __module_address(addr);
|
|
if (!mod)
|
|
goto out;
|
|
|
|
if (!mod->num_exentries)
|
|
goto out;
|
|
|
|
e = search_extable(mod->extable,
|
|
mod->num_exentries,
|
|
addr);
|
|
out:
|
|
preempt_enable();
|
|
|
|
/*
|
|
* Now, if we found one, we are running inside it now, hence
|
|
* we cannot unload the module, hence no refcnt needed.
|
|
*/
|
|
return e;
|
|
}
|
|
|
|
/*
|
|
* is_module_address - is this address inside a module?
|
|
* @addr: the address to check.
|
|
*
|
|
* See is_module_text_address() if you simply want to see if the address
|
|
* is code (not data).
|
|
*/
|
|
bool is_module_address(unsigned long addr)
|
|
{
|
|
bool ret;
|
|
|
|
preempt_disable();
|
|
ret = __module_address(addr) != NULL;
|
|
preempt_enable();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* __module_address - get the module which contains an address.
|
|
* @addr: the address.
|
|
*
|
|
* Must be called with preempt disabled or module mutex held so that
|
|
* module doesn't get freed during this.
|
|
*/
|
|
struct module *__module_address(unsigned long addr)
|
|
{
|
|
struct module *mod;
|
|
|
|
if (addr < module_addr_min || addr > module_addr_max)
|
|
return NULL;
|
|
|
|
module_assert_mutex_or_preempt();
|
|
|
|
mod = mod_find(addr);
|
|
if (mod) {
|
|
BUG_ON(!within_module(addr, mod));
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
mod = NULL;
|
|
}
|
|
return mod;
|
|
}
|
|
|
|
/*
|
|
* is_module_text_address - is this address inside module code?
|
|
* @addr: the address to check.
|
|
*
|
|
* See is_module_address() if you simply want to see if the address is
|
|
* anywhere in a module. See kernel_text_address() for testing if an
|
|
* address corresponds to kernel or module code.
|
|
*/
|
|
bool is_module_text_address(unsigned long addr)
|
|
{
|
|
bool ret;
|
|
|
|
preempt_disable();
|
|
ret = __module_text_address(addr) != NULL;
|
|
preempt_enable();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* __module_text_address - get the module whose code contains an address.
|
|
* @addr: the address.
|
|
*
|
|
* Must be called with preempt disabled or module mutex held so that
|
|
* module doesn't get freed during this.
|
|
*/
|
|
struct module *__module_text_address(unsigned long addr)
|
|
{
|
|
struct module *mod = __module_address(addr);
|
|
if (mod) {
|
|
/* Make sure it's within the text section. */
|
|
if (!within(addr, mod->init_layout.base, mod->init_layout.text_size)
|
|
&& !within(addr, mod->core_layout.base, mod->core_layout.text_size))
|
|
mod = NULL;
|
|
}
|
|
return mod;
|
|
}
|
|
|
|
/* Don't grab lock, we're oopsing. */
|
|
void print_modules(void)
|
|
{
|
|
struct module *mod;
|
|
char buf[MODULE_FLAGS_BUF_SIZE];
|
|
|
|
printk(KERN_DEFAULT "Modules linked in:");
|
|
/* Most callers should already have preempt disabled, but make sure */
|
|
preempt_disable();
|
|
list_for_each_entry_rcu(mod, &modules, list) {
|
|
if (mod->state == MODULE_STATE_UNFORMED)
|
|
continue;
|
|
pr_cont(" %s%s", mod->name, module_flags(mod, buf));
|
|
}
|
|
preempt_enable();
|
|
if (last_unloaded_module[0])
|
|
pr_cont(" [last unloaded: %s]", last_unloaded_module);
|
|
pr_cont("\n");
|
|
}
|
|
|
|
#ifdef CONFIG_MODVERSIONS
|
|
/* Generate the signature for all relevant module structures here.
|
|
* If these change, we don't want to try to parse the module. */
|
|
void module_layout(struct module *mod,
|
|
struct modversion_info *ver,
|
|
struct kernel_param *kp,
|
|
struct kernel_symbol *ks,
|
|
struct tracepoint * const *tp)
|
|
{
|
|
}
|
|
EXPORT_SYMBOL(module_layout);
|
|
#endif
|