Received: by 10.223.185.116 with SMTP id b49csp4937985wrg; Tue, 27 Feb 2018 05:17:27 -0800 (PST) X-Google-Smtp-Source: AG47ELuz9vOmZc37zWJx1HFKWz0nt8G33d9dydNxtcg5YepeGguuuBlArleyPUxyGDjpFKUQrQSy X-Received: by 10.99.183.68 with SMTP id w4mr8310008pgt.113.1519737447495; Tue, 27 Feb 2018 05:17:27 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519737447; cv=none; d=google.com; s=arc-20160816; b=G6q2wmrEVJuXN3AYx2jBzRiIdw1T7ITe/ls7gHYhRAGuBIP6xSKm44bIU79OQ5UWGS B1wsKCdMebZFgW2wjIIXpGd5+XmVoIX3WgdT9tPQ1EHO8KeGMupe/BEXshQITc2wdPwt DiQomQI7uAAPE+Mho1Cat1W+QDizNEeolagYy+reAFu+6cA+nfWChke5EHWLlUHju/mB sbP7ya1s2vZy8A2/zXOF/9IHkoqhbI0d8IroZigpzbuj5yz3dbRx7wRwiPU4+O16K0xr qW9pJ+jcq6kbrtRpDa02lLL950J9tDh93CQAEvWkqzJpMVWGk4nGoDaQub3ih3C+8Hrs lcDg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=tQbEFfJcOkGoLMhcZejkPYa+MAVPx5XPROZbbXWUjkE=; b=Tn1j5IoKbr0gEqsYxER7hP83E2hYmyIU6eK/0xL2LO2zF1z25s9wLOCHNkFvqxasOn 0n559sDtcCDvOpWa671E30dlH4qV61ooAlECfAexz6y1T08YuBgWFzaBqfkwBr6PizJW EqEX/zdc1yd1wJBBbuhHzdWlgp49DBTQlP/0bmHw6FLaloHNdzTiuZN25ybPKOdIwXve kkdnXiZ27g6enR62m9zAfeeO0BcHos9HyA1NEjaDMdzSzmeZnvAytuMrc0kWeNWNCn3A 16wb9oSaIMi/hErdxK63kvh2rRfNPxPWDT6+JBmaaqPtfpy/7MrICXCO96M55HNVXv8l nkMw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=XxJAsUo3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f32-v6si8507544plf.754.2018.02.27.05.17.12; Tue, 27 Feb 2018 05:17:27 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=XxJAsUo3; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753198AbeB0NP1 (ORCPT + 99 others); Tue, 27 Feb 2018 08:15:27 -0500 Received: from mail-lf0-f65.google.com ([209.85.215.65]:45343 "EHLO mail-lf0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753171AbeB0NPZ (ORCPT ); Tue, 27 Feb 2018 08:15:25 -0500 Received: by mail-lf0-f65.google.com with SMTP id x196so27422893lfd.12 for ; Tue, 27 Feb 2018 05:15:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=tQbEFfJcOkGoLMhcZejkPYa+MAVPx5XPROZbbXWUjkE=; b=XxJAsUo3AFqWfLvGPqp6EWL2DYcVohD9JeG9y9jR1AeEsqKqrSKCd0MKjDkJqDw0O9 rSM8CUk7bY30PD8pDzQJ2FvzuYKjDR/2cKIKQp02ZtJbNuva2X1xFnmp7Wcai0olyvMD PlK/0rXRZoOzEuk4iF+VoX6nc8X116MhR0OUAUiLzImhsrLSftGXnxQawJUFiugU+riR 9uSWkpFSBKe9cXprMmV/tOxhjTdBHudBJNAz07Au0GDJ48St6XTqGbGpUrlwQlPNvIE1 iPCMxtb2qRKxti6kbA1Kiyv7AKzX4lmLzGBiGeQlRWAuIBEOKspp704llG2EdNet5UOL KqqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=tQbEFfJcOkGoLMhcZejkPYa+MAVPx5XPROZbbXWUjkE=; b=EvISdNS7O8ikk6LY/30N+Wt//jodKgmSfh9Tw6tIDg9mlW/Ie8bzOhIx4of+KsKqGn H5zm8vgAXXxE3ZAUQfDgjgYeZTwnbrFfV4Oj5U2LPT2NPP/Fi7B4qXuzgy67K9tWidqD OE5JuRisWDDzWZ/IumEgbK8XX52mBbpgtf0FH+9ypTxBkUB4IOp48mDFRZLOJr7xnXz9 RQTIJbNQsVoFC/N8X9KiWuVJLoqt5lxi5Kq8lBk4AA9JeBE/uu6m86bW2cmYs+utphK8 rhLxEsLfRlJoTbjXnNZSLcbZJXZP3ggorDV9O5iGEzVTkUbRQa85jRMXzC1o8Ibt9avB 4vvQ== X-Gm-Message-State: APf1xPCGmEkbGPw0amnMWAzdM1i4GQzZHmT+bRCoiZ7Hxbmc3U6hZSB7 yp0p2JUxytB36NaadZrINAI= X-Received: by 10.25.170.144 with SMTP id t138mr1926816lfe.71.1519737324248; Tue, 27 Feb 2018 05:15:24 -0800 (PST) Received: from localhost.localdomain ([31.44.93.2]) by smtp.gmail.com with ESMTPSA id 202sm2527672ljj.2.2018.02.27.05.15.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 27 Feb 2018 05:15:23 -0800 (PST) From: Ilya Smith To: akpm@linux-foundation.org, dan.j.williams@intel.com, mhocko@suse.com, kirill.shutemov@linux.intel.com, jack@suse.cz, jglisse@redhat.com, hughd@google.com, willy@infradead.org, deller@gmx.de, aarcange@redhat.com, oleg@redhat.com, linux-mm@kvack.org, linux-kernel@vger.kernel.org, kernel-hardening@lists.openwall.com Cc: Ilya Smith Subject: [RFC PATCH] Randomization of address chosen by mmap. Date: Tue, 27 Feb 2018 16:13:38 +0300 Message-Id: <20180227131338.3699-1-blackzert@gmail.com> X-Mailer: git-send-email 2.14.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This is more proof of concept. Current implementation doesn't randomize address returned by mmap. All the entropy ends with choosing mmap_base_addr at the process creation. After that mmap build very predictable layout of address space. It allows to bypass ASLR in many cases. This patch make randomization of address on any mmap call. It works good on 64 bit system, but usage under 32 bit systems is not recommended. This approach uses current implementation to simplify search of address. Here I would like to discuss this approach. Signed-off-by: Ilya Smith --- include/linux/mm.h | 4 ++ mm/mmap.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index ad06d42adb1a..f81b6c8a0bc5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -25,6 +25,7 @@ #include #include #include +#include struct mempolicy; struct anon_vma; @@ -2253,6 +2254,7 @@ struct vm_unmapped_area_info { unsigned long align_offset; }; +extern unsigned long unmapped_area_random(struct vm_unmapped_area_info *info); extern unsigned long unmapped_area(struct vm_unmapped_area_info *info); extern unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info); @@ -2268,6 +2270,8 @@ extern unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info); static inline unsigned long vm_unmapped_area(struct vm_unmapped_area_info *info) { + if (current->flags & PF_RANDOMIZE) + return unmapped_area_random(info); if (info->flags & VM_UNMAPPED_AREA_TOPDOWN) return unmapped_area_topdown(info); else diff --git a/mm/mmap.c b/mm/mmap.c index 9efdc021ad22..58110e065417 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -1780,6 +1781,176 @@ unsigned long mmap_region(struct file *file, unsigned long addr, return error; } +unsigned long unmapped_area_random(struct vm_unmapped_area_info *info) +{ + // first lets find right border with unmapped_area_topdown + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + struct vm_area_struct *right_vma = 0; + unsigned long entropy; + unsigned int entropy_count; + unsigned long length, low_limit, high_limit, gap_start, gap_end; + unsigned long addr, low, high; + + /* Adjust search length to account for worst case alignment overhead */ + length = info->length + info->align_mask; + if (length < info->length) + return -ENOMEM; + + /* + * Adjust search limits by the desired length. + * See implementation comment at top of unmapped_area(). + */ + gap_end = info->high_limit; + if (gap_end < length) + return -ENOMEM; + high_limit = gap_end - length; + + info->low_limit = 0x10000; + if (info->low_limit > high_limit) + return -ENOMEM; + low_limit = info->low_limit + length; + + /* Check highest gap, which does not precede any rbtree node */ + gap_start = mm->highest_vm_end; + if (gap_start <= high_limit) + goto found; + + /* Check if rbtree root looks promising */ + if (RB_EMPTY_ROOT(&mm->mm_rb)) + return -ENOMEM; + vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb); + if (vma->rb_subtree_gap < length) + return -ENOMEM; + + while (true) { + /* Visit right subtree if it looks promising */ + gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; + if (gap_start <= high_limit && vma->vm_rb.rb_right) { + struct vm_area_struct *right = + rb_entry(vma->vm_rb.rb_right, + struct vm_area_struct, vm_rb); + if (right->rb_subtree_gap >= length) { + vma = right; + continue; + } + } + +check_current_down: + /* Check if current node has a suitable gap */ + gap_end = vm_start_gap(vma); + if (gap_end < low_limit) + return -ENOMEM; + if (gap_start <= high_limit && + gap_end > gap_start && gap_end - gap_start >= length) + goto found; + + /* Visit left subtree if it looks promising */ + if (vma->vm_rb.rb_left) { + struct vm_area_struct *left = + rb_entry(vma->vm_rb.rb_left, + struct vm_area_struct, vm_rb); + if (left->rb_subtree_gap >= length) { + vma = left; + continue; + } + } + + /* Go back up the rbtree to find next candidate node */ + while (true) { + struct rb_node *prev = &vma->vm_rb; + + if (!rb_parent(prev)) + return -ENOMEM; + vma = rb_entry(rb_parent(prev), + struct vm_area_struct, vm_rb); + if (prev == vma->vm_rb.rb_right) { + gap_start = vma->vm_prev ? + vm_end_gap(vma->vm_prev) : 0; + goto check_current_down; + } + } + } + +found: + right_vma = vma; + low = gap_start; + high = gap_end - length; + + entropy = get_random_long(); + entropy_count = 0; + + // from left node to right we check if node is fine and + // randomly select it. + vma = mm->mmap; + while (vma != right_vma) { + /* Visit left subtree if it looks promising */ + gap_end = vm_start_gap(vma); + if (gap_end >= low_limit && vma->vm_rb.rb_left) { + struct vm_area_struct *left = + rb_entry(vma->vm_rb.rb_left, + struct vm_area_struct, vm_rb); + if (left->rb_subtree_gap >= length) { + vma = left; + continue; + } + } + + gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : low_limit; +check_current_up: + /* Check if current node has a suitable gap */ + if (gap_start > high_limit) + break; + if (gap_end >= low_limit && + gap_end > gap_start && gap_end - gap_start >= length) { + if (entropy & 1) { + low = gap_start; + high = gap_end - length; + } + entropy >>= 1; + if (++entropy_count == 64) { + entropy = get_random_long(); + entropy_count = 0; + } + } + + /* Visit right subtree if it looks promising */ + if (vma->vm_rb.rb_right) { + struct vm_area_struct *right = + rb_entry(vma->vm_rb.rb_right, + struct vm_area_struct, vm_rb); + if (right->rb_subtree_gap >= length) { + vma = right; + continue; + } + } + + /* Go back up the rbtree to find next candidate node */ + while (true) { + struct rb_node *prev = &vma->vm_rb; + + if (!rb_parent(prev)) + BUG(); // this should not happen + vma = rb_entry(rb_parent(prev), + struct vm_area_struct, vm_rb); + if (prev == vma->vm_rb.rb_left) { + gap_start = vm_end_gap(vma->vm_prev); + gap_end = vm_start_gap(vma); + if (vma == right_vma) + break; + goto check_current_up; + } + } + } + + if (high == low) + return low; + + addr = get_random_long() % ((high - low) >> PAGE_SHIFT); + addr = low + (addr << PAGE_SHIFT); + return addr; +} + unsigned long unmapped_area(struct vm_unmapped_area_info *info) { /* -- 2.14.1