https://source.android.com/docs/security/bulletin/2023-02-01 CVE-2022-39189 CVE-2022-39842 CVE-2022-41222 CVE-2023-20937 CVE-2023-20938 CVE-2022-0850 * tag 'ASB-2023-02-05_4.19-stable' of https://android.googlesource.com/kernel/common: Linux 4.19.272 usb: host: xhci-plat: add wakeup entry at sysfs ipv6: ensure sane device mtu in tunnels exit: Use READ_ONCE() for all oops/warn limit reads docs: Fix path paste-o for /sys/kernel/warn_count panic: Expose "warn_count" to sysfs panic: Introduce warn_limit panic: Consolidate open-coded panic_on_warn checks exit: Allow oops_limit to be disabled exit: Expose "oops_count" to sysfs exit: Put an upper limit on how often we can oops ia64: make IA64_MCA_RECOVERY bool instead of tristate h8300: Fix build errors from do_exit() to make_task_dead() transition hexagon: Fix function name in die() objtool: Add a missing comma to avoid string concatenation exit: Add and use make_task_dead. panic: unset panic_on_warn inside panic() sysctl: add a new register_sysctl_init() interface dmaengine: imx-sdma: Fix a possible memory leak in sdma_transfer_init ARM: dts: imx: Fix pca9547 i2c-mux node name x86/entry/64: Add instruction suffix to SYSRET x86/asm: Fix an assembler warning with current binutils drm/i915/display: fix compiler warning about array overrun x86/i8259: Mark legacy PIC interrupts with IRQ_LEVEL Revert "Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode" net/tg3: resolve deadlock in tg3_reset_task() during EEH net: ravb: Fix possible hang if RIS2_QFF1 happen sctp: fail if no bound addresses can be used for a given scope netrom: Fix use-after-free of a listening socket. netfilter: conntrack: fix vtag checks for ABORT/SHUTDOWN_COMPLETE ipv4: prevent potential spectre v1 gadget in ip_metrics_convert() netlink: annotate data races around sk_state netlink: annotate data races around dst_portid and dst_group netlink: annotate data races around nlk->portid netlink: remove hash::nelems check in netlink_insert netfilter: nft_set_rbtree: skip elements in transaction from garbage collection net: fix UaF in netns ops registration error path EDAC/device: Respect any driver-supplied workqueue polling value ARM: 9280/1: mm: fix warning on phys_addr_t to void pointer assignment cifs: Fix oops due to uncleared server->smbd_conn in reconnect smbd: Make upper layer decide when to destroy the transport trace_events_hist: add check for return value of 'create_hist_field' tracing: Make sure trace_printk() can output as soon as it can be used module: Don't wait for GOING modules scsi: hpsa: Fix allocation size for scsi_host_alloc() Bluetooth: hci_sync: cancel cmd_timer if hci_open failed fs: reiserfs: remove useless new_opts in reiserfs_remount perf env: Do not return pointers to local variables block: fix and cleanup bio_check_ro netfilter: conntrack: do not renew entry stuck in tcp SYN_SENT state w1: fix WARNING after calling w1_process() w1: fix deadloop in __w1_remove_master_device() tcp: avoid the lookup process failing to get sk in ehash table dmaengine: xilinx_dma: call of_node_put() when breaking out of for_each_child_of_node() dmaengine: xilinx_dma: Fix devm_platform_ioremap_resource error handling dmaengine: xilinx_dma: program hardware supported buffer length dmaengine: xilinx_dma: commonize DMA copy size calculation HID: betop: check shape of output reports net: macb: fix PTP TX timestamp failure due to packet padding dmaengine: Fix double increment of client_count in dma_chan_get() net: mlx5: eliminate anonymous module_init & module_exit usb: gadget: f_fs: Ensure ep0req is dequeued before free_request usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait HID: check empty report_list in hid_validate_values() net: mdio: validate parameter addr in mdiobus_get_phy() net: usb: sr9700: Handle negative len wifi: rndis_wlan: Prevent buffer overflow in rndis_query_oid net: nfc: Fix use-after-free in local_cleanup() phy: rockchip-inno-usb2: Fix missing clk_disable_unprepare() in rockchip_usb2phy_power_on() bpf: Fix pointer-leak due to insufficient speculative store bypass mitigation amd-xgbe: Delay AN timeout during KR training amd-xgbe: TX Flow Ctrl Registers are h/w ver dependent affs: initialize fsdata in affs_truncate() IB/hfi1: Fix expected receive setup error exit issues IB/hfi1: Reserve user expected TIDs IB/hfi1: Reject a zero-length user expected buffer tomoyo: fix broken dependency on *.conf.default EDAC/highbank: Fix memory leak in highbank_mc_probe() HID: intel_ish-hid: Add check for ishtp_dma_tx_map ARM: dts: imx6qdl-gw560x: Remove incorrect 'uart-has-rtscts' UPSTREAM: tcp: fix tcp_rmem documentation UPSTREAM: nvmem: core: skip child nodes not matching binding BACKPORT: nvmem: core: Fix a resource leak on error in nvmem_add_cells_from_of() UPSTREAM: sched/eas: Don't update misfit status if the task is pinned BACKPORT: arm64: link with -z norelro for LLD or aarch64-elf UPSTREAM: driver: core: Fix list corruption after device_del() UPSTREAM: coresight: tmc-etr: Fix barrier packet insertion for perf buffer UPSTREAM: f2fs: fix double free of unicode map BACKPORT: net: xfrm: fix memory leak in xfrm_user_policy() UPSTREAM: xfrm/compat: Don't allocate memory with __GFP_ZERO UPSTREAM: xfrm/compat: memset(0) 64-bit padding at right place UPSTREAM: xfrm/compat: Translate by copying XFRMA_UNSPEC attribute UPSTREAM: scsi: ufs: Fix missing brace warning for old compilers UPSTREAM: arm64: vdso32: make vdso32 install conditional UPSTREAM: loop: unset GENHD_FL_NO_PART_SCAN on LOOP_CONFIGURE BACKPORT: drm/virtio: fix missing dma_fence_put() in virtio_gpu_execbuffer_ioctl() BACKPORT: sched/uclamp: Protect uclamp fast path code with static key BACKPORT: sched/uclamp: Fix initialization of struct uclamp_rq UPSTREAM: coresight: etmv4: Fix CPU power management setup in probe() function UPSTREAM: arm64: vdso: Add --eh-frame-hdr to ldflags BACKPORT: arm64: vdso: Add '-Bsymbolic' to ldflags UPSTREAM: drm/virtio: fix a wait_event condition BACKPORT: sched/topology: Don't try to build empty sched domains BACKPORT: binder: prevent UAF read in print_binder_transaction_log_entry() BACKPORT: copy_process(): don't use ksys_close() on cleanups BACKPORT: arm64: vdso: Remove unnecessary asm-offsets.c definitions UPSTREAM: locking/lockdep, cpu/hotplug: Annotate AP thread Revert "xhci: Add a flag to disable USB3 lpm on a xhci root port level." BACKPORT: mac80211_hwsim: add concurrent channels scanning support over virtio BACKPORT: mac80211_hwsim: add frame transmission support over virtio This allows communication with external entities. BACKPORT: driver core: Skip unnecessary work when device doesn't have sync_state() Linux 4.19.271 x86/fpu: Use _Alignof to avoid undefined behavior in TYPE_ALIGN Revert "ext4: generalize extents status tree search functions" Revert "ext4: add new pending reservation mechanism" Revert "ext4: fix reserved cluster accounting at delayed write time" Revert "ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline" gsmi: fix null-deref in gsmi_get_variable serial: atmel: fix incorrect baudrate setup serial: pch_uart: Pass correct sg to dma_unmap_sg() usb-storage: apply IGNORE_UAS only for HIKSEMI MD202 on RTL9210 usb: gadget: f_ncm: fix potential NULL ptr deref in ncm_bitrate() usb: gadget: g_webcam: Send color matching descriptor per frame usb: typec: altmodes/displayport: Fix pin assignment calculation usb: typec: altmodes/displayport: Add pin assignment helper usb: host: ehci-fsl: Fix module alias USB: serial: cp210x: add SCALANCE LPE-9000 device id cifs: do not include page data when checking signature mmc: sunxi-mmc: Fix clock refcount imbalance during unbind comedi: adv_pci1760: Fix PWM instruction handling usb: core: hub: disable autosuspend for TI TUSB8041 USB: misc: iowarrior: fix up header size for USB_DEVICE_ID_CODEMERCS_IOW100 USB: serial: option: add Quectel EM05CN modem USB: serial: option: add Quectel EM05CN (SG) modem USB: serial: option: add Quectel EC200U modem USB: serial: option: add Quectel EM05-G (RS) modem USB: serial: option: add Quectel EM05-G (CS) modem USB: serial: option: add Quectel EM05-G (GR) modem prlimit: do_prlimit needs to have a speculation check xhci: Add a flag to disable USB3 lpm on a xhci root port level. xhci: Fix null pointer dereference when host dies usb: xhci: Check endpoint is valid before dereferencing it xhci-pci: set the dma max_seg_size nilfs2: fix general protection fault in nilfs_btree_insert() Add exception protection processing for vd in axi_chan_handle_err function f2fs: let's avoid panic if extent_tree is not created RDMA/srp: Move large values to a new enum for gcc13 net/ethtool/ioctl: return -EOPNOTSUPP if we have no phy stats pNFS/filelayout: Fix coalescing test for single DS ANDROID: usb: f_accessory: Check buffer size when initialised via composite Linux 4.19.270 serial: tegra: Change lower tolerance baud rate limit for tegra20 and tegra30 serial: tegra: Only print FIFO error message when an error occurs tty: serial: tegra: Handle RX transfer in PIO mode if DMA wasn't started Revert "usb: ulpi: defer ulpi_register on ulpi_read_id timeout" efi: fix NULL-deref in init error path arm64: cmpxchg_double*: hazard against entire exchange variable drm/virtio: Fix GEM handle creation UAF x86/resctrl: Fix task CLOSID/RMID update race x86/resctrl: Use task_curr() instead of task_struct->on_cpu to prevent unnecessary IPI iommu/mediatek-v1: Fix an error handling path in mtk_iommu_v1_probe() iommu/mediatek-v1: Add error handle for mtk_iommu_probe net/mlx5: Fix ptp max frequency adjustment range net/mlx5: Rename ptp clock info nfc: pn533: Wait for out_urb's completion in pn533_usb_send_frame() hvc/xen: lock console list traversal regulator: da9211: Use irq handler when ready EDAC/device: Fix period calculation in edac_device_reset_delay_period() x86/boot: Avoid using Intel mnemonics in AT&T syntax asm netfilter: ipset: Fix overflow before widen in the bitmap_ip_create() function. ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline ext4: fix reserved cluster accounting at delayed write time ext4: add new pending reservation mechanism ext4: generalize extents status tree search functions ext4: fix uninititialized value in 'ext4_evict_inode' ext4: fix use-after-free in ext4_orphan_cleanup ext4: lost matching-pair of trace in ext4_truncate ext4: fix bug_on in __es_tree_search caused by bad quota inode quota: Factor out setup of quota inode usb: ulpi: defer ulpi_register on ulpi_read_id timeout kest.pl: Fix grub2 menu handling for rebooting ktest.pl: Fix incorrect reboot for grub2bls ktest: introduce grub2bls REBOOT_TYPE option ktest: cleanup get_grub_index ktest: introduce _get_grub_index ktest: Add support for meta characters in GRUB_MENU ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later wifi: wilc1000: sdio: fix module autoloading ipv6: raw: Deduct extension header length in rawv6_push_pending_frames platform/x86: sony-laptop: Don't turn off 0x153 keyboard backlight during probe cifs: Fix uninitialized memory read for smb311 posix symlink create ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF net/ulp: prevent ULP without clone op from entering the LISTEN status s390/percpu: add READ_ONCE() to arch_this_cpu_to_op_simple() perf auxtrace: Fix address filter duplicate symbol selection docs: Fix the docs build with Sphinx 6.0 net: sched: disallow noqueue for qdisc classes driver core: Fix bus_type.match() error handling in __driver_attach() parisc: Align parisc MADV_XXX constants with all other architectures mbcache: Avoid nesting of cache->c_list_lock under bit locks hfs/hfsplus: avoid WARN_ON() for sanity check, use proper error handling hfs/hfsplus: use WARN_ON for sanity check ext4: don't allow journal inode to have encrypt flag riscv: uaccess: fix type of 0 variable on error in get_user() nfsd: fix handling of readdir in v4root vs. mount upcall timeout x86/bugs: Flush IBP in ib_prctl_set() ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 tablet udf: Fix extension of the last extent in the file caif: fix memory leak in cfctrl_linkup_request() usb: rndis_host: Secure rndis_query check against int overflow net: sched: atm: dont intepret cls results when asked to drop RDMA/mlx5: Fix validation of max_rd_atomic caps for DC net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe net: amd-xgbe: add missed tasklet_kill nfc: Fix potential resource leaks qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure bpf: pull before calling skb_postpull_rcsum() SUNRPC: ensure the matching upcall is in-flight upon downcall ext4: fix deadlock due to mbcache entry corruption mbcache: automatically delete entries from cache on freeing ext4: fix race when reusing xattr blocks ext4: unindent codeblock in ext4_xattr_block_set() ext4: remove EA inode entry from mbcache on inode eviction mbcache: add functions to delete entry if unused mbcache: don't reclaim used entries ext4: use kmemdup() to replace kmalloc + memcpy ext4: correct inconsistent error msg in nojournal mode ext4: goto right label 'failed_mount3a' driver core: Set deferred_probe_timeout to a longer default if CONFIG_MODULES is set ravb: Fix "failed to switch device to config mode" message during unbind perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor dm thin: resume even if in FAIL mode media: s5p-mfc: Fix in register read and write for H264 media: s5p-mfc: Clear workbit to handle error condition media: s5p-mfc: Fix to handle reference queue during finishing btrfs: replace strncpy() with strscpy() btrfs: send: avoid unnecessary backref lookups when finding clone source ext4: allocate extended attribute value in vmalloc area ext4: avoid unaccounted block allocation when expanding inode ext4: initialize quota before expanding inode in setproject ioctl ext4: fix inode leak in ext4_xattr_inode_create() on an error path ext4: avoid BUG_ON when creating xattrs ext4: fix error code return to user-space in ext4_get_branch() ext4: fix corruption when online resizing a 1K bigalloc fs ext4: init quota for 'old.inode' in 'ext4_rename' ext4: fix bug_on in __es_tree_search caused by bad boot loader inode ext4: add helper to check quota inums ext4: fix undefined behavior in bit shift for ext4_check_flag_values ext4: add inode table check in __ext4_get_inode_loc to aovid possible infinite loop drm/vmwgfx: Validate the box size for the snooped cursor drm/connector: send hotplug uevent on connector cleanup device_cgroup: Roll back to original exceptions after copy failure parisc: led: Fix potential null-ptr-deref in start_task() iommu/amd: Fix ivrs_acpihid cmdline parsing code crypto: n2 - add missing hash statesize PCI/sysfs: Fix double free in error path PCI: Fix pci_device_is_present() for VFs by checking PF ipmi: fix use after free in _ipmi_destroy_user() ima: Fix a potential NULL pointer access in ima_restore_measurement_list ipmi: fix long wait in unload when IPMI disconnect md/bitmap: Fix bitmap chunk size overflow issues cifs: fix confusing debug message media: dvb-core: Fix UAF due to refcount races at releasing media: dvb-core: Fix double free in dvb_register_device() ARM: 9256/1: NWFPE: avoid compiler-generated __aeabi_uldivmod tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line x86/microcode/intel: Do not retry microcode reloading on the APs dm cache: set needs_check flag after aborting metadata dm cache: Fix UAF in destroy() dm thin: Fix UAF in run_timer_softirq() dm thin: Use last transaction's pmd->root when commit failed dm cache: Fix ABBA deadlock between shrink_slab and dm_cache_metadata_abort binfmt: Fix error return code in load_elf_fdpic_binary() binfmt: Move install_exec_creds after setup_new_exec to match binfmt_elf selftests: Use optional USERCFLAGS and USERLDFLAGS ARM: ux500: do not directly dereference __iomem ktest.pl minconfig: Unset configs instead of just removing them soc: qcom: Select REMAP_MMIO for LLCC driver media: stv0288: use explicitly signed char SUNRPC: Don't leak netobj memory when gss_read_proxy_verf() fails tpm: tpm_tis: Add the missed acpi_put_table() to fix memory leak tpm: tpm_crb: Add the missed acpi_put_table() to fix memory leak mmc: vub300: fix warning - do not call blocking ops when !TASK_RUNNING md: fix a crash in mempool_free pnode: terminate at peers of source ALSA: line6: fix stack overflow in line6_midi_transmit ALSA: line6: correct midi status byte when receiving data from podxt ovl: Use ovl mounter's fsuid and fsgid in ovl_link() hfsplus: fix bug causing custom uid and gid being unable to be assigned with mount HID: plantronics: Additional PIDs for double volume key presses quirk powerpc/rtas: avoid scheduling in rtas_os_term() powerpc/rtas: avoid device tree lookups in rtas_os_term() ata: ahci: Fix PCS quirk application for suspend media: dvbdev: fix refcnt bug media: dvbdev: fix build warning due to comments gcov: add support for checksum field iio: adc: ad_sigma_delta: do not use internal iio_dev lock reiserfs: Add missing calls to reiserfs_security_free() HID: wacom: Ensure bootloader PID is usable in hidraw mode usb: dwc3: core: defer probe on ulpi_read_id timeout pstore: Make sure CONFIG_PSTORE_PMSG selects CONFIG_RT_MUTEXES pstore: Switch pmsg_lock to an rt_mutex to avoid priority inversion ASoC: rt5670: Remove unbalanced pm_runtime_put() ASoC: rockchip: spdif: Add missing clk_disable_unprepare() in rk_spdif_runtime_resume() ASoC: wm8994: Fix potential deadlock ASoC: rockchip: pdm: Add missing clk_disable_unprepare() in rockchip_pdm_runtime_resume() ASoC: mediatek: mt8173-rt5650-rt5514: fix refcount leak in mt8173_rt5650_rt5514_dev_probe() orangefs: Fix kmemleak in orangefs_prepare_debugfs_help_string() drm/sti: Fix return type of sti_{dvo,hda,hdmi}_connector_mode_valid() drm/fsl-dcu: Fix return type of fsl_dcu_drm_connector_mode_valid() clk: st: Fix memory leak in st_of_quadfs_setup() media: si470x: Fix use-after-free in si470x_int_in_callback() mmc: f-sdh30: Add quirks for broken timeout clock capability regulator: core: fix use_count leakage when handling boot-on blk-mq: fix possible memleak when register 'hctx' failed media: dvb-usb: fix memory leak in dvb_usb_adapter_init() media: dvbdev: adopts refcnt to avoid UAF media: dvb-frontends: fix leak of memory fw ppp: associate skb with a device at tx mrp: introduce active flags to prevent UAF when applicant uninit md/raid1: stop mdx_raid1 thread when raid1 array run failed drivers/md/md-bitmap: check the return value of md_bitmap_get_counter() drm/sti: Use drm_mode_copy() s390/lcs: Fix return type of lcs_start_xmit() s390/netiucv: Fix return type of netiucv_tx() s390/ctcm: Fix return type of ctc{mp,}m_tx() drm/amdgpu: Fix type of second parameter in trans_msg() callback igb: Do not free q_vector unless new one was allocated wifi: brcmfmac: Fix potential shift-out-of-bounds in brcmf_fw_alloc_request() hamradio: baycom_epp: Fix return type of baycom_send_packet() net: ethernet: ti: Fix return type of netcp_ndo_start_xmit() bpf: make sure skb->len != 0 when redirecting to a tunneling device ipmi: fix memleak when unload ipmi driver ASoC: codecs: rt298: Add quirk for KBL-R RVP platform wifi: ar5523: Fix use-after-free on ar5523_cmd() timed out wifi: ath9k: verify the expected usb_endpoints are present hfs: fix OOB Read in __hfs_brec_find acct: fix potential integer overflow in encode_comp_t() nilfs2: fix shift-out-of-bounds/overflow in nilfs_sb2_bad_offset() ACPICA: Fix error code path in acpi_ds_call_control_method() fs: jfs: fix shift-out-of-bounds in dbDiscardAG udf: Avoid double brelse() in udf_rename() fs: jfs: fix shift-out-of-bounds in dbAllocAG binfmt_misc: fix shift-out-of-bounds in check_special_flags net: stream: purge sk_error_queue in sk_stream_kill_queues() myri10ge: Fix an error handling path in myri10ge_probe() rxrpc: Fix missing unlock in rxrpc_do_sendmsg() net_sched: reject TCF_EM_SIMPLE case for complex ematch module skbuff: Account for tail adjustment during pull operations openvswitch: Fix flow lookup to use unmasked key rtc: mxc_v2: Add missing clk_disable_unprepare() r6040: Fix kmemleak in probe and remove nfc: pn533: Clear nfc_target before being used mISDN: hfcmulti: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave() mISDN: hfcpci: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave() mISDN: hfcsusb: don't call dev_kfree_skb/kfree_skb() under spin_lock_irqsave() nfsd: under NFSv4.1, fix double svc_xprt_put on rpc_create failure rtc: st-lpc: Add missing clk_disable_unprepare in st_rtc_probe() selftests/powerpc: Fix resource leaks powerpc/hv-gpci: Fix hv_gpci event list powerpc/83xx/mpc832x_rdb: call platform_device_put() in error case in of_fsl_spi_probe() powerpc/perf: callchain validate kernel stack pointer bounds powerpc/xive: add missing iounmap() in error path in xive_spapr_populate_irq_data() cxl: Fix refcount leak in cxl_calc_capp_routing powerpc/52xx: Fix a resource leak in an error handling path macintosh/macio-adb: check the return value of ioremap() macintosh: fix possible memory leak in macio_add_one_device() iommu/fsl_pamu: Fix resource leak in fsl_pamu_probe() iommu/amd: Fix pci device refcount leak in ppr_notifier() rtc: snvs: Allow a time difference on clock register read include/uapi/linux/swab: Fix potentially missing __always_inline HSI: omap_ssi_core: Fix error handling in ssi_init() perf symbol: correction while adjusting symbol power: supply: fix residue sysfs file in error handle route of __power_supply_register() HSI: omap_ssi_core: fix possible memory leak in ssi_probe() HSI: omap_ssi_core: fix unbalanced pm_runtime_disable() fbdev: uvesafb: Fixes an error handling path in uvesafb_probe() fbdev: vermilion: decrease reference count in error path fbdev: via: Fix error in via_core_init() fbdev: pm2fb: fix missing pci_disable_device() fbdev: ssd1307fb: Drop optional dependency samples: vfio-mdev: Fix missing pci_disable_device() in mdpy_fb_probe() tracing/hist: Fix issue of losting command info in error_log usb: storage: Add check for kcalloc i2c: ismt: Fix an out-of-bounds bug in ismt_access() vme: Fix error not catched in fake_init() staging: rtl8192e: Fix potential use-after-free in rtllib_rx_Monitor() staging: rtl8192u: Fix use after free in ieee80211_rx() i2c: pxa-pci: fix missing pci_disable_device() on error in ce4100_i2c_probe chardev: fix error handling in cdev_device_add() mcb: mcb-parse: fix error handing in chameleon_parse_gdd() drivers: mcb: fix resource leak in mcb_probe() usb: gadget: f_hid: fix refcount leak on error path usb: gadget: f_hid: fix f_hidg lifetime vs cdev usb: gadget: f_hid: optional SETUP/SET_REPORT mode cxl: fix possible null-ptr-deref in cxl_pci_init_afu|adapter() cxl: fix possible null-ptr-deref in cxl_guest_init_afu|adapter() misc: sgi-gru: fix use-after-free error in gru_set_context_option, gru_fault and gru_handle_user_call_os misc: tifm: fix possible memory leak in tifm_7xx1_switch_media() test_firmware: fix memory leak in test_firmware_init() serial: sunsab: Fix error handling in sunsab_init() serial: altera_uart: fix locking in polling mode tty: serial: altera_uart_{r,t}x_chars() need only uart_port tty: serial: clean up stop-tx part in altera_uart_tx_chars() serial: pch: Fix PCI device refcount leak in pch_request_dma() serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle. serial: amba-pl011: avoid SBSA UART accessing DMACR register usb: typec: Check for ops->exit instead of ops->enter in altmode_exit staging: vme_user: Fix possible UAF in tsi148_dma_list_add usb: fotg210-udc: Fix ages old endianness issues uio: uio_dmem_genirq: Fix deadlock between irq config and handling uio: uio_dmem_genirq: Fix missing unlock in irq configuration vfio: platform: Do not pass return buffer to ACPI _RST method class: fix possible memory leak in __class_register() serial: tegra: Read DMA status before terminating tty: serial: tegra: Activate RX DMA transfer by request serial: tegra: Add PIO mode support serial: tegra: report clk rate errors serial: tegra: add support to adjust baud rate serial: tegra: add support to use 8 bytes trigger serial: tegra: set maximum num of uart ports to 8 serial: tegra: check for FIFO mode enabled status serial: tegra: avoid reg access when clk disabled drivers: dio: fix possible memory leak in dio_init() IB/IPoIB: Fix queue count inconsistency for PKEY child interfaces hwrng: geode - Fix PCI device refcount leak hwrng: amd - Fix PCI device refcount leak crypto: img-hash - Fix variable dereferenced before check 'hdev->req' orangefs: Fix sysfs not cleanup when dev init failed RDMA/hfi1: Fix error return code in parse_platform_config() scsi: snic: Fix possible UAF in snic_tgt_create() scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails scsi: ipr: Fix WARNING in ipr_init() scsi: fcoe: Fix possible name leak when device_register() fails scsi: hpsa: Fix possible memory leak in hpsa_add_sas_device() scsi: hpsa: Fix error handling in hpsa_add_sas_host() crypto: tcrypt - Fix multibuffer skcipher speed test mem leak scsi: hpsa: Fix possible memory leak in hpsa_init_one() scsi: hpsa: use local workqueues instead of system workqueues RDMA/rxe: Fix NULL-ptr-deref in rxe_qp_do_cleanup() when socket create failed crypto: ccree - Make cc_debugfs_global_fini() available for module init function RDMA/hfi: Decrease PCI device reference count in error path PCI: Check for alloc failure in pci_request_irq() scsi: scsi_debug: Fix a warning in resp_write_scat() RDMA/nldev: Return "-EAGAIN" if the cm_id isn't from expected port f2fs: fix normal discard process apparmor: Fix abi check to include v8 abi apparmor: fix lockdep warning when removing a namespace apparmor: fix a memleak in multi_transaction_new() stmmac: fix potential division by 0 Bluetooth: RFCOMM: don't call kfree_skb() under spin_lock_irqsave() Bluetooth: hci_core: don't call kfree_skb() under spin_lock_irqsave() Bluetooth: hci_bcsp: don't call kfree_skb() under spin_lock_irqsave() Bluetooth: hci_h5: don't call kfree_skb() under spin_lock_irqsave() Bluetooth: hci_qca: don't call kfree_skb() under spin_lock_irqsave() Bluetooth: btusb: don't call kfree_skb() under spin_lock_irqsave() ntb_netdev: Use dev_kfree_skb_any() in interrupt context net: lan9303: Fix read error execution path net: amd-xgbe: Check only the minimum speed for active/passive cables net: amd-xgbe: Fix logic around active and passive cables net: amd: lance: don't call dev_kfree_skb() under spin_lock_irqsave() hamradio: don't call dev_kfree_skb() under spin_lock_irqsave() net: ethernet: dnet: don't call dev_kfree_skb() under spin_lock_irqsave() net: emaclite: don't call dev_kfree_skb() under spin_lock_irqsave() net: apple: bmac: don't call dev_kfree_skb() under spin_lock_irqsave() net: apple: mace: don't call dev_kfree_skb() under spin_lock_irqsave() net/tunnel: wait until all sk_user_data reader finish before releasing the sock net: farsync: Fix kmemleak when rmmods farsync ethernet: s2io: don't call dev_kfree_skb() under spin_lock_irqsave() drivers: net: qlcnic: Fix potential memory leak in qlcnic_sriov_init() net: defxx: Fix missing err handling in dfx_init() net: vmw_vsock: vmci: Check memcpy_from_msg() clk: socfpga: use clk_hw_register for a5/c5 clk: socfpga: clk-pll: Remove unused variable 'rc' blktrace: Fix output non-blktrace event when blk_classic option enabled wifi: brcmfmac: Fix error return code in brcmf_sdio_download_firmware() rtl8xxxu: add enumeration for channel bandwidth wifi: rtl8xxxu: Add __packed to struct rtl8723bu_c2h clk: samsung: Fix memory leak in _samsung_clk_register_pll() media: coda: Add check for kmalloc media: coda: Add check for dcoda_iram_alloc media: c8sectpfe: Add of_node_put() when breaking out of loop mmc: mmci: fix return value check of mmc_add_host() mmc: wbsd: fix return value check of mmc_add_host() mmc: via-sdmmc: fix return value check of mmc_add_host() mmc: meson-gx: fix return value check of mmc_add_host() mmc: atmel-mci: fix return value check of mmc_add_host() mmc: wmt-sdmmc: fix return value check of mmc_add_host() mmc: vub300: fix return value check of mmc_add_host() mmc: toshsd: fix return value check of mmc_add_host() mmc: rtsx_usb_sdmmc: fix return value check of mmc_add_host() mmc: mxcmmc: fix return value check of mmc_add_host() mmc: moxart: fix return value check of mmc_add_host() NFSv4.x: Fail client initialisation if state manager thread can't run SUNRPC: Fix missing release socket in rpc_sockname() ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt media: saa7164: fix missing pci_disable_device() regulator: core: fix module refcount leak in set_supply() wifi: cfg80211: Fix not unregister reg_pdev when load_builtin_regdb_keys() fails bonding: uninitialized variable in bond_miimon_inspect() ASoC: pcm512x: Fix PM disable depth imbalance in pcm512x_probe drm/amdgpu: Fix PCI device refcount leak in amdgpu_atrm_get_bios() drm/radeon: Fix PCI device refcount leak in radeon_atrm_get_bios() ALSA: asihpi: fix missing pci_disable_device() NFSv4: Fix a deadlock between nfs4_open_recover_helper() and delegreturn NFSv4.2: Fix a memory stomp in decode_attr_security_label drm/tegra: Add missing clk_disable_unprepare() in tegra_dc_probe() media: s5p-mfc: Add variant data for MFC v7 hardware for Exynos 3250 SoC media: dvb-usb: az6027: fix null-ptr-deref in az6027_i2c_xfer() media: dvb-core: Fix ignored return value in dvb_register_frontend() pinctrl: pinconf-generic: add missing of_node_put() media: imon: fix a race condition in send_packet() drbd: remove call to memset before free device/resource/connection mtd: maps: pxa2xx-flash: fix memory leak in probe bonding: Export skip slave logic to function clk: rockchip: Fix memory leak in rockchip_clk_register_pll() ALSA: seq: fix undefined behavior in bit shift for SNDRV_SEQ_FILTER_USE_EVENT HID: hid-sensor-custom: set fixed size for custom attributes media: platform: exynos4-is: Fix error handling in fimc_md_init() media: solo6x10: fix possible memory leak in solo_sysfs_init() Input: elants_i2c - properly handle the reset GPIO when power is off mtd: lpddr2_nvm: Fix possible null-ptr-deref wifi: ath10k: Fix return value in ath10k_pci_init() ima: Fix misuse of dereference of pointer in template_desc_init_fields() regulator: core: fix unbalanced of node refcount in regulator_dev_lookup() ASoC: pxa: fix null-pointer dereference in filter() drm/radeon: Add the missed acpi_put_table() to fix memory leak net, proc: Provide PROC_FS=n fallback for proc_create_net_single_write() media: camss: Clean up received buffers on failed start of streaming wifi: rsi: Fix handling of 802.3 EAPOL frames sent via control port mtd: Fix device name leak when register device failed in add_mtd_device() media: vivid: fix compose size exceed boundary spi: Update reference to struct spi_controller can: kvaser_usb: Compare requested bittiming parameters with actual parameters in do_set_{,data}_bittiming can: kvaser_usb: Add struct kvaser_usb_busparams can: kvaser_usb_leaf: Fix bogus restart events can: kvaser_usb_leaf: Fix wrong CAN state after stopping can: kvaser_usb_leaf: Fix improved state not being reported can: kvaser_usb_leaf: Set Warning state even without bus errors can: kvaser_usb: kvaser_usb_leaf: Handle CMD_ERROR_EVENT can: kvaser_usb: kvaser_usb_leaf: Rename {leaf,usbcan}_cmd_error_event to {leaf,usbcan}_cmd_can_error_event can: kvaser_usb: kvaser_usb_leaf: Get capabilities from device can: kvaser_usb: do not increase tx statistics when sending error message frames media: i2c: ad5820: Fix error path pata_ipx4xx_cf: Fix unsigned comparison with less than zero wifi: rtl8xxxu: Fix reading the vendor of combo chips wifi: ath9k: hif_usb: Fix use-after-free in ath9k_hif_usb_reg_in_cb() wifi: ath9k: hif_usb: fix memory leak of urbs in ath9k_hif_usb_dealloc_tx_urbs() rapidio: devices: fix missing put_device in mport_cdev_open hfs: Fix OOB Write in hfs_asc2mac relay: fix type mismatch when allocating memory in relay_create_buf() eventfd: change int to __u64 in eventfd_signal() ifndef CONFIG_EVENTFD rapidio: fix possible UAF when kfifo_alloc() fails fs: sysv: Fix sysv_nblocks() returns wrong value MIPS: BCM63xx: Add check for NULL for clk in clk_enable platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]() PM: runtime: Do not call __rpm_callback() from rpm_idle() PM: runtime: Improve path in rpm_idle() when no callback xen/privcmd: Fix a possible warning in privcmd_ioctl_mmap_resource() x86/xen: Fix memory leak in xen_init_lock_cpu() x86/xen: Fix memory leak in xen_smp_intr_init{_pv}() xen/events: only register debug interrupt for 2-level events uprobes/x86: Allow to probe a NOP instruction with 0x66 prefix ACPICA: Fix use-after-free in acpi_ut_copy_ipackage_to_ipackage() clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled rapidio: rio: fix possible name leak in rio_register_mport() rapidio: fix possible name leaks when rio_add_device() fails debugfs: fix error when writing negative value to atomic_t debugfs file lib/notifier-error-inject: fix error when writing -errno to debugfs file libfs: add DEFINE_SIMPLE_ATTRIBUTE_SIGNED for signed value cpufreq: amd_freq_sensitivity: Add missing pci_dev_put() irqchip: gic-pm: Use pm_runtime_resume_and_get() in gic_probe() perf/x86/intel/uncore: Fix reference count leak in hswep_has_limit_sbox() PNP: fix name memory leak in pnp_alloc_dev() MIPS: vpe-cmp: fix possible memory leak while module exiting MIPS: vpe-mt: fix possible memory leak while module exiting ocfs2: fix memory leak in ocfs2_stack_glue_init() proc: fixup uptime selftest timerqueue: Use rb_entry_safe() in timerqueue_getnext() perf: Fix possible memleak in pmu_dev_alloc() selftests/ftrace: event_triggers: wait longer for test_event_enable fs: don't audit the capability check in simple_xattr_list() alpha: fix syscall entry in !AUDUT_SYSCALL case cpuidle: dt: Return the correct numbers of parsed idle states tpm/tpm_crb: Fix error message in __crb_relinquish_locality() pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP ARM: mmp: fix timer_read delay pstore/ram: Fix error return code in ramoops_probe() ARM: dts: turris-omnia: Add switch port 6 node ARM: dts: turris-omnia: Add ethernet aliases ARM: dts: armada-39x: Fix assigned-addresses for every PCIe Root Port ARM: dts: armada-38x: Fix assigned-addresses for every PCIe Root Port ARM: dts: armada-375: Fix assigned-addresses for every PCIe Root Port ARM: dts: armada-xp: Fix assigned-addresses for every PCIe Root Port ARM: dts: armada-370: Fix assigned-addresses for every PCIe Root Port ARM: dts: dove: Fix assigned-addresses for every PCIe Root Port arm64: dts: mediatek: mt6797: Fix 26M oscillator unit name arm64: dts: mt2712-evb: Fix vproc fixed regulators unit names arm64: dts: mt2712e: Fix unit address for pinctrl node arm64: dts: mt2712e: Fix unit_address_vs_reg warning for oscillators perf: arm_dsu: Fix hotplug callback leak in dsu_pmu_init() soc: ti: smartreflex: Fix PM disable depth imbalance in omap_sr_probe arm: dts: spear600: Fix clcd interrupt drivers: soc: ti: knav_qmss_queue: Mark knav_acc_firmwares as static ARM: dts: qcom: apq8064: fix coresight compatible usb: musb: remove extra check in musb_gadget_vbus_draw net: loopback: use NET_NAME_PREDICTABLE for name_assign_type Bluetooth: L2CAP: Fix u8 overflow igb: Initialize mailbox message for VF reset USB: serial: f81534: fix division by zero on line-speed change USB: serial: cp210x: add Kamstrup RF sniffer PIDs USB: serial: option: add Quectel EM05-G modem usb: gadget: uvc: Prevent buffer overflow in setup handler udf: Fix extending file within last block udf: Do not bother looking for prealloc extents if i_lenExtents matches i_size udf: Fix preallocation discarding at indirect extent boundary udf: Discard preallocation before extending file with a hole perf script python: Remove explicit shebang from tests/attr.c ASoC: ops: Correct bounds check for second channel on SX controls can: mcba_usb: Fix termination command argument can: sja1000: fix size of OCR_MODE_MASK define pinctrl: meditatek: Startup with the IRQs disabled ASoC: ops: Check bounds for second channel in snd_soc_put_volsw_sx() nfp: fix use-after-free in area_cache_get() block: unhash blkdev part inode when the part is deleted mm/khugepaged: invoke MMU notifiers in shmem/file collapse paths mm/khugepaged: fix GUP-fast interaction by sending IPI ANDROID: Add more hvc devices for virtio-console. Conflicts: drivers/base/core.c drivers/edac/edac_device.c drivers/hwtracing/coresight/coresight-etm4x.c drivers/net/wireless/mac80211_hwsim.c drivers/scsi/ufs/ufshcd-crypto.c drivers/usb/gadget/function/f_fs.c drivers/usb/gadget/function/f_hid.c Change-Id: Ied998db07e927ccb3376a78f044df36088d9e3b8
1835 lines
46 KiB
C
1835 lines
46 KiB
C
/*
|
|
* linux/kernel/exit.c
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
*/
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/sched/autogroup.h>
|
|
#include <linux/sched/mm.h>
|
|
#include <linux/sched/stat.h>
|
|
#include <linux/sched/task.h>
|
|
#include <linux/sched/task_stack.h>
|
|
#include <linux/sched/cputime.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/module.h>
|
|
#include <linux/capability.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/personality.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/iocontext.h>
|
|
#include <linux/key.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/acct.h>
|
|
#include <linux/tsacct_kern.h>
|
|
#include <linux/file.h>
|
|
#include <linux/fdtable.h>
|
|
#include <linux/freezer.h>
|
|
#include <linux/binfmts.h>
|
|
#include <linux/nsproxy.h>
|
|
#include <linux/pid_namespace.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/profile.h>
|
|
#include <linux/mount.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/mempolicy.h>
|
|
#include <linux/taskstats_kern.h>
|
|
#include <linux/delayacct.h>
|
|
#include <linux/cgroup.h>
|
|
#include <linux/syscalls.h>
|
|
#include <linux/signal.h>
|
|
#include <linux/posix-timers.h>
|
|
#include <linux/cn_proc.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/futex.h>
|
|
#include <linux/pipe_fs_i.h>
|
|
#include <linux/audit.h> /* for audit_free() */
|
|
#include <linux/resource.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/task_io_accounting_ops.h>
|
|
#include <linux/tracehook.h>
|
|
#include <linux/fs_struct.h>
|
|
#include <linux/init_task.h>
|
|
#include <linux/perf_event.h>
|
|
#include <trace/events/sched.h>
|
|
#include <linux/hw_breakpoint.h>
|
|
#include <linux/oom.h>
|
|
#include <linux/writeback.h>
|
|
#include <linux/shm.h>
|
|
#include <linux/kcov.h>
|
|
#include <linux/random.h>
|
|
#include <linux/rcuwait.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/sysfs.h>
|
|
|
|
#include <linux/uaccess.h>
|
|
#include <asm/unistd.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/mmu_context.h>
|
|
|
|
/*
|
|
* The default value should be high enough to not crash a system that randomly
|
|
* crashes its kernel from time to time, but low enough to at least not permit
|
|
* overflowing 32-bit refcounts or the ldsem writer count.
|
|
*/
|
|
static unsigned int oops_limit = 10000;
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
static struct ctl_table kern_exit_table[] = {
|
|
{
|
|
.procname = "oops_limit",
|
|
.data = &oops_limit,
|
|
.maxlen = sizeof(oops_limit),
|
|
.mode = 0644,
|
|
.proc_handler = proc_douintvec,
|
|
},
|
|
{ }
|
|
};
|
|
|
|
static __init int kernel_exit_sysctls_init(void)
|
|
{
|
|
register_sysctl_init("kernel", kern_exit_table);
|
|
return 0;
|
|
}
|
|
late_initcall(kernel_exit_sysctls_init);
|
|
#endif
|
|
|
|
static atomic_t oops_count = ATOMIC_INIT(0);
|
|
|
|
#ifdef CONFIG_SYSFS
|
|
static ssize_t oops_count_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
char *page)
|
|
{
|
|
return sysfs_emit(page, "%d\n", atomic_read(&oops_count));
|
|
}
|
|
|
|
static struct kobj_attribute oops_count_attr = __ATTR_RO(oops_count);
|
|
|
|
static __init int kernel_exit_sysfs_init(void)
|
|
{
|
|
sysfs_add_file_to_group(kernel_kobj, &oops_count_attr.attr, NULL);
|
|
return 0;
|
|
}
|
|
late_initcall(kernel_exit_sysfs_init);
|
|
#endif
|
|
|
|
static void __unhash_process(struct task_struct *p, bool group_dead)
|
|
{
|
|
nr_threads--;
|
|
detach_pid(p, PIDTYPE_PID);
|
|
if (group_dead) {
|
|
detach_pid(p, PIDTYPE_TGID);
|
|
detach_pid(p, PIDTYPE_PGID);
|
|
detach_pid(p, PIDTYPE_SID);
|
|
|
|
list_del_rcu(&p->tasks);
|
|
list_del_init(&p->sibling);
|
|
__this_cpu_dec(process_counts);
|
|
}
|
|
list_del_rcu(&p->thread_group);
|
|
list_del_rcu(&p->thread_node);
|
|
}
|
|
|
|
/*
|
|
* This function expects the tasklist_lock write-locked.
|
|
*/
|
|
static void __exit_signal(struct task_struct *tsk)
|
|
{
|
|
struct signal_struct *sig = tsk->signal;
|
|
bool group_dead = thread_group_leader(tsk);
|
|
struct sighand_struct *sighand;
|
|
struct tty_struct *uninitialized_var(tty);
|
|
u64 utime, stime;
|
|
|
|
sighand = rcu_dereference_check(tsk->sighand,
|
|
lockdep_tasklist_lock_is_held());
|
|
spin_lock(&sighand->siglock);
|
|
|
|
#ifdef CONFIG_POSIX_TIMERS
|
|
posix_cpu_timers_exit(tsk);
|
|
if (group_dead) {
|
|
posix_cpu_timers_exit_group(tsk);
|
|
} else {
|
|
/*
|
|
* This can only happen if the caller is de_thread().
|
|
* FIXME: this is the temporary hack, we should teach
|
|
* posix-cpu-timers to handle this case correctly.
|
|
*/
|
|
if (unlikely(has_group_leader_pid(tsk)))
|
|
posix_cpu_timers_exit_group(tsk);
|
|
}
|
|
#endif
|
|
|
|
if (group_dead) {
|
|
tty = sig->tty;
|
|
sig->tty = NULL;
|
|
} else {
|
|
/*
|
|
* If there is any task waiting for the group exit
|
|
* then notify it:
|
|
*/
|
|
if (sig->notify_count > 0 && !--sig->notify_count)
|
|
wake_up_process(sig->group_exit_task);
|
|
|
|
if (tsk == sig->curr_target)
|
|
sig->curr_target = next_thread(tsk);
|
|
}
|
|
|
|
add_device_randomness((const void*) &tsk->se.sum_exec_runtime,
|
|
sizeof(unsigned long long));
|
|
|
|
/*
|
|
* Accumulate here the counters for all threads as they die. We could
|
|
* skip the group leader because it is the last user of signal_struct,
|
|
* but we want to avoid the race with thread_group_cputime() which can
|
|
* see the empty ->thread_head list.
|
|
*/
|
|
task_cputime(tsk, &utime, &stime);
|
|
write_seqlock(&sig->stats_lock);
|
|
sig->utime += utime;
|
|
sig->stime += stime;
|
|
sig->gtime += task_gtime(tsk);
|
|
sig->min_flt += tsk->min_flt;
|
|
sig->maj_flt += tsk->maj_flt;
|
|
sig->nvcsw += tsk->nvcsw;
|
|
sig->nivcsw += tsk->nivcsw;
|
|
sig->inblock += task_io_get_inblock(tsk);
|
|
sig->oublock += task_io_get_oublock(tsk);
|
|
task_io_accounting_add(&sig->ioac, &tsk->ioac);
|
|
sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
|
|
sig->nr_threads--;
|
|
__unhash_process(tsk, group_dead);
|
|
write_sequnlock(&sig->stats_lock);
|
|
|
|
/*
|
|
* Do this under ->siglock, we can race with another thread
|
|
* doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals.
|
|
*/
|
|
flush_sigqueue(&tsk->pending);
|
|
tsk->sighand = NULL;
|
|
spin_unlock(&sighand->siglock);
|
|
|
|
__cleanup_sighand(sighand);
|
|
clear_tsk_thread_flag(tsk, TIF_SIGPENDING);
|
|
if (group_dead) {
|
|
flush_sigqueue(&sig->shared_pending);
|
|
tty_kref_put(tty);
|
|
}
|
|
}
|
|
|
|
static void delayed_put_task_struct(struct rcu_head *rhp)
|
|
{
|
|
struct task_struct *tsk = container_of(rhp, struct task_struct, rcu);
|
|
|
|
perf_event_delayed_put(tsk);
|
|
trace_sched_process_free(tsk);
|
|
put_task_struct(tsk);
|
|
}
|
|
|
|
void put_task_struct_rcu_user(struct task_struct *task)
|
|
{
|
|
if (refcount_dec_and_test(&task->rcu_users))
|
|
call_rcu(&task->rcu, delayed_put_task_struct);
|
|
}
|
|
|
|
void release_task(struct task_struct *p)
|
|
{
|
|
struct task_struct *leader;
|
|
int zap_leader;
|
|
repeat:
|
|
/* don't need to get the RCU readlock here - the process is dead and
|
|
* can't be modifying its own credentials. But shut RCU-lockdep up */
|
|
rcu_read_lock();
|
|
atomic_dec(&__task_cred(p)->user->processes);
|
|
rcu_read_unlock();
|
|
|
|
proc_flush_task(p);
|
|
cgroup_release(p);
|
|
|
|
write_lock_irq(&tasklist_lock);
|
|
ptrace_release_task(p);
|
|
__exit_signal(p);
|
|
|
|
/*
|
|
* If we are the last non-leader member of the thread
|
|
* group, and the leader is zombie, then notify the
|
|
* group leader's parent process. (if it wants notification.)
|
|
*/
|
|
zap_leader = 0;
|
|
leader = p->group_leader;
|
|
if (leader != p && thread_group_empty(leader)
|
|
&& leader->exit_state == EXIT_ZOMBIE) {
|
|
/*
|
|
* If we were the last child thread and the leader has
|
|
* exited already, and the leader's parent ignores SIGCHLD,
|
|
* then we are the one who should release the leader.
|
|
*/
|
|
zap_leader = do_notify_parent(leader, leader->exit_signal);
|
|
if (zap_leader)
|
|
leader->exit_state = EXIT_DEAD;
|
|
}
|
|
|
|
write_unlock_irq(&tasklist_lock);
|
|
release_thread(p);
|
|
put_task_struct_rcu_user(p);
|
|
|
|
p = leader;
|
|
if (unlikely(zap_leader))
|
|
goto repeat;
|
|
}
|
|
|
|
/*
|
|
* Note that if this function returns a valid task_struct pointer (!NULL)
|
|
* task->usage must remain >0 for the duration of the RCU critical section.
|
|
*/
|
|
struct task_struct *task_rcu_dereference(struct task_struct **ptask)
|
|
{
|
|
struct sighand_struct *sighand;
|
|
struct task_struct *task;
|
|
|
|
/*
|
|
* We need to verify that release_task() was not called and thus
|
|
* delayed_put_task_struct() can't run and drop the last reference
|
|
* before rcu_read_unlock(). We check task->sighand != NULL,
|
|
* but we can read the already freed and reused memory.
|
|
*/
|
|
retry:
|
|
task = rcu_dereference(*ptask);
|
|
if (!task)
|
|
return NULL;
|
|
|
|
probe_kernel_address(&task->sighand, sighand);
|
|
|
|
/*
|
|
* Pairs with atomic_dec_and_test() in put_task_struct(). If this task
|
|
* was already freed we can not miss the preceding update of this
|
|
* pointer.
|
|
*/
|
|
smp_rmb();
|
|
if (unlikely(task != READ_ONCE(*ptask)))
|
|
goto retry;
|
|
|
|
/*
|
|
* We've re-checked that "task == *ptask", now we have two different
|
|
* cases:
|
|
*
|
|
* 1. This is actually the same task/task_struct. In this case
|
|
* sighand != NULL tells us it is still alive.
|
|
*
|
|
* 2. This is another task which got the same memory for task_struct.
|
|
* We can't know this of course, and we can not trust
|
|
* sighand != NULL.
|
|
*
|
|
* In this case we actually return a random value, but this is
|
|
* correct.
|
|
*
|
|
* If we return NULL - we can pretend that we actually noticed that
|
|
* *ptask was updated when the previous task has exited. Or pretend
|
|
* that probe_slab_address(&sighand) reads NULL.
|
|
*
|
|
* If we return the new task (because sighand is not NULL for any
|
|
* reason) - this is fine too. This (new) task can't go away before
|
|
* another gp pass.
|
|
*
|
|
* And note: We could even eliminate the false positive if re-read
|
|
* task->sighand once again to avoid the falsely NULL. But this case
|
|
* is very unlikely so we don't care.
|
|
*/
|
|
if (!sighand)
|
|
return NULL;
|
|
|
|
return task;
|
|
}
|
|
|
|
void rcuwait_wake_up(struct rcuwait *w)
|
|
{
|
|
struct task_struct *task;
|
|
|
|
rcu_read_lock();
|
|
|
|
/*
|
|
* Order condition vs @task, such that everything prior to the load
|
|
* of @task is visible. This is the condition as to why the user called
|
|
* rcuwait_trywake() in the first place. Pairs with set_current_state()
|
|
* barrier (A) in rcuwait_wait_event().
|
|
*
|
|
* WAIT WAKE
|
|
* [S] tsk = current [S] cond = true
|
|
* MB (A) MB (B)
|
|
* [L] cond [L] tsk
|
|
*/
|
|
smp_mb(); /* (B) */
|
|
|
|
/*
|
|
* Avoid using task_rcu_dereference() magic as long as we are careful,
|
|
* see comment in rcuwait_wait_event() regarding ->exit_state.
|
|
*/
|
|
task = rcu_dereference(w->task);
|
|
if (task)
|
|
wake_up_process(task);
|
|
rcu_read_unlock();
|
|
}
|
|
|
|
/*
|
|
* Determine if a process group is "orphaned", according to the POSIX
|
|
* definition in 2.2.2.52. Orphaned process groups are not to be affected
|
|
* by terminal-generated stop signals. Newly orphaned process groups are
|
|
* to receive a SIGHUP and a SIGCONT.
|
|
*
|
|
* "I ask you, have you ever known what it is to be an orphan?"
|
|
*/
|
|
static int will_become_orphaned_pgrp(struct pid *pgrp,
|
|
struct task_struct *ignored_task)
|
|
{
|
|
struct task_struct *p;
|
|
|
|
do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
|
|
if ((p == ignored_task) ||
|
|
(p->exit_state && thread_group_empty(p)) ||
|
|
is_global_init(p->real_parent))
|
|
continue;
|
|
|
|
if (task_pgrp(p->real_parent) != pgrp &&
|
|
task_session(p->real_parent) == task_session(p))
|
|
return 0;
|
|
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int is_current_pgrp_orphaned(void)
|
|
{
|
|
int retval;
|
|
|
|
read_lock(&tasklist_lock);
|
|
retval = will_become_orphaned_pgrp(task_pgrp(current), NULL);
|
|
read_unlock(&tasklist_lock);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static bool has_stopped_jobs(struct pid *pgrp)
|
|
{
|
|
struct task_struct *p;
|
|
|
|
do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
|
|
if (p->signal->flags & SIGNAL_STOP_STOPPED)
|
|
return true;
|
|
} while_each_pid_task(pgrp, PIDTYPE_PGID, p);
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Check to see if any process groups have become orphaned as
|
|
* a result of our exiting, and if they have any stopped jobs,
|
|
* send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
|
|
*/
|
|
static void
|
|
kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent)
|
|
{
|
|
struct pid *pgrp = task_pgrp(tsk);
|
|
struct task_struct *ignored_task = tsk;
|
|
|
|
if (!parent)
|
|
/* exit: our father is in a different pgrp than
|
|
* we are and we were the only connection outside.
|
|
*/
|
|
parent = tsk->real_parent;
|
|
else
|
|
/* reparent: our child is in a different pgrp than
|
|
* we are, and it was the only connection outside.
|
|
*/
|
|
ignored_task = NULL;
|
|
|
|
if (task_pgrp(parent) != pgrp &&
|
|
task_session(parent) == task_session(tsk) &&
|
|
will_become_orphaned_pgrp(pgrp, ignored_task) &&
|
|
has_stopped_jobs(pgrp)) {
|
|
__kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp);
|
|
__kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_MEMCG
|
|
/*
|
|
* A task is exiting. If it owned this mm, find a new owner for the mm.
|
|
*/
|
|
void mm_update_next_owner(struct mm_struct *mm)
|
|
{
|
|
struct task_struct *c, *g, *p = current;
|
|
|
|
retry:
|
|
/*
|
|
* If the exiting or execing task is not the owner, it's
|
|
* someone else's problem.
|
|
*/
|
|
if (mm->owner != p)
|
|
return;
|
|
/*
|
|
* The current owner is exiting/execing and there are no other
|
|
* candidates. Do not leave the mm pointing to a possibly
|
|
* freed task structure.
|
|
*/
|
|
if (atomic_read(&mm->mm_users) <= 1) {
|
|
mm->owner = NULL;
|
|
return;
|
|
}
|
|
|
|
read_lock(&tasklist_lock);
|
|
/*
|
|
* Search in the children
|
|
*/
|
|
list_for_each_entry(c, &p->children, sibling) {
|
|
if (c->mm == mm)
|
|
goto assign_new_owner;
|
|
}
|
|
|
|
/*
|
|
* Search in the siblings
|
|
*/
|
|
list_for_each_entry(c, &p->real_parent->children, sibling) {
|
|
if (c->mm == mm)
|
|
goto assign_new_owner;
|
|
}
|
|
|
|
/*
|
|
* Search through everything else, we should not get here often.
|
|
*/
|
|
for_each_process(g) {
|
|
if (g->flags & PF_KTHREAD)
|
|
continue;
|
|
for_each_thread(g, c) {
|
|
if (c->mm == mm)
|
|
goto assign_new_owner;
|
|
if (c->mm)
|
|
break;
|
|
}
|
|
}
|
|
read_unlock(&tasklist_lock);
|
|
/*
|
|
* We found no owner yet mm_users > 1: this implies that we are
|
|
* most likely racing with swapoff (try_to_unuse()) or /proc or
|
|
* ptrace or page migration (get_task_mm()). Mark owner as NULL.
|
|
*/
|
|
mm->owner = NULL;
|
|
return;
|
|
|
|
assign_new_owner:
|
|
BUG_ON(c == p);
|
|
get_task_struct(c);
|
|
/*
|
|
* The task_lock protects c->mm from changing.
|
|
* We always want mm->owner->mm == mm
|
|
*/
|
|
task_lock(c);
|
|
/*
|
|
* Delay read_unlock() till we have the task_lock()
|
|
* to ensure that c does not slip away underneath us
|
|
*/
|
|
read_unlock(&tasklist_lock);
|
|
if (c->mm != mm) {
|
|
task_unlock(c);
|
|
put_task_struct(c);
|
|
goto retry;
|
|
}
|
|
mm->owner = c;
|
|
task_unlock(c);
|
|
put_task_struct(c);
|
|
}
|
|
#endif /* CONFIG_MEMCG */
|
|
|
|
/*
|
|
* Turn us into a lazy TLB process if we
|
|
* aren't already..
|
|
*/
|
|
static void exit_mm(void)
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
struct core_state *core_state;
|
|
|
|
exit_mm_release(current, mm);
|
|
if (!mm)
|
|
return;
|
|
sync_mm_rss(mm);
|
|
/*
|
|
* Serialize with any possible pending coredump.
|
|
* We must hold mmap_sem around checking core_state
|
|
* and clearing tsk->mm. The core-inducing thread
|
|
* will increment ->nr_threads for each thread in the
|
|
* group with ->mm != NULL.
|
|
*/
|
|
down_read(&mm->mmap_sem);
|
|
core_state = mm->core_state;
|
|
if (core_state) {
|
|
struct core_thread self;
|
|
|
|
up_read(&mm->mmap_sem);
|
|
|
|
self.task = current;
|
|
if (self.task->flags & PF_SIGNALED)
|
|
self.next = xchg(&core_state->dumper.next, &self);
|
|
else
|
|
self.task = NULL;
|
|
/*
|
|
* Implies mb(), the result of xchg() must be visible
|
|
* to core_state->dumper.
|
|
*/
|
|
if (atomic_dec_and_test(&core_state->nr_threads))
|
|
complete(&core_state->startup);
|
|
|
|
for (;;) {
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
if (!self.task) /* see coredump_finish() */
|
|
break;
|
|
freezable_schedule();
|
|
}
|
|
__set_current_state(TASK_RUNNING);
|
|
down_read(&mm->mmap_sem);
|
|
}
|
|
mmgrab(mm);
|
|
BUG_ON(mm != current->active_mm);
|
|
/* more a memory barrier than a real lock */
|
|
task_lock(current);
|
|
current->mm = NULL;
|
|
up_read(&mm->mmap_sem);
|
|
enter_lazy_tlb(mm, current);
|
|
task_unlock(current);
|
|
mm_update_next_owner(mm);
|
|
mmput(mm);
|
|
if (test_thread_flag(TIF_MEMDIE))
|
|
exit_oom_victim();
|
|
}
|
|
|
|
static struct task_struct *find_alive_thread(struct task_struct *p)
|
|
{
|
|
struct task_struct *t;
|
|
|
|
for_each_thread(p, t) {
|
|
if (!(t->flags & PF_EXITING))
|
|
return t;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static struct task_struct *find_child_reaper(struct task_struct *father,
|
|
struct list_head *dead)
|
|
__releases(&tasklist_lock)
|
|
__acquires(&tasklist_lock)
|
|
{
|
|
struct pid_namespace *pid_ns = task_active_pid_ns(father);
|
|
struct task_struct *reaper = pid_ns->child_reaper;
|
|
struct task_struct *p, *n;
|
|
|
|
if (likely(reaper != father))
|
|
return reaper;
|
|
|
|
reaper = find_alive_thread(father);
|
|
if (reaper) {
|
|
pid_ns->child_reaper = reaper;
|
|
return reaper;
|
|
}
|
|
|
|
write_unlock_irq(&tasklist_lock);
|
|
|
|
list_for_each_entry_safe(p, n, dead, ptrace_entry) {
|
|
list_del_init(&p->ptrace_entry);
|
|
release_task(p);
|
|
}
|
|
|
|
zap_pid_ns_processes(pid_ns);
|
|
write_lock_irq(&tasklist_lock);
|
|
|
|
return father;
|
|
}
|
|
|
|
/*
|
|
* When we die, we re-parent all our children, and try to:
|
|
* 1. give them to another thread in our thread group, if such a member exists
|
|
* 2. give it to the first ancestor process which prctl'd itself as a
|
|
* child_subreaper for its children (like a service manager)
|
|
* 3. give it to the init process (PID 1) in our pid namespace
|
|
*/
|
|
static struct task_struct *find_new_reaper(struct task_struct *father,
|
|
struct task_struct *child_reaper)
|
|
{
|
|
struct task_struct *thread, *reaper;
|
|
|
|
thread = find_alive_thread(father);
|
|
if (thread)
|
|
return thread;
|
|
|
|
if (father->signal->has_child_subreaper) {
|
|
unsigned int ns_level = task_pid(father)->level;
|
|
/*
|
|
* Find the first ->is_child_subreaper ancestor in our pid_ns.
|
|
* We can't check reaper != child_reaper to ensure we do not
|
|
* cross the namespaces, the exiting parent could be injected
|
|
* by setns() + fork().
|
|
* We check pid->level, this is slightly more efficient than
|
|
* task_active_pid_ns(reaper) != task_active_pid_ns(father).
|
|
*/
|
|
for (reaper = father->real_parent;
|
|
task_pid(reaper)->level == ns_level;
|
|
reaper = reaper->real_parent) {
|
|
if (reaper == &init_task)
|
|
break;
|
|
if (!reaper->signal->is_child_subreaper)
|
|
continue;
|
|
thread = find_alive_thread(reaper);
|
|
if (thread)
|
|
return thread;
|
|
}
|
|
}
|
|
|
|
return child_reaper;
|
|
}
|
|
|
|
/*
|
|
* Any that need to be release_task'd are put on the @dead list.
|
|
*/
|
|
static void reparent_leader(struct task_struct *father, struct task_struct *p,
|
|
struct list_head *dead)
|
|
{
|
|
if (unlikely(p->exit_state == EXIT_DEAD))
|
|
return;
|
|
|
|
/* We don't want people slaying init. */
|
|
p->exit_signal = SIGCHLD;
|
|
|
|
/* If it has exited notify the new parent about this child's death. */
|
|
if (!p->ptrace &&
|
|
p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
|
|
if (do_notify_parent(p, p->exit_signal)) {
|
|
p->exit_state = EXIT_DEAD;
|
|
list_add(&p->ptrace_entry, dead);
|
|
}
|
|
}
|
|
|
|
kill_orphaned_pgrp(p, father);
|
|
}
|
|
|
|
/*
|
|
* This does two things:
|
|
*
|
|
* A. Make init inherit all the child processes
|
|
* B. Check to see if any process groups have become orphaned
|
|
* as a result of our exiting, and if they have any stopped
|
|
* jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
|
|
*/
|
|
static void forget_original_parent(struct task_struct *father,
|
|
struct list_head *dead)
|
|
{
|
|
struct task_struct *p, *t, *reaper;
|
|
|
|
if (unlikely(!list_empty(&father->ptraced)))
|
|
exit_ptrace(father, dead);
|
|
|
|
/* Can drop and reacquire tasklist_lock */
|
|
reaper = find_child_reaper(father, dead);
|
|
if (list_empty(&father->children))
|
|
return;
|
|
|
|
reaper = find_new_reaper(father, reaper);
|
|
list_for_each_entry(p, &father->children, sibling) {
|
|
for_each_thread(p, t) {
|
|
t->real_parent = reaper;
|
|
BUG_ON((!t->ptrace) != (t->parent == father));
|
|
if (likely(!t->ptrace))
|
|
t->parent = t->real_parent;
|
|
if (t->pdeath_signal)
|
|
group_send_sig_info(t->pdeath_signal,
|
|
SEND_SIG_NOINFO, t,
|
|
PIDTYPE_TGID);
|
|
}
|
|
/*
|
|
* If this is a threaded reparent there is no need to
|
|
* notify anyone anything has happened.
|
|
*/
|
|
if (!same_thread_group(reaper, father))
|
|
reparent_leader(father, p, dead);
|
|
}
|
|
list_splice_tail_init(&father->children, &reaper->children);
|
|
}
|
|
|
|
/*
|
|
* Send signals to all our closest relatives so that they know
|
|
* to properly mourn us..
|
|
*/
|
|
static void exit_notify(struct task_struct *tsk, int group_dead)
|
|
{
|
|
bool autoreap;
|
|
struct task_struct *p, *n;
|
|
LIST_HEAD(dead);
|
|
|
|
write_lock_irq(&tasklist_lock);
|
|
forget_original_parent(tsk, &dead);
|
|
|
|
if (group_dead)
|
|
kill_orphaned_pgrp(tsk->group_leader, NULL);
|
|
|
|
tsk->exit_state = EXIT_ZOMBIE;
|
|
if (unlikely(tsk->ptrace)) {
|
|
int sig = thread_group_leader(tsk) &&
|
|
thread_group_empty(tsk) &&
|
|
!ptrace_reparented(tsk) ?
|
|
tsk->exit_signal : SIGCHLD;
|
|
autoreap = do_notify_parent(tsk, sig);
|
|
} else if (thread_group_leader(tsk)) {
|
|
autoreap = thread_group_empty(tsk) &&
|
|
do_notify_parent(tsk, tsk->exit_signal);
|
|
} else {
|
|
autoreap = true;
|
|
}
|
|
|
|
tsk->exit_state = autoreap ? EXIT_DEAD : EXIT_ZOMBIE;
|
|
if (tsk->exit_state == EXIT_DEAD)
|
|
list_add(&tsk->ptrace_entry, &dead);
|
|
|
|
/* mt-exec, de_thread() is waiting for group leader */
|
|
if (unlikely(tsk->signal->notify_count < 0))
|
|
wake_up_process(tsk->signal->group_exit_task);
|
|
write_unlock_irq(&tasklist_lock);
|
|
|
|
list_for_each_entry_safe(p, n, &dead, ptrace_entry) {
|
|
list_del_init(&p->ptrace_entry);
|
|
release_task(p);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_STACK_USAGE
|
|
static void check_stack_usage(void)
|
|
{
|
|
static DEFINE_SPINLOCK(low_water_lock);
|
|
static int lowest_to_date = THREAD_SIZE;
|
|
unsigned long free;
|
|
|
|
free = stack_not_used(current);
|
|
|
|
if (free >= lowest_to_date)
|
|
return;
|
|
|
|
spin_lock(&low_water_lock);
|
|
if (free < lowest_to_date) {
|
|
pr_info("%s (%d) used greatest stack depth: %lu bytes left\n",
|
|
current->comm, task_pid_nr(current), free);
|
|
lowest_to_date = free;
|
|
}
|
|
spin_unlock(&low_water_lock);
|
|
}
|
|
#else
|
|
static inline void check_stack_usage(void) {}
|
|
#endif
|
|
|
|
void __noreturn do_exit(long code)
|
|
{
|
|
struct task_struct *tsk = current;
|
|
int group_dead;
|
|
|
|
/*
|
|
* We can get here from a kernel oops, sometimes with preemption off.
|
|
* Start by checking for critical errors.
|
|
* Then fix up important state like USER_DS and preemption.
|
|
* Then do everything else.
|
|
*/
|
|
|
|
WARN_ON(blk_needs_flush_plug(tsk));
|
|
|
|
if (unlikely(in_interrupt()))
|
|
panic("Aiee, killing interrupt handler!");
|
|
if (unlikely(!tsk->pid))
|
|
panic("Attempted to kill the idle task!");
|
|
|
|
/*
|
|
* If do_exit is called because this processes oopsed, it's possible
|
|
* that get_fs() was left as KERNEL_DS, so reset it to USER_DS before
|
|
* continuing. Amongst other possible reasons, this is to prevent
|
|
* mm_release()->clear_child_tid() from writing to a user-controlled
|
|
* kernel address.
|
|
*/
|
|
set_fs(USER_DS);
|
|
|
|
if (unlikely(in_atomic())) {
|
|
pr_info("note: %s[%d] exited with preempt_count %d\n",
|
|
current->comm, task_pid_nr(current),
|
|
preempt_count());
|
|
preempt_count_set(PREEMPT_ENABLED);
|
|
}
|
|
|
|
profile_task_exit(tsk);
|
|
kcov_task_exit(tsk);
|
|
|
|
ptrace_event(PTRACE_EVENT_EXIT, code);
|
|
|
|
validate_creds_for_do_exit(tsk);
|
|
|
|
/*
|
|
* We're taking recursive faults here in do_exit. Safest is to just
|
|
* leave this task alone and wait for reboot.
|
|
*/
|
|
if (unlikely(tsk->flags & PF_EXITING)) {
|
|
pr_alert("Fixing recursive fault but reboot is needed!\n");
|
|
futex_exit_recursive(tsk);
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
schedule();
|
|
}
|
|
|
|
exit_signals(tsk); /* sets PF_EXITING */
|
|
sched_exit(tsk);
|
|
|
|
/* sync mm's RSS info before statistics gathering */
|
|
if (tsk->mm)
|
|
sync_mm_rss(tsk->mm);
|
|
acct_update_integrals(tsk);
|
|
group_dead = atomic_dec_and_test(&tsk->signal->live);
|
|
if (group_dead) {
|
|
/*
|
|
* If the last thread of global init has exited, panic
|
|
* immediately to get a useable coredump.
|
|
*/
|
|
if (unlikely(is_global_init(tsk)))
|
|
panic("Attempted to kill init! exitcode=0x%08x\n",
|
|
tsk->signal->group_exit_code ?: (int)code);
|
|
|
|
#ifdef CONFIG_POSIX_TIMERS
|
|
hrtimer_cancel(&tsk->signal->real_timer);
|
|
exit_itimers(tsk->signal);
|
|
#endif
|
|
if (tsk->mm)
|
|
setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm);
|
|
}
|
|
acct_collect(code, group_dead);
|
|
if (group_dead)
|
|
tty_audit_exit();
|
|
audit_free(tsk);
|
|
|
|
tsk->exit_code = code;
|
|
taskstats_exit(tsk, group_dead);
|
|
|
|
exit_mm();
|
|
|
|
if (group_dead)
|
|
acct_process();
|
|
trace_sched_process_exit(tsk);
|
|
|
|
exit_sem(tsk);
|
|
exit_shm(tsk);
|
|
exit_files(tsk);
|
|
exit_fs(tsk);
|
|
if (group_dead)
|
|
disassociate_ctty(1);
|
|
exit_task_namespaces(tsk);
|
|
exit_task_work(tsk);
|
|
exit_thread(tsk);
|
|
|
|
/*
|
|
* Flush inherited counters to the parent - before the parent
|
|
* gets woken up by child-exit notifications.
|
|
*
|
|
* because of cgroup mode, must be called before cgroup_exit()
|
|
*/
|
|
perf_event_exit_task(tsk);
|
|
|
|
sched_autogroup_exit_task(tsk);
|
|
cgroup_exit(tsk);
|
|
|
|
/*
|
|
* FIXME: do that only when needed, using sched_exit tracepoint
|
|
*/
|
|
flush_ptrace_hw_breakpoint(tsk);
|
|
|
|
exit_tasks_rcu_start();
|
|
exit_notify(tsk, group_dead);
|
|
proc_exit_connector(tsk);
|
|
mpol_put_task_policy(tsk);
|
|
#ifdef CONFIG_FUTEX
|
|
if (unlikely(current->pi_state_cache))
|
|
kfree(current->pi_state_cache);
|
|
#endif
|
|
/*
|
|
* Make sure we are holding no locks:
|
|
*/
|
|
debug_check_no_locks_held();
|
|
|
|
if (tsk->io_context)
|
|
exit_io_context(tsk);
|
|
|
|
if (tsk->splice_pipe)
|
|
free_pipe_info(tsk->splice_pipe);
|
|
|
|
if (tsk->task_frag.page)
|
|
put_page(tsk->task_frag.page);
|
|
|
|
validate_creds_for_do_exit(tsk);
|
|
|
|
check_stack_usage();
|
|
preempt_disable();
|
|
if (tsk->nr_dirtied)
|
|
__this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
|
|
exit_rcu();
|
|
exit_tasks_rcu_finish();
|
|
|
|
lockdep_free_task(tsk);
|
|
do_task_dead();
|
|
}
|
|
EXPORT_SYMBOL_GPL(do_exit);
|
|
|
|
void __noreturn make_task_dead(int signr)
|
|
{
|
|
/*
|
|
* Take the task off the cpu after something catastrophic has
|
|
* happened.
|
|
*/
|
|
unsigned int limit;
|
|
|
|
/*
|
|
* Every time the system oopses, if the oops happens while a reference
|
|
* to an object was held, the reference leaks.
|
|
* If the oops doesn't also leak memory, repeated oopsing can cause
|
|
* reference counters to wrap around (if they're not using refcount_t).
|
|
* This means that repeated oopsing can make unexploitable-looking bugs
|
|
* exploitable through repeated oopsing.
|
|
* To make sure this can't happen, place an upper bound on how often the
|
|
* kernel may oops without panic().
|
|
*/
|
|
limit = READ_ONCE(oops_limit);
|
|
if (atomic_inc_return(&oops_count) >= limit && limit)
|
|
panic("Oopsed too often (kernel.oops_limit is %d)", limit);
|
|
|
|
do_exit(signr);
|
|
}
|
|
|
|
void complete_and_exit(struct completion *comp, long code)
|
|
{
|
|
if (comp)
|
|
complete(comp);
|
|
|
|
do_exit(code);
|
|
}
|
|
EXPORT_SYMBOL(complete_and_exit);
|
|
|
|
SYSCALL_DEFINE1(exit, int, error_code)
|
|
{
|
|
do_exit((error_code&0xff)<<8);
|
|
}
|
|
|
|
/*
|
|
* Take down every thread in the group. This is called by fatal signals
|
|
* as well as by sys_exit_group (below).
|
|
*/
|
|
void
|
|
do_group_exit(int exit_code)
|
|
{
|
|
struct signal_struct *sig = current->signal;
|
|
|
|
BUG_ON(exit_code & 0x80); /* core dumps don't get here */
|
|
|
|
if (signal_group_exit(sig))
|
|
exit_code = sig->group_exit_code;
|
|
else if (!thread_group_empty(current)) {
|
|
struct sighand_struct *const sighand = current->sighand;
|
|
|
|
spin_lock_irq(&sighand->siglock);
|
|
if (signal_group_exit(sig))
|
|
/* Another thread got here before we took the lock. */
|
|
exit_code = sig->group_exit_code;
|
|
else {
|
|
sig->group_exit_code = exit_code;
|
|
sig->flags = SIGNAL_GROUP_EXIT;
|
|
zap_other_threads(current);
|
|
}
|
|
spin_unlock_irq(&sighand->siglock);
|
|
}
|
|
|
|
do_exit(exit_code);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/*
|
|
* this kills every thread in the thread group. Note that any externally
|
|
* wait4()-ing process will get the correct exit code - even if this
|
|
* thread is not the thread group leader.
|
|
*/
|
|
SYSCALL_DEFINE1(exit_group, int, error_code)
|
|
{
|
|
do_group_exit((error_code & 0xff) << 8);
|
|
/* NOTREACHED */
|
|
return 0;
|
|
}
|
|
|
|
struct waitid_info {
|
|
pid_t pid;
|
|
uid_t uid;
|
|
int status;
|
|
int cause;
|
|
};
|
|
|
|
struct wait_opts {
|
|
enum pid_type wo_type;
|
|
int wo_flags;
|
|
struct pid *wo_pid;
|
|
|
|
struct waitid_info *wo_info;
|
|
int wo_stat;
|
|
struct rusage *wo_rusage;
|
|
|
|
wait_queue_entry_t child_wait;
|
|
int notask_error;
|
|
};
|
|
|
|
static int eligible_pid(struct wait_opts *wo, struct task_struct *p)
|
|
{
|
|
return wo->wo_type == PIDTYPE_MAX ||
|
|
task_pid_type(p, wo->wo_type) == wo->wo_pid;
|
|
}
|
|
|
|
static int
|
|
eligible_child(struct wait_opts *wo, bool ptrace, struct task_struct *p)
|
|
{
|
|
if (!eligible_pid(wo, p))
|
|
return 0;
|
|
|
|
/*
|
|
* Wait for all children (clone and not) if __WALL is set or
|
|
* if it is traced by us.
|
|
*/
|
|
if (ptrace || (wo->wo_flags & __WALL))
|
|
return 1;
|
|
|
|
/*
|
|
* Otherwise, wait for clone children *only* if __WCLONE is set;
|
|
* otherwise, wait for non-clone children *only*.
|
|
*
|
|
* Note: a "clone" child here is one that reports to its parent
|
|
* using a signal other than SIGCHLD, or a non-leader thread which
|
|
* we can only see if it is traced by us.
|
|
*/
|
|
if ((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Handle sys_wait4 work for one task in state EXIT_ZOMBIE. We hold
|
|
* read_lock(&tasklist_lock) on entry. If we return zero, we still hold
|
|
* the lock and this task is uninteresting. If we return nonzero, we have
|
|
* released the lock and the system call should return.
|
|
*/
|
|
static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
|
|
{
|
|
int state, status;
|
|
pid_t pid = task_pid_vnr(p);
|
|
uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
|
|
struct waitid_info *infop;
|
|
|
|
if (!likely(wo->wo_flags & WEXITED))
|
|
return 0;
|
|
|
|
if (unlikely(wo->wo_flags & WNOWAIT)) {
|
|
status = p->exit_code;
|
|
get_task_struct(p);
|
|
read_unlock(&tasklist_lock);
|
|
sched_annotate_sleep();
|
|
if (wo->wo_rusage)
|
|
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
|
|
put_task_struct(p);
|
|
goto out_info;
|
|
}
|
|
/*
|
|
* Move the task's state to DEAD/TRACE, only one thread can do this.
|
|
*/
|
|
state = (ptrace_reparented(p) && thread_group_leader(p)) ?
|
|
EXIT_TRACE : EXIT_DEAD;
|
|
if (cmpxchg(&p->exit_state, EXIT_ZOMBIE, state) != EXIT_ZOMBIE)
|
|
return 0;
|
|
/*
|
|
* We own this thread, nobody else can reap it.
|
|
*/
|
|
read_unlock(&tasklist_lock);
|
|
sched_annotate_sleep();
|
|
|
|
/*
|
|
* Check thread_group_leader() to exclude the traced sub-threads.
|
|
*/
|
|
if (state == EXIT_DEAD && thread_group_leader(p)) {
|
|
struct signal_struct *sig = p->signal;
|
|
struct signal_struct *psig = current->signal;
|
|
unsigned long maxrss;
|
|
u64 tgutime, tgstime;
|
|
|
|
/*
|
|
* The resource counters for the group leader are in its
|
|
* own task_struct. Those for dead threads in the group
|
|
* are in its signal_struct, as are those for the child
|
|
* processes it has previously reaped. All these
|
|
* accumulate in the parent's signal_struct c* fields.
|
|
*
|
|
* We don't bother to take a lock here to protect these
|
|
* p->signal fields because the whole thread group is dead
|
|
* and nobody can change them.
|
|
*
|
|
* psig->stats_lock also protects us from our sub-theads
|
|
* which can reap other children at the same time. Until
|
|
* we change k_getrusage()-like users to rely on this lock
|
|
* we have to take ->siglock as well.
|
|
*
|
|
* We use thread_group_cputime_adjusted() to get times for
|
|
* the thread group, which consolidates times for all threads
|
|
* in the group including the group leader.
|
|
*/
|
|
thread_group_cputime_adjusted(p, &tgutime, &tgstime);
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
write_seqlock(&psig->stats_lock);
|
|
psig->cutime += tgutime + sig->cutime;
|
|
psig->cstime += tgstime + sig->cstime;
|
|
psig->cgtime += task_gtime(p) + sig->gtime + sig->cgtime;
|
|
psig->cmin_flt +=
|
|
p->min_flt + sig->min_flt + sig->cmin_flt;
|
|
psig->cmaj_flt +=
|
|
p->maj_flt + sig->maj_flt + sig->cmaj_flt;
|
|
psig->cnvcsw +=
|
|
p->nvcsw + sig->nvcsw + sig->cnvcsw;
|
|
psig->cnivcsw +=
|
|
p->nivcsw + sig->nivcsw + sig->cnivcsw;
|
|
psig->cinblock +=
|
|
task_io_get_inblock(p) +
|
|
sig->inblock + sig->cinblock;
|
|
psig->coublock +=
|
|
task_io_get_oublock(p) +
|
|
sig->oublock + sig->coublock;
|
|
maxrss = max(sig->maxrss, sig->cmaxrss);
|
|
if (psig->cmaxrss < maxrss)
|
|
psig->cmaxrss = maxrss;
|
|
task_io_accounting_add(&psig->ioac, &p->ioac);
|
|
task_io_accounting_add(&psig->ioac, &sig->ioac);
|
|
write_sequnlock(&psig->stats_lock);
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
}
|
|
|
|
if (wo->wo_rusage)
|
|
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
|
|
status = (p->signal->flags & SIGNAL_GROUP_EXIT)
|
|
? p->signal->group_exit_code : p->exit_code;
|
|
wo->wo_stat = status;
|
|
|
|
if (state == EXIT_TRACE) {
|
|
write_lock_irq(&tasklist_lock);
|
|
/* We dropped tasklist, ptracer could die and untrace */
|
|
ptrace_unlink(p);
|
|
|
|
/* If parent wants a zombie, don't release it now */
|
|
state = EXIT_ZOMBIE;
|
|
if (do_notify_parent(p, p->exit_signal))
|
|
state = EXIT_DEAD;
|
|
p->exit_state = state;
|
|
write_unlock_irq(&tasklist_lock);
|
|
}
|
|
if (state == EXIT_DEAD)
|
|
release_task(p);
|
|
|
|
out_info:
|
|
infop = wo->wo_info;
|
|
if (infop) {
|
|
if ((status & 0x7f) == 0) {
|
|
infop->cause = CLD_EXITED;
|
|
infop->status = status >> 8;
|
|
} else {
|
|
infop->cause = (status & 0x80) ? CLD_DUMPED : CLD_KILLED;
|
|
infop->status = status & 0x7f;
|
|
}
|
|
infop->pid = pid;
|
|
infop->uid = uid;
|
|
}
|
|
|
|
return pid;
|
|
}
|
|
|
|
static int *task_stopped_code(struct task_struct *p, bool ptrace)
|
|
{
|
|
if (ptrace) {
|
|
if (task_is_traced(p) && !(p->jobctl & JOBCTL_LISTENING))
|
|
return &p->exit_code;
|
|
} else {
|
|
if (p->signal->flags & SIGNAL_STOP_STOPPED)
|
|
return &p->signal->group_exit_code;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* wait_task_stopped - Wait for %TASK_STOPPED or %TASK_TRACED
|
|
* @wo: wait options
|
|
* @ptrace: is the wait for ptrace
|
|
* @p: task to wait for
|
|
*
|
|
* Handle sys_wait4() work for %p in state %TASK_STOPPED or %TASK_TRACED.
|
|
*
|
|
* CONTEXT:
|
|
* read_lock(&tasklist_lock), which is released if return value is
|
|
* non-zero. Also, grabs and releases @p->sighand->siglock.
|
|
*
|
|
* RETURNS:
|
|
* 0 if wait condition didn't exist and search for other wait conditions
|
|
* should continue. Non-zero return, -errno on failure and @p's pid on
|
|
* success, implies that tasklist_lock is released and wait condition
|
|
* search should terminate.
|
|
*/
|
|
static int wait_task_stopped(struct wait_opts *wo,
|
|
int ptrace, struct task_struct *p)
|
|
{
|
|
struct waitid_info *infop;
|
|
int exit_code, *p_code, why;
|
|
uid_t uid = 0; /* unneeded, required by compiler */
|
|
pid_t pid;
|
|
|
|
/*
|
|
* Traditionally we see ptrace'd stopped tasks regardless of options.
|
|
*/
|
|
if (!ptrace && !(wo->wo_flags & WUNTRACED))
|
|
return 0;
|
|
|
|
if (!task_stopped_code(p, ptrace))
|
|
return 0;
|
|
|
|
exit_code = 0;
|
|
spin_lock_irq(&p->sighand->siglock);
|
|
|
|
p_code = task_stopped_code(p, ptrace);
|
|
if (unlikely(!p_code))
|
|
goto unlock_sig;
|
|
|
|
exit_code = *p_code;
|
|
if (!exit_code)
|
|
goto unlock_sig;
|
|
|
|
if (!unlikely(wo->wo_flags & WNOWAIT))
|
|
*p_code = 0;
|
|
|
|
uid = from_kuid_munged(current_user_ns(), task_uid(p));
|
|
unlock_sig:
|
|
spin_unlock_irq(&p->sighand->siglock);
|
|
if (!exit_code)
|
|
return 0;
|
|
|
|
/*
|
|
* Now we are pretty sure this task is interesting.
|
|
* Make sure it doesn't get reaped out from under us while we
|
|
* give up the lock and then examine it below. We don't want to
|
|
* keep holding onto the tasklist_lock while we call getrusage and
|
|
* possibly take page faults for user memory.
|
|
*/
|
|
get_task_struct(p);
|
|
pid = task_pid_vnr(p);
|
|
why = ptrace ? CLD_TRAPPED : CLD_STOPPED;
|
|
read_unlock(&tasklist_lock);
|
|
sched_annotate_sleep();
|
|
if (wo->wo_rusage)
|
|
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
|
|
put_task_struct(p);
|
|
|
|
if (likely(!(wo->wo_flags & WNOWAIT)))
|
|
wo->wo_stat = (exit_code << 8) | 0x7f;
|
|
|
|
infop = wo->wo_info;
|
|
if (infop) {
|
|
infop->cause = why;
|
|
infop->status = exit_code;
|
|
infop->pid = pid;
|
|
infop->uid = uid;
|
|
}
|
|
return pid;
|
|
}
|
|
|
|
/*
|
|
* Handle do_wait work for one task in a live, non-stopped state.
|
|
* read_lock(&tasklist_lock) on entry. If we return zero, we still hold
|
|
* the lock and this task is uninteresting. If we return nonzero, we have
|
|
* released the lock and the system call should return.
|
|
*/
|
|
static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
|
|
{
|
|
struct waitid_info *infop;
|
|
pid_t pid;
|
|
uid_t uid;
|
|
|
|
if (!unlikely(wo->wo_flags & WCONTINUED))
|
|
return 0;
|
|
|
|
if (!(p->signal->flags & SIGNAL_STOP_CONTINUED))
|
|
return 0;
|
|
|
|
spin_lock_irq(&p->sighand->siglock);
|
|
/* Re-check with the lock held. */
|
|
if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) {
|
|
spin_unlock_irq(&p->sighand->siglock);
|
|
return 0;
|
|
}
|
|
if (!unlikely(wo->wo_flags & WNOWAIT))
|
|
p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
|
|
uid = from_kuid_munged(current_user_ns(), task_uid(p));
|
|
spin_unlock_irq(&p->sighand->siglock);
|
|
|
|
pid = task_pid_vnr(p);
|
|
get_task_struct(p);
|
|
read_unlock(&tasklist_lock);
|
|
sched_annotate_sleep();
|
|
if (wo->wo_rusage)
|
|
getrusage(p, RUSAGE_BOTH, wo->wo_rusage);
|
|
put_task_struct(p);
|
|
|
|
infop = wo->wo_info;
|
|
if (!infop) {
|
|
wo->wo_stat = 0xffff;
|
|
} else {
|
|
infop->cause = CLD_CONTINUED;
|
|
infop->pid = pid;
|
|
infop->uid = uid;
|
|
infop->status = SIGCONT;
|
|
}
|
|
return pid;
|
|
}
|
|
|
|
/*
|
|
* Consider @p for a wait by @parent.
|
|
*
|
|
* -ECHILD should be in ->notask_error before the first call.
|
|
* Returns nonzero for a final return, when we have unlocked tasklist_lock.
|
|
* Returns zero if the search for a child should continue;
|
|
* then ->notask_error is 0 if @p is an eligible child,
|
|
* or still -ECHILD.
|
|
*/
|
|
static int wait_consider_task(struct wait_opts *wo, int ptrace,
|
|
struct task_struct *p)
|
|
{
|
|
/*
|
|
* We can race with wait_task_zombie() from another thread.
|
|
* Ensure that EXIT_ZOMBIE -> EXIT_DEAD/EXIT_TRACE transition
|
|
* can't confuse the checks below.
|
|
*/
|
|
int exit_state = READ_ONCE(p->exit_state);
|
|
int ret;
|
|
|
|
if (unlikely(exit_state == EXIT_DEAD))
|
|
return 0;
|
|
|
|
ret = eligible_child(wo, ptrace, p);
|
|
if (!ret)
|
|
return ret;
|
|
|
|
if (unlikely(exit_state == EXIT_TRACE)) {
|
|
/*
|
|
* ptrace == 0 means we are the natural parent. In this case
|
|
* we should clear notask_error, debugger will notify us.
|
|
*/
|
|
if (likely(!ptrace))
|
|
wo->notask_error = 0;
|
|
return 0;
|
|
}
|
|
|
|
if (likely(!ptrace) && unlikely(p->ptrace)) {
|
|
/*
|
|
* If it is traced by its real parent's group, just pretend
|
|
* the caller is ptrace_do_wait() and reap this child if it
|
|
* is zombie.
|
|
*
|
|
* This also hides group stop state from real parent; otherwise
|
|
* a single stop can be reported twice as group and ptrace stop.
|
|
* If a ptracer wants to distinguish these two events for its
|
|
* own children it should create a separate process which takes
|
|
* the role of real parent.
|
|
*/
|
|
if (!ptrace_reparented(p))
|
|
ptrace = 1;
|
|
}
|
|
|
|
/* slay zombie? */
|
|
if (exit_state == EXIT_ZOMBIE) {
|
|
/* we don't reap group leaders with subthreads */
|
|
if (!delay_group_leader(p)) {
|
|
/*
|
|
* A zombie ptracee is only visible to its ptracer.
|
|
* Notification and reaping will be cascaded to the
|
|
* real parent when the ptracer detaches.
|
|
*/
|
|
if (unlikely(ptrace) || likely(!p->ptrace))
|
|
return wait_task_zombie(wo, p);
|
|
}
|
|
|
|
/*
|
|
* Allow access to stopped/continued state via zombie by
|
|
* falling through. Clearing of notask_error is complex.
|
|
*
|
|
* When !@ptrace:
|
|
*
|
|
* If WEXITED is set, notask_error should naturally be
|
|
* cleared. If not, subset of WSTOPPED|WCONTINUED is set,
|
|
* so, if there are live subthreads, there are events to
|
|
* wait for. If all subthreads are dead, it's still safe
|
|
* to clear - this function will be called again in finite
|
|
* amount time once all the subthreads are released and
|
|
* will then return without clearing.
|
|
*
|
|
* When @ptrace:
|
|
*
|
|
* Stopped state is per-task and thus can't change once the
|
|
* target task dies. Only continued and exited can happen.
|
|
* Clear notask_error if WCONTINUED | WEXITED.
|
|
*/
|
|
if (likely(!ptrace) || (wo->wo_flags & (WCONTINUED | WEXITED)))
|
|
wo->notask_error = 0;
|
|
} else {
|
|
/*
|
|
* @p is alive and it's gonna stop, continue or exit, so
|
|
* there always is something to wait for.
|
|
*/
|
|
wo->notask_error = 0;
|
|
}
|
|
|
|
/*
|
|
* Wait for stopped. Depending on @ptrace, different stopped state
|
|
* is used and the two don't interact with each other.
|
|
*/
|
|
ret = wait_task_stopped(wo, ptrace, p);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/*
|
|
* Wait for continued. There's only one continued state and the
|
|
* ptracer can consume it which can confuse the real parent. Don't
|
|
* use WCONTINUED from ptracer. You don't need or want it.
|
|
*/
|
|
return wait_task_continued(wo, p);
|
|
}
|
|
|
|
/*
|
|
* Do the work of do_wait() for one thread in the group, @tsk.
|
|
*
|
|
* -ECHILD should be in ->notask_error before the first call.
|
|
* Returns nonzero for a final return, when we have unlocked tasklist_lock.
|
|
* Returns zero if the search for a child should continue; then
|
|
* ->notask_error is 0 if there were any eligible children,
|
|
* or still -ECHILD.
|
|
*/
|
|
static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk)
|
|
{
|
|
struct task_struct *p;
|
|
|
|
list_for_each_entry(p, &tsk->children, sibling) {
|
|
int ret = wait_consider_task(wo, 0, p);
|
|
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk)
|
|
{
|
|
struct task_struct *p;
|
|
|
|
list_for_each_entry(p, &tsk->ptraced, ptrace_entry) {
|
|
int ret = wait_consider_task(wo, 1, p);
|
|
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int child_wait_callback(wait_queue_entry_t *wait, unsigned mode,
|
|
int sync, void *key)
|
|
{
|
|
struct wait_opts *wo = container_of(wait, struct wait_opts,
|
|
child_wait);
|
|
struct task_struct *p = key;
|
|
|
|
if (!eligible_pid(wo, p))
|
|
return 0;
|
|
|
|
if ((wo->wo_flags & __WNOTHREAD) && wait->private != p->parent)
|
|
return 0;
|
|
|
|
return default_wake_function(wait, mode, sync, key);
|
|
}
|
|
|
|
void __wake_up_parent(struct task_struct *p, struct task_struct *parent)
|
|
{
|
|
__wake_up_sync_key(&parent->signal->wait_chldexit,
|
|
TASK_INTERRUPTIBLE, 1, p);
|
|
}
|
|
|
|
static long do_wait(struct wait_opts *wo)
|
|
{
|
|
struct task_struct *tsk;
|
|
int retval;
|
|
|
|
trace_sched_process_wait(wo->wo_pid);
|
|
|
|
init_waitqueue_func_entry(&wo->child_wait, child_wait_callback);
|
|
wo->child_wait.private = current;
|
|
add_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait);
|
|
repeat:
|
|
/*
|
|
* If there is nothing that can match our criteria, just get out.
|
|
* We will clear ->notask_error to zero if we see any child that
|
|
* might later match our criteria, even if we are not able to reap
|
|
* it yet.
|
|
*/
|
|
wo->notask_error = -ECHILD;
|
|
if ((wo->wo_type < PIDTYPE_MAX) &&
|
|
(!wo->wo_pid || hlist_empty(&wo->wo_pid->tasks[wo->wo_type])))
|
|
goto notask;
|
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
read_lock(&tasklist_lock);
|
|
tsk = current;
|
|
do {
|
|
retval = do_wait_thread(wo, tsk);
|
|
if (retval)
|
|
goto end;
|
|
|
|
retval = ptrace_do_wait(wo, tsk);
|
|
if (retval)
|
|
goto end;
|
|
|
|
if (wo->wo_flags & __WNOTHREAD)
|
|
break;
|
|
} while_each_thread(current, tsk);
|
|
read_unlock(&tasklist_lock);
|
|
|
|
notask:
|
|
retval = wo->notask_error;
|
|
if (!retval && !(wo->wo_flags & WNOHANG)) {
|
|
retval = -ERESTARTSYS;
|
|
if (!signal_pending(current)) {
|
|
schedule();
|
|
goto repeat;
|
|
}
|
|
}
|
|
end:
|
|
__set_current_state(TASK_RUNNING);
|
|
remove_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait);
|
|
return retval;
|
|
}
|
|
|
|
static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
|
|
int options, struct rusage *ru)
|
|
{
|
|
struct wait_opts wo;
|
|
struct pid *pid = NULL;
|
|
enum pid_type type;
|
|
long ret;
|
|
|
|
if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED|
|
|
__WNOTHREAD|__WCLONE|__WALL))
|
|
return -EINVAL;
|
|
if (!(options & (WEXITED|WSTOPPED|WCONTINUED)))
|
|
return -EINVAL;
|
|
|
|
switch (which) {
|
|
case P_ALL:
|
|
type = PIDTYPE_MAX;
|
|
break;
|
|
case P_PID:
|
|
type = PIDTYPE_PID;
|
|
if (upid <= 0)
|
|
return -EINVAL;
|
|
break;
|
|
case P_PGID:
|
|
type = PIDTYPE_PGID;
|
|
if (upid <= 0)
|
|
return -EINVAL;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (type < PIDTYPE_MAX)
|
|
pid = find_get_pid(upid);
|
|
|
|
wo.wo_type = type;
|
|
wo.wo_pid = pid;
|
|
wo.wo_flags = options;
|
|
wo.wo_info = infop;
|
|
wo.wo_rusage = ru;
|
|
ret = do_wait(&wo);
|
|
|
|
put_pid(pid);
|
|
return ret;
|
|
}
|
|
|
|
SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
|
|
infop, int, options, struct rusage __user *, ru)
|
|
{
|
|
struct rusage r;
|
|
struct waitid_info info = {.status = 0};
|
|
long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
|
|
int signo = 0;
|
|
|
|
if (err > 0) {
|
|
signo = SIGCHLD;
|
|
err = 0;
|
|
if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
|
|
return -EFAULT;
|
|
}
|
|
if (!infop)
|
|
return err;
|
|
|
|
if (!user_access_begin(VERIFY_WRITE, infop, sizeof(*infop)))
|
|
return -EFAULT;
|
|
|
|
unsafe_put_user(signo, &infop->si_signo, Efault);
|
|
unsafe_put_user(0, &infop->si_errno, Efault);
|
|
unsafe_put_user(info.cause, &infop->si_code, Efault);
|
|
unsafe_put_user(info.pid, &infop->si_pid, Efault);
|
|
unsafe_put_user(info.uid, &infop->si_uid, Efault);
|
|
unsafe_put_user(info.status, &infop->si_status, Efault);
|
|
user_access_end();
|
|
return err;
|
|
Efault:
|
|
user_access_end();
|
|
return -EFAULT;
|
|
}
|
|
|
|
long kernel_wait4(pid_t upid, int __user *stat_addr, int options,
|
|
struct rusage *ru)
|
|
{
|
|
struct wait_opts wo;
|
|
struct pid *pid = NULL;
|
|
enum pid_type type;
|
|
long ret;
|
|
|
|
if (options & ~(WNOHANG|WUNTRACED|WCONTINUED|
|
|
__WNOTHREAD|__WCLONE|__WALL))
|
|
return -EINVAL;
|
|
|
|
/* -INT_MIN is not defined */
|
|
if (upid == INT_MIN)
|
|
return -ESRCH;
|
|
|
|
if (upid == -1)
|
|
type = PIDTYPE_MAX;
|
|
else if (upid < 0) {
|
|
type = PIDTYPE_PGID;
|
|
pid = find_get_pid(-upid);
|
|
} else if (upid == 0) {
|
|
type = PIDTYPE_PGID;
|
|
pid = get_task_pid(current, PIDTYPE_PGID);
|
|
} else /* upid > 0 */ {
|
|
type = PIDTYPE_PID;
|
|
pid = find_get_pid(upid);
|
|
}
|
|
|
|
wo.wo_type = type;
|
|
wo.wo_pid = pid;
|
|
wo.wo_flags = options | WEXITED;
|
|
wo.wo_info = NULL;
|
|
wo.wo_stat = 0;
|
|
wo.wo_rusage = ru;
|
|
ret = do_wait(&wo);
|
|
put_pid(pid);
|
|
if (ret > 0 && stat_addr && put_user(wo.wo_stat, stat_addr))
|
|
ret = -EFAULT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
|
|
int, options, struct rusage __user *, ru)
|
|
{
|
|
struct rusage r;
|
|
long err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL);
|
|
|
|
if (err > 0) {
|
|
if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
|
|
return -EFAULT;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
#ifdef __ARCH_WANT_SYS_WAITPID
|
|
|
|
/*
|
|
* sys_waitpid() remains for compatibility. waitpid() should be
|
|
* implemented by calling sys_wait4() from libc.a.
|
|
*/
|
|
SYSCALL_DEFINE3(waitpid, pid_t, pid, int __user *, stat_addr, int, options)
|
|
{
|
|
return kernel_wait4(pid, stat_addr, options, NULL);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
COMPAT_SYSCALL_DEFINE4(wait4,
|
|
compat_pid_t, pid,
|
|
compat_uint_t __user *, stat_addr,
|
|
int, options,
|
|
struct compat_rusage __user *, ru)
|
|
{
|
|
struct rusage r;
|
|
long err = kernel_wait4(pid, stat_addr, options, ru ? &r : NULL);
|
|
if (err > 0) {
|
|
if (ru && put_compat_rusage(&r, ru))
|
|
return -EFAULT;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
COMPAT_SYSCALL_DEFINE5(waitid,
|
|
int, which, compat_pid_t, pid,
|
|
struct compat_siginfo __user *, infop, int, options,
|
|
struct compat_rusage __user *, uru)
|
|
{
|
|
struct rusage ru;
|
|
struct waitid_info info = {.status = 0};
|
|
long err = kernel_waitid(which, pid, &info, options, uru ? &ru : NULL);
|
|
int signo = 0;
|
|
if (err > 0) {
|
|
signo = SIGCHLD;
|
|
err = 0;
|
|
if (uru) {
|
|
/* kernel_waitid() overwrites everything in ru */
|
|
if (COMPAT_USE_64BIT_TIME)
|
|
err = copy_to_user(uru, &ru, sizeof(ru));
|
|
else
|
|
err = put_compat_rusage(&ru, uru);
|
|
if (err)
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
if (!infop)
|
|
return err;
|
|
|
|
if (!user_access_begin(VERIFY_WRITE, infop, sizeof(*infop)))
|
|
return -EFAULT;
|
|
|
|
unsafe_put_user(signo, &infop->si_signo, Efault);
|
|
unsafe_put_user(0, &infop->si_errno, Efault);
|
|
unsafe_put_user(info.cause, &infop->si_code, Efault);
|
|
unsafe_put_user(info.pid, &infop->si_pid, Efault);
|
|
unsafe_put_user(info.uid, &infop->si_uid, Efault);
|
|
unsafe_put_user(info.status, &infop->si_status, Efault);
|
|
user_access_end();
|
|
return err;
|
|
Efault:
|
|
user_access_end();
|
|
return -EFAULT;
|
|
}
|
|
#endif
|
|
|
|
__weak void abort(void)
|
|
{
|
|
BUG();
|
|
|
|
/* if that doesn't kill us, halt */
|
|
panic("Oops failed to kill thread");
|
|
}
|
|
EXPORT_SYMBOL(abort);
|