-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Latest kernels implement a new hardening mechanism HARDENED_USERCOPY. When enabled every call to copy_from_user() and copy_to_user() calls to __check_object_size() prior performing the copy operation. This makes several checks as if the orig/destination is a valid heap or stack area, it is not a kernel text area, etc....
For example, when reading from kernel text area the responsible process gets killed and we get this output:
[ 1045.117123] ------------[ cut here ]------------
[ 1045.117222] kernel BUG at /build/linux-v2K05A/linux-4.8.5/mm/usercopy.c:75!
[ 1045.117361] invalid opcode: 0000 [#1] SMP
[ 1045.117481] Modules linked in: r2kmod(OE) vboxsf(OE) vboxvideo(OE) vboxguest(OE) ttm drm_kms_helper drm ppdev sg i2c_piix4 evdev serio_raw battery parport_pc pcspkr parport acpi_cpufreq sb_edac video tpm_tis tpm_tis_core button tpm ac edac_core intel_powerclamp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel loop ip_tables x_tables autofs4 ext4 crc16 jbd2 crc32c_generic fscrypto ecb mbcache sr_mod cdrom sd_mod ata_generic crc32c_intel ata_piix ahci libahci e1000 libata mptspi aesni_intel scsi_transport_spi mptscsih psmouse mptbase aes_x86_64 glue_helper lrw scsi_mod gf128mul ablk_helper cryptd fjes
[ 1045.119039] CPU: 2 PID: 16995 Comm: r2 Tainted: G OE 4.8.0-1-amd64 #1 Debian 4.8.5-1
[ 1045.119325] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 1045.119603] task: ffff96dbd533e140 task.stack: ffff96dbd5378000
[ 1045.119954] RIP: 0010:[<ffffffffa31fe489>] [<ffffffffa31fe489>] __check_object_size+0x69/0x1e8
[ 1045.120272] RSP: 0018:ffff96dbd537bdb8 EFLAGS: 00010286
[ 1045.120602] RAX: 0000000000000063 RBX: ffffffffa35ed270 RCX: 0000000000000000
[ 1045.120704] RDX: 0000000000000000 RSI: ffff96dbdfc8dd48 RDI: ffff96dbdfc8dd48
[ 1045.120704] RBP: 0000000000000100 R08: 0000000000000000 R09: 0000000000000000
[ 1045.120704] R10: 0000000000000000 R11: ffffffffffffffff R12: 0000000000000001
[ 1045.120704] R13: ffffffffa35ed370 R14: ffff96dbd5feb080 R15: 0000000000000000
[ 1045.120704] FS: 00007f649c6ef700(0000) GS:ffff96dbdfc80000(0000) knlGS:0000000000000000
[ 1045.120704] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1045.120704] CR2: 00007ff524d52000 CR3: 000000021225d000 CR4: 00000000000406e0
[ 1045.120704] Stack:
[ 1045.120704] 0000000000000100 ffffffffa35ed270 0000561871e5bd10 ffffffffffffffea
[ 1045.120704] ffffffffc05db2b5 ffff96dbd1984a38 0000000000000246 ffffffffa3408d01
[ 1045.120704] ffff96dbd19848d8 ffff96dbd2764000 00000001d533e140 00000001d1984a30
[ 1045.120704] Call Trace:
[ 1045.120704] [<ffffffffa35ed270>] ? __mutex_lock_slowpath+0x130/0x130
[ 1045.120704] [<ffffffffc05db2b5>] ? io_ioctl+0xd5/0xc70 [r2kmod]
[ 1045.120704] [<ffffffffa3408d01>] ? n_tty_write+0x261/0x490
[ 1045.120704] [<ffffffffa3215dbf>] ? do_vfs_ioctl+0x9f/0x5f0
[ 1045.120704] [<ffffffffa320232f>] ? vfs_write+0x14f/0x1a0
[ 1045.120704] [<ffffffffa32021c8>] ? vfs_read+0x118/0x130
[ 1045.120704] [<ffffffffa3216384>] ? SyS_ioctl+0x74/0x80
[ 1045.120704] [<ffffffffa35ef8f6>] ? system_call_fast_compare_end+0xc/0x96
[ 1045.120704] Code: 48 0f 44 d1 48 c7 c6 5d b9 7f a3 48 c7 c1 ce 54 80 a3 48 0f 45 f1 49 89 e9 49 89 c0 48 89 d9 48 c7 c7 c8 24 80 a3 e8 a5 c5 f7 ff <0f> 0b 48 83 ff 10 0f 86 57 01 00 00 e8 36 68 fc ff 85 c0 0f 85
[ 1045.120704] RIP [<ffffffffa31fe489>] __check_object_size+0x69/0x1e8
[ 1045.120704] RSP <ffff96dbd537bdb8>
[ 1045.120704] fbcon_switch: detected unhandled fb_set_par error, error code -16
[ 1045.120704] fbcon_switch: detected unhandled fb_set_par error, error code -16
[ 1045.134036] ---[ end trace 492eb760cc8f1369 ]---
As a workaround we could create a new a #ifdef CONFIG_HARDENED_USERCOPY, and in case it has been enabled, then there are two options, reimplement the copy operations by ourselves or directly call to the appropriate copy operation per arch:
- x86: __copy_from_user_ll_nozero(), __copy_to_user_ll()
- x86_64: copy_user_generic()
- arm64: __arch_copy_from_user(), __arch_copy_to_user()
- arm: arm_copy_to_user(), arm_copy_from_user()
This might imply some performance hit for example on x86_64 due to always using copy_user_generic() instead of the optimized copy operations for each size. This might also require extra checks when accessing memory or pinning the accessed pages...