Merge 4.14.299 into android-4.14-stable
Merge 4.14.298 into android-4.14-stable
Linux 4.14.299
wifi: brcmfmac: Fix potential buffer overflow in brcmf_fweh_event_worker()
* linux/bits.h: make BIT(), GENMASK(), and friends available in assembly
include/linux/bits.h
* linux/const.h: move UL() macro to include/linux/const.h
arch/arm64/include/asm/memory.h
include/linux/const.h
include/uapi/linux/const.h
* linux/const.h: prefix include guard of uapi/linux/const.h with _UAPI
include/uapi/linux/const.h
KVM: x86: emulator: update the emulation mode after CR0 write
KVM: x86: emulator: introduce emulator_recalc_and_set_mode
KVM: x86: emulator: em_sysexit should update ctxt->mode
KVM: x86: Mask off reserved bits in CPUID.80000008H
* ext4: fix warning in 'ext4_da_release_space'
fs/ext4/migrate.c
parisc: Export iosapic_serial_irq() symbol for serial port driver
* parisc: Make 8250_gsc driver dependend on CONFIG_PARISC
drivers/tty/serial/8250/Kconfig
* efi: random: reduce seed size to 32 bytes
include/linux/efi.h
* ALSA: usb-audio: Add quirks for MacroSilicon MS2100/MS2106 devices
sound/usb/quirks-table.h
sound/usb/quirks.c
* capabilities: fix potential memleak on error path from vfs_getxattr_alloc()
security/commoncap.c
* tcp/udp: Make early_demux back namespacified.
include/net/protocol.h
include/net/tcp.h
include/net/udp.h
net/ipv4/af_inet.c
net/ipv4/ip_input.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/ip6_input.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
btrfs: fix type of parameter generation in btrfs_get_dentry
block, bfq: protect 'bfqd->queued' by 'bfqd->lock'
* Bluetooth: L2CAP: Fix attempting to access uninitialized memory
net/bluetooth/l2cap_core.c
i2c: xiic: Add platform module alias
media: dvb-frontends/drxk: initialize err to 0
media: s5p_cec: limit msg.len to CEC_MAX_MSG_SIZE
* net, neigh: Fix null-ptr-deref in neigh_table_clear()
net/core/neighbour.c
* net: mdio: fix undefined behavior in bit shift for __mdiobus_register
drivers/net/phy/mdio_bus.c
* Bluetooth: L2CAP: fix use-after-free in l2cap_conn_del()
net/bluetooth/l2cap_core.c
* Bluetooth: L2CAP: Fix use-after-free caused by l2cap_reassemble_sdu
net/bluetooth/l2cap_core.c
btrfs: fix ulist leaks in error paths of qgroup self tests
btrfs: fix inode list leak during backref walking at resolve_indirect_refs()
isdn: mISDN: netjet: fix wrong check of device registration
mISDN: fix possible memory leak in mISDN_register_device()
rose: Fix NULL pointer dereference in rose_send_frame()
ipvs: use explicitly signed chars
net: sched: Fix use after free in red_enqueue()
ata: pata_legacy: fix pdc20230_set_piomode()
net: fec: fix improper use of NETDEV_TX_BUSY
nfc: nfcmrvl: Fix potential memory leak in nfcmrvl_i2c_nci_send()
nfc: s3fwrn5: Fix potential memory leak in s3fwrn5_nci_send()
net: dsa: Fix possible memory leaks in dsa_loop_init()
nfs4: Fix kmemleak when allocate slot failed
NFSv4.1: We must always send RECLAIM_COMPLETE after a reboot
NFSv4.1: Handle RECLAIM_COMPLETE trunking errors
* UPSTREAM: linux/const.h: move UL() macro to include/linux/const.h
arch/arm64/include/asm/memory.h
include/linux/const.h
include/uapi/linux/const.h
* UPSTREAM: linux/const.h: prefix include guard of uapi/linux/const.h with _UAPI
include/uapi/linux/const.h
* UPSTREAM: linux/bits.h: make BIT(), GENMASK(), and friends available in assembly
include/linux/bits.h
Linux 4.14.298
can: rcar_canfd: rcar_canfd_handle_global_receive(): fix IRQ storm on global FIFO receive
net: ehea: fix possible memory leak in ehea_register_port()
openvswitch: switch from WARN to pr_warn
ALSA: aoa: Fix I2S device accounting
ALSA: aoa: i2sbus: fix possible memory leak in i2sbus_add_dev()
* PM: domains: Fix handling of unavailable/disabled idle states
drivers/base/power/domain.c
net: ksz884x: fix missing pci_disable_device() on error in pcidev_init()
i40e: Fix flow-type by setting GL_HASH_INSET registers
i40e: Fix ethtool rx-flow-hash setting for X722
* media: videodev2.h: V4L2_DV_BT_BLANKING_HEIGHT should check 'interlaced'
include/uapi/linux/videodev2.h
* media: v4l2-dv-timings: add sanity checks for blanking values
drivers/media/v4l2-core/v4l2-dv-timings.c
media: vivid: dev->bitmap_cap wasn't freed in all cases
media: vivid: s_fbuf: add more sanity checks
PM: hibernate: Allow hybrid sleep to work with s2idle
can: mscan: mpc5xxx: mpc5xxx_can_probe(): add missing put_clock() in error path
* tcp: fix indefinite deferral of RTO with SACK reneging
net/ipv4/tcp_input.c
net: lantiq_etop: don't free skb when returning NETDEV_TX_BUSY
kcm: annotate data-races around kcm->rx_wait
kcm: annotate data-races around kcm->rx_psock
amd-xgbe: add the bit rate quirk for Molex cables
amd-xgbe: fix the SFP compliance codes check for DAC cables
x86/unwind/orc: Fix unreliable stack dump with gcov
ALSA: ac97: fix possible memory leak in snd_ac97_dev_register()
arc: iounmap() arg is volatile
drm/msm: Fix return type of mdp4_lvds_connector_mode_valid
net: ieee802154: fix error return code in dgram_bind()
mm,hugetlb: take hugetlb_lock before decrementing h->resv_huge_pages
xen/gntdev: Prevent leaking grants
Xen/gntdev: don't ignore kernel unmapping error
s390/futex: add missing EX_TABLE entry to __futex_atomic_op()
* kernfs: fix use-after-free in __kernfs_remove
fs/kernfs/dir.c
mmc: core: Fix kernel panic when remove non-standard SDIO card
drm/msm/hdmi: fix memory corruption with too many bridges
mac802154: Fix LQI recording
fbdev: smscufx: Fix several use-after-free bugs
iio: light: tsl2583: Fix module unloading
tools: iio: iio_utils: fix digit calculation
* xhci: Remove device endpoints from bandwidth list when freeing the device
drivers/usb/host/xhci-mem.c
* usb: xhci: add XHCI_SPURIOUS_SUCCESS to ASM1042 despite being a V0.96 controller
drivers/usb/host/xhci-pci.c
usb: bdc: change state when port disconnected
* usb: dwc3: gadget: Don't set IMI for no_interrupt
drivers/usb/dwc3/gadget.c
* USB: add RESET_RESUME quirk for NVIDIA Jetson devices in RCM
drivers/usb/core/quirks.c
ALSA: au88x0: use explicitly signed char
ALSA: Use del_timer_sync() before freeing timer
ACPI: video: Force backlight native for more TongFang devices
* media: v4l2-mem2mem: Apply DST_QUEUE_OFF_BASE on MMAP buffers across ioctls
drivers/media/v4l2-core/v4l2-mem2mem.c
iommu/vt-d: Clean up si_domain in the init_dmars() error path
net: hns: fix possible memory leak in hnae_ae_register()
net/atm: fix proc_mpc_write incorrect return value
* HID: magicmouse: Do not set BTN_MOUSE on double report
drivers/hid/hid-magicmouse.c
ACPI: extlog: Handle multiple records
btrfs: fix processing of delayed data refs during backref walking
* r8152: add PID for the Lenovo OneLink+ Dock
drivers/net/usb/cdc_ether.c
drivers/net/usb/r8152.c
* arm64: errata: Remove AES hwcap for COMPAT tasks
arch/arm64/Kconfig
arch/arm64/include/asm/cpucaps.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
KVM: arm64: vgic: Fix exit condition in scan_its_table()
ata: ahci: Match EM_MAX_SLOTS with SATA_PMP_MAX_PORTS
ata: ahci-imx: Fix MODULE_ALIAS
x86/microcode/AMD: Apply the patch early on every logical thread
ocfs2: fix BUG when iput after ocfs2_mknod fails
ocfs2: clear dinode links count in case of error
Merge 4.14.297 into android-4.14-stable
Linux 4.14.297
x86/speculation: Add RSB VM Exit protections
x86/bugs: Warn when "ibrs" mitigation is selected on Enhanced IBRS parts
x86/speculation: Use DECLARE_PER_CPU for x86_spec_ctrl_current
x86/speculation: Disable RRSBA behavior
x86/bugs: Add Cannon lake to RETBleed affected CPU list
x86/cpu/amd: Enumerate BTC_NO
x86/common: Stamp out the stepping madness
x86/speculation: Fill RSB on vmexit for IBRS
KVM: VMX: Fix IBRS handling after vmexit
KVM: VMX: Prevent guest RSB poisoning attacks with eIBRS
x86/speculation: Remove x86_spec_ctrl_mask
x86/speculation: Use cached host SPEC_CTRL value for guest entry/exit
x86/speculation: Fix SPEC_CTRL write on SMT state change
x86/speculation: Fix firmware entry SPEC_CTRL handling
x86/speculation: Fix RSB filling with CONFIG_RETPOLINE=n
x86/speculation: Add LFENCE to RSB fill sequence
x86/speculation: Change FILL_RETURN_BUFFER to work with objtool
entel_idle: Disable IBRS during long idle
x86/bugs: Report Intel retbleed vulnerability
x86/bugs: Split spectre_v2_select_mitigation() and spectre_v2_user_select_mitigation()
x86/speculation: Add spectre_v2=ibrs option to support Kernel IBRS
x86/bugs: Optimize SPEC_CTRL MSR writes
x86/entry: Add kernel IBRS implementation
x86/bugs: Keep a per-CPU IA32_SPEC_CTRL value
x86/bugs: Add AMD retbleed= boot parameter
* x86/bugs: Report AMD retbleed vulnerability
drivers/base/cpu.c
include/linux/cpu.h
x86/cpufeatures: Move RETPOLINE flags to word 11
x86/entry: Remove skip_r11rcx
* x86/cpu: Add a steppings field to struct x86_cpu_id
include/linux/mod_devicetable.h
x86/cpu: Add consistent CPU match macros
* x86/devicetable: Move x86 specific macro out of generic code
include/linux/mod_devicetable.h
x86/cpufeature: Fix various quality problems in the <asm/cpu_device_hd.h> header
x86/cpufeature: Add facility to check for min microcode revisions
* Revert "x86/cpu: Add a steppings field to struct x86_cpu_id"
include/linux/mod_devicetable.h
Merge 4.14.296 into android-4.14-stable
Linux 4.14.296
thermal: intel_powerclamp: Use first online CPU as control_cpu
* inet: fully convert sk->sk_rx_dst to RCU rules
include/net/sock.h
net/ipv4/af_inet.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
efi: libstub: drop pointless get_memory_map() call
md: Replace snprintf with scnprintf
* ext4: continue to expand file system when the target size doesn't reach
fs/ext4/resize.c
net/ieee802154: don't warn zero-sized raw_sendmsg()
net: ieee802154: return -EINVAL for unknown addr type
perf intel-pt: Fix segfault in intel_pt_print_info() with uClibc
usb: idmouse: fix an uninit-value in idmouse_open
* Revert "usb: storage: Add quirk for Samsung Fit flash"
drivers/usb/storage/unusual_devs.h
usb: musb: Fix musb_gadget.c rxstate overflow bug
* usb: host: xhci: Fix potential memory leak in xhci_alloc_stream_info()
drivers/usb/host/xhci-mem.c
md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d
HID: roccat: Fix use-after-free in roccat_read()
nbd: Fix hung when signal interrupts nbd_start_device_ioctl()
scsi: 3w-9xxx: Avoid disabling device if failing to enable it
media: cx88: Fix a null-ptr-deref bug in buffer_prepare()
ARM: dts: imx6sl: add missing properties for sram
ARM: dts: imx6qp: add missing properties for sram
ARM: dts: imx6dl: add missing properties for sram
ARM: dts: imx6q: add missing properties for sram
ARM: dts: imx7d-sdb: config the max pressure for tsc2046
drm/amdgpu: fix initial connector audio value
platform/x86: msi-laptop: Change DMI match / alias strings to fix module autoloading
drm/vc4: vec: Fix timings for VEC modes
* drm: Prevent drm_copy_field() to attempt copying a NULL pointer
drivers/gpu/drm/drm_ioctl.c
* drm: Use size_t type for len variable in drm_copy_field()
drivers/gpu/drm/drm_ioctl.c
* r8152: Rate limit overflow messages
drivers/net/usb/r8152.c
* Bluetooth: L2CAP: Fix user-after-free
net/bluetooth/l2cap_core.c
* net: If sock is dead don't access sock's sk_wq in sk_stream_wait_memory
net/core/stream.c
wifi: rt2x00: correctly set BBP register 86 for MT7620
wifi: rt2x00: set SoC wmac clock register
wifi: rt2x00: set correct TX_SW_CFG1 MAC register for MT7620
wifi: rt2x00: don't run Rt5592 IQ calibration on MT7620
can: bcm: check the result of can_send() in bcm_can_tx()
* Bluetooth: hci_sysfs: Fix attempting to call device_add multiple times
net/bluetooth/hci_sysfs.c
* Bluetooth: L2CAP: initialize delayed works at l2cap_chan_create()
net/bluetooth/l2cap_core.c
wifi: brcmfmac: fix use-after-free bug in brcmf_netdev_start_xmit()
* xfrm: Update ipcomp_scratches with NULL when freed
net/xfrm/xfrm_ipcomp.c
wifi: ath9k: avoid uninit memory read in ath9k_htc_rx_msg()
* tcp: annotate data-race around tcp_md5sig_pool_populated
net/ipv4/tcp.c
openvswitch: Fix overreporting of drops in dropwatch
openvswitch: Fix double reporting of drops in dropwatch
wifi: brcmfmac: fix invalid address access when enabling SCAN log level
NFSD: Return nfserr_serverfault if splice_ok but buf->pages have data
thermal: intel_powerclamp: Use get_cpu() instead of smp_processor_id() to avoid crash
powercap: intel_rapl: fix UBSAN shift-out-of-bounds issue
MIPS: BCM47XX: Cast memcmp() of function to (void *)
ACPI: video: Add Toshiba Satellite/Portege Z830 quirk
* f2fs: fix race condition on setting FI_NO_EXTENT flag
fs/f2fs/extent_cache.c
crypto: cavium - prevent integer overflow loading firmware
* iommu/iova: Fix module config properly
include/linux/iova.h
iommu/omap: Fix buffer overflow in debugfs
powerpc: Fix SPE Power ISA properties for e500v1 platforms
powerpc/powernv: add missing of_node_put() in opal_export_attrs()
powerpc/pci_dn: Add missing of_node_put()
powerpc/sysdev/fsl_msi: Add missing of_node_put()
powerpc/math_emu/efp: Include module.h
mailbox: bcm-ferxrm-mailbox: Fix error check for dma_map_sg
clk: ti: dra7-atl: Fix reference leak in of_dra7_atl_clk_probe
clk: bcm2835: fix bcm2835_clock_rate_from_divisor declaration
* spmi: pmic-arb: correct duplicate APID to PPID mapping logic
drivers/spmi/spmi-pmic-arb.c
dmaengine: ioat: stop mod_timer from resurrecting deleted timer in __cleanup()
mfd: sm501: Add check for platform_driver_register()
mfd: lp8788: Fix an error handling path in lp8788_irq_init() and lp8788_irq_init()
mfd: lp8788: Fix an error handling path in lp8788_probe()
mfd: fsl-imx25: Fix an error handling path in mx25_tsadc_setup_irq()
mfd: intel_soc_pmic: Fix an error handling path in intel_soc_pmic_i2c_probe()
fsi: core: Check error number after calling ida_simple_get
serial: 8250: Fix restoring termios speed after suspend
firmware: google: Test spinlock on panic path to avoid lockups
phy: qualcomm: call clk_disable_unprepare in the error handling
drivers: serial: jsm: fix some leaks in probe
usb: gadget: function: fix dangling pnp_string in f_printer.c
* xhci: Don't show warning for reinit on known broken suspend
drivers/usb/host/xhci.c
md/raid5: Ensure stripe_fill happens on non-read IO with journal
ata: fix ata_id_has_dipm()
ata: fix ata_id_has_ncq_autosense()
ata: fix ata_id_has_devslp()
ata: fix ata_id_sense_reporting_enabled() and ata_id_has_sense_reporting()
* dyndbg: let query-modname override actual module name
lib/dynamic_debug.c
* dyndbg: fix module.dyndbg handling
include/linux/dynamic_debug.h
RDMA/rxe: Fix the error caused by qp->sk
RDMA/rxe: Fix "kernel NULL pointer dereference" error
media: xilinx: vipp: Fix refcount leak in xvip_graph_dma_init
tty: xilinx_uartps: Fix the ignore_status
media: exynos4-is: fimc-is: Add of_node_put() when breaking out of loop
HSI: omap_ssi_port: Fix dma_map_sg error check
HSI: omap_ssi: Fix refcount leak in ssi_probe
clk: tegra20: Fix refcount leak in tegra20_clock_init
clk: tegra: Fix refcount leak in tegra114_clock_init
clk: tegra: Fix refcount leak in tegra210_clock_init
clk: oxnas: Hold reference returned by of_get_parent()
iio: ABI: Fix wrong format of differential capacitance channel ABI.
* iio: inkern: only release the device node when done with it
drivers/iio/inkern.c
iio: adc: at91-sama5d2_adc: fix AT91_SAMA5D2_MR_TRACKTIM_MAX
ARM: dts: exynos: fix polarity of VBUS GPIO of Origen
ARM: Drop CMDLINE_* dependency on ATAGS
ARM: dts: kirkwood: lsxl: remove first ethernet port
ARM: dts: kirkwood: lsxl: fix serial line
ARM: dts: turris-omnia: Fix mpp26 pin name and comment
* soc: qcom: smem_state: Add refcounting for the 'state->of_node'
drivers/soc/qcom/smem_state.c
soc: qcom: smsm: Fix refcount leak bugs in qcom_smsm_probe()
memory: of: Fix refcount leak bug in of_get_ddr_timings()
mmc: wmt-sdmmc: Fix an error handling path in wmt_mci_probe()
ALSA: dmaengine: increment buffer pointer atomically
ASoC: eureka-tlv320: Hold reference returned from of_find_xxx API
mmc: au1xmmc: Fix an error handling path in au1xmmc_probe()
drm/bridge: megachips: Fix a null pointer dereference bug
platform/x86: msi-laptop: Fix resource cleanup
platform/x86: msi-laptop: Fix old-ec check for backlight registering
* drm/mipi-dsi: Detach devices when removing the host
drivers/gpu/drm/drm_mipi_dsi.c
bnx2x: fix potential memory leak in bnx2x_tpa_stop()
net: rds: don't hold sock lock when cancelling work from rds_tcp_reset_callbacks()
* tcp: fix tcp_cwnd_validate() to not forget is_cwnd_limited
include/linux/tcp.h
include/net/tcp.h
net/ipv4/tcp.c
net/ipv4/tcp_output.c
mISDN: fix use-after-free bugs in l1oip timer handlers
vhost/vsock: Use kvmalloc/kvfree for larger packets.
spi: s3c64xx: Fix large transfers with DMA
netfilter: nft_fib: Fix for rpath check with VRF devices
spi/omap100k:Fix PM disable depth imbalance in omap1_spi100k_probe
net: fs_enet: Fix wrong check in do_pd_setup
wifi: rtl8xxxu: gen2: Fix mistake in path B IQ calibration
wifi: rtl8xxxu: Fix skb misuse in TX queue selection
spi: qup: add missing clk_disable_unprepare on error in spi_qup_pm_resume_runtime()
spi: qup: add missing clk_disable_unprepare on error in spi_qup_resume()
wifi: rtl8xxxu: tighten bounds checking in rtl8xxxu_read_efuse()
wifi: mac80211: allow bw change during channel switch in mesh
wifi: ath10k: add peer map clean up for peer delete in ath10k_sta_state()
sh: machvec: Use char[] for section boundaries
selinux: use "grep -E" instead of "egrep"
gcov: support GCC 12.1 and newer compilers
KVM: nVMX: Unconditionally purge queued/injected events on nested "exit"
KVM: x86/emulator: Fix handing of POP SS to correctly set interruptibility
* ring-buffer: Fix race between reset page and reading page
kernel/trace/ring_buffer.c
* ring-buffer: Check pending waiters when doing wake ups as well
kernel/trace/ring_buffer.c
* ring-buffer: Allow splice to read previous partially read pages
kernel/trace/ring_buffer.c
ftrace: Properly unset FTRACE_HASH_FL_MOD
livepatch: fix race between fork and KLP transition
* ext4: place buffer head allocation before handle start
fs/ext4/inode.c
* ext4: make ext4_lazyinit_thread freezable
fs/ext4/super.c
* ext4: fix null-ptr-deref in ext4_write_info
fs/ext4/super.c
* ext4: avoid crash when inline data creation follows DIO write
fs/ext4/file.c
nilfs2: fix lockdep warnings during disk space reclamation
nilfs2: fix lockdep warnings in page operations for btree nodes
nilfs2: fix use-after-free bug of struct nilfs_root
fbdev: smscufx: Fix use-after-free in ufx_ops_open()
* PCI: Sanitise firmware BAR assignments behind a PCI-PCI bridge
drivers/pci/setup-res.c
UM: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
parisc: fbdev/stifb: Align graphics memory size to 4MB
* Revert "fs: check FMODE_LSEEK to control internal pipe splicing"
fs/splice.c
regulator: qcom_rpm: Fix circular deferral regression
* quota: Check next/prev free block number after reading from quota file
fs/quota/quota_tree.c
* HID: multitouch: Add memory barriers
drivers/hid/hid-multitouch.c
fs: dlm: handle -EBUSY first in lock arg validation
fs: dlm: fix race between test_bit() and queue_work()
iio: dac: ad5593r: Fix i2c read protocol requirements
* ALSA: usb-audio: Fix NULL dererence at error path
sound/usb/endpoint.c
* ALSA: usb-audio: Fix potential memory leaks
sound/usb/endpoint.c
* ALSA: rawmidi: Drop register_mutex in snd_rawmidi_free()
sound/core/rawmidi.c
ALSA: oss: Fix potential deadlock at unregistration
* random: use expired timer rather than wq for mixing fast pool
drivers/char/random.c
* Input: xpad - fix wireless 360 controller breaking after suspend
drivers/input/joystick/xpad.c
* Input: xpad - add supported devices as contributed on github
drivers/input/joystick/xpad.c
wifi: mac80211_hwsim: avoid mac80211 warning on bad rate
* random: avoid reading two cache lines on irq randomness
drivers/char/random.c
* random: restore O_NONBLOCK support
drivers/char/mem.c
drivers/char/random.c
USB: serial: qcserial: add new usb-id for Dell branded EM7455
* scsi: stex: Properly zero out the passthrough command structure
include/scsi/scsi_cmnd.h
ALSA: hda: Fix position reporting on Poulsbo
* random: clamp credited irq bits to maximum mixed
drivers/char/random.c
ceph: don't truncate file in atomic_open
nilfs2: replace WARN_ONs by nilfs_error for checkpoint acquisition failure
nilfs2: fix leak of nilfs_root in case of writer thread creation failure
nilfs2: fix NULL pointer dereference at nilfs_bmap_lookup_at_level()
* netfilter: nf_queue: fix socket leak
net/netfilter/nf_queue.c
* rpmsg: qcom: glink: replace strncpy() with strscpy_pad()
drivers/rpmsg/qcom_glink_native.c
mmc: core: Terminate infinite loop in SD-UHS voltage switch
mmc: core: Replace with already defined values for readability
USB: serial: ftdi_sio: fix 300 bps rate for SIO
usb: mon: make mmapped memory read only
um: Cleanup compiler warning in arch/x86/um/tls_32.c
um: Cleanup syscall_handler_t cast in syscalls_32.h
net/ieee802154: fix uninit value bug in dgram_sendmsg
ARM: dts: fix Moxa SDIO 'compatible', remove 'sdhci' misnomer
dmaengine: xilinx_dma: Report error in case of dma_set_mask_and_coherent API failure
dmaengine: xilinx_dma: cleanup for fetching xlnx,num-fstores property
* fs: fix UAF/GPF bug in nilfs_mdt_destroy
fs/inode.c
ARM: fix function graph tracer and unwinder dependencies
* i2c: dev: prevent ZERO_SIZE_PTR deref in i2cdev_ioctl_rdwr()
drivers/i2c/i2c-dev.c
* Makefile.extrawarn: Move -Wcast-function-type-strict to W=1
scripts/Makefile.extrawarn
clk: iproc: Do not rely on node name for correct PLL setup
clk: iproc: Minor tidy up of iproc pll data structures
selftests: Fix the if conditions of in test_extra_filter()
nvme: Fix IOC_PR_CLEAR and IOC_PR_RELEASE ioctls for nvme devices
nvme: add new line after variable declatation
* usbnet: Fix memory leak in usbnet_disconnect()
drivers/net/usb/usbnet.c
Input: melfas_mip4 - fix return value check in mip4_probe()
Revert "drm: bridge: analogix/dp: add panel prepare/unprepare in suspend/resume time"
soc: sunxi: sram: Fix debugfs info for A64 SRAM C
soc: sunxi: sram: Actually claim SRAM regions
* mm/migrate_device.c: flush TLB while holding PTL
mm/migrate.c
* mm: prevent page_frag_alloc() from corrupting the memory
mm/page_alloc.c
* mm/page_alloc: fix race condition between build_all_zonelists and page allocation
mm/page_alloc.c
mmc: moxart: fix 4-bit bus width and remove 8-bit bus width
ntfs: fix BUG_ON in ntfs_lookup_inode_by_name()
net: usb: qmi_wwan: Add new usb-id for Dell branded EM7455
uas: ignore UAS for Thinkplus chips
usb-storage: Add Hiksemi USB3-FW to IGNORE_UAS
uas: add no-uas quirk for Hiksemi usb_disk
* ANDROID: kbuild: Wrap zero trivial-auto-var-init enablement flag with cc-option
Makefile
* UPSTREAM: f2fs: guarantee to write dirty data when enabling checkpoint back
fs/f2fs/file.c
fs/f2fs/super.c
Bug: 260299968
Change-Id: I3d8686e6dfa612ff0de4a72686637be0ce678aa6
Signed-off-by: Wilson Sung <wilsonsung@google.com>
Signed-off-by: JohnnLee <johnnlee@google.com>
1343 lines
38 KiB
C
1343 lines
38 KiB
C
/* Common capabilities, needed by capability.o.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
*/
|
|
|
|
#include <linux/capability.h>
|
|
#include <linux/audit.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/lsm_hooks.h>
|
|
#include <linux/file.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/swap.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netlink.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/xattr.h>
|
|
#include <linux/hugetlb.h>
|
|
#include <linux/mount.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/prctl.h>
|
|
#include <linux/securebits.h>
|
|
#include <linux/user_namespace.h>
|
|
#include <linux/binfmts.h>
|
|
#include <linux/personality.h>
|
|
|
|
/*
|
|
* If a non-root user executes a setuid-root binary in
|
|
* !secure(SECURE_NOROOT) mode, then we raise capabilities.
|
|
* However if fE is also set, then the intent is for only
|
|
* the file capabilities to be applied, and the setuid-root
|
|
* bit is left on either to change the uid (plausible) or
|
|
* to get full privilege on a kernel without file capabilities
|
|
* support. So in that case we do not raise capabilities.
|
|
*
|
|
* Warn if that happens, once per boot.
|
|
*/
|
|
static void warn_setuid_and_fcaps_mixed(const char *fname)
|
|
{
|
|
static int warned;
|
|
if (!warned) {
|
|
printk(KERN_INFO "warning: `%s' has both setuid-root and"
|
|
" effective capabilities. Therefore not raising all"
|
|
" capabilities.\n", fname);
|
|
warned = 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* __cap_capable - Determine whether a task has a particular effective capability
|
|
* @cred: The credentials to use
|
|
* @ns: The user namespace in which we need the capability
|
|
* @cap: The capability to check for
|
|
* @audit: Whether to write an audit message or not
|
|
*
|
|
* Determine whether the nominated task has the specified capability amongst
|
|
* its effective set, returning 0 if it does, -ve if it does not.
|
|
*
|
|
* NOTE WELL: cap_has_capability() cannot be used like the kernel's capable()
|
|
* and has_capability() functions. That is, it has the reverse semantics:
|
|
* cap_has_capability() returns 0 when a task has a capability, but the
|
|
* kernel's capable() and has_capability() returns 1 for this case.
|
|
*/
|
|
int __cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
|
int cap, int audit)
|
|
{
|
|
struct user_namespace *ns = targ_ns;
|
|
|
|
#ifdef CONFIG_ANDROID_PARANOID_NETWORK
|
|
if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW))
|
|
return 0;
|
|
if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN))
|
|
return 0;
|
|
#endif
|
|
|
|
/* See if cred has the capability in the target user namespace
|
|
* by examining the target user namespace and all of the target
|
|
* user namespace's parents.
|
|
*/
|
|
for (;;) {
|
|
/* Do we have the necessary capabilities? */
|
|
if (ns == cred->user_ns)
|
|
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
|
|
|
|
/*
|
|
* If we're already at a lower level than we're looking for,
|
|
* we're done searching.
|
|
*/
|
|
if (ns->level <= cred->user_ns->level)
|
|
return -EPERM;
|
|
|
|
/*
|
|
* The owner of the user namespace in the parent of the
|
|
* user namespace has all caps.
|
|
*/
|
|
if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))
|
|
return 0;
|
|
|
|
/*
|
|
* If you have a capability in a parent user ns, then you have
|
|
* it over all children user namespaces as well.
|
|
*/
|
|
ns = ns->parent;
|
|
}
|
|
|
|
/* We never get here */
|
|
}
|
|
|
|
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
|
|
int cap, int audit)
|
|
{
|
|
return __cap_capable(cred, targ_ns, cap, audit);
|
|
}
|
|
/**
|
|
* cap_settime - Determine whether the current process may set the system clock
|
|
* @ts: The time to set
|
|
* @tz: The timezone to set
|
|
*
|
|
* Determine whether the current process may set the system clock and timezone
|
|
* information, returning 0 if permission granted, -ve if denied.
|
|
*/
|
|
int cap_settime(const struct timespec64 *ts, const struct timezone *tz)
|
|
{
|
|
if (!capable(CAP_SYS_TIME))
|
|
return -EPERM;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* cap_ptrace_access_check - Determine whether the current process may access
|
|
* another
|
|
* @child: The process to be accessed
|
|
* @mode: The mode of attachment.
|
|
*
|
|
* If we are in the same or an ancestor user_ns and have all the target
|
|
* task's capabilities, then ptrace access is allowed.
|
|
* If we have the ptrace capability to the target user_ns, then ptrace
|
|
* access is allowed.
|
|
* Else denied.
|
|
*
|
|
* Determine whether a process may access another, returning 0 if permission
|
|
* granted, -ve if denied.
|
|
*/
|
|
int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
|
|
{
|
|
int ret = 0;
|
|
const struct cred *cred, *child_cred;
|
|
const kernel_cap_t *caller_caps;
|
|
|
|
rcu_read_lock();
|
|
cred = current_cred();
|
|
child_cred = __task_cred(child);
|
|
if (mode & PTRACE_MODE_FSCREDS)
|
|
caller_caps = &cred->cap_effective;
|
|
else
|
|
caller_caps = &cred->cap_permitted;
|
|
if (cred->user_ns == child_cred->user_ns &&
|
|
cap_issubset(child_cred->cap_permitted, *caller_caps))
|
|
goto out;
|
|
if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE))
|
|
goto out;
|
|
ret = -EPERM;
|
|
out:
|
|
rcu_read_unlock();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* cap_ptrace_traceme - Determine whether another process may trace the current
|
|
* @parent: The task proposed to be the tracer
|
|
*
|
|
* If parent is in the same or an ancestor user_ns and has all current's
|
|
* capabilities, then ptrace access is allowed.
|
|
* If parent has the ptrace capability to current's user_ns, then ptrace
|
|
* access is allowed.
|
|
* Else denied.
|
|
*
|
|
* Determine whether the nominated task is permitted to trace the current
|
|
* process, returning 0 if permission is granted, -ve if denied.
|
|
*/
|
|
int cap_ptrace_traceme(struct task_struct *parent)
|
|
{
|
|
int ret = 0;
|
|
const struct cred *cred, *child_cred;
|
|
|
|
rcu_read_lock();
|
|
cred = __task_cred(parent);
|
|
child_cred = current_cred();
|
|
if (cred->user_ns == child_cred->user_ns &&
|
|
cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
|
|
goto out;
|
|
if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE))
|
|
goto out;
|
|
ret = -EPERM;
|
|
out:
|
|
rcu_read_unlock();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* cap_capget - Retrieve a task's capability sets
|
|
* @target: The task from which to retrieve the capability sets
|
|
* @effective: The place to record the effective set
|
|
* @inheritable: The place to record the inheritable set
|
|
* @permitted: The place to record the permitted set
|
|
*
|
|
* This function retrieves the capabilities of the nominated task and returns
|
|
* them to the caller.
|
|
*/
|
|
int cap_capget(struct task_struct *target, kernel_cap_t *effective,
|
|
kernel_cap_t *inheritable, kernel_cap_t *permitted)
|
|
{
|
|
const struct cred *cred;
|
|
|
|
/* Derived from kernel/capability.c:sys_capget. */
|
|
rcu_read_lock();
|
|
cred = __task_cred(target);
|
|
*effective = cred->cap_effective;
|
|
*inheritable = cred->cap_inheritable;
|
|
*permitted = cred->cap_permitted;
|
|
rcu_read_unlock();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Determine whether the inheritable capabilities are limited to the old
|
|
* permitted set. Returns 1 if they are limited, 0 if they are not.
|
|
*/
|
|
static inline int cap_inh_is_capped(void)
|
|
{
|
|
|
|
/* they are so limited unless the current task has the CAP_SETPCAP
|
|
* capability
|
|
*/
|
|
if (cap_capable(current_cred(), current_cred()->user_ns,
|
|
CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* cap_capset - Validate and apply proposed changes to current's capabilities
|
|
* @new: The proposed new credentials; alterations should be made here
|
|
* @old: The current task's current credentials
|
|
* @effective: A pointer to the proposed new effective capabilities set
|
|
* @inheritable: A pointer to the proposed new inheritable capabilities set
|
|
* @permitted: A pointer to the proposed new permitted capabilities set
|
|
*
|
|
* This function validates and applies a proposed mass change to the current
|
|
* process's capability sets. The changes are made to the proposed new
|
|
* credentials, and assuming no error, will be committed by the caller of LSM.
|
|
*/
|
|
int cap_capset(struct cred *new,
|
|
const struct cred *old,
|
|
const kernel_cap_t *effective,
|
|
const kernel_cap_t *inheritable,
|
|
const kernel_cap_t *permitted)
|
|
{
|
|
if (cap_inh_is_capped() &&
|
|
!cap_issubset(*inheritable,
|
|
cap_combine(old->cap_inheritable,
|
|
old->cap_permitted)))
|
|
/* incapable of using this inheritable set */
|
|
return -EPERM;
|
|
|
|
if (!cap_issubset(*inheritable,
|
|
cap_combine(old->cap_inheritable,
|
|
old->cap_bset)))
|
|
/* no new pI capabilities outside bounding set */
|
|
return -EPERM;
|
|
|
|
/* verify restrictions on target's new Permitted set */
|
|
if (!cap_issubset(*permitted, old->cap_permitted))
|
|
return -EPERM;
|
|
|
|
/* verify the _new_Effective_ is a subset of the _new_Permitted_ */
|
|
if (!cap_issubset(*effective, *permitted))
|
|
return -EPERM;
|
|
|
|
new->cap_effective = *effective;
|
|
new->cap_inheritable = *inheritable;
|
|
new->cap_permitted = *permitted;
|
|
|
|
/*
|
|
* Mask off ambient bits that are no longer both permitted and
|
|
* inheritable.
|
|
*/
|
|
new->cap_ambient = cap_intersect(new->cap_ambient,
|
|
cap_intersect(*permitted,
|
|
*inheritable));
|
|
if (WARN_ON(!cap_ambient_invariant_ok(new)))
|
|
return -EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* cap_inode_need_killpriv - Determine if inode change affects privileges
|
|
* @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV
|
|
*
|
|
* Determine if an inode having a change applied that's marked ATTR_KILL_PRIV
|
|
* affects the security markings on that inode, and if it is, should
|
|
* inode_killpriv() be invoked or the change rejected.
|
|
*
|
|
* Returns 1 if security.capability has a value, meaning inode_killpriv()
|
|
* is required, 0 otherwise, meaning inode_killpriv() is not required.
|
|
*/
|
|
int cap_inode_need_killpriv(struct dentry *dentry)
|
|
{
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
int error;
|
|
|
|
error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
|
|
return error > 0;
|
|
}
|
|
|
|
/**
|
|
* cap_inode_killpriv - Erase the security markings on an inode
|
|
* @dentry: The inode/dentry to alter
|
|
*
|
|
* Erase the privilege-enhancing security markings on an inode.
|
|
*
|
|
* Returns 0 if successful, -ve on error.
|
|
*/
|
|
int cap_inode_killpriv(struct dentry *dentry)
|
|
{
|
|
int error;
|
|
|
|
error = __vfs_removexattr(dentry, XATTR_NAME_CAPS);
|
|
if (error == -EOPNOTSUPP)
|
|
error = 0;
|
|
return error;
|
|
}
|
|
|
|
static bool rootid_owns_currentns(kuid_t kroot)
|
|
{
|
|
struct user_namespace *ns;
|
|
|
|
if (!uid_valid(kroot))
|
|
return false;
|
|
|
|
for (ns = current_user_ns(); ; ns = ns->parent) {
|
|
if (from_kuid(ns, kroot) == 0)
|
|
return true;
|
|
if (ns == &init_user_ns)
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static __u32 sansflags(__u32 m)
|
|
{
|
|
return m & ~VFS_CAP_FLAGS_EFFECTIVE;
|
|
}
|
|
|
|
static bool is_v2header(size_t size, const struct vfs_cap_data *cap)
|
|
{
|
|
if (size != XATTR_CAPS_SZ_2)
|
|
return false;
|
|
return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2;
|
|
}
|
|
|
|
static bool is_v3header(size_t size, const struct vfs_cap_data *cap)
|
|
{
|
|
if (size != XATTR_CAPS_SZ_3)
|
|
return false;
|
|
return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_3;
|
|
}
|
|
|
|
/*
|
|
* getsecurity: We are called for security.* before any attempt to read the
|
|
* xattr from the inode itself.
|
|
*
|
|
* This gives us a chance to read the on-disk value and convert it. If we
|
|
* return -EOPNOTSUPP, then vfs_getxattr() will call the i_op handler.
|
|
*
|
|
* Note we are not called by vfs_getxattr_alloc(), but that is only called
|
|
* by the integrity subsystem, which really wants the unconverted values -
|
|
* so that's good.
|
|
*/
|
|
int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
|
|
bool alloc)
|
|
{
|
|
int size, ret;
|
|
kuid_t kroot;
|
|
u32 nsmagic, magic;
|
|
uid_t root, mappedroot;
|
|
char *tmpbuf = NULL;
|
|
struct vfs_cap_data *cap;
|
|
struct vfs_ns_cap_data *nscap = NULL;
|
|
struct dentry *dentry;
|
|
struct user_namespace *fs_ns;
|
|
|
|
if (strcmp(name, "capability") != 0)
|
|
return -EOPNOTSUPP;
|
|
|
|
dentry = d_find_any_alias(inode);
|
|
if (!dentry)
|
|
return -EINVAL;
|
|
|
|
size = sizeof(struct vfs_ns_cap_data);
|
|
ret = (int) vfs_getxattr_alloc(dentry, XATTR_NAME_CAPS,
|
|
&tmpbuf, size, GFP_NOFS);
|
|
dput(dentry);
|
|
|
|
if (ret < 0 || !tmpbuf) {
|
|
size = ret;
|
|
goto out_free;
|
|
}
|
|
|
|
fs_ns = inode->i_sb->s_user_ns;
|
|
cap = (struct vfs_cap_data *) tmpbuf;
|
|
if (is_v2header((size_t) ret, cap)) {
|
|
root = 0;
|
|
} else if (is_v3header((size_t) ret, cap)) {
|
|
nscap = (struct vfs_ns_cap_data *) tmpbuf;
|
|
root = le32_to_cpu(nscap->rootid);
|
|
} else {
|
|
size = -EINVAL;
|
|
goto out_free;
|
|
}
|
|
|
|
kroot = make_kuid(fs_ns, root);
|
|
|
|
/* If the root kuid maps to a valid uid in current ns, then return
|
|
* this as a nscap. */
|
|
mappedroot = from_kuid(current_user_ns(), kroot);
|
|
if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) {
|
|
size = sizeof(struct vfs_ns_cap_data);
|
|
if (alloc) {
|
|
if (!nscap) {
|
|
/* v2 -> v3 conversion */
|
|
nscap = kzalloc(size, GFP_ATOMIC);
|
|
if (!nscap) {
|
|
size = -ENOMEM;
|
|
goto out_free;
|
|
}
|
|
nsmagic = VFS_CAP_REVISION_3;
|
|
magic = le32_to_cpu(cap->magic_etc);
|
|
if (magic & VFS_CAP_FLAGS_EFFECTIVE)
|
|
nsmagic |= VFS_CAP_FLAGS_EFFECTIVE;
|
|
memcpy(&nscap->data, &cap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
|
|
nscap->magic_etc = cpu_to_le32(nsmagic);
|
|
} else {
|
|
/* use allocated v3 buffer */
|
|
tmpbuf = NULL;
|
|
}
|
|
nscap->rootid = cpu_to_le32(mappedroot);
|
|
*buffer = nscap;
|
|
}
|
|
goto out_free;
|
|
}
|
|
|
|
if (!rootid_owns_currentns(kroot)) {
|
|
size = -EOVERFLOW;
|
|
goto out_free;
|
|
}
|
|
|
|
/* This comes from a parent namespace. Return as a v2 capability */
|
|
size = sizeof(struct vfs_cap_data);
|
|
if (alloc) {
|
|
if (nscap) {
|
|
/* v3 -> v2 conversion */
|
|
cap = kzalloc(size, GFP_ATOMIC);
|
|
if (!cap) {
|
|
size = -ENOMEM;
|
|
goto out_free;
|
|
}
|
|
magic = VFS_CAP_REVISION_2;
|
|
nsmagic = le32_to_cpu(nscap->magic_etc);
|
|
if (nsmagic & VFS_CAP_FLAGS_EFFECTIVE)
|
|
magic |= VFS_CAP_FLAGS_EFFECTIVE;
|
|
memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
|
|
cap->magic_etc = cpu_to_le32(magic);
|
|
} else {
|
|
/* use unconverted v2 */
|
|
tmpbuf = NULL;
|
|
}
|
|
*buffer = cap;
|
|
}
|
|
out_free:
|
|
kfree(tmpbuf);
|
|
return size;
|
|
}
|
|
|
|
static kuid_t rootid_from_xattr(const void *value, size_t size,
|
|
struct user_namespace *task_ns)
|
|
{
|
|
const struct vfs_ns_cap_data *nscap = value;
|
|
uid_t rootid = 0;
|
|
|
|
if (size == XATTR_CAPS_SZ_3)
|
|
rootid = le32_to_cpu(nscap->rootid);
|
|
|
|
return make_kuid(task_ns, rootid);
|
|
}
|
|
|
|
static bool validheader(size_t size, const struct vfs_cap_data *cap)
|
|
{
|
|
return is_v2header(size, cap) || is_v3header(size, cap);
|
|
}
|
|
|
|
/*
|
|
* User requested a write of security.capability. If needed, update the
|
|
* xattr to change from v2 to v3, or to fixup the v3 rootid.
|
|
*
|
|
* If all is ok, we return the new size, on error return < 0.
|
|
*/
|
|
int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size)
|
|
{
|
|
struct vfs_ns_cap_data *nscap;
|
|
uid_t nsrootid;
|
|
const struct vfs_cap_data *cap = *ivalue;
|
|
__u32 magic, nsmagic;
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
struct user_namespace *task_ns = current_user_ns(),
|
|
*fs_ns = inode->i_sb->s_user_ns;
|
|
kuid_t rootid;
|
|
size_t newsize;
|
|
|
|
if (!*ivalue)
|
|
return -EINVAL;
|
|
if (!validheader(size, cap))
|
|
return -EINVAL;
|
|
if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP))
|
|
return -EPERM;
|
|
if (size == XATTR_CAPS_SZ_2)
|
|
if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP))
|
|
/* user is privileged, just write the v2 */
|
|
return size;
|
|
|
|
rootid = rootid_from_xattr(*ivalue, size, task_ns);
|
|
if (!uid_valid(rootid))
|
|
return -EINVAL;
|
|
|
|
nsrootid = from_kuid(fs_ns, rootid);
|
|
if (nsrootid == -1)
|
|
return -EINVAL;
|
|
|
|
newsize = sizeof(struct vfs_ns_cap_data);
|
|
nscap = kmalloc(newsize, GFP_ATOMIC);
|
|
if (!nscap)
|
|
return -ENOMEM;
|
|
nscap->rootid = cpu_to_le32(nsrootid);
|
|
nsmagic = VFS_CAP_REVISION_3;
|
|
magic = le32_to_cpu(cap->magic_etc);
|
|
if (magic & VFS_CAP_FLAGS_EFFECTIVE)
|
|
nsmagic |= VFS_CAP_FLAGS_EFFECTIVE;
|
|
nscap->magic_etc = cpu_to_le32(nsmagic);
|
|
memcpy(&nscap->data, &cap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
|
|
|
|
kvfree(*ivalue);
|
|
*ivalue = nscap;
|
|
return newsize;
|
|
}
|
|
|
|
/*
|
|
* Calculate the new process capability sets from the capability sets attached
|
|
* to a file.
|
|
*/
|
|
static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
|
struct linux_binprm *bprm,
|
|
bool *effective,
|
|
bool *has_cap)
|
|
{
|
|
struct cred *new = bprm->cred;
|
|
unsigned i;
|
|
int ret = 0;
|
|
|
|
if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
|
|
*effective = true;
|
|
|
|
if (caps->magic_etc & VFS_CAP_REVISION_MASK)
|
|
*has_cap = true;
|
|
|
|
CAP_FOR_EACH_U32(i) {
|
|
__u32 permitted = caps->permitted.cap[i];
|
|
__u32 inheritable = caps->inheritable.cap[i];
|
|
|
|
/*
|
|
* pP' = (X & fP) | (pI & fI)
|
|
* The addition of pA' is handled later.
|
|
*/
|
|
new->cap_permitted.cap[i] =
|
|
(new->cap_bset.cap[i] & permitted) |
|
|
(new->cap_inheritable.cap[i] & inheritable);
|
|
|
|
if (permitted & ~new->cap_permitted.cap[i])
|
|
/* insufficient to execute correctly */
|
|
ret = -EPERM;
|
|
}
|
|
|
|
/*
|
|
* For legacy apps, with no internal support for recognizing they
|
|
* do not have enough capabilities, we return an error if they are
|
|
* missing some "forced" (aka file-permitted) capabilities.
|
|
*/
|
|
return *effective ? ret : 0;
|
|
}
|
|
|
|
/*
|
|
* Extract the on-exec-apply capability sets for an executable file.
|
|
*/
|
|
int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
|
|
{
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
__u32 magic_etc;
|
|
unsigned tocopy, i;
|
|
int size;
|
|
struct vfs_ns_cap_data data, *nscaps = &data;
|
|
struct vfs_cap_data *caps = (struct vfs_cap_data *) &data;
|
|
kuid_t rootkuid;
|
|
struct user_namespace *fs_ns;
|
|
|
|
memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
|
|
|
|
if (!inode)
|
|
return -ENODATA;
|
|
|
|
fs_ns = inode->i_sb->s_user_ns;
|
|
size = __vfs_getxattr((struct dentry *)dentry, inode,
|
|
XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ);
|
|
if (size == -ENODATA || size == -EOPNOTSUPP)
|
|
/* no data, that's ok */
|
|
return -ENODATA;
|
|
|
|
if (size < 0)
|
|
return size;
|
|
|
|
if (size < sizeof(magic_etc))
|
|
return -EINVAL;
|
|
|
|
cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps->magic_etc);
|
|
|
|
rootkuid = make_kuid(fs_ns, 0);
|
|
switch (magic_etc & VFS_CAP_REVISION_MASK) {
|
|
case VFS_CAP_REVISION_1:
|
|
if (size != XATTR_CAPS_SZ_1)
|
|
return -EINVAL;
|
|
tocopy = VFS_CAP_U32_1;
|
|
break;
|
|
case VFS_CAP_REVISION_2:
|
|
if (size != XATTR_CAPS_SZ_2)
|
|
return -EINVAL;
|
|
tocopy = VFS_CAP_U32_2;
|
|
break;
|
|
case VFS_CAP_REVISION_3:
|
|
if (size != XATTR_CAPS_SZ_3)
|
|
return -EINVAL;
|
|
tocopy = VFS_CAP_U32_3;
|
|
rootkuid = make_kuid(fs_ns, le32_to_cpu(nscaps->rootid));
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
/* Limit the caps to the mounter of the filesystem
|
|
* or the more limited uid specified in the xattr.
|
|
*/
|
|
if (!rootid_owns_currentns(rootkuid))
|
|
return -ENODATA;
|
|
|
|
CAP_FOR_EACH_U32(i) {
|
|
if (i >= tocopy)
|
|
break;
|
|
cpu_caps->permitted.cap[i] = le32_to_cpu(caps->data[i].permitted);
|
|
cpu_caps->inheritable.cap[i] = le32_to_cpu(caps->data[i].inheritable);
|
|
}
|
|
|
|
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
|
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Attempt to get the on-exec apply capability sets for an executable file from
|
|
* its xattrs and, if present, apply them to the proposed credentials being
|
|
* constructed by execve().
|
|
*/
|
|
static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap)
|
|
{
|
|
int rc = 0;
|
|
struct cpu_vfs_cap_data vcaps;
|
|
|
|
cap_clear(bprm->cred->cap_permitted);
|
|
|
|
if (!file_caps_enabled)
|
|
return 0;
|
|
|
|
if (!mnt_may_suid(bprm->file->f_path.mnt))
|
|
return 0;
|
|
|
|
/*
|
|
* This check is redundant with mnt_may_suid() but is kept to make
|
|
* explicit that capability bits are limited to s_user_ns and its
|
|
* descendants.
|
|
*/
|
|
if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns))
|
|
return 0;
|
|
|
|
rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps);
|
|
if (rc < 0) {
|
|
if (rc == -EINVAL)
|
|
printk(KERN_NOTICE "Invalid argument reading file caps for %s\n",
|
|
bprm->filename);
|
|
else if (rc == -ENODATA)
|
|
rc = 0;
|
|
goto out;
|
|
}
|
|
|
|
rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap);
|
|
if (rc == -EINVAL)
|
|
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
|
|
__func__, rc, bprm->filename);
|
|
|
|
out:
|
|
if (rc)
|
|
cap_clear(bprm->cred->cap_permitted);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* cap_bprm_set_creds - Set up the proposed credentials for execve().
|
|
* @bprm: The execution parameters, including the proposed creds
|
|
*
|
|
* Set up the proposed credentials for a new execution context being
|
|
* constructed by execve(). The proposed creds in @bprm->cred is altered,
|
|
* which won't take effect immediately. Returns 0 if successful, -ve on error.
|
|
*/
|
|
int cap_bprm_set_creds(struct linux_binprm *bprm)
|
|
{
|
|
const struct cred *old = current_cred();
|
|
struct cred *new = bprm->cred;
|
|
bool effective, has_cap = false, is_setid;
|
|
int ret;
|
|
kuid_t root_uid;
|
|
|
|
new->cap_ambient = old->cap_ambient;
|
|
if (WARN_ON(!cap_ambient_invariant_ok(old)))
|
|
return -EPERM;
|
|
|
|
effective = false;
|
|
ret = get_file_caps(bprm, &effective, &has_cap);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
root_uid = make_kuid(new->user_ns, 0);
|
|
|
|
if (!issecure(SECURE_NOROOT)) {
|
|
/*
|
|
* If the legacy file capability is set, then don't set privs
|
|
* for a setuid root binary run by a non-root user. Do set it
|
|
* for a root user just to cause least surprise to an admin.
|
|
*/
|
|
if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) {
|
|
warn_setuid_and_fcaps_mixed(bprm->filename);
|
|
goto skip;
|
|
}
|
|
/*
|
|
* To support inheritance of root-permissions and suid-root
|
|
* executables under compatibility mode, we override the
|
|
* capability sets for the file.
|
|
*
|
|
* If only the real uid is 0, we do not set the effective bit.
|
|
*/
|
|
if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) {
|
|
/* pP' = (cap_bset & ~0) | (pI & ~0) */
|
|
new->cap_permitted = cap_combine(old->cap_bset,
|
|
old->cap_inheritable);
|
|
}
|
|
if (uid_eq(new->euid, root_uid))
|
|
effective = true;
|
|
}
|
|
skip:
|
|
|
|
/* if we have fs caps, clear dangerous personality flags */
|
|
if (!cap_issubset(new->cap_permitted, old->cap_permitted))
|
|
bprm->per_clear |= PER_CLEAR_ON_SETID;
|
|
|
|
|
|
/* Don't let someone trace a set[ug]id/setpcap binary with the revised
|
|
* credentials unless they have the appropriate permit.
|
|
*
|
|
* In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
|
|
*/
|
|
is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid);
|
|
|
|
if ((is_setid ||
|
|
!cap_issubset(new->cap_permitted, old->cap_permitted)) &&
|
|
((bprm->unsafe & ~LSM_UNSAFE_PTRACE) ||
|
|
!ptracer_capable(current, new->user_ns))) {
|
|
/* downgrade; they get no more than they had, and maybe less */
|
|
if (!ns_capable(new->user_ns, CAP_SETUID) ||
|
|
(bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) {
|
|
new->euid = new->uid;
|
|
new->egid = new->gid;
|
|
}
|
|
new->cap_permitted = cap_intersect(new->cap_permitted,
|
|
old->cap_permitted);
|
|
}
|
|
|
|
new->suid = new->fsuid = new->euid;
|
|
new->sgid = new->fsgid = new->egid;
|
|
|
|
/* File caps or setid cancels ambient. */
|
|
if (has_cap || is_setid)
|
|
cap_clear(new->cap_ambient);
|
|
|
|
/*
|
|
* Now that we've computed pA', update pP' to give:
|
|
* pP' = (X & fP) | (pI & fI) | pA'
|
|
*/
|
|
new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient);
|
|
|
|
/*
|
|
* Set pE' = (fE ? pP' : pA'). Because pA' is zero if fE is set,
|
|
* this is the same as pE' = (fE ? pP' : 0) | pA'.
|
|
*/
|
|
if (effective)
|
|
new->cap_effective = new->cap_permitted;
|
|
else
|
|
new->cap_effective = new->cap_ambient;
|
|
|
|
if (WARN_ON(!cap_ambient_invariant_ok(new)))
|
|
return -EPERM;
|
|
|
|
/*
|
|
* Audit candidate if current->cap_effective is set
|
|
*
|
|
* We do not bother to audit if 3 things are true:
|
|
* 1) cap_effective has all caps
|
|
* 2) we are root
|
|
* 3) root is supposed to have all caps (SECURE_NOROOT)
|
|
* Since this is just a normal root execing a process.
|
|
*
|
|
* Number 1 above might fail if you don't have a full bset, but I think
|
|
* that is interesting information to audit.
|
|
*/
|
|
if (!cap_issubset(new->cap_effective, new->cap_ambient)) {
|
|
if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
|
|
!uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
|
|
issecure(SECURE_NOROOT)) {
|
|
ret = audit_log_bprm_fcaps(bprm, new, old);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
|
|
|
|
if (WARN_ON(!cap_ambient_invariant_ok(new)))
|
|
return -EPERM;
|
|
|
|
/* Check for privilege-elevated exec. */
|
|
bprm->cap_elevated = 0;
|
|
if (is_setid) {
|
|
bprm->cap_elevated = 1;
|
|
} else if (!uid_eq(new->uid, root_uid)) {
|
|
if (effective ||
|
|
!cap_issubset(new->cap_permitted, new->cap_ambient))
|
|
bprm->cap_elevated = 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* cap_inode_setxattr - Determine whether an xattr may be altered
|
|
* @dentry: The inode/dentry being altered
|
|
* @name: The name of the xattr to be changed
|
|
* @value: The value that the xattr will be changed to
|
|
* @size: The size of value
|
|
* @flags: The replacement flag
|
|
*
|
|
* Determine whether an xattr may be altered or set on an inode, returning 0 if
|
|
* permission is granted, -ve if denied.
|
|
*
|
|
* This is used to make sure security xattrs don't get updated or set by those
|
|
* who aren't privileged to do so.
|
|
*/
|
|
int cap_inode_setxattr(struct dentry *dentry, const char *name,
|
|
const void *value, size_t size, int flags)
|
|
{
|
|
/* Ignore non-security xattrs */
|
|
if (strncmp(name, XATTR_SECURITY_PREFIX,
|
|
sizeof(XATTR_SECURITY_PREFIX) - 1) != 0)
|
|
return 0;
|
|
|
|
/*
|
|
* For XATTR_NAME_CAPS the check will be done in
|
|
* cap_convert_nscap(), called by setxattr()
|
|
*/
|
|
if (strcmp(name, XATTR_NAME_CAPS) == 0)
|
|
return 0;
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EPERM;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* cap_inode_removexattr - Determine whether an xattr may be removed
|
|
* @dentry: The inode/dentry being altered
|
|
* @name: The name of the xattr to be changed
|
|
*
|
|
* Determine whether an xattr may be removed from an inode, returning 0 if
|
|
* permission is granted, -ve if denied.
|
|
*
|
|
* This is used to make sure security xattrs don't get removed by those who
|
|
* aren't privileged to remove them.
|
|
*/
|
|
int cap_inode_removexattr(struct dentry *dentry, const char *name)
|
|
{
|
|
/* Ignore non-security xattrs */
|
|
if (strncmp(name, XATTR_SECURITY_PREFIX,
|
|
sizeof(XATTR_SECURITY_PREFIX) - 1) != 0)
|
|
return 0;
|
|
|
|
if (strcmp(name, XATTR_NAME_CAPS) == 0) {
|
|
/* security.capability gets namespaced */
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
if (!inode)
|
|
return -EINVAL;
|
|
if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP))
|
|
return -EPERM;
|
|
return 0;
|
|
}
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
return -EPERM;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* cap_emulate_setxuid() fixes the effective / permitted capabilities of
|
|
* a process after a call to setuid, setreuid, or setresuid.
|
|
*
|
|
* 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
|
|
* {r,e,s}uid != 0, the permitted and effective capabilities are
|
|
* cleared.
|
|
*
|
|
* 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
|
|
* capabilities of the process are cleared.
|
|
*
|
|
* 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
|
|
* capabilities are set to the permitted capabilities.
|
|
*
|
|
* fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should
|
|
* never happen.
|
|
*
|
|
* -astor
|
|
*
|
|
* cevans - New behaviour, Oct '99
|
|
* A process may, via prctl(), elect to keep its capabilities when it
|
|
* calls setuid() and switches away from uid==0. Both permitted and
|
|
* effective sets will be retained.
|
|
* Without this change, it was impossible for a daemon to drop only some
|
|
* of its privilege. The call to setuid(!=0) would drop all privileges!
|
|
* Keeping uid 0 is not an option because uid 0 owns too many vital
|
|
* files..
|
|
* Thanks to Olaf Kirch and Peter Benie for spotting this.
|
|
*/
|
|
static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
|
|
{
|
|
kuid_t root_uid = make_kuid(old->user_ns, 0);
|
|
|
|
if ((uid_eq(old->uid, root_uid) ||
|
|
uid_eq(old->euid, root_uid) ||
|
|
uid_eq(old->suid, root_uid)) &&
|
|
(!uid_eq(new->uid, root_uid) &&
|
|
!uid_eq(new->euid, root_uid) &&
|
|
!uid_eq(new->suid, root_uid))) {
|
|
if (!issecure(SECURE_KEEP_CAPS)) {
|
|
cap_clear(new->cap_permitted);
|
|
cap_clear(new->cap_effective);
|
|
}
|
|
|
|
/*
|
|
* Pre-ambient programs expect setresuid to nonroot followed
|
|
* by exec to drop capabilities. We should make sure that
|
|
* this remains the case.
|
|
*/
|
|
cap_clear(new->cap_ambient);
|
|
}
|
|
if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
|
|
cap_clear(new->cap_effective);
|
|
if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid))
|
|
new->cap_effective = new->cap_permitted;
|
|
}
|
|
|
|
/**
|
|
* cap_task_fix_setuid - Fix up the results of setuid() call
|
|
* @new: The proposed credentials
|
|
* @old: The current task's current credentials
|
|
* @flags: Indications of what has changed
|
|
*
|
|
* Fix up the results of setuid() call before the credential changes are
|
|
* actually applied, returning 0 to grant the changes, -ve to deny them.
|
|
*/
|
|
int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
|
|
{
|
|
switch (flags) {
|
|
case LSM_SETID_RE:
|
|
case LSM_SETID_ID:
|
|
case LSM_SETID_RES:
|
|
/* juggle the capabilities to follow [RES]UID changes unless
|
|
* otherwise suppressed */
|
|
if (!issecure(SECURE_NO_SETUID_FIXUP))
|
|
cap_emulate_setxuid(new, old);
|
|
break;
|
|
|
|
case LSM_SETID_FS:
|
|
/* juggle the capabilties to follow FSUID changes, unless
|
|
* otherwise suppressed
|
|
*
|
|
* FIXME - is fsuser used for all CAP_FS_MASK capabilities?
|
|
* if not, we might be a bit too harsh here.
|
|
*/
|
|
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
|
|
kuid_t root_uid = make_kuid(old->user_ns, 0);
|
|
if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid))
|
|
new->cap_effective =
|
|
cap_drop_fs_set(new->cap_effective);
|
|
|
|
if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid))
|
|
new->cap_effective =
|
|
cap_raise_fs_set(new->cap_effective,
|
|
new->cap_permitted);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Rationale: code calling task_setscheduler, task_setioprio, and
|
|
* task_setnice, assumes that
|
|
* . if capable(cap_sys_nice), then those actions should be allowed
|
|
* . if not capable(cap_sys_nice), but acting on your own processes,
|
|
* then those actions should be allowed
|
|
* This is insufficient now since you can call code without suid, but
|
|
* yet with increased caps.
|
|
* So we check for increased caps on the target process.
|
|
*/
|
|
static int cap_safe_nice(struct task_struct *p)
|
|
{
|
|
int is_subset, ret = 0;
|
|
|
|
rcu_read_lock();
|
|
is_subset = cap_issubset(__task_cred(p)->cap_permitted,
|
|
current_cred()->cap_permitted);
|
|
if (!is_subset && !ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE))
|
|
ret = -EPERM;
|
|
rcu_read_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* cap_task_setscheduler - Detemine if scheduler policy change is permitted
|
|
* @p: The task to affect
|
|
*
|
|
* Detemine if the requested scheduler policy change is permitted for the
|
|
* specified task, returning 0 if permission is granted, -ve if denied.
|
|
*/
|
|
int cap_task_setscheduler(struct task_struct *p)
|
|
{
|
|
return cap_safe_nice(p);
|
|
}
|
|
|
|
/**
|
|
* cap_task_ioprio - Detemine if I/O priority change is permitted
|
|
* @p: The task to affect
|
|
* @ioprio: The I/O priority to set
|
|
*
|
|
* Detemine if the requested I/O priority change is permitted for the specified
|
|
* task, returning 0 if permission is granted, -ve if denied.
|
|
*/
|
|
int cap_task_setioprio(struct task_struct *p, int ioprio)
|
|
{
|
|
return cap_safe_nice(p);
|
|
}
|
|
|
|
/**
|
|
* cap_task_ioprio - Detemine if task priority change is permitted
|
|
* @p: The task to affect
|
|
* @nice: The nice value to set
|
|
*
|
|
* Detemine if the requested task priority change is permitted for the
|
|
* specified task, returning 0 if permission is granted, -ve if denied.
|
|
*/
|
|
int cap_task_setnice(struct task_struct *p, int nice)
|
|
{
|
|
return cap_safe_nice(p);
|
|
}
|
|
|
|
/*
|
|
* Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from
|
|
* the current task's bounding set. Returns 0 on success, -ve on error.
|
|
*/
|
|
static int cap_prctl_drop(unsigned long cap)
|
|
{
|
|
struct cred *new;
|
|
|
|
if (!ns_capable(current_user_ns(), CAP_SETPCAP))
|
|
return -EPERM;
|
|
if (!cap_valid(cap))
|
|
return -EINVAL;
|
|
|
|
new = prepare_creds();
|
|
if (!new)
|
|
return -ENOMEM;
|
|
cap_lower(new->cap_bset, cap);
|
|
return commit_creds(new);
|
|
}
|
|
|
|
/**
|
|
* cap_task_prctl - Implement process control functions for this security module
|
|
* @option: The process control function requested
|
|
* @arg2, @arg3, @arg4, @arg5: The argument data for this function
|
|
*
|
|
* Allow process control functions (sys_prctl()) to alter capabilities; may
|
|
* also deny access to other functions not otherwise implemented here.
|
|
*
|
|
* Returns 0 or +ve on success, -ENOSYS if this function is not implemented
|
|
* here, other -ve on error. If -ENOSYS is returned, sys_prctl() and other LSM
|
|
* modules will consider performing the function.
|
|
*/
|
|
int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|
unsigned long arg4, unsigned long arg5)
|
|
{
|
|
const struct cred *old = current_cred();
|
|
struct cred *new;
|
|
|
|
switch (option) {
|
|
case PR_CAPBSET_READ:
|
|
if (!cap_valid(arg2))
|
|
return -EINVAL;
|
|
return !!cap_raised(old->cap_bset, arg2);
|
|
|
|
case PR_CAPBSET_DROP:
|
|
return cap_prctl_drop(arg2);
|
|
|
|
/*
|
|
* The next four prctl's remain to assist with transitioning a
|
|
* system from legacy UID=0 based privilege (when filesystem
|
|
* capabilities are not in use) to a system using filesystem
|
|
* capabilities only - as the POSIX.1e draft intended.
|
|
*
|
|
* Note:
|
|
*
|
|
* PR_SET_SECUREBITS =
|
|
* issecure_mask(SECURE_KEEP_CAPS_LOCKED)
|
|
* | issecure_mask(SECURE_NOROOT)
|
|
* | issecure_mask(SECURE_NOROOT_LOCKED)
|
|
* | issecure_mask(SECURE_NO_SETUID_FIXUP)
|
|
* | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)
|
|
*
|
|
* will ensure that the current process and all of its
|
|
* children will be locked into a pure
|
|
* capability-based-privilege environment.
|
|
*/
|
|
case PR_SET_SECUREBITS:
|
|
if ((((old->securebits & SECURE_ALL_LOCKS) >> 1)
|
|
& (old->securebits ^ arg2)) /*[1]*/
|
|
|| ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|
|
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|
|
|| (cap_capable(current_cred(),
|
|
current_cred()->user_ns, CAP_SETPCAP,
|
|
SECURITY_CAP_AUDIT) != 0) /*[4]*/
|
|
/*
|
|
* [1] no changing of bits that are locked
|
|
* [2] no unlocking of locks
|
|
* [3] no setting of unsupported bits
|
|
* [4] doing anything requires privilege (go read about
|
|
* the "sendmail capabilities bug")
|
|
*/
|
|
)
|
|
/* cannot change a locked bit */
|
|
return -EPERM;
|
|
|
|
new = prepare_creds();
|
|
if (!new)
|
|
return -ENOMEM;
|
|
new->securebits = arg2;
|
|
return commit_creds(new);
|
|
|
|
case PR_GET_SECUREBITS:
|
|
return old->securebits;
|
|
|
|
case PR_GET_KEEPCAPS:
|
|
return !!issecure(SECURE_KEEP_CAPS);
|
|
|
|
case PR_SET_KEEPCAPS:
|
|
if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
|
|
return -EINVAL;
|
|
if (issecure(SECURE_KEEP_CAPS_LOCKED))
|
|
return -EPERM;
|
|
|
|
new = prepare_creds();
|
|
if (!new)
|
|
return -ENOMEM;
|
|
if (arg2)
|
|
new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
|
|
else
|
|
new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
|
|
return commit_creds(new);
|
|
|
|
case PR_CAP_AMBIENT:
|
|
if (arg2 == PR_CAP_AMBIENT_CLEAR_ALL) {
|
|
if (arg3 | arg4 | arg5)
|
|
return -EINVAL;
|
|
|
|
new = prepare_creds();
|
|
if (!new)
|
|
return -ENOMEM;
|
|
cap_clear(new->cap_ambient);
|
|
return commit_creds(new);
|
|
}
|
|
|
|
if (((!cap_valid(arg3)) | arg4 | arg5))
|
|
return -EINVAL;
|
|
|
|
if (arg2 == PR_CAP_AMBIENT_IS_SET) {
|
|
return !!cap_raised(current_cred()->cap_ambient, arg3);
|
|
} else if (arg2 != PR_CAP_AMBIENT_RAISE &&
|
|
arg2 != PR_CAP_AMBIENT_LOWER) {
|
|
return -EINVAL;
|
|
} else {
|
|
if (arg2 == PR_CAP_AMBIENT_RAISE &&
|
|
(!cap_raised(current_cred()->cap_permitted, arg3) ||
|
|
!cap_raised(current_cred()->cap_inheritable,
|
|
arg3) ||
|
|
issecure(SECURE_NO_CAP_AMBIENT_RAISE)))
|
|
return -EPERM;
|
|
|
|
new = prepare_creds();
|
|
if (!new)
|
|
return -ENOMEM;
|
|
if (arg2 == PR_CAP_AMBIENT_RAISE)
|
|
cap_raise(new->cap_ambient, arg3);
|
|
else
|
|
cap_lower(new->cap_ambient, arg3);
|
|
return commit_creds(new);
|
|
}
|
|
|
|
default:
|
|
/* No functionality available - continue with default */
|
|
return -ENOSYS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* cap_vm_enough_memory - Determine whether a new virtual mapping is permitted
|
|
* @mm: The VM space in which the new mapping is to be made
|
|
* @pages: The size of the mapping
|
|
*
|
|
* Determine whether the allocation of a new virtual mapping by the current
|
|
* task is permitted, returning 1 if permission is granted, 0 if not.
|
|
*/
|
|
int cap_vm_enough_memory(struct mm_struct *mm, long pages)
|
|
{
|
|
int cap_sys_admin = 0;
|
|
|
|
if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
|
|
SECURITY_CAP_NOAUDIT) == 0)
|
|
cap_sys_admin = 1;
|
|
return cap_sys_admin;
|
|
}
|
|
|
|
/*
|
|
* cap_mmap_addr - check if able to map given addr
|
|
* @addr: address attempting to be mapped
|
|
*
|
|
* If the process is attempting to map memory below dac_mmap_min_addr they need
|
|
* CAP_SYS_RAWIO. The other parameters to this function are unused by the
|
|
* capability security module. Returns 0 if this mapping should be allowed
|
|
* -EPERM if not.
|
|
*/
|
|
int cap_mmap_addr(unsigned long addr)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (addr < dac_mmap_min_addr) {
|
|
ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
|
|
SECURITY_CAP_AUDIT);
|
|
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
|
|
if (ret == 0)
|
|
current->flags |= PF_SUPERPRIV;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int cap_mmap_file(struct file *file, unsigned long reqprot,
|
|
unsigned long prot, unsigned long flags)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_SECURITY
|
|
|
|
struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
|
|
LSM_HOOK_INIT(capable, cap_capable),
|
|
LSM_HOOK_INIT(settime, cap_settime),
|
|
LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check),
|
|
LSM_HOOK_INIT(ptrace_traceme, cap_ptrace_traceme),
|
|
LSM_HOOK_INIT(capget, cap_capget),
|
|
LSM_HOOK_INIT(capset, cap_capset),
|
|
LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds),
|
|
LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv),
|
|
LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv),
|
|
LSM_HOOK_INIT(inode_getsecurity, cap_inode_getsecurity),
|
|
LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),
|
|
LSM_HOOK_INIT(mmap_file, cap_mmap_file),
|
|
LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid),
|
|
LSM_HOOK_INIT(task_prctl, cap_task_prctl),
|
|
LSM_HOOK_INIT(task_setscheduler, cap_task_setscheduler),
|
|
LSM_HOOK_INIT(task_setioprio, cap_task_setioprio),
|
|
LSM_HOOK_INIT(task_setnice, cap_task_setnice),
|
|
LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory),
|
|
};
|
|
|
|
void __init capability_add_hooks(void)
|
|
{
|
|
security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
|
|
"capability");
|
|
}
|
|
|
|
#endif /* CONFIG_SECURITY */
|