https://source.android.com/docs/security/bulletin/2022-12-01
CVE-2022-23960
# By Yang Yingliang (18) and others
# Via Greg Kroah-Hartman
* tag 'ASB-2022-12-05_4.19-stable' of https://android.googlesource.com/kernel/common:
Linux 4.19.268
ipc/sem: Fix dangling sem_array access in semtimedop race
mmc: sdhci: Fix voltage switch delay
mmc: sdhci: use FIELD_GET for preset value bit masks
x86/ioremap: Fix page aligned size calculation in __ioremap_caller()
Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM
x86/pm: Add enumeration check before spec MSRs save/restore setup
x86/tsx: Add a feature bit for TSX control MSR support
nvme: restrict management ioctls to admin
tcp/udp: Fix memory leak in ipv6_renew_options().
Kconfig.debug: provide a little extra FRAME_WARN leeway when KASAN is enabled
parisc: Increase FRAME_WARN to 2048 bytes on parisc
xtensa: increase size of gcc stack frame check
parisc: Increase size of gcc stack frame check
iommu/vt-d: Fix PCI device refcount leak in dmar_dev_scope_init()
pinctrl: single: Fix potential division by zero
ASoC: ops: Fix bounds check for _sx controls
mm: Fix '.data.once' orphan section warning
arm64: errata: Fix KVM Spectre-v2 mitigation selection for Cortex-A57/A72
arm64: Fix panic() when Spectre-v2 causes Spectre-BHB to re-allocate KVM vectors
pinctrl: intel: Save and restore pins in "direct IRQ" mode
x86/bugs: Make sure MSR_SPEC_CTRL is updated properly upon resume from S3
nilfs2: fix NULL pointer dereference in nilfs_palloc_commit_free_entry()
tools/vm/slabinfo-gnuplot: use "grep -E" instead of "egrep"
error-injection: Add prompt for function error injection
btrfs: qgroup: fix sleep from invalid context bug in btrfs_qgroup_inherit()
hwmon: (coretemp) fix pci device refcount leak in nv1a_ram_new()
hwmon: (coretemp) Check for null before removing sysfs attrs
net: ethernet: renesas: ravb: Fix promiscuous mode after system resumed
packet: do not set TP_STATUS_CSUM_VALID on CHECKSUM_COMPLETE
net: tun: Fix use-after-free in tun_detach()
net: hsr: Fix potential use-after-free
dsa: lan9303: Correct stat name
net/9p: Fix a potential socket leak in p9_socket_open
net: net_netdev: Fix error handling in ntb_netdev_init_module()
net: phy: fix null-ptr-deref while probe() failed
qlcnic: fix sleep-in-atomic-context bugs caused by msleep
can: cc770: cc770_isa_probe(): add missing free_cc770dev()
can: sja1000_isa: sja1000_isa_probe(): add missing free_sja1000dev()
net/mlx5: Fix uninitialized variable bug in outlen_write()
of: property: decrement node refcount in of_fwnode_get_reference_args()
hwmon: (ibmpex) Fix possible UAF when ibmpex_register_bmc() fails
hwmon: (i5500_temp) fix missing pci_disable_device()
scripts/faddr2line: Fix regression in name resolution on ppc64le
iio: light: rpr0521: add missing Kconfig dependencies
iio: health: afe4404: Fix oob read in afe4404_[read|write]_raw
iio: health: afe4403: Fix oob read in afe4403_read_raw
Revert "x86/speculation: Change FILL_RETURN_BUFFER to work with objtool"
v4l2: don't fall back to follow_pfn() if pin_user_pages_fast() fails
proc: proc_skip_spaces() shouldn't think it is working on C strings
proc: avoid integer type confusion in get_proc_long
spi: spi-imx: Fix spi_bus_clk if requested clock is higher than input clock
btrfs: free btrfs_path before copying inodes to userspace
drm/amdgpu: always register an MMU notifier for userptr
drm/amd/dc/dce120: Fix audio register mapping, stop triggering KASAN
btrfs: free btrfs_path before copying subvol info to userspace
btrfs: free btrfs_path before copying fspath to userspace
btrfs: free btrfs_path before copying root refs to userspace
dm integrity: flush the journal on suspend
net: usb: qmi_wwan: add Telit 0x103a composition
tcp: configurable source port perturb table size
platform/x86: hp-wmi: Ignore Smart Experience App event
platform/x86: acer-wmi: Enable SW_TABLET_MODE on Switch V 10 (SW5-017)
platform/x86: asus-wmi: add missing pci_dev_put() in asus_wmi_set_xusb2pr()
xen/platform-pci: add missing free_irq() in error path
serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()
Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode
nilfs2: fix nilfs_sufile_mark_dirty() not set segment usage as dirty
ceph: avoid putting the realm twice when decoding snaps fails
ceph: do not update snapshot context when there is no new snapshot
iio: pressure: ms5611: fixed value compensation bug
iio: ms5611: Simplify IO callback parameters
nios2: add FORCE for vmlinuz.gz
iio: core: Fix entry not deleted when iio_register_sw_trigger_type() fails
iio: light: apds9960: fix wrong register for gesture gain
arm64: dts: rockchip: lower rk3399-puma-haikou SD controller clock frequency
s390/crashdump: fix TOD programmable field size
net: thunderx: Fix the ACPI memory leak
nfc: st-nci: fix memory leaks in EVT_TRANSACTION
nfc: st-nci: fix incorrect validating logic in EVT_TRANSACTION
s390/dasd: fix no record found for raw_track_access
dccp/tcp: Reset saddr on failure after inet6?_hash_connect().
bnx2x: fix pci device refcount leak in bnx2x_vf_is_pcie_pending()
NFC: nci: fix memory leak in nci_rx_data_packet()
xfrm: Fix ignored return value in xfrm6_init()
tipc: check skb_linearize() return value in tipc_disc_rcv()
tipc: add an extra conn_get in tipc_conn_alloc
tipc: set con sock in tipc_conn_alloc
net/mlx5: Fix FW tracer timestamp calculation
Drivers: hv: vmbus: fix possible memory leak in vmbus_device_register()
Drivers: hv: vmbus: fix double free in the error path of vmbus_add_channel_work()
net: pch_gbe: fix pci device refcount leak while module exiting
net/qla3xxx: fix potential memleak in ql3xxx_send()
net/mlx4: Check retval of mlx4_bitmap_init
ARM: mxs: fix memory leak in mxs_machine_init()
9p/fd: fix issue of list_del corruption in p9_fd_cancel()
net: pch_gbe: fix potential memleak in pch_gbe_tx_queue()
nfc/nci: fix race with opening and closing
ARM: dts: at91: sam9g20ek: enable udc vbus gpio pinctrl
bus: sunxi-rsb: Support atomic transfers
ASoC: sgtl5000: Reset the CHIP_CLK_CTRL reg on remove
ARM: dts: am335x-pcm-953: Define fixed regulators in root node
af_key: Fix send_acquire race with pfkey_register
MIPS: pic32: treat port as signed integer
RISC-V: vdso: Do not add missing symbols to version section in linker script
drm: panel-orientation-quirks: Add quirk for Acer Switch V 10 (SW5-017)
spi: stm32: fix stm32_spi_prepare_mbr() that halves spi clk for every run
wifi: mac80211: Fix ack frame idr leak when mesh has no route
audit: fix undefined behavior in bit shift for AUDIT_BIT
wifi: mac80211_hwsim: fix debugfs attribute ps with rc table support
Linux 4.19.267
ntfs: check overflow when iterating ATTR_RECORDs
ntfs: fix out-of-bounds read in ntfs_attr_find()
ntfs: fix use-after-free in ntfs_attr_find()
mm: fs: initialize fsdata passed to write_begin/write_end interface
9p/trans_fd: always use O_NONBLOCK read/write
gfs2: Switch from strlcpy to strscpy
gfs2: Check sb_bsize_shift after reading superblock
9p: trans_fd/p9_conn_cancel: drop client lock earlier
kcm: close race conditions on sk_receive_queue
bpf, test_run: Fix alignment problem in bpf_prog_test_run_skb()
kcm: avoid potential race in kcm_tx_work
tcp: cdg: allow tcp_cdg_release() to be called multiple times
macvlan: enforce a consistent minimal mtu
serial: 8250: Flush DMA Rx on RLSI
Input: i8042 - fix leaking of platform device on module removal
scsi: target: tcm_loop: Fix possible name leak in tcm_loop_setup_hba_bus()
misc/vmw_vmci: fix an infoleak in vmci_host_do_receive_datagram()
docs: update mediator contact information in CoC doc
mmc: sdhci-pci: Fix possible memory leak caused by missing pci_dev_put()
mmc: core: properly select voltage range without power cycle
serial: 8250_lpss: Configure DMA also w/o DMA filter
serial: 8250: Fall back to non-DMA Rx if IIR_RDI occurs
dm ioctl: fix misbehavior if list_versions races with module loading
iio: pressure: ms5611: changed hardcoded SPI speed to value limited
iio: trigger: sysfs: fix possible memory leak in iio_sysfs_trig_init()
iio: adc: at91_adc: fix possible memory leak in at91_adc_allocate_trigger()
usb: chipidea: fix deadlock in ci_otg_del_timer
usb: add NO_LPM quirk for Realforce 87U Keyboard
USB: serial: option: add Fibocom FM160 0x0111 composition
USB: serial: option: add u-blox LARA-L6 modem
USB: serial: option: add u-blox LARA-R6 00B modem
USB: serial: option: remove old LARA-R6 PID
USB: serial: option: add Sierra Wireless EM9191
speakup: fix a segfault caused by switching consoles
slimbus: stream: correct presence rate frequencies
ALSA: usb-audio: Drop snd_BUG_ON() from snd_usbmidi_output_open()
ring_buffer: Do not deactivate non-existant pages
ftrace: Fix null pointer dereference in ftrace_add_mod()
ftrace: Optimize the allocation for mcount entries
ftrace: Fix the possible incorrect kernel message
net: thunderbolt: Fix error handling in tbnet_init()
cifs: Fix wrong return value checking when GETFLAGS
net/x25: Fix skb leak in x25_lapb_receive_frame()
drbd: use after free in drbd_create_device()
xen/pcpu: fix possible memory leak in register_pcpu()
bnxt_en: Remove debugfs when pci_register_driver failed
net: caif: fix double disconnect client in chnl_net_open()
mISDN: fix misuse of put_device() in mISDN_register_device()
mISDN: fix possible memory leak in mISDN_dsp_element_register()
net: bgmac: Drop free_netdev() from bgmac_enet_remove()
ata: libata-transport: fix double ata_host_put() in ata_tport_add()
pinctrl: devicetree: fix null pointer dereferencing in pinctrl_dt_to_map
parport_pc: Avoid FIFO port location truncation
siox: fix possible memory leak in siox_device_add()
block: sed-opal: kmalloc the cmd/resp buffers
ASoC: soc-utils: Remove __exit for snd_soc_util_exit()
tty: n_gsm: fix sleep-in-atomic-context bug in gsm_control_send
serial: imx: Add missing .thaw_noirq hook
serial: 8250: omap: Flush PM QOS work on remove
serial: 8250_omap: remove wait loop from Errata i202 workaround
ASoC: core: Fix use-after-free in snd_soc_exit()
Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm
btrfs: remove pointless and double ulist frees in error paths of qgroup tests
drm/imx: imx-tve: Fix return type of imx_tve_connector_mode_valid
NFSv4: Retry LOCK on OLD_STATEID during delegation return
selftests/intel_pstate: fix build for ARCH=x86_64
selftests/futex: fix build for clang
spi: intel: Fix the offset to get the 64K erase opcode
ASoC: wm8997: Revert "ASoC: wm8997: Fix PM disable depth imbalance in wm8997_probe"
ASoC: wm5110: Revert "ASoC: wm5110: Fix PM disable depth imbalance in wm5110_probe"
ASoC: wm5102: Revert "ASoC: wm5102: Fix PM disable depth imbalance in wm5102_probe"
x86/cpu: Restore AMD's DE_CFG MSR after resume
net: tun: call napi_schedule_prep() to ensure we own a napi
dmaengine: at_hdmac: Check return code of dma_async_device_register
dmaengine: at_hdmac: Fix impossible condition
dmaengine: at_hdmac: Don't allow CPU to reorder channel enable
dmaengine: at_hdmac: Fix completion of unissued descriptor in case of errors
dmaengine: at_hdmac: Don't start transactions at tx_submit level
dmaengine: at_hdmac: Fix at_lli struct definition
cert host tools: Stop complaining about deprecated OpenSSL functions
udf: Fix a slab-out-of-bounds write bug in udf_find_entry()
btrfs: selftests: fix wrong error check in btrfs_free_dummy_root()
platform/x86: hp_wmi: Fix rfkill causing soft blocked wifi
drm/i915/dmabuf: fix sg_table handling in map_dma_buf
nilfs2: fix use-after-free bug of ns_writer on remount
nilfs2: fix deadlock in nilfs_count_free_blocks()
vmlinux.lds.h: Fix placement of '.data..decrypted' section
ALSA: usb-audio: Add DSD support for Accuphase DAC-60
ALSA: usb-audio: Add quirk entry for M-Audio Micro
ALSA: hda: fix potential memleak in 'add_widget_node'
ALSA: hda/ca0132: add quirk for EVGA Z390 DARK
arm64: efi: Fix handling of misaligned runtime regions and drop warning
riscv: process: fix kernel info leakage
net: macvlan: fix memory leaks of macvlan_common_newlink
net: mv643xx_eth: disable napi when init rxq or txq failed in mv643xx_eth_open()
ethernet: s2io: disable napi when start nic failed in s2io_card_up()
net: cxgb3_main: disable napi when bind qsets failed in cxgb_up()
net: nixge: disable napi when enable interrupts failed in nixge_open()
drivers: net: xgene: disable napi when register irq failed in xgene_enet_open()
dmaengine: mv_xor_v2: Fix a resource leak in mv_xor_v2_remove()
tipc: fix the msg->req tlv len check in tipc_nl_compat_name_table_dump_header
ipv6: addrlabel: fix infoleak when sending struct ifaddrlblmsg to network
drm/vc4: Fix missing platform_unregister_drivers() call in vc4_drm_register()
hamradio: fix issue of dev reference count leakage in bpq_device_event()
net: lapbether: fix issue of dev reference count leakage in lapbeth_device_event()
capabilities: fix undefined behavior in bit shift for CAP_TO_MASK
net: fman: Unregister ethernet device on removal
bnxt_en: fix potentially incorrect return value for ndo_rx_flow_steer
net: tun: Fix memory leaks of napi_get_frags
net: gso: fix panic on frag_list with mixed head alloc types
HID: hyperv: fix possible memory leak in mousevsc_probe()
wifi: cfg80211: fix memory leak in query_regdb_file()
phy: stm32: fix an error code in probe
Linux 4.19.266
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: Change FILL_RETURN_BUFFER to work with objtool
intel_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/entry: Remove skip_r11rcx
x86/bugs: Keep a per-CPU IA32_SPEC_CTRL value
x86/bugs: Add AMD retbleed= boot parameter
x86/bugs: Report AMD retbleed vulnerability
x86/cpufeatures: Move RETPOLINE flags to word 11
x86/cpu: Add a steppings field to struct x86_cpu_id
x86/cpu: Add consistent CPU match macros
x86/devicetable: Move x86 specific macro out of generic code
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"
Revert "x86/speculation: Add RSB VM Exit protections"
ANDROID: preserve CRC for some DRM functions
Revert "tcp/udp: Make early_demux back namespacified."
Linux 4.19.265
wifi: brcmfmac: Fix potential buffer overflow in brcmf_fweh_event_worker()
linux/bits.h: make BIT(), GENMASK(), and friends available in assembly
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'
parisc: Avoid printing the hardware path twice
parisc: Export iosapic_serial_irq() symbol for serial port driver
parisc: Make 8250_gsc driver dependend on CONFIG_PARISC
efi: random: reduce seed size to 32 bytes
ALSA: usb-audio: Add quirks for MacroSilicon MS2100/MS2106 devices
capabilities: fix potential memleak on error path from vfs_getxattr_alloc()
tracing/histogram: Update document for KEYS_MAX size
kprobe: reverse kp->flags when arm_kprobe failed
tcp/udp: Make early_demux back namespacified.
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
i2c: xiic: Add platform module alias
HID: saitek: add madcatz variant of MMO7 mouse device ID
media: dvb-frontends/drxk: initialize err to 0
media: cros-ec-cec: limit msg.len to CEC_MAX_MSG_SIZE
media: s5p_cec: limit msg.len to CEC_MAX_MSG_SIZE
ipv6: fix WARNING in ip6_route_net_exit_late()
net, neigh: Fix null-ptr-deref in neigh_table_clear()
net: mdio: fix undefined behavior in bit shift for __mdiobus_register
Bluetooth: L2CAP: fix use-after-free in l2cap_conn_del()
Bluetooth: L2CAP: Fix use-after-free caused by l2cap_reassemble_sdu
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: fix WARNING in ip_vs_app_net_cleanup()
ipvs: fix WARNING in __ip_vs_cleanup_batch()
ipvs: use explicitly signed chars
net: tun: fix bugs for oversize packet when napi frags enabled
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()
RDMA/qedr: clean up work queue on failure in qedr_alloc_resources()
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
BACKPORT: ARM: 9039/1: assembler: generalize byte swapping macro into rev_l
BACKPORT: ARM: 9035/1: uncompress: Add be32tocpu macro
Conflicts:
drivers/mmc/host/sdhci.c
drivers/slimbus/stream.c
Change-Id: Ic112be181f3558a83f85d01fb4e25444f14c7548
1403 lines
40 KiB
C
1403 lines
40 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>
|
|
|
|
#ifdef CONFIG_ANDROID_PARANOID_NETWORK
|
|
#include <linux/android_aid.h>
|
|
#endif
|
|
|
|
/*
|
|
* 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, unsigned int opts)
|
|
{
|
|
struct user_namespace *ns = targ_ns;
|
|
|
|
/* 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 */
|
|
}
|
|
|
|
/**
|
|
* 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, CAP_OPT_NONE) == 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_fcap)
|
|
{
|
|
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_fcap = 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_fcap)
|
|
{
|
|
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_fcap);
|
|
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;
|
|
}
|
|
|
|
static inline bool root_privileged(void) { return !issecure(SECURE_NOROOT); }
|
|
|
|
static inline bool __is_real(kuid_t uid, struct cred *cred)
|
|
{ return uid_eq(cred->uid, uid); }
|
|
|
|
static inline bool __is_eff(kuid_t uid, struct cred *cred)
|
|
{ return uid_eq(cred->euid, uid); }
|
|
|
|
static inline bool __is_suid(kuid_t uid, struct cred *cred)
|
|
{ return !__is_real(uid, cred) && __is_eff(uid, cred); }
|
|
|
|
/*
|
|
* handle_privileged_root - Handle case of privileged root
|
|
* @bprm: The execution parameters, including the proposed creds
|
|
* @has_fcap: Are any file capabilities set?
|
|
* @effective: Do we have effective root privilege?
|
|
* @root_uid: This namespace' root UID WRT initial USER namespace
|
|
*
|
|
* Handle the case where root is privileged and hasn't been neutered by
|
|
* SECURE_NOROOT. If file capabilities are set, they won't be combined with
|
|
* set UID root and nothing is changed. If we are root, cap_permitted is
|
|
* updated. If we have become set UID root, the effective bit is set.
|
|
*/
|
|
static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap,
|
|
bool *effective, kuid_t root_uid)
|
|
{
|
|
const struct cred *old = current_cred();
|
|
struct cred *new = bprm->cred;
|
|
|
|
if (!root_privileged())
|
|
return;
|
|
/*
|
|
* 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_fcap && __is_suid(root_uid, new)) {
|
|
warn_setuid_and_fcaps_mixed(bprm->filename);
|
|
return;
|
|
}
|
|
/*
|
|
* To support inheritance of root-permissions and suid-root
|
|
* executables under compatibility mode, we override the
|
|
* capability sets for the file.
|
|
*/
|
|
if (__is_eff(root_uid, new) || __is_real(root_uid, new)) {
|
|
/* pP' = (cap_bset & ~0) | (pI & ~0) */
|
|
new->cap_permitted = cap_combine(old->cap_bset,
|
|
old->cap_inheritable);
|
|
}
|
|
/*
|
|
* If only the real uid is 0, we do not set the effective bit.
|
|
*/
|
|
if (__is_eff(root_uid, new))
|
|
*effective = true;
|
|
}
|
|
|
|
#define __cap_gained(field, target, source) \
|
|
!cap_issubset(target->cap_##field, source->cap_##field)
|
|
#define __cap_grew(target, source, cred) \
|
|
!cap_issubset(cred->cap_##target, cred->cap_##source)
|
|
#define __cap_full(field, cred) \
|
|
cap_issubset(CAP_FULL_SET, cred->cap_##field)
|
|
|
|
static inline bool __is_setuid(struct cred *new, const struct cred *old)
|
|
{ return !uid_eq(new->euid, old->uid); }
|
|
|
|
static inline bool __is_setgid(struct cred *new, const struct cred *old)
|
|
{ return !gid_eq(new->egid, old->gid); }
|
|
|
|
/*
|
|
* 1) 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 became root *OR* are were already 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.
|
|
*
|
|
* A number of other conditions require logging:
|
|
* 2) something prevented setuid root getting all caps
|
|
* 3) non-setuid root gets fcaps
|
|
* 4) non-setuid root gets ambient
|
|
*/
|
|
static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old,
|
|
kuid_t root, bool has_fcap)
|
|
{
|
|
bool ret = false;
|
|
|
|
if ((__cap_grew(effective, ambient, new) &&
|
|
!(__cap_full(effective, new) &&
|
|
(__is_eff(root, new) || __is_real(root, new)) &&
|
|
root_privileged())) ||
|
|
(root_privileged() &&
|
|
__is_suid(root, new) &&
|
|
!__cap_full(effective, new)) ||
|
|
(!__is_setuid(new, old) &&
|
|
((has_fcap &&
|
|
__cap_gained(permitted, new, old)) ||
|
|
__cap_gained(ambient, new, old))))
|
|
|
|
ret = true;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 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 = false, has_fcap = 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;
|
|
|
|
ret = get_file_caps(bprm, &effective, &has_fcap);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
root_uid = make_kuid(new->user_ns, 0);
|
|
|
|
handle_privileged_root(bprm, has_fcap, &effective, root_uid);
|
|
|
|
/* if we have fs caps, clear dangerous personality flags */
|
|
if (__cap_gained(permitted, new, old))
|
|
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 = __is_setuid(new, old) || __is_setgid(new, old);
|
|
|
|
if ((is_setid || __cap_gained(permitted, new, old)) &&
|
|
((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_fcap || 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;
|
|
|
|
if (nonroot_raised_pE(new, old, root_uid, has_fcap)) {
|
|
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 ||
|
|
(!__is_real(root_uid, new) &&
|
|
(effective ||
|
|
__cap_grew(permitted, ambient, new))))
|
|
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)
|
|
{
|
|
struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
|
|
|
|
/* 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 (!ns_capable(user_ns, 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)
|
|
{
|
|
struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
|
|
|
|
/* 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 (!ns_capable(user_ns, 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,
|
|
CAP_OPT_NONE) != 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, CAP_OPT_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,
|
|
CAP_OPT_NONE);
|
|
/* 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 */
|