Received: by 2002:a05:6a10:16a7:0:0:0:0 with SMTP id gp39csp1834996pxb; Fri, 20 Nov 2020 23:04:34 -0800 (PST) X-Google-Smtp-Source: ABdhPJz2LK1x+4Lmi8zOIa0qSrLLUIN3eWSjJlNN8Ap9w2uhF+K7NB6qj5bisbtYA6sCnPqGkNph X-Received: by 2002:a17:906:374a:: with SMTP id e10mr25760958ejc.246.1605942273894; Fri, 20 Nov 2020 23:04:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1605942273; cv=none; d=google.com; s=arc-20160816; b=jKI4HJsZXQ3keV2tHvjLe2IYRRtQimxiNpiVzRmvd784AAcAeh00QqUpWLDBwP6g44 8Se/VFcjGM577tTxhOyX/4jlrrD/P4HRoD/aouwGDU45z8XA48QnOMP4cqUcWxav/Ff2 QRU2FWJ4ZK8iSypMgauVDoChVSslUvqsX47vtUmylvi5+tHhZXLSoQ7nEcD6nXGCRNVP 0exelGcDOoU3rC7H2EzoIh2JHs8PMpxPMwmlZ4GlnmF6iYmSwBVhkie4y3QuHLUSqZnj 3DrPhNzXuAEQHQoeLOlEKZ3GlOO37BfF17ly89aDpja2YEGD5v0Zk23LpaGT7UYK4ZY1 EZrA== 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=zCcA4sLycmShyMxZ6i9Eumf1OUB1JNsCrcUOdwj1SQI=; b=cL7BEr1KuFPLVMXir8uTHs7ec7zk5HhNJ/ghbZxvkY/91o5dSwKvzYntUCs1fEEWcB SCKjV2Atn+xFJlWdlayfLjWaLuj/1FVp/DhEmYkMzpHpPAWX8k8zjOF7IhBQ0Ks8WY5G dSB93tyZg5x7YwoQUbopsLhaj6vr0BqSMvUL3q8fJ9FlqgnSPsRbARh96JTZvylO5uvc 3yoOmp9sf5FyHg1fpGTAantrmYRf7nZKcPNc7mVS75R+DKtKFKEev2n0BNwphpFP9FUy rXgbutUR55Ryz2aaazliM6SdjgPmsB9qHz8RTgsInOf2mU0k+dqH144UN5Z1P1SuKcDU Ly7Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=dyVl3+GK; 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 z7si2990037ejw.347.2020.11.20.23.04.11; Fri, 20 Nov 2020 23:04:33 -0800 (PST) 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=dyVl3+GK; 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 S1727112AbgKUHAu (ORCPT + 99 others); Sat, 21 Nov 2020 02:00:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727107AbgKUHAt (ORCPT ); Sat, 21 Nov 2020 02:00:49 -0500 Received: from mail-lj1-x243.google.com (mail-lj1-x243.google.com [IPv6:2a00:1450:4864:20::243]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 34CF8C061A48 for ; Fri, 20 Nov 2020 23:00:49 -0800 (PST) Received: by mail-lj1-x243.google.com with SMTP id t22so55478ljk.0 for ; Fri, 20 Nov 2020 23:00:49 -0800 (PST) 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=zCcA4sLycmShyMxZ6i9Eumf1OUB1JNsCrcUOdwj1SQI=; b=dyVl3+GKSo/xVNAFCoPUWUc6gQmdnw/aoaQ4OWYQZWi2kHziBvNSeTnr32XAufXgxx hKm1lXxIoBOeyloaPYvydgxjC+QYQhPhdTBvC3QDAyA7AJyAjx1Sfg+qUFcGGSyONF8a rMKz4vmvLjBUQoyU5nljmBLmfmujXCOPYrMhv1QkKNn3puxg8Bv8DNt5W2ZOwFPaeWbF Wzo6H7mzy9nAyHb2lga5U1+/aFxC+fqkiabeBSqjroyj0XzDF5MUiNTLKPowTk9qU32M 0Frm4j8FEeopwqA7QqTNyauy419MUnrYWXvN0JzetsvpCro/b6d4UfZLXFRL8XQqSWR4 iSWQ== 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=zCcA4sLycmShyMxZ6i9Eumf1OUB1JNsCrcUOdwj1SQI=; b=Xw0Qry4VkPy98wArtpRG2blnDbbrNdBDmmz347brQmj37SkFl4Opqeo9LVlYtg/g5q fU2pznUIS+xktwP7zStH6L2XbpkqTnyif77p/qsvKx8UJYZIR3PSwWR+aUO9GnQ/Huaj sN8PE1z4KrRBEa4N+6MrLpKsYUre4iHMPCu8+wsmKnlfj0sbLLr4Id+oalaSv7cvsfGg DDncFL6IHlDovcEOX4xlTcV0zt/BbWiK/FQfF9UIBgFA1VWev51h/bfN8AiEqEwiEnPa MzlXRJlacrggpGogMIE4Nf2ggJxhCZZcCDSxiHBMw0heaDTlHduSI/slqYMTiTql0pBh 0qhQ== X-Gm-Message-State: AOAM5326F7UIq45Jlc3L1LihvN0gAHlvDPtwQCMBP0v0A5lbMOkru1gr gV95KK3IaFC8YJYDaR5Pr0kIaw2mhUlgTQMcgpfSBg== X-Received: by 2002:a2e:9d8d:: with SMTP id c13mr9054289ljj.160.1605942047455; Fri, 20 Nov 2020 23:00:47 -0800 (PST) MIME-Version: 1.0 References: <20201112205141.775752-1-mic@digikod.net> <20201112205141.775752-8-mic@digikod.net> In-Reply-To: <20201112205141.775752-8-mic@digikod.net> From: Jann Horn Date: Sat, 21 Nov 2020 08:00:00 +0100 Message-ID: Subject: Re: [PATCH v24 07/12] landlock: Support filesystem access-control To: =?UTF-8?B?TWlja2HDq2wgU2FsYcO8bg==?= Cc: James Morris , "Serge E . Hallyn" , Al Viro , Andy Lutomirski , Anton Ivanov , Arnd Bergmann , Casey Schaufler , Jeff Dike , Jonathan Corbet , Kees Cook , Michael Kerrisk , Richard Weinberger , Shuah Khan , Vincent Dagonneau , Kernel Hardening , Linux API , linux-arch , "open list:DOCUMENTATION" , linux-fsdevel , kernel list , "open list:KERNEL SELFTEST FRAMEWORK" , linux-security-module , "the arch/x86 maintainers" , =?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 Thu, Nov 12, 2020 at 9:52 PM Micka=C3=ABl Sala=C3=BCn = wrote: > Thanks to the Landlock objects and ruleset, it is possible to identify > inodes according to a process's domain. To enable an unprivileged > process to express a file hierarchy, it first needs to open a directory > (or a file) and pass this file descriptor to the kernel through > landlock_add_rule(2). When checking if a file access request is > allowed, we walk from the requested dentry to the real root, following > the different mount layers. The access to each "tagged" inodes are > collected according to their rule layer level, and ANDed to create > access to the requested file hierarchy. This makes possible to identify > a lot of files without tagging every inodes nor modifying the > filesystem, while still following the view and understanding the user > has from the filesystem. > > Add a new ARCH_EPHEMERAL_INODES for UML because it currently does not > keep the same struct inodes for the same inodes whereas these inodes are > in use. > > This commit adds a minimal set of supported filesystem access-control > which doesn't enable to restrict all file-related actions. This is the > result of multiple discussions to minimize the code of Landlock to ease > review. Thanks to the Landlock design, extending this access-control > without breaking user space will not be a problem. Moreover, seccomp > filters can be used to restrict the use of syscall families which may > not be currently handled by Landlock. > > Cc: Al Viro > Cc: Anton Ivanov > Cc: James Morris > Cc: Jann Horn > Cc: Jeff Dike > Cc: Kees Cook > Cc: Richard Weinberger > Cc: Serge E. Hallyn > Signed-off-by: Micka=C3=ABl Sala=C3=BCn > --- > > Changes since v23: > * Enforce deterministic interleaved path rules. To have consistent > layered rules, granting access to a path implies that all accesses > tied to inodes, from the requested file to the real root, must be > checked. Otherwise, stacked rules may result to overzealous > restrictions. By excluding the ability to add exceptions in the same > layer (e.g. /a allowed, /a/b denied, and /a/b/c allowed), we get > deterministic interleaved path rules. This removes an optimization I don't understand the "deterministic interleaved path rules" part. What if I have a policy like this? /home/user READ /home/user/Downloads READ+WRITE That's a reasonable policy, right? If I then try to open /home/user/Downloads/foo in WRITE mode, the loop will first check against the READ+WRITE rule for /home/user, that check will pass, and then it will check against the READ rule for /, which will deny the access, right? That seems bad. The v22 code ensured that for each layer, the most specific rule (the first we encounter on the walk) always wins, right? What's the problem with that? > which could be replaced by a proper cache mechanism. This also > further simplifies and explain check_access_path_continue(). From the interdiff between v23 and v24 (git range-diff 99ade5d59b23~1..99ade5d59b23 faa8c09be9fd~1..faa8c09be9fd): @@ security/landlock/fs.c (new) + rcu_dereference(landlock_inode(inode)->object)); + rcu_read_unlock(); + -+ /* Checks for matching layers. */ -+ if (rule && (rule->layers | *layer_mask)) { -+ if ((rule->access & access_request) =3D=3D access_request) = { -+ *layer_mask &=3D ~rule->layers; -+ return true; -+ } else { -+ return false; -+ } ++ if (!rule) ++ /* Continues to walk if there is no rule for this inode. */ ++ return true; ++ /* ++ * We must check all layers for each inode because we may encounter ++ * multiple different accesses from the same layer in a walk. Each ++ * layer must at least allow the access request one time (i.e. with= one ++ * inode). This enables to have a deterministic behavior whatever ++ * inode is tagged within interleaved layers. ++ */ ++ if ((rule->access & access_request) =3D=3D access_request) { ++ /* Validates layers for which all accesses are allowed. */ ++ *layer_mask &=3D ~rule->layers; ++ /* Continues to walk until all layers are validated. */ ++ return true; + } -+ return true; ++ /* Stops if a rule in the path don't allow all requested access. */ ++ return false; +} + +static int check_access_path(const struct landlock_ruleset *const dom= ain, @@ security/landlock/fs.c (new) + &layer_mask)) { + struct dentry *parent_dentry; + -+ /* Stops when a rule from each layer granted access. */ -+ if (layer_mask =3D=3D 0) { -+ allowed =3D true; -+ break; -+ } -+ This change also made it so that disconnected paths aren't accessible unless they're internal, right? While previously, the access could be permitted if the walk stops before reaching the disconnected point? I guess that's fine, but it should probably be documented. +jump_up: + /* + * Does not work with orphaned/private mounts like overlayf= s @@ security/landlock/fs.c (new) + goto jump_up; + } else { + /* -+ * Stops at the real root. Denies access -+ * because not all layers have granted acce= ss. ++ * Stops at the real root. Denies access i= f ++ * not all layers granted access. + */ -+ allowed =3D false; ++ allowed =3D (layer_mask =3D=3D 0); + break; + } + }