Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp991123imm; Sat, 26 May 2018 17:32:58 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpGrGEr3WOsSRn++wDDAuhPKrQtHz/IwkvHJlKz6E5lVZXCAOpSIaSOEgHwDwtMypVsT3tz X-Received: by 2002:a65:5c89:: with SMTP id a9-v6mr4445331pgt.51.1527381178263; Sat, 26 May 2018 17:32:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527381178; cv=none; d=google.com; s=arc-20160816; b=whxLwTapUhHg0B0EYQ743pP9V3qEBtUaVctnqUzwLIUFbDEpr8UDg+uV2TWuPkW7cC 6cKPfKDWefrSgln9eyD6wYM9XaM3T0ho9f1IEz7P1Q0u7tu08I7qAUvp3GQ+d0TvAY1U 76wrg5Qhr2JL/mK3pA8xE88qlHKhF+UE0Ded8Rirhjsxbf+W6pyVxCiI7+UYNLUMsa0C LHN1ZFpejhPozgwt9M11K45Dat0J5OqJStYI+rBAejzdxtBPfWR4L1qjbJ0je8F/b+nI a49UIBD8F+ZJfNxLQgbcT37NezGwd9pSXLDSYCPZ/FO0JaCr+nlDlBo9+8P5XWXnUaKg ZRIA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature:dkim-signature :arc-authentication-results; bh=t30DQxWQtaWhM4iPC7XWASli8TeRwqP/mnW25nd39yw=; b=OotFpyJLBnaQq68U5COLg4B0IeMK0RugS1NxY9rwzH94BDYE/dKAiXqQjwQGQJxwDB vCEj26albjHbGRUE4oGk5iIfb/RxLNOvklA0bMK3x5K/2jFnRBEHqGXgdPxQtx/avhoa KlDAduiNhfs8CQQ7tiMw3lVqJ3Vv/PhMBe1cT4MDwPjqCHxkLakYxogEzmfjzEpkHL1x uxtUJA0je7uwimSJrtT/cnOOwRAE+0vYjw45J4oUGhlzQli3Y6YGgVFHS7wtffD6wK4Y PBatmx+m8UB6CD9sPOf0aoXRp8xHtcmA7dcKq4tsDTrLPtq39O8qJKlUYhYfcpHCR11v MhXQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@google.com header.s=20161025 header.b=GZ8+oLgO; dkim=fail header.i=@chromium.org header.s=google header.b=C2hZEw7f; 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=fail (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j20-v6si27549085pfa.57.2018.05.26.17.32.11; Sat, 26 May 2018 17:32:58 -0700 (PDT) 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=fail header.i=@google.com header.s=20161025 header.b=GZ8+oLgO; dkim=fail header.i=@chromium.org header.s=google header.b=C2hZEw7f; 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=fail (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1032504AbeE0AcB (ORCPT + 99 others); Sat, 26 May 2018 20:32:01 -0400 Received: from mail-vk0-f68.google.com ([209.85.213.68]:35271 "EHLO mail-vk0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1032474AbeE0Ab6 (ORCPT ); Sat, 26 May 2018 20:31:58 -0400 Received: by mail-vk0-f68.google.com with SMTP id g72-v6so5209294vke.2 for ; Sat, 26 May 2018 17:31:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=t30DQxWQtaWhM4iPC7XWASli8TeRwqP/mnW25nd39yw=; b=GZ8+oLgOFvp/0n5dr5uhErwqkl4/GIrOu9tBomiD8P9G/calsDxK+OqcvLXHwnS/pC ueht2/9ORDTdkQfxoKbcQC6kS/RxfqXNJrQKGf7i6GSqzTRAZBuelslpqnKCl067pwm0 dxnj0FjC61h/pFpWgF8AO0PDsT/wl3l07hz0Y547GNe/t+j8A7heVPz8tMQjXkc31JEH nWVB3b+8M+ZZLTzRfxOQNME2ySxuX76Za+oJ1D1aJKelR3B12WyFL/4Lg/BnfDkS6fbz UYE5d+c5AkiF8DhTIS2BiGNGqcOnOS/D82rRw6Gn+WDsHG/EPzLgrYCmmydq39u5Ls/U iIVw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=t30DQxWQtaWhM4iPC7XWASli8TeRwqP/mnW25nd39yw=; b=C2hZEw7fB2Oq+gwI95u1gXPsu41P+mNNmWFv/wCrtLhk7Dtw3Rbe01E9gXgNoaAZTA v7PxT2ruuCSbCj6+zItuxaovCEUxFVDyIPXzggak9NkTtSNITRy8iWDj6TXzG0qcF/xP a8/R2lLNR2G6JOBnYWBerFa+aeeihsREpu71g= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=t30DQxWQtaWhM4iPC7XWASli8TeRwqP/mnW25nd39yw=; b=FaY/MH+mBIwgYHUBpUBTvFTuT0uGLTjrUkpa6iHhwSL1V9cuP8WpCLHrkjWIe8e+5S gi/1xpiycpkRnKoj3TUk3m+Lu63lUCeOQ8+i7oKKTrnVygQe0Do39rwXd8uDIYJ6EObA PCUcGb2PCy+rXeeKSC62q2Cj2iks4s+sWsvlpxyl14WWJQq/Zzy91kmx3zJcXrqtZq9b SfnwKX8E6KHMEpkFeBxiODm9sRtG2Hn5yBVGCqtQSkOZdtyKqBd6KJXbo8n+1CPNH8zA FVxw+O9I/xAUFQPPvFMfLA7OVP79FM1UBQImjbjL50BWDQ6QdPgyr40R7EBIFVlePeWk 6UjQ== X-Gm-Message-State: ALKqPwd9lSUXiTOYoVZmc4VLF6efBtXZkdRs1nLSL1wRGYvTE6pZP6Wg ed1w/mH7CU0JknhTbn3XpDr+LbgdJGLediousRA7OA== X-Received: by 2002:a1f:3096:: with SMTP id w144-v6mr4745767vkw.121.1527381116765; Sat, 26 May 2018 17:31:56 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a1f:bd1:0:0:0:0:0 with HTTP; Sat, 26 May 2018 17:31:56 -0700 (PDT) In-Reply-To: <1527346246-1334-1-git-send-email-s.mesoraca16@gmail.com> References: <1527346246-1334-1-git-send-email-s.mesoraca16@gmail.com> From: Kees Cook Date: Sat, 26 May 2018 17:31:56 -0700 X-Google-Sender-Auth: h4FcRs9803G33zGE_Mfx8i4POac Message-ID: Subject: Re: [PATCH] proc: prevent a task from writing on its own /proc/*/mem To: Salvatore Mesoraca , Linus Torvalds , Jann Horn Cc: Kernel Hardening , linux-security-module , LKML , Linux-MM , Andrew Morton , Alexey Dobriyan , Akinobu Mita , Dmitry Vyukov , Arnd Bergmann , Davidlohr Bueso Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Sat, May 26, 2018 at 7:50 AM, Salvatore Mesoraca wrote: > Prevent a task from opening, in "write" mode, any /proc/*/mem > file that operates on the task's mm. > /proc/*/mem is mainly a debugging means and, as such, it shouldn't > be used by the inspected process itself. > Current implementation always allow a task to access its own > /proc/*/mem file. > A process can use it to overwrite read-only memory, making > pointless the use of security_file_mprotect() or other ways to > enforce RO memory. I went through some old threads from 2012 when e268337dfe26 was introduced, and later when things got looked at during DirtyCOW. There was discussion about removing FOLL_FORCE (in order to block writes on a read-only memory region). But that was much more general, touched ptrace, etc. I think this patch would be okay, since it's specific to the proc "self" mem interface, not remote processes (via ptrace). This patch would also have blocked the /proc/self/mem path to DirtyCOW (though not ptrace), so that would be nice if we have similar issues in the future. So, as long as this doesn't break anything, I'm for it in general. I've CCed Linus and Jann too, since they've stared at this a lot too. :P Note that you're re-checking the mm-check-for-self in mm_access(). That's used in /proc and for process_vm_write(). Ptrace (and mm_access()) uses ptrace_may_access() for stuff (which has a similar check to bypass LSMs), so I'd be curious what would happen if this logic was plumbed into mm_access() instead of into proc_mem_open(). (Does anything open /proc/$pid files for writing? Does anything using process_vm_write() on itself?) -Kees > > Signed-off-by: Salvatore Mesoraca > --- > fs/proc/base.c | 25 ++++++++++++++++++------- > fs/proc/internal.h | 3 ++- > fs/proc/task_mmu.c | 4 ++-- > fs/proc/task_nommu.c | 2 +- > 4 files changed, 23 insertions(+), 11 deletions(-) > > diff --git a/fs/proc/base.c b/fs/proc/base.c > index 1a76d75..01ecfec 100644 > --- a/fs/proc/base.c > +++ b/fs/proc/base.c > @@ -762,8 +762,9 @@ static int proc_single_open(struct inode *inode, struct file *filp) > .release = single_release, > }; > > - > -struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode) > +struct mm_struct *proc_mem_open(struct inode *inode, > + unsigned int mode, > + fmode_t f_mode) > { > struct task_struct *task = get_proc_task(inode); > struct mm_struct *mm = ERR_PTR(-ESRCH); > @@ -773,10 +774,20 @@ struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode) > put_task_struct(task); > > if (!IS_ERR_OR_NULL(mm)) { > - /* ensure this mm_struct can't be freed */ > - mmgrab(mm); > - /* but do not pin its memory */ > - mmput(mm); > + /* > + * Prevent this interface from being used as a mean > + * to bypass memory restrictions, including those > + * imposed by LSMs. > + */ > + if (mm == current->mm && > + f_mode & FMODE_WRITE) > + mm = ERR_PTR(-EACCES); > + else { > + /* ensure this mm_struct can't be freed */ > + mmgrab(mm); > + /* but do not pin its memory */ > + mmput(mm); > + } > } > } > > @@ -785,7 +796,7 @@ struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode) > > static int __mem_open(struct inode *inode, struct file *file, unsigned int mode) > { > - struct mm_struct *mm = proc_mem_open(inode, mode); > + struct mm_struct *mm = proc_mem_open(inode, mode, file->f_mode); > > if (IS_ERR(mm)) > return PTR_ERR(mm); > diff --git a/fs/proc/internal.h b/fs/proc/internal.h > index 0f1692e..8d38cc7 100644 > --- a/fs/proc/internal.h > +++ b/fs/proc/internal.h > @@ -275,7 +275,8 @@ struct proc_maps_private { > #endif > } __randomize_layout; > > -struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode); > +struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode, > + fmode_t f_mode); > > extern const struct file_operations proc_pid_maps_operations; > extern const struct file_operations proc_tid_maps_operations; > diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c > index c486ad4..efb6535 100644 > --- a/fs/proc/task_mmu.c > +++ b/fs/proc/task_mmu.c > @@ -227,7 +227,7 @@ static int proc_maps_open(struct inode *inode, struct file *file, > return -ENOMEM; > > priv->inode = inode; > - priv->mm = proc_mem_open(inode, PTRACE_MODE_READ); > + priv->mm = proc_mem_open(inode, PTRACE_MODE_READ, file->f_mode); > if (IS_ERR(priv->mm)) { > int err = PTR_ERR(priv->mm); > > @@ -1534,7 +1534,7 @@ static int pagemap_open(struct inode *inode, struct file *file) > { > struct mm_struct *mm; > > - mm = proc_mem_open(inode, PTRACE_MODE_READ); > + mm = proc_mem_open(inode, PTRACE_MODE_READ, file->f_mode); > if (IS_ERR(mm)) > return PTR_ERR(mm); > file->private_data = mm; > diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c > index 5b62f57..dc38516 100644 > --- a/fs/proc/task_nommu.c > +++ b/fs/proc/task_nommu.c > @@ -280,7 +280,7 @@ static int maps_open(struct inode *inode, struct file *file, > return -ENOMEM; > > priv->inode = inode; > - priv->mm = proc_mem_open(inode, PTRACE_MODE_READ); > + priv->mm = proc_mem_open(inode, PTRACE_MODE_READ, file->f_mode); > if (IS_ERR(priv->mm)) { > int err = PTR_ERR(priv->mm); > > -- > 1.9.1 > -- Kees Cook Pixel Security