Received: by 2002:a05:6a10:9848:0:0:0:0 with SMTP id x8csp4465436pxf; Tue, 16 Mar 2021 14:21:48 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz37OgUaqZQPDYCVQaG0fv8Ce1S/pyFUcXAMNBf2KKCsCN4KqpEctMS0dQi9bvaVe+2Gnrg X-Received: by 2002:a17:906:380b:: with SMTP id v11mr32567076ejc.183.1615929708048; Tue, 16 Mar 2021 14:21:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1615929708; cv=none; d=google.com; s=arc-20160816; b=jfoNa3x2Aitqm9sfv3QjS/I0noPHiMKz5IcYEY8OJotro2REN6/laE6Qdf0JJA1aIP 3Ra3f5vHv42q2LRz+2l4LktjabZC9534SSZ9eFwUfmax6oBcfzEK4woiufT9Ofj5oVmi T54FHkiDpLCYMhcCIkNCbQ4Qiu4MDgvdRmzra7QkTKUOQrkMu7FAEheAomjicvJgigs3 SrjrCFG94rDTmK4k5HFW2VOR9IWB+5/fyFp1u6N05i5rc6HNZcW3Xdb76sEbAoDUDPIo Jj2n0fu2JCJEBnUuODrAaRs4Uk51qe0JO0keNxns4SkHbE67Q5upcjjvOnkL+fd49vU9 StRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:cc:to:subject :message-id:date:from:in-reply-to:references:mime-version :dkim-signature; bh=4xmctPJghbzCxK0UlOH+Mq1rZavHE0MB6cGIt7/nfNk=; b=mGfzw7M5WYbzVHNujuBQNf/TabbzP8cRAU9Cv7KO0SERfwBIWEU6Skse2is7WMDNun hM8ysLQH8LAKRKoiMt6ALqPhAESZtdS7An2cy5A4uwBr2FGKZblVGEwF/D6HH8Muudqp mpifYDA+UZb1muND9nwMq4/9BQjud6jXVXdnEj1ED5moYZ5q8fuNXEMzKNzhN7EoMJII 4gNRbCIGU5t8Uwpt3OBUBGG9YOLY7+atuAxzwA4QWZcA/sTp9ZHWYut6qwmGyZPLZLzK 3McQGZaOg+nyAKnnt65/ERBTKip8/tTmXRLd7CGl1AocdE++XZ1ap6lWl7erDl8uDgxr G8vg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Fvq3zYIW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id b26si13927182eja.162.2021.03.16.14.21.25; Tue, 16 Mar 2021 14:21:48 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Fvq3zYIW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240261AbhCPTE5 (ORCPT + 99 others); Tue, 16 Mar 2021 15:04:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55238 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240251AbhCPTEw (ORCPT ); Tue, 16 Mar 2021 15:04:52 -0400 Received: from mail-lj1-x231.google.com (mail-lj1-x231.google.com [IPv6:2a00:1450:4864:20::231]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9BC99C06174A for ; Tue, 16 Mar 2021 12:04:40 -0700 (PDT) Received: by mail-lj1-x231.google.com with SMTP id y1so87263ljm.10 for ; Tue, 16 Mar 2021 12:04:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=4xmctPJghbzCxK0UlOH+Mq1rZavHE0MB6cGIt7/nfNk=; b=Fvq3zYIWJXqeliEpcPw2DlNd4Z7cuzmPSXt5zH7IOtyT/4qCHkCM2dQv/y3Pg7SCE+ 4fVIx1+gg2iqyDqKxbYreKbYwuAFUwcQCCfb4rwfKEPe1n4XNUFRrJI8fcrdQlE+H9zH 5+4OO7YkHLl0ikW3SmS5/GqFseKPGqkKzafSDtVFeURjUbqMK+DW56fyPKUQ5IMboY82 x3JzGW+Oy76GhErg03A187ggg/ZAdsMbNoIxe+HVyi4lXCn0+3q2EalQBlrhGdYx5hxz SYyZeuVlO7rUzqKw0jFxB1Pwt6DkBDK6+wvFOkr7GGiSd9iAdQIIh+dlEAyKxYAQfTPd UPxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=4xmctPJghbzCxK0UlOH+Mq1rZavHE0MB6cGIt7/nfNk=; b=LNlmCmXuwK6Ps0vJAQca8RDL9vJprp7XW4HFzA048AoDUKUXtIgFTKDKrYjmRieKDk Omh/rGAuUnvmwIkbFfZoNzZcXq4ckhqKMPAgMgOCBsQ6o4aZiE5eBlhLplGx25YaxsWY jnHRaet/CG19lhF9J/nwgLW1NefGPlA0WUOLYbZ6Z5d80m1Y7rptwMwM9qHmgaU+nzHS ArEmrDwko1FFZCCAykF8q8P0tGcmVjTX1oLwmNNHBA198eLwc5FT4hA+9EUFrVGgv/IM HU7zRoa7bTH8E5598EZSoPebHh4LUxQ32NLfeWR9mcGpiL4apPzwUh5qzn/rigmZWTwW lB2g== X-Gm-Message-State: AOAM532nvrNHHzwib1p7LMLtu6KvjYSGWn+U5E06rumRsRy25ji+LAN9 ywCxh7jS2KGZhrfH3/5/olwGYXB/ZU3+MtznvQS6QQ== X-Received: by 2002:a05:651c:1134:: with SMTP id e20mr76134ljo.385.1615921475761; Tue, 16 Mar 2021 12:04:35 -0700 (PDT) MIME-Version: 1.0 References: <20210316170135.226381-1-mic@digikod.net> <20210316170135.226381-2-mic@digikod.net> In-Reply-To: <20210316170135.226381-2-mic@digikod.net> From: Jann Horn Date: Tue, 16 Mar 2021 20:04:09 +0100 Message-ID: Subject: Re: [PATCH v4 1/1] fs: Allow no_new_privs tasks to call chroot(2) To: =?UTF-8?B?TWlja2HDq2wgU2FsYcO8bg==?= Cc: Al Viro , James Morris , Serge Hallyn , Andy Lutomirski , Casey Schaufler , Christian Brauner , Christoph Hellwig , David Howells , Dominik Brodowski , "Eric W . Biederman" , John Johansen , Kees Cook , Kentaro Takeda , Tetsuo Handa , Kernel Hardening , linux-fsdevel , kernel list , linux-security-module , =?UTF-8?B?TWlja2HDq2wgU2FsYcO8bg==?= Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Mar 16, 2021 at 6:02 PM Micka=C3=ABl Sala=C3=BCn = wrote: > One could argue that chroot(2) is useless without a properly populated > root hierarchy (i.e. without /dev and /proc). However, there are > multiple use cases that don't require the chrooting process to create > file hierarchies with special files nor mount points, e.g.: > * A process sandboxing itself, once all its libraries are loaded, may > not need files other than regular files, or even no file at all. > * Some pre-populated root hierarchies could be used to chroot into, > provided for instance by development environments or tailored > distributions. > * Processes executed in a chroot may not require access to these special > files (e.g. with minimal runtimes, or by emulating some special files > with a LD_PRELOADed library or seccomp). > > Unprivileged chroot is especially interesting for userspace developers > wishing to harden their applications. For instance, chroot(2) and Yama > enable to build a capability-based security (i.e. remove filesystem > ambient accesses) by calling chroot/chdir with an empty directory and > accessing data through dedicated file descriptors obtained with > openat2(2) and RESOLVE_BENEATH/RESOLVE_IN_ROOT/RESOLVE_NO_MAGICLINKS. I don't entirely understand. Are you writing this with the assumption that a future change will make it possible to set these RESOLVE flags process-wide, or something like that? As long as that doesn't exist, I think that to make this safe, you'd have to do something like the following - let a child process set up a new mount namespace for you, and then chroot() into that namespace's root: struct shared_data { int root_fd; }; int helper_fn(void *args) { struct shared_data *shared =3D args; mount("none", "/tmp", "tmpfs", MS_NOSUID|MS_NODEV, ""); mkdir("/tmp/old_root", 0700); pivot_root("/tmp", "/tmp/old_root"); umount("/tmp/old_root", ""); shared->root_fd =3D open("/", O_PATH); } void setup_chroot() { struct shared_data shared =3D {}; prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); clone(helper_fn, my_stack, CLONE_VFORK|CLONE_VM|CLONE_FILES|CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL); fchdir(shared.root_fd); chroot("."); } [...] > diff --git a/fs/open.c b/fs/open.c [...] > +static inline int current_chroot_allowed(void) > +{ > + /* > + * Changing the root directory for the calling task (and its futu= re > + * children) requires that this task has CAP_SYS_CHROOT in its > + * namespace, or be running with no_new_privs and not sharing its > + * fs_struct and not escaping its current root (cf. create_user_n= s()). > + * As for seccomp, checking no_new_privs avoids scenarios where > + * unprivileged tasks can affect the behavior of privileged child= ren. > + */ > + if (task_no_new_privs(current) && current->fs->users =3D=3D 1 && this read of current->fs->users should be using READ_ONCE() > + !current_chrooted()) > + return 0; > + if (ns_capable(current_user_ns(), CAP_SYS_CHROOT)) > + return 0; > + return -EPERM; > +} [...] Overall I think this change is a good idea.