x86/vm86: Block non-root vm86(old) if mmap_min_addr != 0
vm86 exposes an interesting attack surface against the entry code. Since vm86 is mostly useless anyway if mmap_min_addr != 0, just turn it off in that case. There are some reports that vbetool can work despite setting mmap_min_addr to zero. This shouldn't break that use case, as CAP_SYS_RAWIO already overrides mmap_min_addr. Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Andy Lutomirski <luto@kernel.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Austin S Hemmelgarn <ahferroin7@gmail.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Josh Boyer <jwboyer@fedoraproject.org> Cc: Kees Cook <keescook@chromium.org> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stas Sergeev <stsp@list.ru> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
95cd2ea7d5
commit
76fc5e7b23
2 changed files with 30 additions and 2 deletions
|
@ -45,6 +45,7 @@
|
||||||
#include <linux/audit.h>
|
#include <linux/audit.h>
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
@ -232,6 +233,32 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
|
||||||
struct pt_regs *regs = current_pt_regs();
|
struct pt_regs *regs = current_pt_regs();
|
||||||
unsigned long err = 0;
|
unsigned long err = 0;
|
||||||
|
|
||||||
|
err = security_mmap_addr(0);
|
||||||
|
if (err) {
|
||||||
|
/*
|
||||||
|
* vm86 cannot virtualize the address space, so vm86 users
|
||||||
|
* need to manage the low 1MB themselves using mmap. Given
|
||||||
|
* that BIOS places important data in the first page, vm86
|
||||||
|
* is essentially useless if mmap_min_addr != 0. DOSEMU,
|
||||||
|
* for example, won't even bother trying to use vm86 if it
|
||||||
|
* can't map a page at virtual address 0.
|
||||||
|
*
|
||||||
|
* To reduce the available kernel attack surface, simply
|
||||||
|
* disallow vm86(old) for users who cannot mmap at va 0.
|
||||||
|
*
|
||||||
|
* The implementation of security_mmap_addr will allow
|
||||||
|
* suitably privileged users to map va 0 even if
|
||||||
|
* vm.mmap_min_addr is set above 0, and we want this
|
||||||
|
* behavior for vm86 as well, as it ensures that legacy
|
||||||
|
* tools like vbetool will not fail just because of
|
||||||
|
* vm.mmap_min_addr.
|
||||||
|
*/
|
||||||
|
pr_info_once("Denied a call to vm86(old) from %s[%d] (uid: %d). Set the vm.mmap_min_addr sysctl to 0 and/or adjust LSM mmap_min_addr policy to enable vm86 if you are using a vm86-based DOS emulator.\n",
|
||||||
|
current->comm, task_pid_nr(current),
|
||||||
|
from_kuid_munged(&init_user_ns, current_uid()));
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vm86) {
|
if (!vm86) {
|
||||||
if (!(vm86 = kzalloc(sizeof(*vm86), GFP_KERNEL)))
|
if (!(vm86 = kzalloc(sizeof(*vm86), GFP_KERNEL)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -116,8 +116,9 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
|
||||||
v86->regs.eip = eip;
|
v86->regs.eip = eip;
|
||||||
ret = vm86(VM86_ENTER, v86);
|
ret = vm86(VM86_ENTER, v86);
|
||||||
|
|
||||||
if (ret == -1 && errno == ENOSYS) {
|
if (ret == -1 && (errno == ENOSYS || errno == EPERM)) {
|
||||||
printf("[SKIP]\tvm86 not supported\n");
|
printf("[SKIP]\tvm86 %s\n",
|
||||||
|
errno == ENOSYS ? "not supported" : "not allowed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue