mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
* 'android-4.14-stable' of https://android.googlesource.com/kernel/common: Linux 4.14.277 Revert "net: micrel: fix KS8851_MLL Kconfig" ax25: Fix UAF bugs in ax25 timers ax25: Fix NULL pointer dereferences in ax25 timers ax25: fix NPD bug in ax25_disconnect ax25: fix UAF bug in ax25_send_control() ax25: Fix refcount leaks caused by ax25_cb_del() ax25: fix UAF bugs of net_device caused by rebinding operation ax25: fix reference count leaks of ax25_dev ax25: add refcount in ax25_dev to avoid UAF bugs block/compat_ioctl: fix range check in BLKGETSIZE staging: ion: Prevent incorrect reference counting behavour ext4: force overhead calculation if the s_overhead_cluster makes no sense ext4: fix overhead calculation to account for the reserved gdt blocks ext4: limit length to bitmap_maxbytes - blocksize in punch_hole ext4: fix symlink file size not match to file content ARC: entry: fix syscall_trace_exit argument e1000e: Fix possible overflow in LTR decoding ASoC: soc-dapm: fix two incorrect uses of list iterator openvswitch: fix OOB access in reserve_sfa_size() powerpc/perf: Fix power9 event alternatives dma: at_xdmac: fix a missing check on list iterator ata: pata_marvell: Check the 'bmdma_addr' beforing reading stat: fix inconsistency between struct stat and struct compat_stat net: macb: Restart tx only if queue pointer is lagging drm/msm/mdp5: check the return of kzalloc() brcmfmac: sdio: Fix undefined behavior due to shift overflowing the constant cifs: Check the IOCB_DIRECT flag, not O_DIRECT vxlan: fix error return code in vxlan_fdb_append ALSA: usb-audio: Fix undefined behavior due to shift overflowing the constant platform/x86: samsung-laptop: Fix an unsigned comparison which can never be negative ARM: vexpress/spc: Avoid negative array index when !SMP netlink: reset network and mac headers in netlink_dump() net/packet: fix packet_sock xmit return value checking dmaengine: imx-sdma: Fix error checking in sdma_event_remap tcp: Fix potential use-after-free due to double kfree() tcp: fix race condition when creating child sockets from syncookies ALSA: usb-audio: Clear MIDI port active flag after draining gfs2: assign rgrp glock before compute_bitstructs can: usb_8dev: usb_8dev_start_xmit(): fix double dev_kfree_skb() in error path tracing: Dump stacktrace trigger to the corresponding instance tracing: Have traceon and traceoff trigger honor the instance mm: page_alloc: fix building error on -Werror=array-compare etherdevice: Adjust ether_addr* prototypes to silence -Wstringop-overead Linux 4.14.276 i2c: pasemi: Wait for write xfers to finish smp: Fix offline cpu check in flush_smp_call_function_queue() ARM: davinci: da850-evm: Avoid NULL pointer dereference ALSA: pcm: Test for "silence" field in struct "pcm_format_data" gcc-plugins: latent_entropy: use /dev/urandom mm: kmemleak: take a full lowmem check in kmemleak_*_phys() mm, page_alloc: fix build_zonerefs_node() drivers: net: slip: fix NPD bug in sl_tx_timeout() scsi: mvsas: Add PCI ID of RocketRaid 2640 gpu: ipu-v3: Fix dev_dbg frequency output ata: libata-core: Disable READ LOG DMA EXT for Samsung 840 EVOs net: micrel: fix KS8851_MLL Kconfig scsi: ibmvscsis: Increase INITIAL_SRP_LIMIT to 1024 scsi: target: tcmu: Fix possible page UAF Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer drm/amdkfd: Check for potential null return of kmalloc_array() drm/amd: Add USBC connector ID cifs: potential buffer overflow in handling symlinks nfc: nci: add flush_workqueue to prevent uaf net: ethernet: stmmac: fix altr_tse_pcs function when using a fixed-link mlxsw: i2c: Fix initialization error flow gpiolib: acpi: use correct format characters veth: Ensure eth header is in skb's linear part memory: atmel-ebi: Fix missing of_node_put in atmel_ebi_probe xfrm: policy: match with both mark and mask on user interfaces cgroup: Use open-time cgroup namespace for process migration perm checks cgroup: Allocate cgroup_file_ctx for kernfs_open_file->priv cgroup: Use open-time credentials for process migraton perm checks mm/sparsemem: fix 'mem_section' will never be NULL gcc 12 warning arm64: module: remove (NOLOAD) from linker script mm: don't skip swap entry even if zap_details specified dmaengine: Revert "dmaengine: shdma: Fix runtime PM imbalance on error" tools build: Use $(shell ) instead of `` to get embedded libperl's ccopts perf: qcom_l2_pmu: fix an incorrect NULL check on list iterator arm64: patch_text: Fixup last cpu should be master btrfs: fix qgroup reserve overflow the qgroup limit x86/speculation: Restore speculation related MSRs during S3 resume x86/pm: Save the MSR validity status at context setup mm/mempolicy: fix mpol_new leak in shared_policy_replace mmmremap.c: avoid pointless invalidate_range_start/end on mremap(old_size=0) Revert "mmc: sdhci-xenon: fix annoying 1.8V regulator warning" drbd: Fix five use after free bugs in get_initial_state drm/imx: Fix memory leak in imx_pd_connector_get_modes net: stmmac: Fix unset max_speed difference between DT and non-DT platforms scsi: zorro7xx: Fix a resource leak in zorro7xx_remove_one() drm/amdgpu: fix off by one in amdgpu_gfx_kiq_acquire() mm: fix race between MADV_FREE reclaim and blkdev direct IO read net: add missing SOF_TIMESTAMPING_OPT_ID support ipv6: add missing tx timestamping on IPPROTO_RAW parisc: Fix CPU affinity for Lasi, WAX and Dino chips jfs: prevent NULL deref in diFree virtio_console: eliminate anonymous module_init & module_exit serial: samsung_tty: do not unlock port->lock for uart_write_wakeup() NFS: swap-out must always use STABLE writes. NFS: swap IO handling is slightly different for O_DIRECT IO SUNRPC/call_alloc: async tasks mustn't block waiting for memory w1: w1_therm: fixes w1_seq for ds28ea00 sensors init/main.c: return 1 from handled __setup() functions Bluetooth: Fix use after free in hci_send_acl xtensa: fix DTC warning unit_address_format usb: dwc3: omap: fix "unbalanced disables for smps10_out1" on omap5evm scsi: libfc: Fix use after free in fc_exch_abts_resp() MIPS: fix fortify panic when copying asm exception handlers bnxt_en: Eliminate unintended link toggle during FW reset macvtap: advertise link netns via netlink net/smc: correct settings of RMB window update limit scsi: aha152x: Fix aha152x_setup() __setup handler return value scsi: pm8001: Fix pm8001_mpi_task_abort_resp() dm ioctl: prevent potential spectre v1 gadget iommu/arm-smmu-v3: fix event handling soft lockup PCI: aardvark: Fix support for MSI interrupts powerpc: Set crashkernel offset to mid of RMA region power: supply: axp20x_battery: properly report current when discharging scsi: bfa: Replace snprintf() with sysfs_emit() scsi: mvsas: Replace snprintf() with sysfs_emit() powerpc: dts: t104xrdb: fix phy type for FMAN 4/5 ptp: replace snprintf with sysfs_emit ath5k: fix OOB in ath5k_eeprom_read_pcal_info_5111 KVM: x86/svm: Clear reserved bits written to PerfEvtSeln MSRs ARM: 9187/1: JIVE: fix return value of __setup handler rtc: wm8350: Handle error for wm8350_register_irq ubifs: Rectify space amount budget for mkdir/tmpfile operations KVM: x86: Forbid VMM to set SYNIC/STIMER MSRs when SynIC wasn't activated openvswitch: Fixed nd target mask field in the flow dump. ARM: dts: spear13xx: Update SPI dma properties ARM: dts: spear1340: Update serial node properties ASoC: topology: Allow TLV control to be either read or write ubi: fastmap: Return error code if memory allocation fails in add_aeb() mm/memcontrol: return 1 from cgroup.memory __setup() handler mm/mmap: return 1 from stack_guard_gap __setup() handler ACPI: CPPC: Avoid out of bounds access when parsing _CPC data ubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctl pinctrl: pinconf-generic: Print arguments for bias-pull-* gfs2: Make sure FITRIM minlen is rounded up to fs block size can: mcba_usb: properly check endpoint type can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path ubifs: rename_whiteout: correct old_dir size computing ubifs: setflags: Make dirtied_ino_d 8 bytes aligned ubifs: Add missing iput if do_tmpfile() failed in rename whiteout ubifs: rename_whiteout: Fix double free for whiteout_ui->data KVM: Prevent module exit until all VMs are freed scsi: qla2xxx: Suppress a kernel complaint in qla_create_qpair() scsi: qla2xxx: Fix warning for missing error code powerpc/lib/sstep: Fix build errors with newer binutils powerpc/lib/sstep: Fix 'sthcx' instruction mmc: host: Return an error when ->enable_sdio_irq() ops is missing media: hdpvr: initialize dev->worker at hdpvr_register_videodev video: fbdev: sm712fb: Fix crash in smtcfb_write() ARM: mmp: Fix failure to remove sram device ARM: tegra: tamonten: Fix I2C3 pad setting media: cx88-mpeg: clear interrupt status register before streaming video ASoC: soc-core: skip zero num_dai component in searching dai name video: fbdev: omapfb: panel-tpo-td043mtea1: Use sysfs_emit() instead of snprintf() video: fbdev: omapfb: panel-dsi-cm: Use sysfs_emit() instead of snprintf() ARM: dts: bcm2837: Add the missing L1/L2 cache information ARM: dts: qcom: fix gic_irq_domain_translate warnings for msm8960 video: fbdev: omapfb: acx565akm: replace snprintf with sysfs_emit video: fbdev: cirrusfb: check pixclock to avoid divide by zero video: fbdev: w100fb: Reset global state video: fbdev: nvidiafb: Use strscpy() to prevent buffer overflow ntfs: add sanity check on allocation size ext4: don't BUG if someone dirty pages without asking ext4 first spi: tegra20: Use of_device_get_match_data() PM: core: keep irq flags in device_pm_check_callbacks() ACPI/APEI: Limit printable size of BERT table data ACPICA: Avoid walking the ACPI Namespace if it is not there irqchip/nvic: Release nvic_base upon failure Fix incorrect type in assignment of ipv6 port for audit loop: use sysfs_emit() in the sysfs xxx show() selinux: use correct type for context length lib/test: use after free in register_test_dev_kmod() NFSv4/pNFS: Fix another issue with a list iterator pointing to the head net/x25: Fix null-ptr-deref caused by x25_disconnect qlcnic: dcb: default to returning -EOPNOTSUPP net: phy: broadcom: Fix brcm_fet_config_init() xen: fix is_xen_pmu() netfilter: nf_conntrack_tcp: preserve liberal flag in tcp options jfs: fix divide error in dbNextAG kgdbts: fix return value of __setup handler kgdboc: fix return value of __setup handler tty: hvc: fix return value of __setup handler pinctrl/rockchip: Add missing of_node_put() in rockchip_pinctrl_probe pinctrl: nomadik: Add missing of_node_put() in nmk_pinctrl_probe pinctrl: mediatek: Fix missing of_node_put() in mtk_pctrl_init NFS: remove unneeded check in decode_devicenotify_args() clk: tegra: tegra124-emc: Fix missing put_device() call in emc_ensure_emc_driver clk: clps711x: Terminate clk_div_table with sentinel element clk: loongson1: Terminate clk_div_table with sentinel element remoteproc: qcom_wcnss: Add missing of_node_put() in wcnss_alloc_memory_region clk: qcom: clk-rcg2: Update the frac table for pixel clock iio: adc: Add check for devm_request_threaded_irq serial: 8250: Fix race condition in RTS-after-send handling serial: 8250_mid: Balance reference count for PCI DMA device staging:iio:adc:ad7280a: Fix handing of device address bit reversing. pwm: lpc18xx-sct: Initialize driver data and hardware before pwmchip_add() mxser: fix xmit_buf leak in activate when LSR == 0xff mfd: asic3: Add missing iounmap() on error asic3_mfd_probe tcp: ensure PMTU updates are processed during fastopen i2c: mux: demux-pinctrl: do not deactivate a master that is not active af_netlink: Fix shift out of bounds in group mask calculation USB: storage: ums-realtek: fix error code in rts51x_read_mem() mtd: rawnand: atmel: fix refcount issue in atmel_nand_controller_init MIPS: RB532: fix return value of __setup handler vxcan: enable local echo for sent CAN frames mfd: mc13xxx: Add check for mc13xxx_irq_request powerpc/sysdev: fix incorrect use to determine if list is empty PCI: Reduce warnings on possible RW1C corruption power: supply: wm8350-power: Add missing free in free_charger_irq power: supply: wm8350-power: Handle error for wm8350_register_irq i2c: xiic: Make bus names unique KVM: x86/emulator: Defer not-present segment check in __load_segment_descriptor() KVM: x86: Fix emulation in writing cr8 power: supply: bq24190_charger: Fix bq24190_vbus_is_enabled() wrong false return drm/tegra: Fix reference leak in tegra_dsi_ganged_probe ext2: correct max file size computing TOMOYO: fix __setup handlers return values scsi: pm8001: Fix abort all task initialization scsi: pm8001: Fix payload initialization in pm80xx_set_thermal_config() scsi: pm8001: Fix command initialization in pm8001_chip_ssp_tm_req() scsi: pm8001: Fix command initialization in pm80XX_send_read_log() dm crypt: fix get_key_size compiler warning if !CONFIG_KEYS iwlwifi: Fix -EIO error code that is never returned HID: i2c-hid: fix GET/SET_REPORT for unnumbered reports power: supply: ab8500: Fix memory leak in ab8500_fg_sysfs_init ray_cs: Check ioremap return value power: reset: gemini-poweroff: Fix IRQ check in gemini_poweroff_probe ath9k_htc: fix uninit value bugs drm/edid: Don't clear formats if using deep color mtd: onenand: Check for error irq ASoC: msm8916-wcd-digital: Fix missing clk_disable_unprepare() in msm8916_wcd_digital_probe ASoC: imx-es8328: Fix error return code in imx_es8328_probe() ASoC: mxs: Fix error handling in mxs_sgtl5000_probe ASoC: dmaengine: do not use a NULL prepare_slave_config() callback video: fbdev: omapfb: Add missing of_node_put() in dvic_probe_of ASoC: fsi: Add check for clk_enable ASoC: wm8350: Handle error for wm8350_register_irq ASoC: atmel: Add missing of_node_put() in at91sam9g20ek_audio_probe media: stk1160: If start stream fails, return buffers with VB2_BUF_STATE_QUEUED ALSA: firewire-lib: fix uninitialized flag for AV/C deferred transaction memory: emif: check the pointer temp in get_device_details() memory: emif: Add check for setup_interrupts ASoC: atmel_ssc_dai: Handle errors for clk_enable ASoC: mxs-saif: Handle errors for clk_enable printk: fix return value of printk.devkmsg __setup handler arm64: dts: broadcom: Fix sata nodename arm64: dts: ns2: Fix spi-cpol and spi-cpha property ALSA: spi: Add check for clk_enable() ASoC: ti: davinci-i2s: Add check for clk_enable() media: usb: go7007: s2250-board: fix leak in probe() soc: ti: wkup_m3_ipc: Fix IRQ check in wkup_m3_ipc_probe ARM: dts: qcom: ipq4019: fix sleep clock video: fbdev: fbcvt.c: fix printing in fb_cvt_print_name() video: fbdev: smscufx: Fix null-ptr-deref in ufx_usb_probe() media: coda: Fix missing put_device() call in coda_get_vdoa_data perf/x86/intel/pt: Fix address filter config for 32-bit kernel perf/core: Fix address filter parser for multiple filters sched/debug: Remove mpol_get/put and task_lock/unlock from sched_show_numa clocksource: acpi_pm: fix return value of __setup handler hwmon: (pmbus) Add Vin unit off handling crypto: ccp - ccp_dmaengine_unregister release dma channels ACPI: APEI: fix return value of __setup handlers crypto: vmx - add missing dependencies hwrng: atmel - disable trng on failure path PM: suspend: fix return value of __setup handler PM: hibernate: fix __setup handler error handling hwmon: (sch56xx-common) Replace WDOG_ACTIVE with WDOG_HW_RUNNING hwmon: (pmbus) Add mutex to regulator ops spi: pxa2xx-pci: Balance reference count for PCI DMA device selftests/x86: Add validity check and allow field splitting spi: tegra114: Add missing IRQ check in tegra_spi_probe crypto: mxs-dcp - Fix scatterlist processing crypto: authenc - Fix sleep in atomic context in decrypt_tail PCI: pciehp: Clear cmd_busy bit in polling mode brcmfmac: pcie: Replace brcmf_pcie_copy_mem_todev with memcpy_toio brcmfmac: firmware: Allocate space for default boardrev in nvram media: davinci: vpif: fix unbalanced runtime PM get DEC: Limit PMAX memory probing to R3k systems lib/raid6/test: fix multiple definition linking error thermal: int340x: Increase bitmap size carl9170: fix missing bit-wise or operator for tx_params ARM: dts: exynos: add missing HDMI supplies on SMDK5420 ARM: dts: exynos: add missing HDMI supplies on SMDK5250 ARM: dts: exynos: fix UART3 pins configuration in Exynos5250 ARM: dts: at91: sama5d2: Fix PMERRLOC resource size video: fbdev: atari: Atari 2 bpp (STe) palette bugfix video: fbdev: sm712fb: Fix crash in smtcfb_read() drivers: hamradio: 6pack: fix UAF bug caused by mod_timer() ACPI: properties: Consistently return -ENOENT if there are no more references drbd: fix potential silent data corruption ALSA: cs4236: fix an incorrect NULL check on list iterator Revert "Input: clear BTN_RIGHT/MIDDLE on buttonpads" qed: validate and restrict untrusted VFs vlan promisc mode qed: display VF trust config scsi: libsas: Fix sas_ata_qc_issue() handling of NCQ NON DATA commands mempolicy: mbind_range() set_policy() after vma_merge() mm/pages_alloc.c: don't create ZONE_MOVABLE beyond the end of a node jffs2: fix memory leak in jffs2_scan_medium jffs2: fix memory leak in jffs2_do_mount_fs jffs2: fix use-after-free in jffs2_clear_xattr_subsystem can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path pinctrl: samsung: drop pin banks references on error paths NFSD: prevent underflow in nfssvc_decode_writeargs() SUNRPC: avoid race between mod_timer() and del_timer_sync() Documentation: update stable tree link Documentation: add link to stable release candidate tree ptrace: Check PTRACE_O_SUSPEND_SECCOMP permission on PTRACE_SEIZE clk: uniphier: Fix fixed-rate initialization iio: inkern: make a best effort on offset calculation iio: inkern: apply consumer scale when no channel scale is available iio: inkern: apply consumer scale on IIO_VAL_INT cases coresight: Fix TRCCONFIGR.QE sysfs interface USB: usb-storage: Fix use of bitfields for hardware data in ene_ub6250.c virtio-blk: Use blk_validate_block_size() to validate block size block: Add a helper to validate the block size tpm: fix reference counting for struct tpm_chip fuse: fix pipe buffer lifetime for direct_io af_key: add __GFP_ZERO flag for compose_sadb_supported in function pfkey_register spi: Fix erroneous sgs value with min_t() spi: Fix invalid sgs value ethernet: sun: Free the coherent when failing in probing virtio_console: break out of buf poll on remove netdevice: add the case if dev is NULL USB: serial: simple: add Nokia phone driver USB: serial: pl2303: add IBM device IDs ANDROID: incremental-fs: limit mount stack depth UPSTREAM: binderfs: use __u32 for device numbers Linux 4.14.275 arm64: Use the clearbhb instruction in mitigations arm64: add ID_AA64ISAR2_EL1 sys register KVM: arm64: Allow SMCCC_ARCH_WORKAROUND_3 to be discovered and migrated arm64: Mitigate spectre style branch history side channels KVM: arm64: Add templates for BHB mitigation sequences arm64: proton-pack: Report Spectre-BHB vulnerabilities as part of Spectre-v2 arm64: Add percpu vectors for EL1 arm64: entry: Add macro for reading symbol addresses from the trampoline arm64: entry: Add vectors that have the bhb mitigation sequences arm64: entry: Add non-kpti __bp_harden_el1_vectors for mitigations arm64: entry: Allow the trampoline text to occupy multiple pages arm64: entry: Make the kpti trampoline's kpti sequence optional arm64: entry: Move trampoline macros out of ifdef'd section arm64: entry: Don't assume tramp_vectors is the start of the vectors arm64: entry: Allow tramp_alias to access symbols after the 4K boundary arm64: entry: Move the trampoline data page before the text page arm64: entry: Free up another register on kpti's tramp_exit path arm64: entry: Make the trampoline cleanup optional arm64: entry.S: Add ventry overflow sanity checks arm64: Add Cortex-X2 CPU part definition arm64: Add Neoverse-N2, Cortex-A710 CPU part definition arm64: Add part number for Arm Cortex-A77 arm64: Add part number for Neoverse N1 arm64: Make ARM64_ERRATUM_1188873 depend on COMPAT arm64: Add silicon-errata.txt entry for ARM erratum 1188873 arm64: arch_timer: avoid unused function warning arm64: arch_timer: Add workaround for ARM erratum 1188873 Linux 4.14.274 llc: only change llc->dev when bind() succeeds mac80211: fix potential double free on mesh join crypto: qat - disable registration of algorithms ACPI: video: Force backlight native for Clevo NL5xRU and NL5xNU ACPI: battery: Add device HID and quirk for Microsoft Surface Go 3 ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board netfilter: nf_tables: initialize registers in nft_do_chain() drivers: net: xgene: Fix regression in CRC stripping ALSA: pci: fix reading of swapped values from pcmreg in AC97 codec ALSA: cmipci: Restore aux vol on suspend/resume ALSA: usb-audio: Add mute TLV for playback volumes on RODE NT-USB ALSA: pcm: Add stream lock during PCM reset ioctl operations llc: fix netdevice reference leaks in llc_ui_bind() thermal: int340x: fix memory leak in int3400_notify() staging: fbtft: fb_st7789v: reset display before initialization esp: Fix possible buffer overflow in ESP transformation net: ipv6: fix skb_over_panic in __ip6_append_data nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION Linux 4.14.273 perf symbols: Fix symbol size calculation condition Input: aiptek - properly check endpoint type usb: gadget: Fix use-after-free bug by not setting udc->dev.driver usb: gadget: rndis: prevent integer overflow in rndis_set_response() net: handle ARPHRD_PIMREG in dev_is_mac_header_xmit() atm: eni: Add check for dma_map_single net/packet: fix slab-out-of-bounds access in packet_recvmsg() efi: fix return value of __setup handlers fs: sysfs_emit: Remove PAGE_SIZE alignment check kselftest/vm: fix tests build with old libc sfc: extend the locking on mcdi->seqno tcp: make tcp_read_sock() more robust nl80211: Update bss channel on channel switch for P2P_CLIENT atm: firestream: check the return value of ioremap() in fs_init() can: rcar_canfd: rcar_canfd_channel_probe(): register the CAN device when fully ready ARM: 9178/1: fix unmet dependency on BITREVERSE for HAVE_ARCH_BITREVERSE MIPS: smp: fill in sibling and core maps earlier ARM: dts: rockchip: fix a typo on rk3288 crypto-controller arm64: dts: rockchip: fix rk3399-puma eMMC HS400 signal integrity xfrm: Fix xfrm migrate issues when address family changes sctp: fix the processing for INIT_ACK chunk sctp: fix the processing for INIT chunk Linux 4.14.272 btrfs: unlock newly allocated extent buffer after error ext4: add check to prevent attempting to resize an fs with sparse_super2 ARM: fix Thumb2 regression with Spectre BHB virtio: acknowledge all features before access virtio: unexport virtio_finalize_features staging: gdm724x: fix use after free in gdm_lte_rx() ARM: Spectre-BHB: provide empty stub for non-config selftests/memfd: clean up mapping in mfd_fail_write tracing: Ensure trace buffer is at least 4096 bytes large Revert "xen-netback: Check for hotplug-status existence before watching" Revert "xen-netback: remove 'hotplug-status' once it has served its purpose" net-sysfs: add check for netdevice being present to speed_show sctp: fix kernel-infoleak for SCTP sockets gpio: ts4900: Do not set DAT and OE together NFC: port100: fix use-after-free in port100_send_complete net/mlx5: Fix size field in bufferx_reg struct ax25: Fix NULL pointer dereference in ax25_kill_by_device net: ethernet: lpc_eth: Handle error for clk_enable net: ethernet: ti: cpts: Handle error for clk_enable ethernet: Fix error handling in xemaclite_of_probe qed: return status of qed_iov_get_link net: qlogic: check the return value of dma_alloc_coherent() in qed_vf_hw_prepare()
724 lines
19 KiB
C
724 lines
19 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* mm/mremap.c
|
|
*
|
|
* (C) Copyright 1996 Linus Torvalds
|
|
*
|
|
* Address space accounting code <alan@lxorguk.ukuu.org.uk>
|
|
* (C) Copyright 2002 Red Hat Inc, All Rights Reserved
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/hugetlb.h>
|
|
#include <linux/shm.h>
|
|
#include <linux/ksm.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/swap.h>
|
|
#include <linux/capability.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/swapops.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/security.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/mmu_notifier.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/mm-arch-hooks.h>
|
|
#include <linux/userfaultfd_k.h>
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/tlbflush.h>
|
|
|
|
#include "internal.h"
|
|
|
|
static pmd_t *get_old_pmd(struct mm_struct *mm, unsigned long addr)
|
|
{
|
|
pgd_t *pgd;
|
|
p4d_t *p4d;
|
|
pud_t *pud;
|
|
pmd_t *pmd;
|
|
|
|
pgd = pgd_offset(mm, addr);
|
|
if (pgd_none_or_clear_bad(pgd))
|
|
return NULL;
|
|
|
|
p4d = p4d_offset(pgd, addr);
|
|
if (p4d_none_or_clear_bad(p4d))
|
|
return NULL;
|
|
|
|
pud = pud_offset(p4d, addr);
|
|
if (pud_none_or_clear_bad(pud))
|
|
return NULL;
|
|
|
|
pmd = pmd_offset(pud, addr);
|
|
if (pmd_none(*pmd))
|
|
return NULL;
|
|
|
|
return pmd;
|
|
}
|
|
|
|
static pmd_t *alloc_new_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
unsigned long addr)
|
|
{
|
|
pgd_t *pgd;
|
|
p4d_t *p4d;
|
|
pud_t *pud;
|
|
pmd_t *pmd;
|
|
|
|
pgd = pgd_offset(mm, addr);
|
|
p4d = p4d_alloc(mm, pgd, addr);
|
|
if (!p4d)
|
|
return NULL;
|
|
pud = pud_alloc(mm, p4d, addr);
|
|
if (!pud)
|
|
return NULL;
|
|
|
|
pmd = pmd_alloc(mm, pud, addr);
|
|
if (!pmd)
|
|
return NULL;
|
|
|
|
VM_BUG_ON(pmd_trans_huge(*pmd));
|
|
|
|
return pmd;
|
|
}
|
|
|
|
static void take_rmap_locks(struct vm_area_struct *vma)
|
|
{
|
|
if (vma->vm_file)
|
|
i_mmap_lock_write(vma->vm_file->f_mapping);
|
|
if (vma->anon_vma)
|
|
anon_vma_lock_write(vma->anon_vma);
|
|
}
|
|
|
|
static void drop_rmap_locks(struct vm_area_struct *vma)
|
|
{
|
|
if (vma->anon_vma)
|
|
anon_vma_unlock_write(vma->anon_vma);
|
|
if (vma->vm_file)
|
|
i_mmap_unlock_write(vma->vm_file->f_mapping);
|
|
}
|
|
|
|
static pte_t move_soft_dirty_pte(pte_t pte)
|
|
{
|
|
/*
|
|
* Set soft dirty bit so we can notice
|
|
* in userspace the ptes were moved.
|
|
*/
|
|
#ifdef CONFIG_MEM_SOFT_DIRTY
|
|
if (pte_present(pte))
|
|
pte = pte_mksoft_dirty(pte);
|
|
else if (is_swap_pte(pte))
|
|
pte = pte_swp_mksoft_dirty(pte);
|
|
#endif
|
|
return pte;
|
|
}
|
|
|
|
static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
|
|
unsigned long old_addr, unsigned long old_end,
|
|
struct vm_area_struct *new_vma, pmd_t *new_pmd,
|
|
unsigned long new_addr, bool need_rmap_locks)
|
|
{
|
|
struct mm_struct *mm = vma->vm_mm;
|
|
pte_t *old_pte, *new_pte, pte;
|
|
spinlock_t *old_ptl, *new_ptl;
|
|
bool force_flush = false;
|
|
unsigned long len = old_end - old_addr;
|
|
|
|
/*
|
|
* When need_rmap_locks is true, we take the i_mmap_rwsem and anon_vma
|
|
* locks to ensure that rmap will always observe either the old or the
|
|
* new ptes. This is the easiest way to avoid races with
|
|
* truncate_pagecache(), page migration, etc...
|
|
*
|
|
* When need_rmap_locks is false, we use other ways to avoid
|
|
* such races:
|
|
*
|
|
* - During exec() shift_arg_pages(), we use a specially tagged vma
|
|
* which rmap call sites look for using is_vma_temporary_stack().
|
|
*
|
|
* - During mremap(), new_vma is often known to be placed after vma
|
|
* in rmap traversal order. This ensures rmap will always observe
|
|
* either the old pte, or the new pte, or both (the page table locks
|
|
* serialize access to individual ptes, but only rmap traversal
|
|
* order guarantees that we won't miss both the old and new ptes).
|
|
*/
|
|
if (need_rmap_locks)
|
|
take_rmap_locks(vma);
|
|
|
|
/*
|
|
* We don't have to worry about the ordering of src and dst
|
|
* pte locks because exclusive mmap_sem prevents deadlock.
|
|
*/
|
|
old_pte = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl);
|
|
new_pte = pte_offset_map(new_pmd, new_addr);
|
|
new_ptl = pte_lockptr(mm, new_pmd);
|
|
if (new_ptl != old_ptl)
|
|
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
|
|
flush_tlb_batched_pending(vma->vm_mm);
|
|
arch_enter_lazy_mmu_mode();
|
|
|
|
for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
|
|
new_pte++, new_addr += PAGE_SIZE) {
|
|
if (pte_none(*old_pte))
|
|
continue;
|
|
|
|
pte = ptep_get_and_clear(mm, old_addr, old_pte);
|
|
/*
|
|
* If we are remapping a valid PTE, make sure
|
|
* to flush TLB before we drop the PTL for the
|
|
* PTE.
|
|
*
|
|
* NOTE! Both old and new PTL matter: the old one
|
|
* for racing with page_mkclean(), the new one to
|
|
* make sure the physical page stays valid until
|
|
* the TLB entry for the old mapping has been
|
|
* flushed.
|
|
*/
|
|
if (pte_present(pte))
|
|
force_flush = true;
|
|
pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr);
|
|
pte = move_soft_dirty_pte(pte);
|
|
set_pte_at(mm, new_addr, new_pte, pte);
|
|
}
|
|
|
|
arch_leave_lazy_mmu_mode();
|
|
if (force_flush)
|
|
flush_tlb_range(vma, old_end - len, old_end);
|
|
if (new_ptl != old_ptl)
|
|
spin_unlock(new_ptl);
|
|
pte_unmap(new_pte - 1);
|
|
pte_unmap_unlock(old_pte - 1, old_ptl);
|
|
if (need_rmap_locks)
|
|
drop_rmap_locks(vma);
|
|
}
|
|
|
|
#define LATENCY_LIMIT (64 * PAGE_SIZE)
|
|
|
|
#ifdef CONFIG_HAVE_MOVE_PMD
|
|
static bool move_normal_pmd(struct vm_area_struct *vma, unsigned long old_addr,
|
|
unsigned long new_addr, unsigned long old_end,
|
|
pmd_t *old_pmd, pmd_t *new_pmd)
|
|
{
|
|
spinlock_t *old_ptl, *new_ptl;
|
|
struct mm_struct *mm = vma->vm_mm;
|
|
pmd_t pmd;
|
|
|
|
if ((old_addr & ~PMD_MASK) || (new_addr & ~PMD_MASK)
|
|
|| old_end - old_addr < PMD_SIZE)
|
|
return false;
|
|
|
|
/*
|
|
* The destination pmd shouldn't be established, free_pgtables()
|
|
* should have release it.
|
|
*/
|
|
if (WARN_ON(!pmd_none(*new_pmd)))
|
|
return false;
|
|
|
|
/*
|
|
* We don't have to worry about the ordering of src and dst
|
|
* ptlocks because exclusive mmap_sem prevents deadlock.
|
|
*/
|
|
old_ptl = pmd_lock(vma->vm_mm, old_pmd);
|
|
new_ptl = pmd_lockptr(mm, new_pmd);
|
|
if (new_ptl != old_ptl)
|
|
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
|
|
|
|
/* Clear the pmd */
|
|
pmd = *old_pmd;
|
|
pmd_clear(old_pmd);
|
|
|
|
VM_BUG_ON(!pmd_none(*new_pmd));
|
|
|
|
/* Set the new pmd */
|
|
set_pmd_at(mm, new_addr, new_pmd, pmd);
|
|
flush_tlb_range(vma, old_addr, old_addr + PMD_SIZE);
|
|
if (new_ptl != old_ptl)
|
|
spin_unlock(new_ptl);
|
|
spin_unlock(old_ptl);
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
unsigned long move_page_tables(struct vm_area_struct *vma,
|
|
unsigned long old_addr, struct vm_area_struct *new_vma,
|
|
unsigned long new_addr, unsigned long len,
|
|
bool need_rmap_locks)
|
|
{
|
|
unsigned long extent, next, old_end;
|
|
pmd_t *old_pmd, *new_pmd;
|
|
unsigned long mmun_start; /* For mmu_notifiers */
|
|
unsigned long mmun_end; /* For mmu_notifiers */
|
|
|
|
if (!len)
|
|
return 0;
|
|
|
|
old_end = old_addr + len;
|
|
flush_cache_range(vma, old_addr, old_end);
|
|
|
|
mmun_start = old_addr;
|
|
mmun_end = old_end;
|
|
mmu_notifier_invalidate_range_start(vma->vm_mm, mmun_start, mmun_end);
|
|
|
|
for (; old_addr < old_end; old_addr += extent, new_addr += extent) {
|
|
cond_resched();
|
|
next = (old_addr + PMD_SIZE) & PMD_MASK;
|
|
/* even if next overflowed, extent below will be ok */
|
|
extent = next - old_addr;
|
|
if (extent > old_end - old_addr)
|
|
extent = old_end - old_addr;
|
|
old_pmd = get_old_pmd(vma->vm_mm, old_addr);
|
|
if (!old_pmd)
|
|
continue;
|
|
new_pmd = alloc_new_pmd(vma->vm_mm, vma, new_addr);
|
|
if (!new_pmd)
|
|
break;
|
|
if (is_swap_pmd(*old_pmd) || pmd_trans_huge(*old_pmd) || pmd_devmap(*old_pmd)) {
|
|
if (extent == HPAGE_PMD_SIZE) {
|
|
bool moved;
|
|
/* See comment in move_ptes() */
|
|
if (need_rmap_locks)
|
|
take_rmap_locks(vma);
|
|
moved = move_huge_pmd(vma, old_addr, new_addr,
|
|
old_end, old_pmd, new_pmd);
|
|
if (need_rmap_locks)
|
|
drop_rmap_locks(vma);
|
|
if (moved)
|
|
continue;
|
|
}
|
|
split_huge_pmd(vma, old_pmd, old_addr);
|
|
if (pmd_trans_unstable(old_pmd))
|
|
continue;
|
|
} else if (extent == PMD_SIZE) {
|
|
#ifdef CONFIG_HAVE_MOVE_PMD
|
|
/*
|
|
* If the extent is PMD-sized, try to speed the move by
|
|
* moving at the PMD level if possible.
|
|
*/
|
|
bool moved;
|
|
|
|
if (need_rmap_locks)
|
|
take_rmap_locks(vma);
|
|
moved = move_normal_pmd(vma, old_addr, new_addr,
|
|
old_end, old_pmd, new_pmd);
|
|
if (need_rmap_locks)
|
|
drop_rmap_locks(vma);
|
|
if (moved)
|
|
continue;
|
|
#endif
|
|
}
|
|
|
|
if (pte_alloc(new_vma->vm_mm, new_pmd, new_addr))
|
|
break;
|
|
next = (new_addr + PMD_SIZE) & PMD_MASK;
|
|
if (extent > next - new_addr)
|
|
extent = next - new_addr;
|
|
if (extent > LATENCY_LIMIT)
|
|
extent = LATENCY_LIMIT;
|
|
move_ptes(vma, old_pmd, old_addr, old_addr + extent, new_vma,
|
|
new_pmd, new_addr, need_rmap_locks);
|
|
}
|
|
|
|
mmu_notifier_invalidate_range_end(vma->vm_mm, mmun_start, mmun_end);
|
|
|
|
return len + old_addr - old_end; /* how much done */
|
|
}
|
|
|
|
static unsigned long move_vma(struct vm_area_struct *vma,
|
|
unsigned long old_addr, unsigned long old_len,
|
|
unsigned long new_len, unsigned long new_addr,
|
|
bool *locked, struct vm_userfaultfd_ctx *uf,
|
|
struct list_head *uf_unmap)
|
|
{
|
|
struct mm_struct *mm = vma->vm_mm;
|
|
struct vm_area_struct *new_vma;
|
|
unsigned long vm_flags = vma->vm_flags;
|
|
unsigned long new_pgoff;
|
|
unsigned long moved_len;
|
|
unsigned long excess = 0;
|
|
unsigned long hiwater_vm;
|
|
int split = 0;
|
|
int err;
|
|
bool need_rmap_locks;
|
|
|
|
/*
|
|
* We'd prefer to avoid failure later on in do_munmap:
|
|
* which may split one vma into three before unmapping.
|
|
*/
|
|
if (mm->map_count >= sysctl_max_map_count - 3)
|
|
return -ENOMEM;
|
|
|
|
/*
|
|
* Advise KSM to break any KSM pages in the area to be moved:
|
|
* it would be confusing if they were to turn up at the new
|
|
* location, where they happen to coincide with different KSM
|
|
* pages recently unmapped. But leave vma->vm_flags as it was,
|
|
* so KSM can come around to merge on vma and new_vma afterwards.
|
|
*/
|
|
err = ksm_madvise(vma, old_addr, old_addr + old_len,
|
|
MADV_UNMERGEABLE, &vm_flags);
|
|
if (err)
|
|
return err;
|
|
|
|
new_pgoff = vma->vm_pgoff + ((old_addr - vma->vm_start) >> PAGE_SHIFT);
|
|
new_vma = copy_vma(&vma, new_addr, new_len, new_pgoff,
|
|
&need_rmap_locks);
|
|
if (!new_vma)
|
|
return -ENOMEM;
|
|
|
|
/* new_vma is returned protected by copy_vma, to prevent speculative
|
|
* page fault to be done in the destination area before we move the pte.
|
|
* Now, we must also protect the source VMA since we don't want pages
|
|
* to be mapped in our back while we are copying the PTEs.
|
|
*/
|
|
if (vma != new_vma)
|
|
vm_raw_write_begin(vma);
|
|
|
|
moved_len = move_page_tables(vma, old_addr, new_vma, new_addr, old_len,
|
|
need_rmap_locks);
|
|
if (moved_len < old_len) {
|
|
err = -ENOMEM;
|
|
} else if (vma->vm_ops && vma->vm_ops->mremap) {
|
|
err = vma->vm_ops->mremap(new_vma);
|
|
}
|
|
|
|
if (unlikely(err)) {
|
|
/*
|
|
* On error, move entries back from new area to old,
|
|
* which will succeed since page tables still there,
|
|
* and then proceed to unmap new area instead of old.
|
|
*/
|
|
move_page_tables(new_vma, new_addr, vma, old_addr, moved_len,
|
|
true);
|
|
if (vma != new_vma)
|
|
vm_raw_write_end(vma);
|
|
vma = new_vma;
|
|
old_len = new_len;
|
|
old_addr = new_addr;
|
|
new_addr = err;
|
|
} else {
|
|
mremap_userfaultfd_prep(new_vma, uf);
|
|
arch_remap(mm, old_addr, old_addr + old_len,
|
|
new_addr, new_addr + new_len);
|
|
if (vma != new_vma)
|
|
vm_raw_write_end(vma);
|
|
}
|
|
vm_raw_write_end(new_vma);
|
|
|
|
/* Conceal VM_ACCOUNT so old reservation is not undone */
|
|
if (vm_flags & VM_ACCOUNT) {
|
|
vma->vm_flags &= ~VM_ACCOUNT;
|
|
excess = vma->vm_end - vma->vm_start - old_len;
|
|
if (old_addr > vma->vm_start &&
|
|
old_addr + old_len < vma->vm_end)
|
|
split = 1;
|
|
}
|
|
|
|
/*
|
|
* If we failed to move page tables we still do total_vm increment
|
|
* since do_munmap() will decrement it by old_len == new_len.
|
|
*
|
|
* Since total_vm is about to be raised artificially high for a
|
|
* moment, we need to restore high watermark afterwards: if stats
|
|
* are taken meanwhile, total_vm and hiwater_vm appear too high.
|
|
* If this were a serious issue, we'd add a flag to do_munmap().
|
|
*/
|
|
hiwater_vm = mm->hiwater_vm;
|
|
vm_stat_account(mm, vma->vm_flags, new_len >> PAGE_SHIFT);
|
|
|
|
/* Tell pfnmap has moved from this vma */
|
|
if (unlikely(vma->vm_flags & VM_PFNMAP))
|
|
untrack_pfn_moved(vma);
|
|
|
|
if (do_munmap(mm, old_addr, old_len, uf_unmap) < 0) {
|
|
/* OOM: unable to split vma, just get accounts right */
|
|
vm_unacct_memory(excess >> PAGE_SHIFT);
|
|
excess = 0;
|
|
}
|
|
mm->hiwater_vm = hiwater_vm;
|
|
|
|
/* Restore VM_ACCOUNT if one or two pieces of vma left */
|
|
if (excess) {
|
|
vma->vm_flags |= VM_ACCOUNT;
|
|
if (split)
|
|
vma->vm_next->vm_flags |= VM_ACCOUNT;
|
|
}
|
|
|
|
if (vm_flags & VM_LOCKED) {
|
|
mm->locked_vm += new_len >> PAGE_SHIFT;
|
|
*locked = true;
|
|
}
|
|
|
|
return new_addr;
|
|
}
|
|
|
|
static struct vm_area_struct *vma_to_resize(unsigned long addr,
|
|
unsigned long old_len, unsigned long new_len, unsigned long *p)
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
struct vm_area_struct *vma = find_vma(mm, addr);
|
|
unsigned long pgoff;
|
|
|
|
if (!vma || vma->vm_start > addr)
|
|
return ERR_PTR(-EFAULT);
|
|
|
|
/*
|
|
* !old_len is a special case where an attempt is made to 'duplicate'
|
|
* a mapping. This makes no sense for private mappings as it will
|
|
* instead create a fresh/new mapping unrelated to the original. This
|
|
* is contrary to the basic idea of mremap which creates new mappings
|
|
* based on the original. There are no known use cases for this
|
|
* behavior. As a result, fail such attempts.
|
|
*/
|
|
if (!old_len && !(vma->vm_flags & (VM_SHARED | VM_MAYSHARE))) {
|
|
pr_warn_once("%s (%d): attempted to duplicate a private mapping with mremap. This is not supported.\n", current->comm, current->pid);
|
|
return ERR_PTR(-EINVAL);
|
|
}
|
|
|
|
if (is_vm_hugetlb_page(vma))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
/* We can't remap across vm area boundaries */
|
|
if (old_len > vma->vm_end - addr)
|
|
return ERR_PTR(-EFAULT);
|
|
|
|
if (new_len == old_len)
|
|
return vma;
|
|
|
|
/* Need to be careful about a growing mapping */
|
|
pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
|
|
pgoff += vma->vm_pgoff;
|
|
if (pgoff + (new_len >> PAGE_SHIFT) < pgoff)
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
|
|
return ERR_PTR(-EFAULT);
|
|
|
|
if (vma->vm_flags & VM_LOCKED) {
|
|
unsigned long locked, lock_limit;
|
|
locked = mm->locked_vm << PAGE_SHIFT;
|
|
lock_limit = rlimit(RLIMIT_MEMLOCK);
|
|
locked += new_len - old_len;
|
|
if (locked > lock_limit && !capable(CAP_IPC_LOCK))
|
|
return ERR_PTR(-EAGAIN);
|
|
}
|
|
|
|
if (!may_expand_vm(mm, vma->vm_flags,
|
|
(new_len - old_len) >> PAGE_SHIFT))
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
if (vma->vm_flags & VM_ACCOUNT) {
|
|
unsigned long charged = (new_len - old_len) >> PAGE_SHIFT;
|
|
if (security_vm_enough_memory_mm(mm, charged))
|
|
return ERR_PTR(-ENOMEM);
|
|
*p = charged;
|
|
}
|
|
|
|
return vma;
|
|
}
|
|
|
|
static unsigned long mremap_to(unsigned long addr, unsigned long old_len,
|
|
unsigned long new_addr, unsigned long new_len, bool *locked,
|
|
struct vm_userfaultfd_ctx *uf,
|
|
struct list_head *uf_unmap_early,
|
|
struct list_head *uf_unmap)
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
struct vm_area_struct *vma;
|
|
unsigned long ret = -EINVAL;
|
|
unsigned long charged = 0;
|
|
unsigned long map_flags;
|
|
|
|
if (offset_in_page(new_addr))
|
|
goto out;
|
|
|
|
if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len)
|
|
goto out;
|
|
|
|
/* Ensure the old/new locations do not overlap */
|
|
if (addr + old_len > new_addr && new_addr + new_len > addr)
|
|
goto out;
|
|
|
|
ret = do_munmap(mm, new_addr, new_len, uf_unmap_early);
|
|
if (ret)
|
|
goto out;
|
|
|
|
if (old_len >= new_len) {
|
|
ret = do_munmap(mm, addr+new_len, old_len - new_len, uf_unmap);
|
|
if (ret && old_len != new_len)
|
|
goto out;
|
|
old_len = new_len;
|
|
}
|
|
|
|
vma = vma_to_resize(addr, old_len, new_len, &charged);
|
|
if (IS_ERR(vma)) {
|
|
ret = PTR_ERR(vma);
|
|
goto out;
|
|
}
|
|
|
|
map_flags = MAP_FIXED;
|
|
if (vma->vm_flags & VM_MAYSHARE)
|
|
map_flags |= MAP_SHARED;
|
|
|
|
ret = get_unmapped_area(vma->vm_file, new_addr, new_len, vma->vm_pgoff +
|
|
((addr - vma->vm_start) >> PAGE_SHIFT),
|
|
map_flags);
|
|
if (offset_in_page(ret))
|
|
goto out1;
|
|
|
|
ret = move_vma(vma, addr, old_len, new_len, new_addr, locked, uf,
|
|
uf_unmap);
|
|
if (!(offset_in_page(ret)))
|
|
goto out;
|
|
out1:
|
|
vm_unacct_memory(charged);
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static int vma_expandable(struct vm_area_struct *vma, unsigned long delta)
|
|
{
|
|
unsigned long end = vma->vm_end + delta;
|
|
if (end < vma->vm_end) /* overflow */
|
|
return 0;
|
|
if (vma->vm_next && vma->vm_next->vm_start < end) /* intersection */
|
|
return 0;
|
|
if (get_unmapped_area(NULL, vma->vm_start, end - vma->vm_start,
|
|
0, MAP_FIXED) & ~PAGE_MASK)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Expand (or shrink) an existing mapping, potentially moving it at the
|
|
* same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
|
|
*
|
|
* MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise
|
|
* This option implies MREMAP_MAYMOVE.
|
|
*/
|
|
SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
|
|
unsigned long, new_len, unsigned long, flags,
|
|
unsigned long, new_addr)
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
struct vm_area_struct *vma;
|
|
unsigned long ret = -EINVAL;
|
|
unsigned long charged = 0;
|
|
bool locked = false;
|
|
struct vm_userfaultfd_ctx uf = NULL_VM_UFFD_CTX;
|
|
LIST_HEAD(uf_unmap_early);
|
|
LIST_HEAD(uf_unmap);
|
|
|
|
addr = untagged_addr(addr);
|
|
|
|
if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
|
|
return ret;
|
|
|
|
if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE))
|
|
return ret;
|
|
|
|
if (offset_in_page(addr))
|
|
return ret;
|
|
|
|
old_len = PAGE_ALIGN(old_len);
|
|
new_len = PAGE_ALIGN(new_len);
|
|
|
|
/*
|
|
* We allow a zero old-len as a special case
|
|
* for DOS-emu "duplicate shm area" thing. But
|
|
* a zero new-len is nonsensical.
|
|
*/
|
|
if (!new_len)
|
|
return ret;
|
|
|
|
if (down_write_killable(¤t->mm->mmap_sem))
|
|
return -EINTR;
|
|
|
|
if (flags & MREMAP_FIXED) {
|
|
ret = mremap_to(addr, old_len, new_addr, new_len,
|
|
&locked, &uf, &uf_unmap_early, &uf_unmap);
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* Always allow a shrinking remap: that just unmaps
|
|
* the unnecessary pages..
|
|
* do_munmap does all the needed commit accounting
|
|
*/
|
|
if (old_len >= new_len) {
|
|
ret = do_munmap(mm, addr+new_len, old_len - new_len, &uf_unmap);
|
|
if (ret && old_len != new_len)
|
|
goto out;
|
|
ret = addr;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* Ok, we need to grow..
|
|
*/
|
|
vma = vma_to_resize(addr, old_len, new_len, &charged);
|
|
if (IS_ERR(vma)) {
|
|
ret = PTR_ERR(vma);
|
|
goto out;
|
|
}
|
|
|
|
/* old_len exactly to the end of the area..
|
|
*/
|
|
if (old_len == vma->vm_end - addr) {
|
|
/* can we just expand the current mapping? */
|
|
if (vma_expandable(vma, new_len - old_len)) {
|
|
int pages = (new_len - old_len) >> PAGE_SHIFT;
|
|
|
|
if (vma_adjust(vma, vma->vm_start, addr + new_len,
|
|
vma->vm_pgoff, NULL)) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
vm_stat_account(mm, vma->vm_flags, pages);
|
|
if (vma->vm_flags & VM_LOCKED) {
|
|
mm->locked_vm += pages;
|
|
locked = true;
|
|
new_addr = addr;
|
|
}
|
|
ret = addr;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We weren't able to just expand or shrink the area,
|
|
* we need to create a new one and move it..
|
|
*/
|
|
ret = -ENOMEM;
|
|
if (flags & MREMAP_MAYMOVE) {
|
|
unsigned long map_flags = 0;
|
|
if (vma->vm_flags & VM_MAYSHARE)
|
|
map_flags |= MAP_SHARED;
|
|
|
|
new_addr = get_unmapped_area(vma->vm_file, 0, new_len,
|
|
vma->vm_pgoff +
|
|
((addr - vma->vm_start) >> PAGE_SHIFT),
|
|
map_flags);
|
|
if (offset_in_page(new_addr)) {
|
|
ret = new_addr;
|
|
goto out;
|
|
}
|
|
|
|
ret = move_vma(vma, addr, old_len, new_len, new_addr,
|
|
&locked, &uf, &uf_unmap);
|
|
}
|
|
out:
|
|
if (offset_in_page(ret)) {
|
|
vm_unacct_memory(charged);
|
|
locked = 0;
|
|
}
|
|
up_write(¤t->mm->mmap_sem);
|
|
if (locked && new_len > old_len)
|
|
mm_populate(new_addr + old_len, new_len - old_len);
|
|
userfaultfd_unmap_complete(mm, &uf_unmap_early);
|
|
mremap_userfaultfd_complete(&uf, addr, new_addr, old_len);
|
|
userfaultfd_unmap_complete(mm, &uf_unmap);
|
|
return ret;
|
|
}
|