mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 03:50:24 +09:00
This is the merge of the upstream LTS release of 5.10.118 into the android13-5.10 branch. It contains the following commits:64f18041ddMerge branch 'android13-5.10' into branch 'android13-5.10-lts'3cbab1c9acRevert "xfrm: Add possibility to set the default to block if we have no policy"49412256c9Revert "net: xfrm: fix shift-out-of-bounce"65b0a22abcRevert "xfrm: make user policy API complete"b60c58879eRevert "xfrm: notify default policy on update"51b82c1241Revert "xfrm: fix dflt policy check when there is no policy configured"f91fa99d4bRevert "xfrm: rework default policy structure"c932832406Revert "xfrm: fix "disable_policy" flag use when arriving from different devices"6629a18b57Revert "include/uapi/linux/xfrm.h: Fix XFRM_MSG_MAPPING ABI breakage"a6c120a514Merge "Merge 5.10.118 into android13-5.10-lts" into android13-5.10-lts17267bb8e8ANDROID: Adding Image.gz and boot-gz.img3b28477cb8ANDROID: Creating boot-img.tar.gz for aarch644cbf7ff510Merge 5.10.118 into android13-5.10-lts9ab92c66baMerge 5.10.117 into android13-5.10-ltsd96a068cc6Merge 5.10.116 into android13-5.10-lts8e6b4843beMerge 5.10.115 into android13-5.10-ltsa8cb914f75ANDROID: GKI: update the abi .xml file due to hex_to_bin() changes3828f1164cRevert "tcp: ensure to use the most recently sent skb when filling the rate sample"52ddbabcb3Merge 5.10.114 into android13-5.10-lts902d7527c1Revert "ipv6: make ip6_rt_gc_expire an atomic_t"d3d4f869cdRevert "oom_kill.c: futex: delay the OOM reaper to allow time for proper futex cleanup"11565b017bMerge 5.10.113 into android13-5.10-ltsfe917bad60Merge 5.10.112 into android13-5.10-ltsc356141b2bANDROID: fix up gpio change in 5.10.11144eebe417eMerge 5.10.111 into android13-5.10-ltsc204ee3350Linux 5.10.11856642f6af2module: check for exit sections in layout_sections() instead of module_init_section()633be494c3include/uapi/linux/xfrm.h: Fix XFRM_MSG_MAPPING ABI breakage61a4cc41e5afs: Fix afs_getattr() to refetch file status if callback break occurred606011cb6ai2c: mt7621: fix missing clk_disable_unprepare() on error in mtk_i2c_probe()030de84d45module: treat exit sections the same as init sections when !CONFIG_MODULE_UNLOAD355141fdbfdt-bindings: pinctrl: aspeed-g6: remove FWQSPID groupd30fdf7d13Input: ili210x - fix reset timinga698bf1f72arm64: Enable repeat tlbi workaround on KRYO4XX gold CPUs696292b9b5net: atlantic: verify hw_head_ lies within TX buffer ringcd66ab20a8net: atlantic: add check for MAX_SKB_FRAGS9bee8b4275net: atlantic: reduce scope of is_rsc_complete9b84e83a92net: atlantic: fix "frag[0] not initialized"0ae23a1d47net: stmmac: fix missing pci_disable_device() on error in stmmac_pci_probe()d4c6e5cebcethernet: tulip: fix missing pci_disable_device() on error in tulip_init_one()3a6dee284fnl80211: fix locking in nl80211_set_tx_bitrate_mask()efe580c436selftests: add ping test with ping_group_range tuned1cfbf6d3a7nl80211: validate S1G channel widtha0f5ff2049mac80211: fix rx reordering with non explicit / psmp ack policye21d734fd0scsi: qla2xxx: Fix missed DMA unmap for aborted commandsc5af341747perf bench numa: Address compiler error on s390210ea7da5cgpio: mvebu/pwm: Refuse requests with inverted polarity30d4721fecgpio: gpio-vf610: do not touch other bits when set the target bitea8a9cb4a7riscv: dts: sifive: fu540-c000: align dma node name with dtschemadfd1f0cb62net: bridge: Clear offload_fwd_mark when passing frame up bridge interface.579061f391igb: skip phy status check where unavailablea89888648eARM: 9197/1: spectre-bhb: fix loop8 sequence for Thumb21756b45d8dARM: 9196/1: spectre-bhb: enable for Cortex-A157b676abe32net: af_key: add check for pfkey_broadcast in function pfkey_process697f3219eenet/mlx5e: Properly block LRO when XDP is enabledb503d0228cNFC: nci: fix sleep in atomic context bugs caused by nci_skb_alloc42d4287cc1net/qla3xxx: Fix a test in ql_reset_work()d35bf8d766clk: at91: generated: consider range when calculating best rate9e0e75a5e7ice: fix possible under reporting of ethtool Tx and Rx statistics6e2caee5cdnet: vmxnet3: fix possible NULL pointer dereference in vmxnet3_rq_cleanup()a54d86cf41net: vmxnet3: fix possible use-after-free bugs in vmxnet3_rq_alloc_rx_buf()201e5b5c27net: systemport: Fix an error handling path in bcm_sysport_probe()9bfe898e2bnet/sched: act_pedit: sanitize shift argument before usage47f04f95edxfrm: fix "disable_policy" flag use when arriving from different devices0d2e9d8000xfrm: rework default policy structure57c1bbe709xfrm: fix dflt policy check when there is no policy configured9856c3a129xfrm: notify default policy on update20fd28df40xfrm: make user policy API completeab610ee1d1net: xfrm: fix shift-out-of-bounce5b7f84b1f9xfrm: Add possibility to set the default to block if we have no policy243e72e204net: evaluate net.ipvX.conf.all.disable_policy and disable_xfrm1bc27eb71bnet: macb: Increment rx bd head after allocating skb and buffer998e305bd1net: ipa: record proper RX transaction count0599d5a8b4ARM: dts: aspeed-g6: fix SPI1/SPI2 quad pin group0a2847d448pinctrl: pinctrl-aspeed-g6: remove FWQSPID group in pinctrld8ca684c3dARM: dts: aspeed-g6: remove FWQSPID group in pinctrl dtsi3fc2846099dma-buf: fix use of DMA_BUF_SET_NAME_{A,B} in userspacee5289affbadrm/dp/mst: fix a possible memory leak in fetch_monitor_name()8ceca1a069libceph: fix potential use-after-free on linger ping and resends233a3cc60ecrypto: qcom-rng - fix infinite loop on requests not multiple of WORD_SZ6013ef5f51arm64: mte: Ensure the cleared tags are visible before setting the PTEa817f78ed6arm64: paravirt: Use RCU read locks to guard stolen_timeb49bc8d615KVM: x86/mmu: Update number of zapped pages even if page list is stable146128ba26PCI/PM: Avoid putting Elo i2 PCIe Ports in D3coldec0d801d1aFix double fget() in vhost_net_set_backend()b42e5e3a84selinux: fix bad cleanup on error in hashtab_duplicate()3ee8e109c3perf: Fix sys_perf_event_open() race against self18fb7d533cALSA: hda/realtek: Add quirk for TongFang devices with pop noise3eaf770163ALSA: wavefront: Proper check of get_user() errora34d018b6eALSA: usb-audio: Restore Rane SL-1 quirkf3f2247ac3Reinstate some of "swiotlb: rework "fix info leak with DMA_FROM_DEVICE""e2cfa7b093Revert "swiotlb: fix info leak with DMA_FROM_DEVICE"fe5ac3da50nilfs2: fix lockdep warnings during disk space reclamationd626fcdabenilfs2: fix lockdep warnings in page operations for btree nodesaca18bacdbARM: 9191/1: arm/stacktrace, kasan: Silence KASAN warnings in unwind_frame()0acaf9cacdplatform/chrome: cros_ec_debugfs: detach log reader wq from devm5a19f3c2d3drbd: remove usage of list iterator variable after loop9b7f321106MIPS: lantiq: check the return value of kzalloc()05c073b1adfs: fix an infinite loop in iomap_fiemap00d8b06a4ertc: mc146818-lib: Fix the AltCentury for AMD platforms87fd0dd43envme-multipath: fix hang when disk goes live over reconnect3663d6023atools/virtio: compile with -pthread5a4cbcb3dfvhost_vdpa: don't setup irq offloading when irq_num < 0f0931ee125s390/pci: improve zpci_dev reference counting7d3f69cbdeALSA: hda/realtek: Enable headset mic on Lenovo P360a59450656bcrypto: x86/chacha20 - Avoid spurious jumps to other functions39acee8aeacrypto: stm32 - fix reference leak in stm32_crc_remove703c80ff43rtc: sun6i: Fix time overflow handlingbab037ebbegfs2: Disable page faults during lockless buffered readse803f12ea2nvme-pci: add quirks for Samsung X5 SSDs5565fc538dInput: stmfts - fix reference leak in stmfts_input_opend5e88c2d76Input: add bounds checking to input_set_capability()ea6a86886cum: Cleanup syscall_handler_t definition/cast, fix warningc39b91fcd5rtc: pcf2127: fix bug when reading alarm registers2b4e5a2d7drtc: fix use-after-free on device removal67136fff5bigc: Update I226_K device IDd0229838b6igc: Remove phy->type checking170110adbeigc: Remove _I_PHY_ID checking55c820c1b2Revert "drm/i915/opregion: check port number bounds for SWSCI display power state"911b362678floppy: use a statically allocated error counter3c48558be5io_uring: always grab file table for deferred statxa1a2c957dausb: gadget: fix race when gadget driver register via ioctl7686a5c2a8Linux 5.10.117937c6b0e3eSUNRPC: Fix fall-through warnings for Clang29f077d070io_uring: always use original task when preparing req identity1444e0568busb: gadget: uvc: allow for application to cleanly shutdown42505e3622usb: gadget: uvc: rename function to be more consistent002e7223dcping: fix address binding wrt vrfd9a1e82bf6arm[64]/memremap: don't abuse pfn_valid() to ensure presence of linear map49750c5e9anet: phy: Fix race condition on link status changee68b60ae29SUNRPC: Ensure we flush any closed sockets before xs_xprt_free()dbe6974a39SUNRPC: Don't call connect() more than once on a TCP socket47541ed4d4SUNRPC: Prevent immediate close+reconnect2ab569edd8SUNRPC: Clean up scheduling of autoclose85844ea29fdrm/vmwgfx: Initialize drm_mode_fb_cmd27e849dbe60cgroup/cpuset: Remove cpus_allowed/mems_allowed setup in cpuset_init_smp()6aa239d82enet: atlantic: always deep reset on pm op, fixing up my null deref regression6158df4fa5i40e: i40e_main: fix a missing check on list iterator819796024cdrm/nouveau/tegra: Stop using iommu_present()e06605af8bceph: fix setting of xattrs on async created inodes86db01f373serial: 8250_mtk: Fix register address for XON/XOFF character84ad84e495serial: 8250_mtk: Fix UART_EFR register addressf8d8440f13slimbus: qcom: Fix IRQ check in qcom_slim_probed7b7c5532aUSB: serial: option: add Fibocom MA510 modem2ba0034e36USB: serial: option: add Fibocom L610 modem319b312edbUSB: serial: qcserial: add support for Sierra Wireless EM7590994395f356USB: serial: pl2303: add device id for HP LM930 Display8276a3dbe2usb: typec: tcpci_mt6360: Update for BMC PHY setting54979aa49eusb: typec: tcpci: Don't skip cleanup in .remove() on error7335a6b11dusb: cdc-wdm: fix reading stuck on device close6d47eceaf3tty: n_gsm: fix mux activation issues in gsm_config()69139a45b8tty/serial: digicolor: fix possible null-ptr-deref in digicolor_uart_probe()5a73581116firmware_loader: use kernel credentials when reading firmwared254309aabtcp: resalt the secret every 10 seconds3abbfac1abnet: sfp: Add tx-fault workaround for Huawei MA5671A SFP ONT48f1dd67a8net: emaclite: Don't advertise 1000BASE-T and do auto negotiation5c09dbdfd4s390: disable -Warray-bounds03ebc6fd5cASoC: ops: Validate input values in snd_soc_put_volsw_range()31606a73baASoC: max98090: Generate notifications on changes for custom controlce154bd3bcASoC: max98090: Reject invalid values in custom control put()5ecaaaeb2chwmon: (f71882fg) Fix negative temperature88091c0275gfs2: Fix filesystem block deallocation for short writesfccf4bf3f2tls: Fix context leak on tls_device_down161c4edecanet: sfc: ef10: fix memory leak in efx_ef10_mtd_probe()d5e1b41bf7net/smc: non blocking recvmsg() return -EAGAIN when no data and signal_pendinge417a8fceanet: dsa: bcm_sf2: Fix Wake-on-LAN with mac_link_down()9012209f43net: bcmgenet: Check for Wake-on-LAN interrupt probe deferralabe35bf3benet/sched: act_pedit: really ensure the skb is writableb816ed53f3s390/lcs: fix variable dereferenced before check4d3c6d7418s390/ctcm: fix potential memory leak5497f87edcs390/ctcm: fix variable dereferenced before checkcc71c9f17cselftests: vm: Makefile: rename TARGETS to VMTARGETSce12e5ff8dhwmon: (ltq-cputemp) restrict it to SOC_XWAYceb3db723fdim: initialize all struct fields8b1b8fc819ionic: fix missing pci_release_regions() on error in ionic_probe()2cb8689f45nfs: fix broken handling of the softreval mount option49c10784b9mac80211_hwsim: call ieee80211_tx_prepare_skb under RCU protection79432d2237net: sfc: fix memory leak due to ptp channelbdb8d4aed1sfc: Use swap() instead of open coding it33c93f6e55netlink: do not reset transport header in netlink_recvmsg()9e40f2c513drm/nouveau: Fix a potential theorical leak in nouveau_get_backlight_name()54f26fc07eipv4: drop dst in multicast routing pathc07a84492fnet: mscc: ocelot: avoid corrupting hardware counters when moving VCAP filtersabb237c544net: mscc: ocelot: restrict tc-trap actions to VCAP IS2 lookup 0f9674c52a1net: mscc: ocelot: fix VCAP IS2 filters matching on both lookupsc1184d2888net: mscc: ocelot: fix last VCAP IS1/IS2 filter persisting in hardware when deletede2cdde89d2net: Fix features skip in for_each_netdev_feature()c420d66047mac80211: Reset MBSSID parameters upon connection9cbf2a7d5dhwmon: (tmp401) Add OF device ID table85eba08be2iwlwifi: iwl-dbg: Use del_timer_sync() before freeinga6a73781b4batman-adv: Don't skb_split skbuffs with frag_list85cac60500ANDROID: fix up abi issue with struct snd_pcm_runtime, again7d94299466ANDROID: GKI: fix crc issue with commitce1927b8cf("block: don't merge across cgroup boundaries if blkcg is enabled")07a4d3649aLinux 5.10.116d1ac096f88mm: userfaultfd: fix missing cache flush in mcopy_atomic_pte() and __mcopy_atomic()c6cbf5431amm: hugetlb: fix missing cache flush in copy_huge_page_from_user()308ff6a6e7mm: fix missing cache flush for all tail pages of compound page185fa5984dBluetooth: Fix the creation of hdev->name9ff4a6b806arm: remove CONFIG_ARCH_HAS_HOLES_MEMORYMODELdfb55dcf9dnfp: bpf: silence bitwise vs. logical OR warningf89f76f4b0drm/amd/display/dc/gpio/gpio_service: Pass around correct dce_{version, environment} typesefd1429fa9block: drbd: drbd_nl: Make conversion to 'enum drbd_ret_code' explicita71658c7dbregulator: consumer: Add missing stubs to regulator/consumer.h7648f42d1aMIPS: Use address-of operator on section symbolsbaaf34359dRevert "coredump: Snapshot the vmas in do_coredump"1ad18c9235Revert "coredump: Remove the WARN_ON in dump_vma_snapshot"e64fed6577Revert "coredump: Use the vma snapshot in fill_files_note"5a0cd73f55Revert "pstore: Don't use semaphores in always-atomic-context code"95002a201fRevert "PCI: Reduce warnings on possible RW1C corruption"15136f3380ANDROID: remove CONFIG_HW_RANDOM_CAVIUM from arm64 gki_defconfig74d428eb6bUPSTREAM: Linux 5.10.110a352ccd683ANDROID: fix up abi issue with struct snd_pcm_runtimec31dae74edUPSTREAM: Linux 5.10.109359ee5274bBACKPORT: vsock: each transport cycles only on its own sockets4a29d82a6dRevert "vsock: each transport cycles only on its own sockets"279ff602d6UPSTREAM: Linux 5.10.1081f7d764785ANDROID: reset android13-5.10-lts branch back to android13-5.10 statee61686bb77Linux 5.10.1158528806abemmc: rtsx: add 74 Clocks in power on flowe1ab92302bPCI: aardvark: Fix reading MSI interrupt number49143c9ed2PCI: aardvark: Clear all MSIs at setup7676a5b99fdm: interlock pending dm_io and dm_wait_for_bios_completiona439819f47block-map: add __GFP_ZERO flag for alloc_page in function bio_copy_kerna22d66eb51rcu: Apply callbacks processing time limit only on softirq40fb3812d9rcu: Fix callbacks processing time limit retaining cond_resched()43dbc3edadKVM: LAPIC: Enable timer posted-interrupt only when mwait/hlt is advertised9c8474fa34KVM: x86/mmu: avoid NULL-pointer dereference on page freeing bugsa474ee5eceKVM: x86: Do not change ICR on write to APIC_SELF_IPI64e3e16dbcx86/kvm: Preserve BSP MSR_KVM_POLL_CONTROL across suspend/resume5f884e0c2enet/mlx5: Fix slab-out-of-bounds while reading resource dump menu599fc32e74kvm: x86/cpuid: Only provide CPUID leaf 0xA if host has architectural PMU0a960a3672net: igmp: respect RCU rules in ip_mc_source() and ip_mc_msfilter()4fd45ef704btrfs: always log symlinks in full mode687167eef9smsc911x: allow using IRQ0b280877eabselftests: ocelot: tc_flower_chains: specify conform-exceed action for policera9fd5d6cd5bnxt_en: Fix unnecessary dropping of RX packets72e4fc1a4ebnxt_en: Fix possible bnxt_open() failure caused by wrong RFS flag9ac9f07f0fselftests: mirror_gre_bridge_1q: Avoid changing PVID while interface is operational475237e807hinic: fix bug of wq out of bound access1b9f1f455dnet: emaclite: Add error handling for of_address_to_resource()8459485db7net: cpsw: add missing of_node_put() in cpsw_probe_dt()4eee980950net: stmmac: dwmac-sun8i: add missing of_node_put() in sun8i_dwmac_register_mdio_mux()2347e9c922net: dsa: mt7530: add missing of_node_put() in mt7530_setup()1092656cc4net: ethernet: mediatek: add missing of_node_put() in mtk_sgmii_init()408fb2680eNFSv4: Don't invalidate inode attributes on delegation returnc1b480e6beRDMA/siw: Fix a condition race issue in MPA request processing5bf2a45e33selftests/seccomp: Don't call read() on TTY from background pgrp3ea0b44c01net/mlx5: Avoid double clear or set of sync reset requested2455331591net/mlx5e: Fix the calling of update_buffer_lossy() APIe07c13fbddnet/mlx5e: CT: Fix queued up restore put() executing after relevant ft released8338a7a09net/mlx5e: Don't match double-vlan packets if cvlan is not setc7f87ad115net/mlx5e: Fix trust state reset in reload87f0d9a518ASoC: dmaengine: Restore NULL prepare_slave_config() callbackad87f8498ehwmon: (adt7470) Fix warning on module removal997b8605e8gpio: pca953x: fix irq_stat not updated when irq is disabled (irq_mask not set)879b075a9aNFC: netlink: fix sleep in atomic bug when firmware download timeout1961c5a688nfc: nfcmrvl: main: reorder destructive operations in nfcmrvl_nci_unregister_dev to avoid bugs8a9e7c64f4nfc: replace improper check device_is_registered() in netlink related functions11adc9ab3ecan: grcan: only use the NAPI poll budget for RX4df5e498e0can: grcan: grcan_probe(): fix broken system id check for errata workaround needsdd973c0185can: grcan: use ofdev->dev when allocating DMA memory45bdcb5ca4can: isotp: remove re-binding of bound socket13959b9117can: grcan: grcan_close(): fix deadlock6c7c0e131es390/dasd: Fix read inconsistency for ESE DASD devices6e02c0413as390/dasd: Fix read for ESE with blksize < 4kecc8396827s390/dasd: prevent double format of tracks for ESE devices30e008ab3fs390/dasd: fix data corruption for ESE devicesd53d47faddASoC: meson: Fix event generation for AUI CODEC mux93a1f0755eASoC: meson: Fix event generation for G12A tohdmi muxe8b08e2f17ASoC: meson: Fix event generation for AUI ACODEC mux954d55170fASoC: wm8958: Fix change notifications for DSP controlsf45359824aASoC: da7219: Fix change notifications for tone generator frequencye6e61aab49genirq: Synchronize interrupt thread startupdcf1150f2enet: stmmac: disable Split Header (SPH) for Intel platforms68f35987d4firewire: core: extend card->lock in fw_core_handle_bus_reset629b4003a7firewire: remove check of list iterator against head past the loop bodye757ff4bbcfirewire: fix potential uaf in outbound_phy_packet_callback()70d25d4fbaRevert "SUNRPC: attempt AF_LOCAL connect on setup"466721d767drm/amd/display: Avoid reading audio pattern past AUDIO_CHANNELS_COUNT2e6f3d665aiommu/vt-d: Calculate mask for non-aligned flushesfbb7c61e76KVM: x86/svm: Account for family 17h event renumberings in amd_pmc_perf_hw_idb085afe226gpiolib: of: fix bounds check for 'gpio-reserved-ranges'2b7cb072d0mmc: core: Set HS clock speed before sending HS CMD1366651d7199mmc: sdhci-msm: Reset GCC_SDCC_BCR register for SDHC2906c73632ALSA: fireworks: fix wrong return count shorter than expected by 4 bytes03ab174805ALSA: hda/realtek: Add quirk for Yoga Duet 7 13ITL6 speakersa196f277c5parisc: Merge model and model name into one line in /proc/cpuinfo326f02f172MIPS: Fix CP0 counter erratum detection for R4k CPUsf40e35e79cLinux 5.10.1142d74f61787perf symbol: Remove arch__symbols__fixup_end()bf98302e68tty: n_gsm: fix software flow control handling95b267271atty: n_gsm: fix incorrect UA handling70b045d9aetty: n_gsm: fix reset fifo race condition320a24c4eftty: n_gsm: fix wrong command frame length field encoding935f314b6ftty: n_gsm: fix wrong command retry handling17b86db43ctty: n_gsm: fix missing explicit ldisc flusha2baa907c2tty: n_gsm: fix wrong DLCI release order705925e693tty: n_gsm: fix insufficient txframe size842a9bbbefnetfilter: nft_socket: only do sk lookups when indev is available7346e54dbftty: n_gsm: fix malformed counter for out of frame datad19613895etty: n_gsm: fix wrong signal octet encoding in convergence layer type 226f127f6d9tty: n_gsm: fix mux cleanup after unregister tty devicef26c271492tty: n_gsm: fix decoupled mux resource47132f9f7ftty: n_gsm: fix restart handling via CLD commandb3c88d46dbperf symbol: Update symbols__fixup_end()3d0a3168a3perf symbol: Pass is_kallsyms to symbols__fixup_end()2ab14625b8x86/cpu: Load microcode during restore_processor_state()795afbe8b4thermal: int340x: Fix attr.show callback prototype11d16498d7net: ethernet: stmmac: fix write to sgmii_adapter_base236dd62230drm/i915: Fix SEL_FETCH_PLANE_*(PIPE_B+) register addresses78d4dccf16kasan: prevent cpu_quarantine corruption when CPU offline and cache shrink occur at same time5fef6df273zonefs: Clear inode information flags on inode creation92ed64a920zonefs: Fix management of open zones42e8ec3b4bpowerpc/perf: Fix 32bit compileac3d077043drivers: net: hippi: Fix deadlock in rr_close()5399e7b80ccifs: destage any unwritten data to the server before calling copychunk_write80fc45377fx86: __memcpy_flushcache: fix wrong alignment if size > 2^32585ef03c9eext4: fix bug_on in start_this_handle during umount filesystem07da0be588ASoC: wm8731: Disable the regulator when probing fails1b1747ad7eASoC: Intel: soc-acpi: correct device endpoints for max98373aa138efd2btcp: fix F-RTO may not work correctly when receiving DSACK9d56e369bdRevert "ibmvnic: Add ethtool private flag for driver-defined queue limits"96904c8289ibmvnic: fix miscellaneous checks17f71272efixgbe: ensure IPsec VF<->PF compatibilityc33d717e06net: fec: add missing of_node_put() in fec_enet_init_stop_mode()9591967ac4bnx2x: fix napi API usage sequence1781beb879tls: Skip tls_append_frag on zero copy size77b922683edrm/amd/display: Fix memory leak in dcn21_clock_source_create18068e0527drm/amdkfd: Fix GWS queue countc0396f5e5bnet: dsa: lantiq_gswip: Don't set GSWIP_MII_CFG_RMII_CLK1204386e26net: phy: marvell10g: fix return value on errore974c730f0net: bcmgenet: hide status block before TX timestampingee71b47da5clk: sunxi: sun9i-mmc: check return value after calling platform_get_resource()8dacbef4febus: sunxi-rsb: Fix the return value of sunxi_rsb_device_create()9f29f6f8datcp: make sure treq->af_specific is initialized8a9d6ca360tcp: fix potential xmit stalls caused by TCP_NOTSENT_LOWAT720b6ced85ip_gre, ip6_gre: Fix race condition on o_seqno in collect_md mode41661b4c1aip6_gre: Make o_seqno start from 0 in native mode7b187fbd7eip_gre: Make o_seqno start from 0 in native mode83d128daffnet/smc: sync err code when tcp connection was refused9eb25e00f5net: hns3: add return value for mailbox handling in PF929c30c02dnet: hns3: add validity check for message data lengthe3ec78d82dnet: hns3: modify the return code of hclge_get_ring_chain_from_mbx06a40e7105cpufreq: fix memory leak in sun50i_cpufreq_nvmem_probefb172e93f8pinctrl: pistachio: fix use of irq_of_parse_and_map()8f042884afarm64: dts: imx8mn-ddr4-evk: Describe the 32.768 kHz PMIC clock73c35379dbARM: dts: imx6ull-colibri: fix vqmmc regulator61a89d0a5bsctp: check asoc strreset_chunk in sctp_generate_reconf_event41d6ac687dwireguard: device: check for metadata_dst with skb_valid_dst()3c464db03ctcp: ensure to use the most recently sent skb when filling the rate samplece4c3f7087pinctrl: stm32: Keep pinctrl block clock enabled when LEVEL IRQ requested0c60271df0tcp: md5: incorrect tcp_header_len for incoming connectionsf4dad5a48dpinctrl: rockchip: fix RK3308 pinmux bits9ef33d23f8bpf, lwt: Fix crash when using bpf_skb_set_tunnel_key() from bpf_xmit lwt hook6ac03e6dddnetfilter: nft_set_rbtree: overlap detection with element re-addition after deletion72ae15d5cenet: dsa: Add missing of_node_put() in dsa_port_link_register_of14cc2044c1memory: renesas-rpc-if: Fix HF/OSPI data transfer in Manual Mode690c1bc4bfpinctrl: stm32: Do not call stm32_gpio_get() for edge triggered IRQs in EOI6f2bf9c5ddmtd: fix 'part' field data corruption in mtd_info4da421035bmtd: rawnand: Fix return value check of wait_for_completion_timeout94ca69b702pinctrl: mediatek: moore: Fix build error123b7e0388ipvs: correctly print the memory size of ip_vs_conn_tabf4446f2136ARM: dts: logicpd-som-lv: Fix wrong pinmuxing on OMAP354a526cc29cARM: dts: am3517-evm: Fix misc pinmuxingb622bca852ARM: dts: Fix mmc order for omap3-gta049419d27fe1phy: ti: Add missing pm_runtime_disable() in serdes_am654_probe9e00a6e1fdphy: mapphone-mdm6600: Fix PM error handling in phy_mdm6600_probeeb659608e6ARM: dts: at91: sama5d4_xplained: fix pinctrl phandle namebb524f5a95ARM: dts: at91: Map MCLK for wm8731 on at91sam9g20ek4691ce8f28phy: ti: omap-usb2: Fix error handling in omap_usb2_enable_clocks76d1591a38bus: ti-sysc: Make omap3 gpt12 quirk handling SoC specific1b9855bf31ARM: OMAP2+: Fix refcount leak in omap_gic_of_init93cc8f184ephy: samsung: exynos5250-sata: fix missing device put in probe error paths3ca7491570phy: samsung: Fix missing of_node_put() in exynos_sata_phy_probe8f7644ac24ARM: dts: imx6qdl-apalis: Fix sgtl5000 detection issue23b0711fcdUSB: Fix xhci event ring dequeue pointer ERDP update issue712302aed1mtd: rawnand: fix ecc parameters for mt7622207c7af341iio:imu:bmi160: disable regulator in error path70d2df257earm64: dts: meson: remove CPU opps below 1GHz for SM1 boards2d320609bearm64: dts: meson: remove CPU opps below 1GHz for G12B boardsc4fb41bdf4video: fbdev: udlfb: properly check endpoint type0967830e72iocost: don't reset the inuse weight of under-weighted debtorsad604cbd1dx86/pci/xen: Disable PCI/MSI[-X] masking for XEN_HVM guests8fcce58c59riscv: patch_text: Fixup last cpu should be master51477d3b38hex2bin: fix access beyond string end616d354fb9hex2bin: make the function hex_to_bin constant-time1633cb2d4apinctrl: samsung: fix missing GPIOLIB on ARM64 Exynos configbdc3ad9251arch_topology: Do not set llc_sibling if llc_id is invalidaaee3f6617serial: 8250: Correct the clock for EndRun PTP/1588 PCIe device662f945a20serial: 8250: Also set sticky MCR bits in console restoration8be962c89dserial: imx: fix overrun interrupts in DMA moded22d92230fusb: phy: generic: Get the vbus supplyb820764c64usb: cdns3: Fix issue for clear halt endpointbd7f84708eusb: dwc3: gadget: Return proper request statusa633b8c341usb: dwc3: core: Only handle soft-reset in DCTL5fa59bb867usb: dwc3: core: Fix tx/rx threshold settings140801d3fbusb: dwc3: Try usb-role-switch first in dwc3_drd_init4dd5feb279usb: gadget: configfs: clear deactivation flag in configfs_composite_unbind()6c3da0e19cusb: gadget: uvc: Fix crash when encoding data for usb requestfb1fe1a455usb: typec: ucsi: Fix role swapping06826eb063usb: typec: ucsi: Fix reuse of completion structure7b510d4bb4usb: misc: fix improper handling of refcount in uss720_probe()bb8ecca2ddiio: imu: inv_icm42600: Fix I2C init possible nackca2b54b6adiio: magnetometer: ak8975: Fix the error handling in ak8975_power_on()1060604fc7iio: dac: ad5446: Fix read_raw not returning set value6ff33c01beiio: dac: ad5592r: Fix the missing return value.06ada9487fxhci: increase usb U3 -> U0 link resume timeout from 100ms to 500mse1be000166xhci: stop polling roothubs after shutdown2eb6c86891xhci: Enable runtime PM on second Alderlake controller63eda431b2USB: serial: option: add Telit 0x1057, 0x1058, 0x1075 compositionse9971dac69USB: serial: option: add support for Cinterion MV32-WA/MV32-WB34ff5455eeUSB: serial: cp210x: add PIDs for Kamstrup USB Meter Reader729a81ae10USB: serial: whiteheat: fix heap overflow in WHITEHEAT_GET_DTR_RTS008ba29f33USB: quirks: add STRING quirk for VCOM deviceac6ad0ef83USB: quirks: add a Realtek card reader8ba02cebb7usb: mtu3: fix USB 3.0 dual-role-switch from device to host549209caablightnvm: disable the subsystem54c028cfc4floppy: disable FDRAWCMD by default54af9dd2b9Linux 5.10.1137992fdb045Revert "net: micrel: fix KS8851_MLL Kconfig"8bedbc8f7fblock/compat_ioctl: fix range check in BLKGETSIZEfea24b07edstaging: ion: Prevent incorrect reference counting behavourdccee748afspi: atmel-quadspi: Fix the buswidth adjustment between spi-mem and controller572761645bjbd2: fix a potential race while discarding reserved buffers after an abort50aac44273can: isotp: stop timeout monitoring when no first frame was sente1e96e3727ext4: force overhead calculation if the s_overhead_cluster makes no sense4789149b9eext4: fix overhead calculation to account for the reserved gdt blocks0c54b09376ext4, doc: fix incorrect h_reserved size22c450d39fext4: limit length to bitmap_maxbytes - blocksize in punch_hole75ac724684ext4: fix use-after-free in ext4_search_dira46b3d8498ext4: fix symlink file size not match to file contentf6038d43b2ext4: fix fallocate to use file_modified to update permissions consistently19590bbc69perf report: Set PERF_SAMPLE_DATA_SRC bit for Arm SPE evente012f9d1afpowerpc/perf: Fix power9 event alternatives0a2cef65b3drm/vc4: Use pm_runtime_resume_and_get to fix pm_runtime_get_sync() usagef8f8b3124bKVM: PPC: Fix TCE handling for VFIO405d984274drm/panel/raspberrypi-touchscreen: Initialise the bridge in prepare231381f521drm/panel/raspberrypi-touchscreen: Avoid NULL deref if not initialised51d9cbbb0fperf/core: Fix perf_mmap fail when CONFIG_PERF_USE_VMALLOC enabled88fcfd6ee6sched/pelt: Fix attach_entity_load_avg() corner casec55327bc37arm_pmu: Validate single/group leader events5580b974a8ARC: entry: fix syscall_trace_exit argument7082650eb8e1000e: Fix possible overflow in LTR decoding43a2a3734aASoC: soc-dapm: fix two incorrect uses of list iterator54e6180c8cgpio: Request interrupts after IRQ is initialized0837ff17d0openvswitch: fix OOB access in reserve_sfa_size()19f6dcb1f0xtensa: fix a7 clobbering in coprocessor context load/storef399ab11ddxtensa: patch_text: Fixup last cpu should be masterba2716da23net: atlantic: invert deep par in pm functions, preventing null derefs358a3846f6dma: at_xdmac: fix a missing check on list iteratorcf23a960c5ata: pata_marvell: Check the 'bmdma_addr' beforing reading9ca66d7914mm/mmu_notifier.c: fix race in mmu_interval_notifier_remove()ed5d4efb4doom_kill.c: futex: delay the OOM reaper to allow time for proper futex cleanup6b932920b9mm, hugetlb: allow for "high" userspace addresses50cbc583faEDAC/synopsys: Read the error count from the correct register7ec6e06ee4nvme-pci: disable namespace identifiers for Qemu controllers316bd86c22nvme: add a quirk to disable namespace identifiers76101c8e0cstat: fix inconsistency between struct stat and struct compat_statbf28bba304scsi: qedi: Fix failed disconnect handlinga284cca3d8net: macb: Restart tx only if queue pointer is lagging9581e07b54drm/msm/mdp5: check the return of kzalloc()8d71edabb0dpaa_eth: Fix missing of_node_put in dpaa_get_ts_info()b3afe5a7fdbrcmfmac: sdio: Fix undefined behavior due to shift overflowing the constant202748f441mt76: Fix undefined behavior due to shift overflowing the constant0de9c104d0net: atlantic: Avoid out-of-bounds indexing5bef9fc38fcifs: Check the IOCB_DIRECT flag, not O_DIRECTe129c55153vxlan: fix error return code in vxlan_fdb_append8e7ea11364arm64: dts: imx: Fix imx8*-var-som touchscreen property sizescd227ac03fALSA: usb-audio: Fix undefined behavior due to shift overflowing the constant490815f0b5platform/x86: samsung-laptop: Fix an unsigned comparison which can never be negativecb17b56a9breset: tegra-bpmp: Restore Handle errors in BPMP responsed513ea9b7eARM: vexpress/spc: Avoid negative array index when !SMP052e4a661farm64: mm: fix p?d_leaf()18ff7a2efaarm64/mm: Remove [PUD|PMD]_TABLE_BIT from [pud|pmd]_bad()3bf8ca3501selftests: mlxsw: vxlan_flooding: Prevent flooding of unwanted packets520aab8b72dmaengine: idxd: add RO check for wq max_transfer_size write9a3c026dc3dmaengine: idxd: add RO check for wq max_batch_size writef593f49fcdnet: stmmac: Use readl_poll_timeout_atomic() in atomic state3d55b19574netlink: reset network and mac headers in netlink_dump()49516e6ed9ipv6: make ip6_rt_gc_expire an atomic_t078d839f11l3mdev: l3mdev_master_upper_ifindex_by_index_rcu should be using netdev_master_upper_dev_get_rcu0ac8f83d8fnet/sched: cls_u32: fix possible leak in u32_init_knode()93366275beip6_gre: Fix skb_under_panic in __gre6_xmit()200f96ebb3ip6_gre: Avoid updating tunnel->tun_hlen in __gre6_xmit()8fb76adb89net/packet: fix packet_sock xmit return value checkinga499cb5f3enet/smc: Fix sock leak when release after smc_shutdown()60592f16a4rxrpc: Restore removed timer deletionfc7116a79aigc: Fix BUG: scheduling while atomic46b0e4f998igc: Fix infinite loop in release_swfw_syncc075c3ea03esp: limit skb_page_frag_refill use to a single page3f7914dbeaspi: spi-mtk-nor: initialize spi controller after resumef714abf28fdmaengine: mediatek:Fix PM usage reference leak of mtk_uart_apdma_alloc_chan_resources9bc949a181dmaengine: imx-sdma: Fix error checking in sdma_event_remap12aa8021c7ASoC: codecs: wcd934x: do not switch off SIDO Buck when codec is in useb6f474cd30ASoC: msm8916-wcd-digital: Check failure for devm_snd_soc_register_component608fc58858ASoC: atmel: Remove system clock tree configuration for at91sam9g20ekd29c78d3f9dm: fix mempool NULL pointer race when completing IOcf9b195464ALSA: hda/realtek: Add quirk for Clevo NP70PNP8ce3820fc9ALSA: usb-audio: Clear MIDI port active flag after draining43ce33a68enet/sched: cls_u32: fix netns refcount changes in u32_change()04dd45d977gfs2: assign rgrp glock before compute_bitstructs378061c9b8perf tools: Fix segfault accessing sample_id xyarray5e8446e382tracing: Dump stacktrace trigger to the corresponding instance69848f9488mm: page_alloc: fix building error on -Werror=array-compare08ad7a770eetherdevice: Adjust ether_addr* prototypes to silence -Wstringop-overead95c07d1955ANDROID: Suppress build.sh deprecation warnings.d7beefb20aANDROID: Update the ABI symbol list1052f9bce6Linux 5.10.1125c62d3bf14ax25: Fix UAF bugs in ax25 timersf934fa478dax25: Fix NULL pointer dereferences in ax25 timers145ea8d213ax25: fix NPD bug in ax25_disconnecta4942c6feaax25: fix UAF bug in ax25_send_control()b20a5ab0f5ax25: Fix refcount leaks caused by ax25_cb_del()57cc15f5fdax25: fix UAF bugs of net_device caused by rebinding operation5ddae8d064ax25: fix reference count leaks of ax25_dev5ea00fc606ax25: add refcount in ax25_dev to avoid UAF bugs361288633bscsi: iscsi: Fix unbound endpoint error handling129db30599scsi: iscsi: Fix endpoint reuse regression26f827e095dma-direct: avoid redundant memory sync for swiotlb9a5a4d23e2timers: Fix warning condition in __run_timers()84837f43e5i2c: pasemi: Wait for write xfers to finish89496d80bfsmp: Fix offline cpu check in flush_smp_call_function_queue()cd02b2687ddm integrity: fix memory corruption when tag_size is less than digest size0a312ec66aARM: davinci: da850-evm: Avoid NULL pointer dereference0806f19305tick/nohz: Use WARN_ON_ONCE() to prevent console saturation0275c75955genirq/affinity: Consider that CPUs on nodes can be unbalanced1fcfe37d17drm/amdgpu: Enable gfxoff quirk on MacBook Pro68ae52efa1drm/amd/display: don't ignore alpha property on pre-multiplied modea263712ba8ipv6: fix panic when forwarding a pkt with no in6 dev659214603bnl80211: correctly check NL80211_ATTR_REG_ALPHA2 size912797e54cALSA: pcm: Test for "silence" field in struct "pcm_format_data"48d070ca5eALSA: hda/realtek: add quirk for Lenovo Thinkpad X12 speakers163e162471ALSA: hda/realtek: Add quirk for Clevo PD50PNT5e4dd17998btrfs: mark resumed async balance as writing1d2eda18f6btrfs: fix root ref counts in error handling in btrfs_get_root_ref9b7ec35253ath9k: Fix usage of driver-private space in tx_info0f65cedae5ath9k: Properly clear TX status area before reporting to mac80211cc21ae9326gcc-plugins: latent_entropy: use /dev/urandomc089ffc846memory: renesas-rpc-if: fix platform-device leak in error path342454231eKVM: x86/mmu: Resolve nx_huge_pages when kvm.ko is loaded06c348fde5mm: kmemleak: take a full lowmem check in kmemleak_*_phys()20ed94f818mm: fix unexpected zeroed page mapping with zram swap192e507ef8mm, page_alloc: fix build_zonerefs_node()000b3921b4perf/imx_ddr: Fix undefined behavior due to shift overflowing the constantca24c5e8f0drivers: net: slip: fix NPD bug in sl_tx_timeout()e8cf1e4d95scsi: megaraid_sas: Target with invalid LUN ID is deleted during scan5b7ce74b6bscsi: mvsas: Add PCI ID of RocketRaid 26404b44cd5840drm/amd/display: Fix allocate_mst_payload assert on resume34ea097fb6drm/amd/display: Revert FEC check in validationfa5ee7c423myri10ge: fix an incorrect free for skb in myri10ge_sw_tsod90df6da50net: usb: aqc111: Fix out-of-bounds accesses in RX fixup9c12fcf1d8net: axienet: setup mdio unconditionallyb643807a73tlb: hugetlb: Add more sizes to tlb_remove_huge_tlb_entry98973d2bddarm64: alternatives: mark patch_alternative() as `noinstr`2462faffbfregulator: wm8994: Add an off-on delay for WM8994 variantaa8cdedaf7gpu: ipu-v3: Fix dev_dbg frequency output150fe861c5ata: libata-core: Disable READ LOG DMA EXT for Samsung 840 EVOs1ff5359afanet: micrel: fix KS8851_MLL Kconfigd3478709edscsi: ibmvscsis: Increase INITIAL_SRP_LIMIT to 1024b9a110fa75scsi: lpfc: Fix queue failures when recovering from PCI parity erroraec36b98a1scsi: target: tcmu: Fix possible page UAF4366679805Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer1d7a5aae88drm/amdkfd: Check for potential null return of kmalloc_array()e5afacc826drm/amdgpu/vcn: improve vcn dpg stop procedured2e0931e6ddrm/amdkfd: Fix Incorrect VMIDs passed to HWS7fc0610ad8drm/amd/display: Update VTEM Infopacket definition6906e05cf3drm/amd/display: FEC check in timing validation756c61c168drm/amd/display: fix audio format not updated after edid updated76e086ce7bbtrfs: do not warn for free space inode in cow_file_range217190dc66btrfs: fix fallocate to use file_modified to update permissions consistently9b5d1b3413drm/amd: Add USBC connector ID6f9c06501dnet: bcmgenet: Revert "Use stronger register read/writes to assure ordering"504c15f07fdm mpath: only use ktime_get_ns() in historical selector4e166a4118cifs: potential buffer overflow in handling symlinks67677050cenfc: nci: add flush_workqueue to prevent uafbfba9722cfperf tools: Fix misleading add event PMU debug message280f721edctesting/selftests/mqueue: Fix mq_perf_tests to free the allocated cpu seteb8873b324sctp: Initialize daddr on peeled off socket45226fac4dscsi: iscsi: Fix conn cleanup and stop race during iscsid restart73805795c9scsi: iscsi: Fix offload conn cleanup when iscsid restarts699bd835c3scsi: iscsi: Move iscsi_ep_disconnect()46f37a34a5scsi: iscsi: Fix in-kernel conn failure handling8125738967scsi: iscsi: Rel ref after iscsi_lookup_endpoint()22608545b8scsi: iscsi: Use system_unbound_wq for destroy_work4029a1e992scsi: iscsi: Force immediate failure during shutdown17d14456f6scsi: iscsi: Stop queueing during ep_disconnectda9cf24aa7scsi: pm80xx: Enable upper inbound, outbound queuese08d269712scsi: pm80xx: Mask and unmask upper interrupt vectors 32-6335b91e49bcnet/smc: Fix NULL pointer dereference in smc_pnet_find_ib()98a7f6c4addrm/msm/dsi: Use connector directly in msm_dsi_manager_connector_init()5f78ad9383drm/msm: Fix range size vs end confusion5513f9a0b0cfg80211: hold bss_lock while updating nontrans_lista44938950enet/sched: taprio: Check if socket flags are valid08d5e3e954net: ethernet: stmmac: fix altr_tse_pcs function when using a fixed-link2ad9d890d8net: dsa: felix: suppress -EPROBE_DEFER errorsf2cc341fccnet/sched: fix initialization order when updating chain 0 head7a7cf84148mlxsw: i2c: Fix initialization error flow43e58e119anet: mdio: Alphabetically sort header inclusion9709c8b5cdgpiolib: acpi: use correct format charactersd67c900f19veth: Ensure eth header is in skb's linear part845f44ce3dnet/sched: flower: fix parsing of ethertype following VLAN header85ee17ca21SUNRPC: Fix the svc_deferred_event trace classaf12dd7123media: rockchip/rga: do proper error checking in probe5637129712firmware: arm_scmi: Fix sorting of retrieved clock rates16c628b0c6memory: atmel-ebi: Fix missing of_node_put in atmel_ebi_probecb66641f81drm/msm: Add missing put_task_struct() in debugfs path921fdc45a0btrfs: remove unused variable in btrfs_{start,write}_dirty_block_groups()5d131318bbACPI: processor idle: Check for architectural support for LPI503934df31cpuidle: PSCI: Move the `has_lpi` check to the beginning of the functioncfa98ffc42hamradio: remove needs_free_netdev to avoid UAF80a4df1464hamradio: defer 6pack kfree after unregister_netdevf0c31f192fdrm/amdkfd: Use drm_priv to pass VM from KFD to amdgpu232d82176fANDROID: Move BRANCH from build.config.common to .constants.6c8e5cb264Linux 5.10.111d36febbcd5powerpc: Fix virt_addr_valid() for 64-bit Book3E & 32-bit5c672073bcmm/sparsemem: fix 'mem_section' will never be NULL gcc 12 warning5973f7507airqchip/gic, gic-v3: Prevent GSI to SGI translations000e09462fDrivers: hv: vmbus: Replace smp_store_mb() with virt_store_mb()e1f540b752arm64: module: remove (NOLOAD) from linker script919823bd67selftests: cgroup: Test open-time cgroup namespace usage for migration checks637eca44b8selftests: cgroup: Test open-time credential usage for migration checks9dd39d2c65selftests: cgroup: Make cg_create() use 0755 for permission instead of 0644e74da71e66selftests/cgroup: Fix build on older distros4665722d36cgroup: Use open-time credentials for process migraton perm checksf089471d1bmm: don't skip swap entry even if zap_details specified58823a9b09ubsan: remove CONFIG_UBSAN_OBJECT_SIZE03b39bbbecdmaengine: Revert "dmaengine: shdma: Fix runtime PM imbalance on error"40e00885a6tools build: Use $(shell ) instead of `` to get embedded libperl's ccopts75c8558d41tools build: Filter out options and warnings not supported by clang6374faf49eperf python: Fix probing for some clang command line options79abc219baperf build: Don't use -ffat-lto-objects in the python feature test when building with clang-1382e4395014drm/amdkfd: Create file descriptor after client is added to smi_clients list326b408e7edrm/nouveau/pmu: Add missing callbacks for Tegra devices786ae8de3adrm/amdgpu/smu10: fix SoC/fclk units in auto modeff24114bb0irqchip/gic-v3: Fix GICR_CTLR.RWP polling451214b266perf: qcom_l2_pmu: fix an incorrect NULL check on list iteratorfc629224aaata: sata_dwc_460ex: Fix crash due to OOB write7e88a50704gpio: Restrict usage of GPIO chip irq members before initialization5f54364ff6RDMA/hfi1: Fix use-after-free bug for mm struct8bb4168291arm64: patch_text: Fixup last cpu should be mastera044bca8efbtrfs: prevent subvol with swapfile from being deleted82ae73ac96btrfs: fix qgroup reserve overflow the qgroup limitfc4bdaed4dx86/speculation: Restore speculation related MSRs during S3 resume8c9e26c890x86/pm: Save the MSR validity status at context setup2827328e64io_uring: fix race between timeout flush and removalf7e183b0a7mm/mempolicy: fix mpol_new leak in shared_policy_replace7d659cb176mmmremap.c: avoid pointless invalidate_range_start/end on mremap(old_size=0)6adc01a7aalz4: fix LZ4_decompress_safe_partial read out of bound8b6f04b4c9mmc: renesas_sdhi: don't overwrite TAP settings when HS400 tuning is complete029b417073mmc: mmci: stm32: correctly check all elements of sg list41a519c05bRevert "mmc: sdhci-xenon: fix annoying 1.8V regulator warning"9de98470dbarm64: Add part number for Arm Cortex-A78AE4604b5738dperf session: Remap buf if there is no space for event362ced3769perf tools: Fix perf's libperf_print callback65210fac63perf: arm-spe: Fix perf report --mem-modebd905fed87iommu/omap: Fix regression in probe for NULL pointer dereferenceb3c00be2ffSUNRPC: svc_tcp_sendmsg() should handle errors from xdr_alloc_bvec()9a45e08636SUNRPC: Handle low memory situations in call_status()132cbe2f18SUNRPC: Handle ENOMEM in call_transmit_status()aed30a2054io_uring: don't touch scm_fp_list after queueing skb594205b493drbd: Fix five use after free bugs in get_initial_state970a6bb729bpf: Support dual-stack sockets in bpf_tcp_check_syncookie6c17f4ef3cspi: bcm-qspi: fix MSPI only access with bcm_qspi_exec_mem_op()8928239e5eqede: confirm skb is allocated before usingb7893388bbnet: phy: mscc-miim: reject clause 45 register accesses08ff0e74farxrpc: fix a race in rxrpc_exit_net()5ae05b5eb5net: openvswitch: fix leak of nested actions42ab401d22net: openvswitch: don't send internal clone attribute to the userspace.e54ea8fc51ice: synchronize_rcu() when terminating ringse3dd1202abipv6: Fix stats accounting in ip6_pkt_dropffce126c95ice: Do not skip not enabled queues in ice_vc_dis_qs_msgb003fc4913ice: Set txq_teid to ICE_INVAL_TEID on ring creationebd1e3458ddpaa2-ptp: Fix refcount leak in dpaa2_ptp_probe43c2d7890eIB/rdmavt: add lock to call to rvt_error_qp to prevent a race condition3a57babfb6RDMA/mlx5: Don't remove cache MRs when a delay is neededd8992b393fsfc: Do not free an empty page_ring0ac74169ebbnxt_en: reserve space inside receive page for skb_shared_infof8b0ef0a58drm/imx: Fix memory leak in imx_pd_connector_get_modes25bc9fd4c8drm/imx: imx-ldb: Check for null pointer after calling kmemdup02ab4abe5bnet: stmmac: Fix unset max_speed difference between DT and non-DT platforms63ea57478anet: ipv4: fix route with nexthop object delete warning4be6ed0310ice: Clear default forwarding VSI during VSI release589154d0f1net/tls: fix slab-out-of-bounds bug in decrypt_internalc5f77b5953scsi: zorro7xx: Fix a resource leak in zorro7xx_remove_one()45b9932b4dNFSv4: fix open failure with O_ACCMODE flagc688705a39Revert "NFSv4: Handle the special Linux file open access mode"cf580d2e38Drivers: hv: vmbus: Fix potential crash on module unload0c122eb3a1drm/amdgpu: fix off by one in amdgpu_gfx_kiq_acquire()84e5dfc05fRevert "hv: utils: add PTP_1588_CLOCK to Kconfig to fix build"3c3fbfa6ddmm: fix race between MADV_FREE reclaim and blkdev direct IO read1753a49e26parisc: Fix patch code locking and flushingf7c3522030parisc: Fix CPU affinity for Lasi, WAX and Dino chipsc74e2f6eccNFS: Avoid writeback threads getting stuck in mempool_alloc()34681aeddcNFS: nfsiod should not block forever in mempool_alloc()7a506fabcfSUNRPC: Fix socket waits for write buffer spaceb9c5ac0a15jfs: prevent NULL deref in diFreec69b442125virtio_console: eliminate anonymous module_init & module_exit3309b32217serial: samsung_tty: do not unlock port->lock for uart_write_wakeup()9cb90f9ad5x86/Kconfig: Do not allow CONFIG_X86_X32_ABI=y with llvm-objcopyb3882e78aaNFS: swap-out must always use STABLE writes.d4170a2821NFS: swap IO handling is slightly different for O_DIRECT IO4b6f122bdfSUNRPC: remove scheduling boost for "SWAPPER" tasks.f4fc47e71eSUNRPC/xprt: async tasks mustn't block waiting for memoryf9244d31e0SUNRPC/call_alloc: async tasks mustn't block waiting for memorye2b2542f74clk: Enforce that disjoints limits are invalid1e9b5538cfclk: ti: Preserve node in ti_dt_clocks_register()a2a0e04f64xen: delay xen_hvm_init_time_ops() if kdump is boot on vcpu>=324a2544ce24NFSv4: Protect the state recovery thread against direct reclaim9b9feec97cNFSv4.2: fix reference count leaks in _nfs42_proc_copy_notify()2e16895d06w1: w1_therm: fixes w1_seq for ds28ea00 sensors93498c6e77staging: wfx: fix an error handling in wfx_init_common()8f1d24f85fphy: amlogic: meson8b-usb2: Use dev_err_probe()aa0b729678staging: vchiq_core: handle NULL result of find_service_by_handlebe4ecca958clk: si5341: fix reported clk_rate when output divider is 2c9cf6baabfminix: fix bug when opening a file with O_DIRECT8d9efd4434init/main.c: return 1 from handled __setup() functionsf442978612ceph: fix memory leak in ceph_readdir when note_last_dentry returns errord745512d54netlabel: fix out-of-bounds memory accesses2cc803804eBluetooth: Fix use after free in hci_send_acl789621df19MIPS: ingenic: correct unit node address61e25021e6xtensa: fix DTC warning unit_address_formatf6b9550f53usb: dwc3: omap: fix "unbalanced disables for smps10_out1" on omap5evma4dd3e9e5anet: sfp: add 2500base-X quirk for Lantech SFP module278b652f0anet: limit altnames to 64k total423e7107f6net: account alternate interface name memory74c4d50255can: isotp: set default value for N_As to 50 micro seconds1d7effe5ffscsi: libfc: Fix use after free in fc_exch_abts_resp()02222bf4f0powerpc/secvar: fix refcount leak in format_show()fd416c3f5aMIPS: fix fortify panic when copying asm exception handlers7c657c0694PCI: endpoint: Fix misused goto label79cfc0052fbnxt_en: Eliminate unintended link toggle during FW reset9567d54e70Bluetooth: use memset avoid memory leaksf9b183f133Bluetooth: Fix not checking for valid hdev on bt_dev_{info,warn,err,dbg}647b35aaf4tuntap: add sanity checks about msg_controllen in sendmsg797b4ea951macvtap: advertise link netns via netlink142ae7d4f2mips: ralink: fix a refcount leak in ill_acc_of_setup()f2565cb40enet/smc: correct settings of RMB window update limit224903cc60scsi: hisi_sas: Free irq vectors in order for v3 HWf49ffaa85dscsi: aha152x: Fix aha152x_setup() __setup handler return value91ee8a14efmt76: mt7615: Fix assigning negative values to unsigned variabled83574666bscsi: pm8001: Fix memory leak in pm8001_chip_fw_flash_update_req()a0bb65eadbscsi: pm8001: Fix tag leaks on error2051044d79scsi: pm8001: Fix task leak in pm8001_send_abort_all()3bd9a28798scsi: pm8001: Fix pm8001_mpi_task_abort_resp()ef969095c4scsi: pm8001: Fix pm80xx_pci_mem_copy() interfacefe4b6d5a0ddrm/amdkfd: make CRAT table missing message informational only2f2f017ea8dm: requeue IO if mapping table not yet available71c8df33fddm ioctl: prevent potential spectre v1 gadgetf655b724b4ipv4: Invalidate neighbour for broadcast address upon address additionbae03957e8iwlwifi: mvm: Correctly set fragmented EBS9538563d31power: supply: axp288-charger: Set Vhold to 4.4Vc66cc04043PCI: pciehp: Add Qualcomm quirk for Command Completed erratumb1b27b0e8dtcp: Don't acquire inet_listen_hashbucket::lock with disabled BH.b02a1a6502PCI: endpoint: Fix alignment fault error in copy tests4820847e8busb: ehci: add pci device support for Aspeed platforms0b9cf0b599iommu/arm-smmu-v3: fix event handling soft lockupe07e420a00PCI: aardvark: Fix support for MSI interrupts6694b8643bdrm/amdgpu: Fix recursive locking warningea21eaea7fpowerpc: Set crashkernel offset to mid of RMA regionfb5ac62fbeipv6: make mc_forwarding atomic5baf92a2c4libbpf: Fix build issue with llvm-readelf26a1e4739ecfg80211: don't add non transmitted BSS to 6GHz scanned channels9a56e2b271mt76: dma: initialize skip_unmap in mt76_dma_rx_fillb42b6d0ec3power: supply: axp20x_battery: properly report current when dischargingde9505936cscsi: bfa: Replace snprintf() with sysfs_emit()ed7db95920scsi: mvsas: Replace snprintf() with sysfs_emit()995f517888bpf: Make dst_port field in struct bpf_sock 16-bit wide339bd0b55eath11k: mhi: use mhi_sync_power_up()c6a815f5abath11k: fix kernel panic during unload/load ath11k modulese4d2d72013powerpc: dts: t104xrdb: fix phy type for FMAN 4/502e2ee8619ptp: replace snprintf with sysfs_emit9ea17b9f1dusb: gadget: tegra-xudc: Fix control endpoint's definitions07971b818eusb: gadget: tegra-xudc: Do not program SPARAM927beb05aadrm/amd/amdgpu/amdgpu_cs: fix refcount leak of a dma_fence obj85313d9bc7drm/amd/display: Add signal type check when verify stream backends same9d7d83d039ath5k: fix OOB in ath5k_eeprom_read_pcal_info_5111850c4351e8drm: Add orientation quirk for GPD Win Maxa24479c5e9KVM: x86/emulator: Emulate RDPID only if it is enabled in guest66b0fa6b22KVM: x86/svm: Clear reserved bits written to PerfEvtSeln MSRs2e52a29470rtc: wm8350: Handle error for wm8350_register_irq0777fe98a4gfs2: gfs2_setattr_size error path fixf349d7f9eegfs2: Fix gfs2_release for non-writers regression3f53715fd5gfs2: Check for active reservation in gfs2_release2dc49f58a2ubifs: Rectify space amount budget for mkdir/tmpfile operations65eadb5fc4Merge 5.10.110 into android13-5.10-lts35ce455788ANDROID: Update the ABI symbol list3238bffaf9Linux 5.10.110cf342cbfb3PCI: xgene: Revert "PCI: xgene: Use inbound resources for setup"a25864c5bcarm64: Do not defer reserve_crashkernel() for platforms with no DMA memory zones558564db44coredump: Use the vma snapshot in fill_files_noteb7933f145acoredump/elf: Pass coredump_params into fill_note_infob043ae637acoredump: Remove the WARN_ON in dump_vma_snapshot936c8be4d1coredump: Snapshot the vmas in do_coredump5318cdf4fdcan: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error path869016a293can: m_can: m_can_tx_handler(): fix use after free of skbe90518d10cKVM: x86/mmu: do compare-and-exchange of gPTE via the user addresse36c45263aopenvswitch: Fixed nd target mask field in the flow dump.415edc68b6docs: sysctl/kernel: add missing bit to panic_print272c74323dum: Fix uml_mconsole stop/goc0a6a54738ARM: dts: spear13xx: Update SPI dma propertiesea3912af8bARM: dts: spear1340: Update serial node properties74f7971985ASoC: topology: Allow TLV control to be either read or write3ca47556d9ubi: fastmap: Return error code if memory allocation fails in add_aeb()7704f243cbdt-bindings: spi: mxic: The interrupt property is not mandatory648ab1dcc1dt-bindings: mtd: nand-controller: Fix a comment in the examples71917e45e1dt-bindings: mtd: nand-controller: Fix the reg property description73f2f37417bpf: Fix comment for helper bpf_current_task_under_cgroup()90805175a2bpf: Adjust BPF stack helper functions to accommodate skip > 086489492e8mm/usercopy: return 1 from hardened_usercopy __setup() handler81a04b9a32mm/memcontrol: return 1 from cgroup.memory __setup() handlerf321621f5cARM: 9187/1: JIVE: fix return value of __setup handlerd57feed3b1mm/mmap: return 1 from stack_guard_gap __setup() handler73f7cbb151batman-adv: Check ptr for NULL before reducing its refcntf6da750bfaASoC: soc-compress: Change the check for codec_daid3f786b7cfstaging: mt7621-dts: fix pinctrl-0 items to be size-1 items on ethernet12e380bb6fproc: bootconfig: Add null pointer check90ec1b1538can: isotp: restore accidentally removed MSG_PEEK feature16960ac92bplatform/chrome: cros_ec_typec: Check for EC devicee5b681822cACPI: CPPC: Avoid out of bounds access when parsing _CPC data785a53373criscv module: remove (NOLOAD)b27de7011cio_uring: fix memory leak of uid in files registration20499ed3c0ARM: iop32x: offset IRQ numbers by 1432b057f8eubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctlf28a857a61ASoC: mediatek: mt6358: add missing EXPORT_SYMBOLsecfc3f8a63pinctrl: nuvoton: npcm7xx: Use %zu printk format for ARRAY_SIZE()503868a7c0pinctrl: nuvoton: npcm7xx: Rename DS() macro to DSTR()d9afc5146bwatchdog: rti-wdt: Add missing pm_runtime_disable() in probe function402b53dc7cpinctrl: pinconf-generic: Print arguments for bias-pull-*7169f60110watch_queue: Free the page array when watch_queue is dismantlede64dc94990crypto: arm/aes-neonbs-cbc - Select generic cbc and aesa16f5ae8admailbox: imx: fix wakeup failure from freeze mode051360e513rxrpc: Fix call timer start racing with call destructiona94d98e06enet: hns3: fix software vlan talbe of vlan 0 inconsistent with hardwarec73af4bc8agfs2: Make sure FITRIM minlen is rounded up to fs block size33c204266crtc: check if __rtc_read_time was successful381636f33fXArray: Update the LRU list in xas_split()3b9fabe8f6can: mcp251xfd: mcp251xfd_register_get_dev_id(): fix return of error valueef0acc5141can: mcba_usb: properly check endpoint type0801a51d79can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path1ac49c8fd4XArray: Fix xas_create_range() when multi-order entry present49f77ab50awireguard: socket: ignore v6 endpoints when ipv6 is disabled096f9d35cawireguard: socket: free skb in send6 when ipv6 is disabledcd032f218cwireguard: queueing: use CFI-safe ptr_ring cleanup function8a0c70c238ubifs: rename_whiteout: correct old_dir size computingc34ae24a25ubifs: Fix to add refcount once page is set private07a209fadeubifs: Fix read out-of-bounds in ubifs_wbuf_write_nolock()d07a242169ubifs: setflags: Make dirtied_ino_d 8 bytes aligned13b2a8151eubifs: Add missing iput if do_tmpfile() failed in rename whiteout83e42a7842ubifs: Fix deadlock in concurrent rename whiteout and inode writebacka90e2dbe66ubifs: rename_whiteout: Fix double free for whiteout_ui->data0c307349feASoC: SOF: Intel: Fix NULL ptr dereference when ENOMEM0fb470eb48KVM: SVM: fix panic on out-of-bounds guest IRQcd8c2d7c7cKVM: x86: fix sending PV IPIeccfee4494KVM: Prevent module exit until all VMs are freed09c771c45cKVM: x86: Forbid VMM to set SYNIC/STIMER MSRs when SynIC wasn't activatedaea4ffdcf3platform: chrome: Split trace include filed3a913ba1fscsi: qla2xxx: Use correct feature type field during RFF_ID processing633450063cscsi: qla2xxx: Reduce false trigger to logindd48727cabscsi: qla2xxx: Fix N2N inconsistent PLOGI0910a791a6scsi: qla2xxx: Fix missed DMA unmap for NVMe ls requestsf296e888e9scsi: qla2xxx: Fix hang due to session stuckedea037716scsi: qla2xxx: Fix incorrect reporting of task management failure9dc104edd7scsi: qla2xxx: Fix disk failure to rediscoverf97316dd39scsi: qla2xxx: Suppress a kernel complaint in qla_create_qpair()0e4a89efc2scsi: qla2xxx: Check for firmware dump already collectedef10a7530cscsi: qla2xxx: Add devids and conditionals for 28xxbad77c9a47scsi: qla2xxx: Fix device reconnect in loop topology8b52e20c22scsi: qla2xxx: Fix warning for missing error code7c9745421dscsi: qla2xxx: Fix wrong FDMI data for 64G adapter7fef50214dscsi: qla2xxx: Fix scheduling while atomicc45147018dscsi: qla2xxx: Fix stuck session in gpdb031547f4c6powerpc: Fix build errors with newer binutils68fa67e939powerpc/lib/sstep: Fix build errors with newer binutilsad806b4022powerpc/lib/sstep: Fix 'sthcx' instructionf39a330939powerpc/kasan: Fix early region not updated correctly89e5a42687KVM: x86/mmu: Check for present SPTE when clearing dirty bit in TDP MMUa3ad453008ALSA: hda/realtek: Add alc256-samsung-headphone fixupaa2ad067cdmedia: atomisp: fix bad usage at error handling logic2412a5d294mmc: host: Return an error when ->enable_sdio_irq() ops is missing808990afd8media: hdpvr: initialize dev->worker at hdpvr_register_videodev32582f82dfmedia: Revert "media: em28xx: add missing em28xx_close_extension"b1c2857752video: fbdev: sm712fb: Fix crash in smtcfb_write()e7bb29df2aARM: mmp: Fix failure to remove sram deviceadd823a9a5ARM: tegra: tamonten: Fix I2C3 pad setting08ec8450f3lib/test_lockup: fix kernel pointer check for separate address spaces40a5c93a74uaccess: fix type mismatch warnings from access_ok()a49b687a75media: cx88-mpeg: clear interrupt status register before streaming video4606350268ASoC: soc-core: skip zero num_dai component in searching dai namea840fc067eARM: dts: bcm2711: Add the missing L1/L2 cache information681a317034video: fbdev: udlfb: replace snprintf in show functions with sysfs_emita7c624abf6video: fbdev: omapfb: panel-tpo-td043mtea1: Use sysfs_emit() instead of snprintf()543dae0a46video: fbdev: omapfb: panel-dsi-cm: Use sysfs_emit() instead of snprintf()910715c4b4arm64: defconfig: build imx-sdma as a module14df2556a1ARM: dts: imx7: Use audio_mclk_post_div instead audio_mclk_root_clkc241cfd0a5ARM: ftrace: avoid redundant loads or clobbering IP41082d6432media: atomisp: fix dummy_ptr check to avoid duplicate active_bob554196e6dmedia: atomisp_gmin_platform: Add DMI quirk to not turn AXP ELDO2 regulator off on some boards370b50492eASoC: madera: Add dependencies on MFD0020667edcARM: dts: bcm2837: Add the missing L1/L2 cache informationf040c08102ARM: dts: qcom: fix gic_irq_domain_translate warnings for msm8960da210b1b55video: fbdev: omapfb: acx565akm: replace snprintf with sysfs_emit8c7e2141fbvideo: fbdev: cirrusfb: check pixclock to avoid divide by zero1e33f19746video: fbdev: w100fb: Reset global state08dff48201video: fbdev: nvidiafb: Use strscpy() to prevent buffer overflow99e3f83539media: ir_toy: free before error exitingd658178b5amedia: staging: media: zoran: fix various V4L2 compliance errorsbafec1a6bamedia: staging: media: zoran: calculate the right buffer number for zoran_reap_stat_combd01629315media: staging: media: zoran: move videodev allocb230f2d944ntfs: add sanity check on allocation sizef7e8aff062f2fs: compress: fix to print raw data size in error path of lz4 decompressiond91d1e681cNFSD: Fix nfsd_breaker_owns_lease() return values498b7088dbf2fs: fix to do sanity check on curseg->alloc_type330d0e44fcext4: don't BUG if someone dirty pages without asking ext4 firstcd6d719534ext4: fix ext4_mb_mark_bb() with flex_bg with fast_commit69d2421b55ext4: correct cluster len and clusters changed accounting in ext4_mb_mark_bbecd384c436locking/lockdep: Iterate lock_classes directly when reading lockdep files3ad817f1bdspi: tegra20: Use of_device_get_match_data()1c200c8bcenvme-tcp: lockdep: annotate in-kernel sockets7e4967e913parisc: Fix handling off probe non-access faultsede1ef1a7dPM: core: keep irq flags in device_pm_check_callbacks()227718c8bbACPI/APEI: Limit printable size of BERT table datacc051f497eRevert "Revert "block, bfq: honor already-setup queue merges""1b69302bfalib/raid6/test/Makefile: Use $(pound) instead of \# for Make 4.31b87ce6a77ACPICA: Avoid walking the ACPI Namespace if it is not theredf6e00b1a5bfq: fix use-after-free in bfq_dispatch_requestdd85ed4af8fs/binfmt_elf: Fix AT_PHDR for unusual ELF files9fc899ce5airqchip/nvic: Release nvic_base upon failure4bbd910de1irqchip/qcom-pdc: Fix broken lockingf038185b6aFix incorrect type in assignment of ipv6 port for audit012c572007loop: use sysfs_emit() in the sysfs xxx show()448857f580selinux: allow FIOCLEX and FIONCLEX with policy capability4b9b60b5bfselinux: use correct type for context length7507ead1e9block, bfq: don't move oom_bfqq79b16d00depinctrl: npcm: Fix broken references to chip->parent_device9d1d8e5e42gcc-plugins/stackleak: Exactly match strings instead of prefixesb0f2f89d74regulator: rpi-panel: Handle I2C errors/timing to the Atmel2784604c8cLSM: general protection fault in legacy_parse_parame600b5973efs: fix fd table size alignment properly327f07e370lib/test: use after free in register_test_dev_kmod()00d2b9fe5efs: fd tables have to be multiples of BITS_PER_LONG1752fcd404net: dsa: bcm_sf2_cfp: fix an incorrect NULL check on list iteratoredb91a475dNFSv4/pNFS: Fix another issue with a list iterator pointing to the head5c94b6205enet/x25: Fix null-ptr-deref caused by x25_disconnect4896c308a5qlcnic: dcb: default to returning -EOPNOTSUPP2165d0ebfbselftests: test_vxlan_under_vrf: Fix broken test casef98dc124a4net: phy: broadcom: Fix brcm_fet_config_init()3e7a483af3net: hns3: fix bug when PF set the duplicate MAC address for VFs3eb92660e6net: enetc: report software timestamping via SO_TIMESTAMPINGe9445a7a59xen: fix is_xen_pmu()af0c3ced24clk: Initialize orphan req_rate845e734f97clk: qcom: gcc-msm8994: Fix gpll4 widthe2a2625392kdb: Fix the putarea helper functiona9fa7d48a1NFSv4.1: don't retry BIND_CONN_TO_SESSION on session error8cd30d28danetfilter: nf_conntrack_tcp: preserve liberal flag in tcp optionsfbd56a61cejfs: fix divide error in dbNextAGacb96e62e6driver core: dd: fix return value of __setup handler89748be18ffirmware: google: Properly state IOMEM dependency3d934d7b90kgdbts: fix return value of __setup handlerf65ba8b988serial: 8250: fix XOFF/XON sending when DMA is used45e95a7bf8kgdboc: fix return value of __setup handler96038b1cf4tty: hvc: fix return value of __setup handler566e30289dpinctrl/rockchip: Add missing of_node_put() in rockchip_pinctrl_probe669b05ff43pinctrl: nomadik: Add missing of_node_put() in nmk_pinctrl_probe9d095fe2fbpinctrl: mediatek: paris: Skip custom extra pin config dump for virtual GPIOs861946289dpinctrl: mediatek: paris: Fix pingroup pin config state readback7675fb2aafpinctrl: mediatek: paris: Fix "argument" argument type for mtk_pinconf_get()901e192ac9pinctrl: mediatek: paris: Fix PIN_CONFIG_BIAS_* readback72ea0fefeapinctrl: mediatek: Fix missing of_node_put() in mtk_pctrl_initfddbfe43bfstaging: mt7621-dts: fix GB-PC2 devicetree00e0739ca1staging: mt7621-dts: fix pinctrl properties for ethernet47c31fe8castaging: mt7621-dts: fix formatting59ec187d7cstaging: mt7621-dts: fix LEDs and pinctrl on GB-PC1 devicetree942f68bf29NFS: remove unneeded check in decode_devicenotify_args()e025c66387clk: tegra: tegra124-emc: Fix missing put_device() call in emc_ensure_emc_driver54c8128297clk: clps711x: Terminate clk_div_table with sentinel element9ff533033dclk: loongson1: Terminate clk_div_table with sentinel elementbb680cabf2clk: actions: Terminate clk_div_table with sentinel element431f8a9cecnvdimm/region: Fix default alignment for small regionsf7210ca29aremoteproc: qcom_q6v5_mss: Fix some leaks in q6v5_alloc_memory_region7a494580a8remoteproc: qcom_wcnss: Add missing of_node_put() in wcnss_alloc_memory_region5c1d484d96remoteproc: qcom: Fix missing of_node_put in adsp_alloc_memory_regionf95fd61dd8dmaengine: hisi_dma: fix MSI allocate fail when reload hisi_dmad047d68ff0clk: qcom: clk-rcg2: Update the frac table for pixel clock334720f418clk: qcom: clk-rcg2: Update logic to calculate D value for RCG639744b242clk: at91: sama7g5: fix parents of PDMCs' GCLK0553ecbce9clk: imx7d: Remove audio_mclk_root_clk867258d3f3dma-debug: fix return value of __setup handlers2f3885514eNFS: Return valid errors from nfs2/3_decode_dirent()7b59afe84ahabanalabs: Add check for pci_enable_deviceafcbc63752iio: adc: Add check for devm_request_threaded_irqdf2dc4cf71serial: 8250: Fix race condition in RTS-after-send handling469ce5119fNFS: Use of mapping_set_error() results in spurious errors659fe4d653serial: 8250_lpss: Balance reference count for PCI DMA device0aebb3944aserial: 8250_mid: Balance reference count for PCI DMA devicec92bd51313phy: dphy: Correct lpx parameter and its derivatives(ta_{get,go,sure})80805f555eclk: qcom: ipq8074: Use floor ops for SDCC1 clockfd2601e366pinctrl: renesas: checker: Fix miscalculation of number of statesc5cf977515pinctrl: renesas: r8a77470: Reduce size for narrow VIN1 channelb5db33a81estaging:iio:adc:ad7280a: Fix handing of device address bit reversing.f5b01abf5fiio: mma8452: Fix probe failing when an i2c_device_id is used8b89c9e68aclk: qcom: ipq8074: fix PCI-E clock oopsa70d5dbe2esoundwire: intel: fix wrong register name in intel_shim_wake091704a9a7cpufreq: qcom-cpufreq-nvmem: fix reading of PVS Valid fusef90ad94322misc: alcor_pci: Fix an error handling path553541c453fsi: Aspeed: Fix a potential double freecb212c3f0dfsi: aspeed: convert to devm_platform_ioremap_resourcec0b3c06414pwm: lpc18xx-sct: Initialize driver data and hardware before pwmchip_add()2cd05c38a2mxser: fix xmit_buf leak in activate when LSR == 0xff8513c93eadmfd: asic3: Add missing iounmap() on error asic3_mfd_probe084be6309ftipc: fix the timer expires after interval 100ms5d8162371copenvswitch: always update flow key after nat4593c76a65tcp: ensure PMTU updates are processed during fastopenb26091a020net: bcmgenet: Use stronger register read/writes to assure ordering9088614323PCI: Avoid broken MSI on SB600 USB devices75a4a97b74selftests/bpf/test_lirc_mode2.sh: Exit with proper code0d3ad6142ai2c: mux: demux-pinctrl: do not deactivate a master that is not activec483f8002di2c: meson: Fix wrong speed use from probeb089836218af_netlink: Fix shift out of bounds in group mask calculation40f3b8dadaipv4: Fix route lookups when handling ICMP redirects and PMTU updates70a6cf749dBluetooth: btmtksdio: Fix kernel oops in btmtksdio_interruptb441fcdff2Bluetooth: call hci_le_conn_failed with hdev lock in hci_le_conn_failed876cfe1380selftests/bpf: Fix error reporting from sock_fields programsac1ec6f319bareudp: use ipv6_mod_enabled to check if IPv6 enabledc037e13539can: isotp: support MSG_TRUNC flag when reading from socketf402c49865can: isotp: return -EADDRNOTAVAIL when reading from unbound socket8a9d996d4eUSB: storage: ums-realtek: fix error code in rts51x_read_mem()f9a6661009samples/bpf, xdpsock: Fix race when running for fix duration of timecd84ea3920bpf, sockmap: Fix double uncharge the mem of sk_msg7b812a369ebpf, sockmap: Fix more uncharged while msg has more_databec34a91ebbpf, sockmap: Fix memleak in tcp_bpf_sendmsg while sk msg is fullc98d903ff9RDMA/mlx5: Fix memory leak in error flow for subscribe event routinea3587259aemtd: rawnand: atmel: fix refcount issue in atmel_nand_controller_initfa3d444245MIPS: pgalloc: fix memory leak caused by pgd_free()8c4808ff9eMIPS: RB532: fix return value of __setup handleref1728e3cbmips: cdmm: Fix refcount leak in mips_cdmm_phys_base315772133aath10k: Fix error handling in ath10k_setup_msa_resources71f311b123vxcan: enable local echo for sent CAN frames3c2a397849powerpc: 8xx: fix a return value error in mpc8xx_pic_init956fab99adplatform/x86: huawei-wmi: check the return value of device_create_file()1ba28cb692selftests/bpf: Make test_lwt_ip_encap more stable and faster08ab406781libbpf: Unmap rings when umem deleted6fa8edfc90mfd: mc13xxx: Add check for mc13xxx_irq_requestbcf93175edpowerpc/sysdev: fix incorrect use to determine if list is emptyab0a335b54mips: DEC: honor CONFIG_MIPS_FP_SUPPORT=nbbd91cdb62net: axienet: fix RX ring refill allocation failure handling9ec698984dPCI: Reduce warnings on possible RW1C corruptiona84cb039d2IB/hfi1: Allow larger MTU without AIP48d23ef901power: supply: wm8350-power: Add missing free in free_charger_irq9d3dab40afpower: supply: wm8350-power: Handle error for wm8350_register_irq5cf1371628i2c: xiic: Make bus names uniquef01e08083chv_balloon: rate-limit "Unhandled message" warningba2c6e353bKVM: x86/emulator: Defer not-present segment check in __load_segment_descriptor()fa9089949dKVM: x86: Fix emulation in writing cr83e7e73ae2bpowerpc/Makefile: Don't pass -mcpu=powerpc64 when building 32-bit05abd49972powerpc/mm/numa: skip NUMA_NO_NODE onlining in parse_numa_properties()3e04a837dblibbpf: Skip forward declaration when counting duplicated type names6bb107332dgpu: host1x: Fix a memory leak in 'host1x_remove()'d1c7759304bpf, arm64: Feed byte-offset into bpf line info694398af5fbpf, arm64: Call build_prologue() first in first JIT pass06a0001366drm/bridge: cdns-dsi: Make sure to to create proper aliases for dta3d53f0005scsi: hisi_sas: Change permission of parameter prot_mask705c70399epower: supply: bq24190_charger: Fix bq24190_vbus_is_enabled() wrong false return1e06710c43drm/tegra: Fix reference leak in tegra_dsi_ganged_probe9ffa07c699ext2: correct max file size computing60605acf5bTOMOYO: fix __setup handlers return valuesadb7c8d1dedrm/amd/display: Remove vupdate_int_entry definitione462b0f518RDMA/mlx5: Fix the flow of a miss in the allocation of a cache ODP MR279f318bd7scsi: pm8001: Fix abort all task initialization780c668a2dscsi: pm8001: Fix NCQ NON DATA command completion handlingf7a3f9e4e8scsi: pm8001: Fix NCQ NON DATA command task initializationf76bbee39escsi: pm8001: Fix le32 values handling in pm80xx_chip_sata_req()6bc86bca35scsi: pm8001: Fix le32 values handling in pm80xx_chip_ssp_io_req()27ccdcaa01scsi: pm8001: Fix payload initialization in pm80xx_encrypt_update()6c0e850c22scsi: pm8001: Fix le32 values handling in pm80xx_set_sas_protocol_timer_config()edde1ede76scsi: pm8001: Fix payload initialization in pm80xx_set_thermal_config()257a55622cscsi: pm8001: Fix command initialization in pm8001_chip_ssp_tm_req()f55a7bc38fscsi: pm8001: Fix command initialization in pm80XX_send_read_log()5349cde1dfdm crypt: fix get_key_size compiler warning if !CONFIG_KEYSd4862bea08drm/msm/dpu: fix dp audio condition7b52fb813cdrm/msm/dpu: add DSPP blocks teardown413c62697bdrm/msm/dp: populate connector of struct dp_panel441a83ff27iwlwifi: mvm: Fix an error code in iwl_mvm_up()c12692c3e9iwlwifi: Fix -EIO error code that is never returnedec376f5c11dax: make sure inodes are flushed before destroy cache5e6b030ac3IB/cma: Allow XRC INI QPs to set their local ACK timeout9c384e1afadrm/amd/display: Add affected crtcs to atomic state for dsc mst unplug80b96ac9d2drm/amd/pm: enable pm sysfs write for one VF mode06e778d184iommu/ipmmu-vmsa: Check for error num after setting maskab63b24ae6HID: i2c-hid: fix GET/SET_REPORT for unnumbered reports879356a6a0power: supply: ab8500: Fix memory leak in ab8500_fg_sysfs_initf03ef518c1drm/bridge: dw-hdmi: use safe format when first in bridge chaine0e25e131dPCI: aardvark: Fix reading PCI_EXP_RTSTA_PME bit on emulated bridgeb1af8b9ec0livepatch: Fix build failure on 32 bits processors6f095441f8scripts/dtc: Call pkg-config POSIXly correct080822563bnet: dsa: mv88e6xxx: Enable port policy support on 60972ac4f049dbmt76: mt7615: check sta_rates pointer in mt7615_sta_rate_tbl_update2430af1241mt76: mt7603: check sta_rates pointer in mt7603_sta_rate_tbl_update232c1cc986mt76: mt7915: use proper aid value in mt7915_mcu_sta_basic_tlv253cc4aafcmt76: mt7915: use proper aid value in mt7915_mcu_wtbl_generic_tlv in sta modeb5d363ff17powerpc/perf: Don't use perf_hw_context for trace IMC PMUc18b538617KVM: PPC: Book3S HV: Check return value of kvmppc_radix_init8b64c158a0powerpc: dts: t1040rdb: fix ports names for Seville Ethernet switchbe703360edray_cs: Check ioremap return value43f2fe2a69power: reset: gemini-poweroff: Fix IRQ check in gemini_poweroff_probeda71a1483bi40e: respect metadata on XSK Rx to skbb2e48cd141i40e: don't reserve excessive XDP_PACKET_HEADROOM on XSK Rx to skbe8fe653fa7KVM: PPC: Fix vmx/vsx mixup in mmio emulation11cb9eba06RDMA/core: Set MR type in ib_reg_user_mr11f11ac281ath9k_htc: fix uninit value bugs6e669baa33drm/amd/pm: return -ENOTSUPP if there is no get_dpm_ultimate_freq function19a7eba284drm/amd/display: Fix a NULL pointer dereference in amdgpu_dm_connector_add_common_modes()9abee51534drm/nouveau/acr: Fix undefined behavior in nvkm_acr_hsfw_load_bl()47402eaf88ionic: fix type complaint in ionic_dev_cmd_clean()1ba10e5c39drm/edid: Don't clear formats if using deep colord99e7feaedmtd: rawnand: gpmi: fix controller timings setting364b2eee62mtd: onenand: Check for error irq96ea88eb9bBluetooth: hci_serdev: call init_rwsem() before p->open()b267a8118cudmabuf: validate ubuf->pagecount56722aa77blibbpf: Fix possible NULL pointer dereference when destroying skeleton4a9c268a40drm/panfrost: Check for error num after setting mask5d1114ede5ath10k: fix memory overwrite of the WoWLAN wakeup packet patternfb2be762a4drm: bridge: adv7511: Fix ADV7535 HPD enablementd9d61beb21drm/bridge: nwl-dsi: Fix PM disable depth imbalance in nwl_dsi_probe064e7f7532drm/bridge: Add missing pm_runtime_disable() in __dw_mipi_dsi_probed8db734df6drm/bridge: Fix free wrong object in sii8620_init_rcp_input_devec3924eab5drm/meson: osd_afbcd: Add an exit callback to struct meson_afbcd_opsa1c665f5b7ARM: configs: multi_v5_defconfig: re-enable CONFIG_V4L_PLATFORM_DRIVERS1f24716e38ASoC: codecs: wcd934x: Add missing of_node_put() in wcd934x_codec_parse_dataabefbf602cASoC: msm8916-wcd-analog: Fix error handling in pm8916_wcd_analog_spmi_probe90ac679aa6ASoC: atmel: Fix error handling in sam9x5_wm8731_driver_probeec26e3ce3cASoC: atmel: sam9x5_wm8731: use devm_snd_soc_register_card()541251b903mmc: davinci_mmc: Handle error for clk_enable19eb5c7957ASoC: msm8916-wcd-digital: Fix missing clk_disable_unprepare() in msm8916_wcd_digital_probe42042c7a3dASoC: imx-es8328: Fix error return code in imx_es8328_probe()fe4db4ea21ASoC: fsl_spdif: Disable TX clock when stop86b6cf9894ASoC: mxs: Fix error handling in mxs_sgtl5000_probec8c981cfc0ASoC: dmaengine: do not use a NULL prepare_slave_config() callbackf452cff025ASoC: SOF: Add missing of_node_put() in imx8m_probe0d82401d46ASoC: rockchip: i2s: Fix missing clk_disable_unprepare() in rockchip_i2s_probe7e8b0fd0ebASoC: rockchip: i2s: Use devm_platform_get_and_ioremap_resource()b5664a584eivtv: fix incorrect device_caps for ivtvfbebd4f1501emedia: saa7134: fix incorrect use to determine if list is emptydd67315994media: saa7134: convert list_for_each to entry variant066d9b48f9video: fbdev: omapfb: Add missing of_node_put() in dvic_probe_of20da8404e4ASoC: fsi: Add check for clk_enabledb1c00a025ASoC: wm8350: Handle error for wm8350_register_irq662ee5ac6bASoC: atmel: Add missing of_node_put() in at91sam9g20ek_audio_probe663e7a7287media: vidtv: Check for null return of vzalloc4d68603cc4media: stk1160: If start stream fails, return buffers with VB2_BUF_STATE_QUEUEDb02752d753m68k: coldfire/device.c: only build for MCF_EDMA when h/w macros are defined9ca3635a0aarm64: dts: rockchip: Fix SDIO regulator supply properties on rk3399-firefly7e6f578662ALSA: firewire-lib: fix uninitialized flag for AV/C deferred transaction64eee4127cmemory: emif: check the pointer temp in get_device_details()330a9b0d38memory: emif: Add check for setup_interrupts4639c1d97fASoC: soc-compress: prevent the potentially use of null pointera6ee60d4a9ASoC: dwc-i2s: Handle errors for clk_enable39bee81e30ASoC: atmel_ssc_dai: Handle errors for clk_enabledc947d175cASoC: mxs-saif: Handle errors for clk_enablea754ea0de3printk: fix return value of printk.devkmsg __setup handler87a265e292arm64: dts: broadcom: Fix sata nodenamef63122803darm64: dts: ns2: Fix spi-cpol and spi-cpha property5d6a0dc6baALSA: spi: Add check for clk_enable()039fae34f8ASoC: ti: davinci-i2s: Add check for clk_enable()94cb9fe5d8ASoC: rt5663: check the return value of devm_kzalloc() in rt5663_parse_dp()7ce3e6e103uaccess: fix nios2 and microblaze get_user_8()19894751f6ASoC: codecs: wcd934x: fix return value of wcd934x_rx_hph_mode_putf126dcbe70media: cedrus: h264: Fix neighbour info buffer sizec011ae1665media: cedrus: H265: Fix neighbour info buffer size44973633b0media: usb: go7007: s2250-board: fix leak in probe()ec8a37b2d9media: em28xx: initialize refcount before kref_get1b46f57d51media: video/hdmi: handle short reads of hdmi info frame.170ad3942bARM: dts: imx: Add missing LVDS decoder on M53Menlo2a0eb50d9aARM: dts: sun8i: v3s: Move the csi1 block to follow address order77406ac6efsoc: ti: wkup_m3_ipc: Fix IRQ check in wkup_m3_ipc_probe18b2ec361afirmware: ti_sci: Fix compilation failure when CONFIG_TI_SCI_PROTOCOL is not defined8395a17ef6arm64: dts: qcom: sm8150: Correct TCS configuration for apps rscd19248e23farm64: dts: qcom: sdm845: fix microphone bias properties and values2042c6fbfbsoc: qcom: aoss: remove spurious IRQF_ONESHOT flags5a990a65d4soc: qcom: ocmem: Fix missing put_device() call in of_get_ocmemb5d6eba719soc: qcom: rpmpd: Check for null return of devm_kcalloc0c11cb8db4ARM: dts: qcom: ipq4019: fix sleep clock22474dfd0cfirmware: qcom: scm: Remove reassignment to desc following initializerbf4bad1114video: fbdev: fbcvt.c: fix printing in fb_cvt_print_name()6de6a64f23video: fbdev: atmel_lcdfb: fix an error code in atmel_lcdfb_probe()64ec3e678dvideo: fbdev: smscufx: Fix null-ptr-deref in ufx_usb_probe()0dff86aeb1video: fbdev: controlfb: Fix COMPILE_TEST buildec1c20b02avideo: fbdev: controlfb: Fix set but not used warningsf8bf19f7f3video: fbdev: matroxfb: set maxvram of vbG200eW to the same as vbG200 to avoid black screen3187a1d4d5media: aspeed: Correct value for h-total-pixels245561612bmedia: hantro: Fix overfill bottom register field name032b141a91media: meson: vdec: potential dereference of null pointerd3e5106c67media: coda: Fix missing put_device() call in coda_get_vdoa_datac9f4586d99ASoC: generic: simple-card-utils: remove useless assignment2c357e0277ASoC: xilinx: xlnx_formatter_pcm: Handle sysclk setting712dd2ac26media: bttv: fix WARNING regression on tunerless devicesbc2573abc6media: mtk-vcodec: potential dereference of null pointer8a83731a09media: v4l2-mem2mem: Apply DST_QUEUE_OFF_BASE on MMAP buffers across ioctlsc76188715dmedia: staging: media: zoran: fix usage of vb2_dma_contig_set_max_seg_sizef622bd0758kunit: make kunit_test_timeout compatible with comment9e63bcb71dselftests, x86: fix how check_cc.sh is being invokedd2c53e77b0f2fs: fix compressed file start atomic write may cause data corruption1c4d94e4f0f2fs: compress: remove unneeded read when rewrite whole cluster2c4741d1b0btrfs: fix unexpected error path when reflinking an inline extent3ef3bc75cdf2fs: fix to avoid potential deadlock85cc399b65nfsd: more robust allocation failure handling in nfsd_file_cache_init1a11a87374f2fs: fix missing free nid in f2fs_handle_failed_inodec0cffc1fb3perf/x86/intel/pt: Fix address filter config for 32-bit kernel13c8e37e1fperf/core: Fix address filter parser for multiple filtersa9faa5bedarseq: Remove broken uapi field layout on 32-bit little endianf0250e05e5rseq: Optimise rseq_get_rseq_cs() and clear_rseq_cs()ecc17de4b9sched/core: Export pelt_thermal_tp40732cab51sched/debug: Remove mpol_get/put and task_lock/unlock from sched_show_numa2b5d41bcf2f2fs: fix to enable ATGC correctly via gc_idle sysfs interface9d92be1a09watch_queue: Actually free the watch5ae75b4ed3watch_queue: Fix NULL dereference in error cleanup509565faedio_uring: terminate manual loop iterator loop correctly for non-vecs44a77e52bdclocksource: acpi_pm: fix return value of __setup handlerd678f002f0hwmon: (pmbus) Add Vin unit off handling7ca525b4cchwrng: nomadik - Change clk_disable to clk_disable_unpreparee4c777fd8camba: Make the remove callback return void1c6ac39763vfio: platform: simplify device removalc93017c8d5crypto: ccree - Fix use after free in cc_cipher_exit()78622926fecrypto: ccp - ccp_dmaengine_unregister release dma channels9eeee6f684ACPI: APEI: fix return value of __setup handlers0b45bf1659clocksource/drivers/timer-of: Check return value of of_iomap in timer_of_base_init()b33c753cffclocksource/drivers/timer-microchip-pit64b: Use notracedb9d00461bclocksource/drivers/exynos_mct: Handle DTS with higher number of interruptsd4e13c4a6fclocksource/drivers/exynos_mct: Refactor resources allocation42d331a279clocksource/drivers/timer-ti-dm: Fix regression from errata i940 fixaedff03da4crypto: vmx - add missing dependencies51939008cacrypto: amlogic - call finalize with bh disabled24857d87cccrypto: sun8i-ce - call finalize with bh disabledbf4814d58bcrypto: sun8i-ss - call finalize with bh disableda4067ccb97hwrng: atmel - disable trng on failure pathb7940bef6fspi: spi-zynqmp-gqspi: Handle error for dma_set_mask3928a04bc6PM: suspend: fix return value of __setup handler052a218db0PM: hibernate: fix __setup handler error handling0b5924a14dblock: don't delete queue kobject before its children40b288a861nvme: cleanup __nvme_check_ids32c4db2a52hwmon: (sch56xx-common) Replace WDOG_ACTIVE with WDOG_HW_RUNNINGec8536f701hwmon: (pmbus) Add mutex to regulator ops18a18594aespi: pxa2xx-pci: Balance reference count for PCI DMA device55259cb374crypto: ccree - don't attempt 0 len DMA mappingsd788ad472fEVM: fix the evm= __setup handler return valuea137f93ae5audit: log AUDIT_TIME_* records only from rules5e9501e60bcrypto: rockchip - ECB does not need IV8265bea7d8selftests/x86: Add validity check and allow field splittingf7d9249af3arm64/mm: avoid fixmap race condition when create pud mapping99a8dfce7cspi: tegra114: Add missing IRQ check in tegra_spi_probe71dba67138thermal: int340x: Check for NULL after calling kmemdup()8e57117142crypto: mxs-dcp - Fix scatterlist processingec1d372974crypto: authenc - Fix sleep in atomic context in decrypt_tailfdfaafeb4bcrypto: sun8i-ss - really disable hash on A8019693838c8hwrng: cavium - HW_RANDOM_CAVIUM should depend on ARCH_THUNDERbc20294cc8hwrng: cavium - Check health status while reading random data962d1f59d5selinux: check return value of sel_make_avc_files1ae9b020ddregulator: qcom_smd: fix for_each_child.cocci warningsc20975954ePCI: xgene: Revert "PCI: xgene: Fix IB window setup"0f56f24015PCI: pciehp: Clear cmd_busy bit in polling mode89ddcc8191drm/i915/gem: add missing boundary check in vm_accessb84857c06edrm/i915/opregion: check port number bounds for SWSCI display power state88975951d4brcmfmac: pcie: Fix crashes due to early IRQs1cbcf93a93brcmfmac: pcie: Replace brcmf_pcie_copy_mem_todev with memcpy_toiof3820ddaf4brcmfmac: pcie: Release firmwares in the brcmf_pcie_setup error pathdaa07f2902brcmfmac: firmware: Allocate space for default boardrev in nvram1dd031eb99xtensa: fix xtensa_wsr always writing 0dac518bbcextensa: fix stop_machine_cpuslocked call in patch_text20f974dce5media: davinci: vpif: fix unbalanced runtime PM enable7c9b915b94media: davinci: vpif: fix unbalanced runtime PM getcde90e8291media: gpio-ir-tx: fix transmit with long spaces on Orange Pi PC785ffce44aDEC: Limit PMAX memory probing to R3k systems8dde2296ecbcache: fixup multiple threads crash37d2b4fa5ccrypto: rsa-pkcs1pad - fix buffer overread in pkcs1pad_verify_complete()b89fb8b882crypto: rsa-pkcs1pad - restore signature length checkf38c318068crypto: rsa-pkcs1pad - correctly get hash from source scatterlistc1db3f44f2crypto: rsa-pkcs1pad - only allow with rsa27a6f495b6exec: Force single empty string when argv is emptyb02d33171dlib/raid6/test: fix multiple definition linking errorbf057eac9athermal: int340x: Increase bitmap size86a926c3f0pstore: Don't use semaphores in always-atomic-context codeb26f400e4fcarl9170: fix missing bit-wise or operator for tx_params3aef4df6e1mgag200 fix memmapsl configuration in GCTL6 registeref1df91685ARM: dts: exynos: add missing HDMI supplies on SMDK54203cde68a1ebARM: dts: exynos: add missing HDMI supplies on SMDK52505ac205c414ARM: dts: exynos: fix UART3 pins configuration in Exynos52507187c9beb7ARM: dts: at91: sama5d2: Fix PMERRLOC resource size2ca2a5552avideo: fbdev: atari: Atari 2 bpp (STe) palette bugfix72af881092video: fbdev: sm712fb: Fix crash in smtcfb_read()ba09b04173drm/edid: check basic audio support on CEA extension blockce1927b8cfblock: don't merge across cgroup boundaries if blkcg is enabled6e0d24598cblock: limit request dispatch loop duration958e9b56demailbox: tegra-hsp: Flush whole channelf67a140078drivers: hamradio: 6pack: fix UAF bug caused by mod_timer()b35eb48471ext4: fix fs corruption when tring to remove a non-empty directory with IO errora1e6884b2dext4: fix ext4_fc_stats trace pointc119fb65f6coredump: Also dump first pages of non-executable ELF libraries7ad5ccc3daACPI: properties: Consistently return -ENOENT if there are no more referencesef3a87e0c4arm64: dts: ti: k3-j7200: Fix gic-v3 compatible regs18864e8b83arm64: dts: ti: k3-j721e: Fix gic-v3 compatible regse85fa9f4e9arm64: dts: ti: k3-am65: Fix gic-v3 compatible regs7ce550a01barm64: signal: nofpsimd: Do not allocate fp/simd context when not available210e7b43d4udp: call udp_encap_enable for v6 sockets when enabling encape1a58498efpowerpc/kvm: Fix kvm_use_magic_paged72866a7f5can: isotp: sanitize CAN ID checks in isotp_bind()fde8c5cad0drbd: fix potential silent data corruptionb101e74f9adm integrity: set journal entry unused when shrinking deviced5d5804accmm/kmemleak: reset tag when compare object pointerbc2f58b8e4mm,hwpoison: unmap poisoned page before invalidation608c501d70Revert "mm: madvise: skip unmapped vma holes passed to process_madvise"8b354e3032mm: madvise: return correct bytes advised with process_madvise928c06c114mm: madvise: skip unmapped vma holes passed to process_madvise51f7557c3cALSA: hda/realtek: Fix audio regression on Mi Notebook Pro 20209017201e8dALSA: pcm: Fix potential AB/BA lock with buffer_mutex and mmap_lock7b7a03d8b5ALSA: hda: Avoid unsol event during RPM suspendinga55e2d7423ALSA: cs4236: fix an incorrect NULL check on list iteratoredefc4b2a8cifs: fix NULL ptr dereference in smb2_ioctl_query_info()9963ccea60cifs: prevent bad output lengths in smb2_ioctl_query_info()b75198eddaRevert "Input: clear BTN_RIGHT/MIDDLE on buttonpads"34bc1f69bfriscv: Increase stack size under KASAN24b9b8e95criscv: Fix fill_callchain return value0f8c0bd0a4qed: validate and restrict untrusted VFs vlan promisc modea3af3d4319qed: display VF trust configaa28075f06scsi: libsas: Fix sas_ata_qc_issue() handling of NCQ NON DATA commands4bcefc78c8mempolicy: mbind_range() set_policy() after vma_merge()fa37c17143mm: invalidate hwpoison page cache page in fault path7188e7c96fmm/pages_alloc.c: don't create ZONE_MOVABLE beyond the end of a node51dbb5e36djffs2: fix memory leak in jffs2_scan_medium607d3aab73jffs2: fix memory leak in jffs2_do_mount_fs7bb7428dd7jffs2: fix use-after-free in jffs2_clear_xattr_subsystemb417f9c505can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path3a21ee89bcmtd: rawnand: protect access to rawnand devices while in suspend145a63201dspi: mxic: Fix the transmit pathbe22ebe79epinctrl: samsung: drop pin banks references on error pathsb97b305656remoteproc: Fix count check in rproc_coredump_write()784630df17f2fs: fix to do sanity check on .cp_pack_total_block_counte58ee6bd93f2fs: quota: fix loop condition at f2fs_quota_sync()ec67040703f2fs: fix to unlock page correctly in error path of is_alive()7af164fa2fNFSD: prevent integer overflow on 32 bit systems65e21cc042NFSD: prevent underflow in nfssvc_decode_writeargs()b7b430104aSUNRPC: avoid race between mod_timer() and del_timer_sync()f51ab2f60aHID: intel-ish-hid: Use dma_alloc_coherent for firmware updatea1df8e60f2firmware: stratix10-svc: add missing callback parameter on RSUe94f5fbe7aDocumentation: update stable tree linkf4bab992eeDocumentation: add link to stable release candidate tree10ee5662d5KEYS: fix length validation in keyctl_pkey_params_get_2()5a41a3033aptrace: Check PTRACE_O_SUSPEND_SECCOMP permission on PTRACE_SEIZE2775d8e364clk: uniphier: Fix fixed-rate initialization25cd5872d9greybus: svc: fix an error handling bug in gb_svc_hello()9f0cd81174iio: inkern: make a best effort on offset calculation19e533452fiio: inkern: apply consumer scale when no channel scale is availablee10dbe7f6aiio: inkern: apply consumer scale on IIO_VAL_INT cases9f4fffc2abiio: afe: rescale: use s64 for temporary scale calculations9cd1b02655coresight: Fix TRCCONFIGR.QE sysfs interface7b478cb67bmei: avoid iterator usage outside of list_for_each_entryec8975417dmei: me: add Alder Lake N device id.0a0c61dd07xhci: fix uninitialized string returned by xhci_decode_ctrl_ctx()811f403519xhci: make xhci_handshake timeout for xhci_reset() adjustable3a820d1ca1xhci: fix runtime PM imbalance in USB2 resumec41387f96axhci: fix garbage USBSTS being logged in some cases1e0f089f70USB: usb-storage: Fix use of bitfields for hardware data in ene_ub6250.c39a70732ebvirtio-blk: Use blk_validate_block_size() to validate block size290e05f346tpm: fix reference counting for struct tpm_chipfcd3c31dd1iommu/iova: Improve 32-bit free space estimate68c80088f5locking/lockdep: Avoid potential access of invalid memory in lock_classf19d8dfad6net: dsa: microchip: add spi_device_id tables8d3f4ad430af_key: add __GFP_ZERO flag for compose_sadb_supported in function pfkey_registeref1a6ab36dInput: zinitix - do not report shadow fingers21680aabc4spi: Fix erroneous sgs value with min_t()8fb7af1b5aRevert "gpio: Revert regression in sysfs-gpio (gpiolib.c)"18a4417a19net:mcf8390: Use platform_get_irq() to get the interrupt102d7f6c2espi: Fix invalid sgs valuea4f4ce3deegpio: Revert regression in sysfs-gpio (gpiolib.c)fc9a35627cethernet: sun: Free the coherent when failing in probing3c84471925tools/virtio: fix virtio_test execution6d98dc2369vdpa/mlx5: should verify CTRL_VQ feature exists for MQc97ffb4184virtio_console: break out of buf poll on remove0c00d38337ARM: mstar: Select HAVE_ARM_ARCH_TIMERa7e75e5ed4xfrm: fix tunnel model fragmentation behaviore05ae08ea8HID: logitech-dj: add new lightspeed receiver idff919a7ad9netdevice: add the case if dev is NULLc4dc584a2dhv: utils: add PTP_1588_CLOCK to Kconfig to fix buildd136a2574aUSB: serial: simple: add Nokia phone driver38e3d48ffeUSB: serial: pl2303: add IBM device IDsd4d975e792swiotlb: fix info leak with DMA_FROM_DEVICEe2faffea7fMerge 5.10.109 into android13-5.10-ltsd9c5818a0bLinux 5.10.109163960a7dellc: only change llc->dev when bind() succeeds2b5a6d7714nds32: fix access_ok() checks in get/put_userc064268eb8wcn36xx: Differentiate wcn3660 from wcn362095193d12f1tpm: use try_get_ops() in tpm-space.c5d3ff9542amac80211: fix potential double free on mesh joinfcc9797d0drcu: Don't deboost before reporting expedited quiescent state87f7ed7c36Revert "ath: add support for special 0x0 regulatory domain"c971e6a1c8crypto: qat - disable registration of algorithms9f4e64611eACPI: video: Force backlight native for Clevo NL5xRU and NL5xNU0b2ffba2deACPI: battery: Add device HID and quirk for Microsoft Surface Go 32724b72b22ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board2c74374c2enetfilter: nf_tables: initialize registers in nft_do_chain()eb1ba8d1c3drivers: net: xgene: Fix regression in CRC strippinga2368d10b7ALSA: pci: fix reading of swapped values from pcmreg in AC97 codec6936d2ecf8ALSA: cmipci: Restore aux vol on suspend/resumecbd27127afALSA: usb-audio: Add mute TLV for playback volumes on RODE NT-USB0ae81ef3eaALSA: pcm: Add stream lock during PCM reset ioctl operationsb560d670c8ALSA: pcm: Fix races among concurrent prealloc proc writesa38440f006ALSA: pcm: Fix races among concurrent prepare and hw_params/hw_free calls8527c8f052ALSA: pcm: Fix races among concurrent read/write and buffer changes0f6947f5f5ALSA: pcm: Fix races among concurrent hw_params and hw_free calls014c81dfb3ALSA: hda/realtek: Add quirk for ASUS GA40205256f3fd6ALSA: hda/realtek - Fix headset mic problem for a HP machine with alc671ca8247b4dfALSA: hda/realtek: Add quirk for Clevo NP50PNJ26fe8f3103ALSA: hda/realtek: Add quirk for Clevo NP70PNJ80eab86a86ALSA: usb-audio: add mapping for new Corsair Virtuoso SE5ce74ff705ALSA: oss: Fix PCM OSS buffer allocation overflowdb03abd0daASoC: sti: Fix deadlock via snd_pcm_stop_xrun() call571df3393fllc: fix netdevice reference leaks in llc_ui_bind()56dc187b35staging: fbtft: fb_st7789v: reset display before initialization351493858etpm: Fix error handling in async workea21245cdccgroup-v1: Correct privileges check in release_agent writes824a950c3fcgroup: Use open-time cgroup namespace for process migration perm checksf28364fe38cgroup: Allocate cgroup_file_ctx for kernfs_open_file->priv9eeaa2d7d5exfat: avoid incorrectly releasing for root inodeae8ec5eabbnet: ipv6: fix skb_over_panic in __ip6_append_data25c23fe40enfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTIONf0c4090040Merge 5.10.108 into android13-5.10-lts9940314ebfLinux 5.10.10837119edab8Revert "selftests/bpf: Add test for bpf_timer overwriting crash"9248694dacesp: Fix possible buffer overflow in ESP transformation96340cdd55smsc95xx: Ignore -ENODEV errors when device is unpluggede27b51af54net: usb: Correct reset handling of smsc95xxb54daeafc1net: usb: Correct PHY handling of smsc95xx204d38dc6aperf symbols: Fix symbol size calculation conditionf0d43d22d2Input: aiptek - properly check endpoint type98e7a654a5scsi: mpt3sas: Page fault in reply q processing10a805334ausb: usbtmc: Fix bug in pipe direction for control transfers00bdd9bf1ausb: gadget: Fix use-after-free bug by not setting udc->dev.driver28bc026739usb: gadget: rndis: prevent integer overflow in rndis_set_response()2c010c61e6arm64: fix clang warning about TRAMP_VALIAS277b7f6394net: mscc: ocelot: fix backwards compatibility with single-chain tc-flower offload2550afba2anet: bcmgenet: skip invalid partial checksumsbf5b7aae86bnx2x: fix built-in kernel driver load failurec07fdba12fnet: phy: mscc: Add MODULE_FIRMWARE macrosba50073cf4net: dsa: Add missing of_node_put() in dsa_port_parse_ofa630ad5e8bnet: handle ARPHRD_PIMREG in dev_is_mac_header_xmit()336b6be6addrm/panel: simple: Fix Innolux G070Y2-L01 BPP settings9d45aec02fdrm/imx: parallel-display: Remove bus flags check in imx_pd_bridge_atomic_check()9b763ceda6hv_netvsc: Add check for kvmalloc_array09a7264fb0atm: eni: Add check for dma_map_single70b7b3c055net/packet: fix slab-out-of-bounds access in packet_recvmsg()169add82d2net: phy: marvell: Fix invalid comparison in the resume and suspend functions01fac1ca8aesp6: fix check on ipv6_skip_exthdr's return valued9fe590970vsock: each transport cycles only on its own socketsac7dd60946efi: fix return value of __setup handlersfa3aa103e7mm: swap: get rid of livelock in swapin readaheaddf3301dc60ocfs2: fix crash when initialize filecheck kobj fails0f9b7b8df1crypto: qcom-rng - ensure buffer for generate is completely filled Change-Id: Iacc484b0ea31dd8f14ab254d6978b189acddc4d9 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
4811 lines
122 KiB
C
4811 lines
122 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.
|
|
|
|
*/
|
|
|
|
#define INCLUDE_VERMAGIC
|
|
|
|
#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/kernel_read_file.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);
|
|
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
|
|
}
|
|
|
|
#if defined(CONFIG_MODULE_SIG) && !defined(CONFIG_MODULE_SIG_PROTECT)
|
|
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);
|
|
}
|
|
|
|
#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);
|
|
MODINFO_ATTR(scmversion);
|
|
|
|
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();
|
|
}
|
|
EXPORT_SYMBOL(__symbol_put);
|
|
|
|
/* 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_scmversion,
|
|
&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 && namespace[0]) {
|
|
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[];
|
|
};
|
|
|
|
#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[];
|
|
};
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* 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)
|
|
*/
|
|
|
|
/*
|
|
* Since some arches are moving towards PAGE_KERNEL module allocations instead
|
|
* of PAGE_KERNEL_EXEC, keep frob_text() and module_enable_x() outside of the
|
|
* CONFIG_STRICT_MODULE_RWX block below because they are needed regardless of
|
|
* whether we are strict.
|
|
*/
|
|
#ifdef CONFIG_ARCH_HAS_STRICT_MODULE_RWX
|
|
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);
|
|
}
|
|
|
|
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_x(const struct module *mod) { }
|
|
#endif /* CONFIG_ARCH_HAS_STRICT_MODULE_RWX */
|
|
|
|
#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);
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
|
|
static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
|
char *secstrings, struct module *mod)
|
|
{
|
|
const unsigned long shf_wx = SHF_WRITE|SHF_EXECINSTR;
|
|
int i;
|
|
|
|
for (i = 0; i < hdr->e_shnum; i++) {
|
|
if ((sechdrs[i].sh_flags & shf_wx) == shf_wx) {
|
|
pr_err("%s: section %s (index %d) has invalid WRITE|EXEC flags\n",
|
|
mod->name, secstrings + sechdrs[i].sh_name, i);
|
|
return -ENOEXEC;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else /* !CONFIG_STRICT_MODULE_RWX */
|
|
static void module_enable_nx(const struct module *mod) { }
|
|
static void module_enable_ro(const struct module *mod, bool after_init) {}
|
|
static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
|
char *secstrings, struct module *mod)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_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);
|
|
|
|
/* 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;
|
|
}
|
|
EXPORT_SYMBOL_GPL(__symbol_get);
|
|
|
|
static bool module_init_layout_section(const char *sname)
|
|
{
|
|
#ifndef CONFIG_MODULE_UNLOAD
|
|
if (module_exit_section(sname))
|
|
return true;
|
|
#endif
|
|
return module_init_section(sname);
|
|
}
|
|
|
|
/*
|
|
* 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 (!mod->sig_ok && gki_is_module_exported_symbol(
|
|
kernel_symbol_name(s))) {
|
|
pr_err("%s: exporting protected symbol(%s)\n",
|
|
mod->name, kernel_symbol_name(s));
|
|
return -EACCES;
|
|
}
|
|
|
|
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:
|
|
if (!mod->sig_ok &&
|
|
gki_is_module_protected_symbol(name)) {
|
|
pr_err("%s: is not an Android GKI signed module. It can not access protected symbol: %s\n",
|
|
mod->name, name);
|
|
return -EACCES;
|
|
}
|
|
|
|
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;
|
|
|
|
if (info->sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH)
|
|
err = klp_apply_section_relocs(mod, info->sechdrs,
|
|
info->secstrings,
|
|
info->strtab,
|
|
info->index.sym, i,
|
|
NULL);
|
|
else 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
|
|
|| module_init_layout_section(sname))
|
|
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
|
|
|| !module_init_layout_section(sname))
|
|
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_node_range(size, 1, VMALLOC_START, VMALLOC_END,
|
|
GFP_KERNEL, PAGE_KERNEL_EXEC, VM_FLUSH_RESET_PERMS,
|
|
NUMA_NO_NODE, __builtin_return_address(0));
|
|
}
|
|
|
|
bool __weak module_init_section(const char *name)
|
|
{
|
|
return strstarts(name, ".init");
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* ANDROID: GKI: Do not prevent loading of unsigned modules;
|
|
* as all modules except GKI modules are not signed.
|
|
*/
|
|
#ifndef CONFIG_MODULE_SIG_PROTECT
|
|
return security_locked_down(LOCKDOWN_MODULE_SIGNATURE);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
#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, true);
|
|
if (err)
|
|
return err;
|
|
|
|
/* Suck in entire file: we'll want most of it. */
|
|
info->hdr = __vmalloc(info->len, GFP_KERNEL | __GFP_NOWARN);
|
|
if (!info->hdr)
|
|
return -ENOMEM;
|
|
|
|
if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) {
|
|
err = -EFAULT;
|
|
goto out;
|
|
}
|
|
|
|
err = security_kernel_post_load_data((char *)info->hdr, info->len,
|
|
LOADING_MODULE, "init_module");
|
|
out:
|
|
if (err)
|
|
vfree(info->hdr);
|
|
|
|
return err;
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
/* 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
|
|
|
|
mod->noinstr_text_start = section_objs(info, ".noinstr.text", 1,
|
|
&mod->noinstr_text_size);
|
|
|
|
#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
|
|
#ifdef CONFIG_KPROBES
|
|
mod->kprobes_text_start = section_objs(info, ".kprobes.text", 1,
|
|
&mod->kprobes_text_size);
|
|
mod->kprobe_blacklist = section_objs(info, "_kprobe_blacklist",
|
|
sizeof(unsigned long),
|
|
&mod->num_kprobe_blacklist);
|
|
#endif
|
|
#ifdef CONFIG_HAVE_STATIC_CALL_INLINE
|
|
mod->static_call_sites = section_objs(info, ".static_call_sites",
|
|
sizeof(*mod->static_call_sites),
|
|
&mod->num_static_call_sites);
|
|
#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, "__dyndbg",
|
|
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)
|
|
{
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
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);
|
|
|
|
err = module_enforce_rwx_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 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);
|
|
|
|
/* 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;
|
|
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;
|
|
|
|
again:
|
|
mutex_lock(&module_mutex);
|
|
old = find_module_all(mod->name, strlen(mod->name), true);
|
|
if (old != NULL) {
|
|
if (old->state != MODULE_STATE_LIVE) {
|
|
/* 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;
|
|
goto again;
|
|
}
|
|
err = -EEXIST;
|
|
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;
|
|
|
|
err = blocking_notifier_call_chain_robust(&module_notify_list,
|
|
MODULE_STATE_COMING, MODULE_STATE_GOING, mod);
|
|
err = notifier_to_errno(err);
|
|
if (err)
|
|
klp_module_going(mod);
|
|
|
|
return err;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static void cfi_init(struct module *mod);
|
|
|
|
/* 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;
|
|
pr_err("Module %s is blacklisted\n", info->name);
|
|
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);
|
|
}
|
|
#else
|
|
mod->sig_ok = 0;
|
|
#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);
|
|
|
|
/* Setup CFI for the module. */
|
|
cfi_init(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:
|
|
ftrace_release_mod(mod);
|
|
dynamic_debug_remove(mod, info->debug);
|
|
synchronize_rcu();
|
|
kfree(mod->args);
|
|
free_arch_cleanup:
|
|
cfi_cleanup(mod);
|
|
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 = { };
|
|
void *hdr = NULL;
|
|
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, 0, &hdr, INT_MAX, NULL,
|
|
READING_MODULE);
|
|
if (err < 0)
|
|
return err;
|
|
info.hdr = hdr;
|
|
info.len = err;
|
|
|
|
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 inline int is_cfi_typeid_symbol(const char *str)
|
|
{
|
|
return !strncmp(str, "__typeid__", 10);
|
|
}
|
|
|
|
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))
|
|
|| is_cfi_typeid_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
|
|
initcall_t *init;
|
|
exitcall_t *exit;
|
|
|
|
rcu_read_lock_sched();
|
|
mod->cfi_check = (cfi_check_fn)
|
|
find_kallsyms_symbol_value(mod, "__cfi_check");
|
|
init = (initcall_t *)
|
|
find_kallsyms_symbol_value(mod, "__cfi_jt_init_module");
|
|
exit = (exitcall_t *)
|
|
find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module");
|
|
rcu_read_unlock_sched();
|
|
|
|
/* Fix init/exit functions to point to the CFI jump table */
|
|
if (init) mod->init = *init;
|
|
if (exit) mod->exit = *exit;
|
|
|
|
cfi_module_add(mod, module_addr_min);
|
|
#endif
|
|
}
|
|
|
|
static void cfi_cleanup(struct module *mod)
|
|
{
|
|
#ifdef CONFIG_CFI_CLANG
|
|
cfi_module_remove(mod, module_addr_min);
|
|
#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 proc_ops modules_proc_ops = {
|
|
.proc_flags = PROC_ENTRY_PERMANENT,
|
|
.proc_open = modules_open,
|
|
.proc_read = seq_read,
|
|
.proc_lseek = seq_lseek,
|
|
.proc_release = seq_release,
|
|
};
|
|
|
|
static int __init proc_modules_init(void)
|
|
{
|
|
proc_create("modules", 0, NULL, &modules_proc_ops);
|
|
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_ANDROID_DEBUG_SYMBOLS
|
|
void android_debug_for_each_module(int (*fn)(const char *mod_name, void *mod_addr, void *data),
|
|
void *data)
|
|
{
|
|
struct module *module;
|
|
|
|
preempt_disable();
|
|
list_for_each_entry_rcu(module, &modules, list) {
|
|
if (fn(module->name, module->core_layout.base, data))
|
|
goto out;
|
|
}
|
|
out:
|
|
preempt_enable();
|
|
}
|
|
EXPORT_SYMBOL_GPL(android_debug_for_each_module);
|
|
#endif
|
|
|
|
#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
|