From patchwork Tue Feb 20 09:27:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563732 Received: from mail-ej1-f54.google.com (mail-ej1-f54.google.com [209.85.218.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7821A5FDB2 for ; Tue, 20 Feb 2024 09:27:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421251; cv=none; b=iVzon5hywJ7j72PBYMz6iSMAQambgc45nahbV2d5ZtTxF6gilIlDMgJxe1YRHX/ixUufODzK3pgYLx2neutMgRuzQB4DEIsdIJhqdgScyg97rF5BCE2hA5iUCvuv5XMcrfzcgTZDt/Y9mIQMBDFtr/KLfJcS0K8rCG2D5/tTqmU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421251; c=relaxed/simple; bh=AL20AmpyQfee6Z/j0ZATVimRlJXhAXHnqSaawdUpLe4=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=jNaAXsvICC4uDt7HAevBAaD+YiA6dOrWYvfL2lOShgJvyvIY58iPd4qGaFOm8/ky+RrQY4nNNk3IXG+EBiQqDy0XmXvCt5n3hH7o2XfrPmwZ18hvSqMVnjTFMQkaIfEbFUxZOyecNeRDQxyOYZsh6bFkR5I0rvRQKHFAbCC5qFs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=02+7I3BM; arc=none smtp.client-ip=209.85.218.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="02+7I3BM" Received: by mail-ej1-f54.google.com with SMTP id a640c23a62f3a-a3eb1f48fa9so202680566b.1 for ; Tue, 20 Feb 2024 01:27:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421248; x=1709026048; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=lz7fHeDd50+R3cUNoViqANc65ILW8vP9xX9CHfsnXXw=; b=02+7I3BMjRvK1eP4WZQPlFGj0nnbdApxKrW2ASAzuBs1dPCnPi4VFo8AfXAv9eMV3o GigoFtByj/6Hv6woJZbTzVfTdx4dMJsSD/yccgWO8MJ9+faDQ9M8fePEPDDTZyAShRpR /1eUgHUO4zW9FAG9Fb6DgyAq+1Vd1xGMy/1UoPvRyl9jmwd/PNWwzDdhO8jNXa6S7z7j sbAunneAhwc85GEZ2Af3cifsvcNK62fPYngFlnGRMAFiuUifSsulq19T0lZl6757bBSC MsGJuMKuPu6jbaXH+92kI3dGti47tlITXf0/YSHNJt5kh5surs345XegKvXkjML8zYdw z4Qw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421248; x=1709026048; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=lz7fHeDd50+R3cUNoViqANc65ILW8vP9xX9CHfsnXXw=; b=A0mkONm1GJvQswjYrZE8ZrgaWucLpYgYe45XyAQ36D/Bnwjq1Y4L9919AeV0aYQ/TB s6Ej0IKnmUnU07V7Bk39kOjT/48LJdLExb4gdSAiuV6PH+XFsBZCo4YCUBCijhZgCUCz 1HjCO7LiVt+n27E8LZ/iFpF/GjRSTmcwiQLUWd7TaxSD9O1fA4Nfg1d0uN4XAx1iLMuf SNLNKSO/xHpXRawhfF0njw2oVUm7ZkHUxF/G06jblSsINKtWzSf9nlZUOFi1ksXys9d8 knRnIa6rRJ/Sv1rjj3HqsO3F3l5jaR98lGz782ONtc5b2U4zNeN41RfxZCxyo8klznzN HSgg== X-Forwarded-Encrypted: i=1; AJvYcCWzq4Qc/hFC5/r5CllCtE7iJ29uht0agAkp2sHOJeuJwxGZefa2IyhR0Lxup556gJRQqBdWcPuSAUHQeFVl+ee7muDAADc4ToyNfsAn0Q== X-Gm-Message-State: AOJu0YxduYyZDQSupJh+mn0p1oNwujoV0sCO53Az7iWcVLD/Xd2WBOQa VHaB6HIYL5izitXr0t8z9FUicf/nNZC42A0m5XDl91tUNTcobh7vvPA3lY/GNw== X-Google-Smtp-Source: AGHT+IGkr0X0lMpAqjaEt3s6FP4GjyxMCgxuHHrR+OCBptQEv3+5AjDUsbbybmJOtGRSNWz+EdK0jg== X-Received: by 2002:a17:906:a19a:b0:a3d:2a52:380f with SMTP id s26-20020a170906a19a00b00a3d2a52380fmr9595331ejy.72.1708421247549; Tue, 20 Feb 2024 01:27:27 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id jj12-20020a170907984c00b00a3e64bcd2c1sm2531070ejc.142.2024.02.20.01.27.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:27:27 -0800 (PST) Date: Tue, 20 Feb 2024 09:27:23 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 01/11] bpf: make bpf_d_path() helper use probe-read semantics Message-ID: <5643840bd57d0c2345635552ae228dfb2ed3428c.1708377880.git.mattbobrowski@google.com> References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: There has now been several reported instances [0, 1, 2] where the usage of the BPF helper bpf_d_path() has led to some form of memory corruption issue. The fundamental reason behind why we repeatedly see bpf_d_path() being susceptible to such memory corruption issues is because it only enforces ARG_PTR_TO_BTF_ID constraints onto it's struct path argument. This essentially means that it only requires an in-kernel pointer of type struct path to be provided to it. Depending on the underlying context and where the supplied struct path was obtained from and when, depends on whether the struct path is fully intact or not when calling bpf_d_path(). It's certainly possible to call bpf_d_path() and subsequently d_path() from contexts where the supplied struct path to bpf_d_path() has already started being torn down by __fput() and such. An example of this is perfectly illustrated in [0]. Moving forward, we simply cannot enforce KF_TRUSTED_ARGS semantics onto struct path of bpf_d_path(), as this approach would presumably lead to some pretty wide scale and highly undesirable BPF program breakage. To avoid breaking any pre-existing BPF program that is dependent on bpf_d_path(), I propose that we take a different path and re-implement an incredibly minimalistic and bare bone version of d_path() which is entirely backed by kernel probe-read semantics. IOW, a version of d_path() that is backed by copy_from_kernel_nofault(). This ensures that any reads performed against the supplied struct path to bpf_d_path() which may end up faulting for whatever reason end up being gracefully handled and fixed up. The caveats with such an approach is that we can't fully uphold all of d_path()'s path resolution capabilities. Resolving a path which is comprised of a dentry that make use of dynamic names via isn't possible as we can't enforce probe-read semantics onto indirect function calls performed via d_op as they're implementation dependent. For such cases, we just return -EOPNOTSUPP. This might be a little surprising to some users, especially those that are interested in resolving paths that involve a dentry that resides on some non-mountable pseudo-filesystem, being pipefs/sockfs/nsfs, but it's arguably better than enforcing KF_TRUSTED_ARGS onto bpf_d_path() and causing an unnecessary shemozzle for users. Additionally, we don't make use of all the locking semantics, or handle all the erroneous cases in which d_path() naturally would. This is fine however, as we're only looking to provide users with a rather acceptable version of a reconstructed path, whilst they eventually migrate over to the trusted bpf_path_d_path() BPF kfunc variant. Note that the selftests that go with this change to bpf_d_path() have been purposely split out into a completely separate patch. This is so that the reviewers attention is not torn by noise and can remain focused on reviewing the implementation details contained within this patch. [0] https://lore.kernel.org/bpf/CAG48ez0ppjcT=QxU-jtCUfb5xQb3mLr=5FcwddF_VKfEBPs_Dg@mail.gmail.com/ [1] https://lore.kernel.org/bpf/20230606181714.532998-1-jolsa@kernel.org/ [2] https://lore.kernel.org/bpf/20220219113744.1852259-1-memxor@gmail.com/ Signed-off-by: Matt Bobrowski --- fs/Makefile | 6 +- fs/probe_read_d_path.c | 150 ++++++++++++++++++++++++++++++ include/linux/probe_read_d_path.h | 13 +++ kernel/trace/bpf_trace.c | 13 ++- 4 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 fs/probe_read_d_path.c create mode 100644 include/linux/probe_read_d_path.h diff --git a/fs/Makefile b/fs/Makefile index c09016257f05..945c9c84d35d 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -4,7 +4,7 @@ # # 14 Sep 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. -# +# obj-y := open.o read_write.o file_table.o super.o \ @@ -12,7 +12,7 @@ obj-y := open.o read_write.o file_table.o super.o \ ioctl.o readdir.o select.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ - pnode.o splice.o sync.o utimes.o d_path.o \ + pnode.o splice.o sync.o utimes.o d_path.o probe_read_d_path.o \ stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \ fs_types.o fs_context.o fs_parser.o fsopen.o init.o \ kernel_read_file.o mnt_idmapping.o remap_range.o @@ -58,7 +58,7 @@ obj-$(CONFIG_CONFIGFS_FS) += configfs/ obj-y += devpts/ obj-$(CONFIG_DLM) += dlm/ - + # Do not add any filesystems before this line obj-$(CONFIG_NETFS_SUPPORT) += netfs/ obj-$(CONFIG_REISERFS_FS) += reiserfs/ diff --git a/fs/probe_read_d_path.c b/fs/probe_read_d_path.c new file mode 100644 index 000000000000..8d0db902f836 --- /dev/null +++ b/fs/probe_read_d_path.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Google LLC. + */ + +#include "asm/ptrace.h" +#include +#include +#include +#include +#include +#include + +#include "mount.h" + +#define PROBE_READ(src) \ + ({ \ + typeof(src) __r; \ + if (copy_from_kernel_nofault((void *)(&__r), (&src), \ + sizeof((__r)))) \ + memset((void *)(&__r), 0, sizeof((__r))); \ + __r; \ + }) + +static inline bool probe_read_d_unlinked(const struct dentry *dentry) +{ + return !PROBE_READ(dentry->d_hash.pprev) && + !(dentry == PROBE_READ(dentry->d_parent)); +} + +static long probe_read_prepend(const char *s, int len, char *buf, int *buflen) +{ + /* + * The supplied len that is to be copied into the buffer will result in + * an overflow. The true implementation of d_path() already returns an + * error for such overflow cases, so the semantics with regards to the + * bpf_d_path() helper returning the same error value for overflow cases + * remain the same. + */ + if (len > *buflen) + return -ENAMETOOLONG; + + /* + * The supplied string fits completely into the remaining buffer + * space. Attempt to make the copy. + */ + *buflen -= len; + buf += *buflen; + return copy_from_kernel_nofault(buf, s, len); +} + +static bool use_dname(const struct path *path) +{ + const struct dentry_operations *d_op; + char *(*d_dname)(struct dentry *, char *, int); + + d_op = PROBE_READ(path->dentry->d_op); + d_dname = PROBE_READ(d_op->d_dname); + + return d_op && d_dname && + (!(path->dentry == PROBE_READ(path->dentry->d_parent)) || + path->dentry != PROBE_READ(path->mnt->mnt_root)); +} + +char *probe_read_d_path(const struct path *path, char *buf, int buflen) +{ + int len; + long err; + struct path root; + struct mount *mnt; + struct dentry *dentry; + + dentry = path->dentry; + mnt = container_of(path->mnt, struct mount, mnt); + + /* + * We cannot back dentry->d_op->d_dname() with probe-read semantics, so + * just return an error to the caller when the supplied path contains a + * dentry component that makes use of a dynamic name. + */ + if (use_dname(path)) + return ERR_PTR(-EOPNOTSUPP); + + err = probe_read_prepend("\0", 1, buf, &buflen); + if (err) + return ERR_PTR(err); + + if (probe_read_d_unlinked(dentry)) { + err = probe_read_prepend(" (deleted)", 10, buf, &buflen); + if (err) + return ERR_PTR(err); + } + + len = buflen; + root = PROBE_READ(current->fs->root); + while (dentry != root.dentry || &mnt->mnt != root.mnt) { + struct dentry *parent; + if (dentry == PROBE_READ(mnt->mnt.mnt_root)) { + struct mount *m; + + m = PROBE_READ(mnt->mnt_parent); + if (mnt != m) { + dentry = PROBE_READ(mnt->mnt_mountpoint); + mnt = m; + continue; + } + + /* + * If we've reached the global root, then there's + * nothing we can really do but bail. + */ + break; + } + + parent = PROBE_READ(dentry->d_parent); + if (dentry == parent) { + /* + * Escaped? We return an ECANCELED error here to signify + * that we've prematurely terminated pathname + * reconstruction. We've potentially hit a root dentry + * that isn't associated with any roots from the mounted + * filesystems that we've jumped through, so it's not + * clear where we are in the VFS exactly. + */ + err = -ECANCELED; + break; + } + + err = probe_read_prepend(dentry->d_name.name, + PROBE_READ(dentry->d_name.len), buf, + &buflen); + if (err) + break; + + err = probe_read_prepend("/", 1, buf, &buflen); + if (err) + break; + dentry = parent; + } + + if (err) + return ERR_PTR(err); + + if (len == buflen) { + err = probe_read_prepend("/", 1, buf, &buflen); + if (err) + return ERR_PTR(err); + } + return buf + buflen; +} diff --git a/include/linux/probe_read_d_path.h b/include/linux/probe_read_d_path.h new file mode 100644 index 000000000000..9b3908746657 --- /dev/null +++ b/include/linux/probe_read_d_path.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Google LLC. + */ + +#ifndef _LINUX_PROBE_READ_D_PATH_H +#define _LINUX_PROBE_READ_D_PATH_H + +#include + +extern char *probe_read_d_path(const struct path *path, char *buf, int buflen); + +#endif /* _LINUX_PROBE_READ_D_PATH_H */ diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 241ddf5e3895..12dbd9cef1fa 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -923,14 +924,12 @@ BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz) if (len < 0) return len; - p = d_path(©, buf, sz); - if (IS_ERR(p)) { - len = PTR_ERR(p); - } else { - len = buf + sz - p; - memmove(buf, p, len); - } + p = probe_read_d_path(©, buf, sz); + if (IS_ERR(p)) + return PTR_ERR(p); + len = buf + sz - p; + memmove(buf, p, len); return len; } From patchwork Tue Feb 20 09:27:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563733 Received: from mail-ej1-f41.google.com (mail-ej1-f41.google.com [209.85.218.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0E0825FDC9 for ; Tue, 20 Feb 2024 09:27:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421257; cv=none; b=MqjWuA04OwieE7svelnKt8M+B6htJAb+2Cft890+IccL4VZkVIjycSA83lr8KH0h4WQKYyJnjGTi7X6/1b2/R7OiDKz42x615nwHa1JJsF51FOrqiHnBvtGZlxzLjKePSzfLeRZg790rdQe0y1Yr78UIbo+ONqJ0wP2/ouZGJxI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421257; c=relaxed/simple; bh=MNS3Wenvd3CPGUa+1nbec3ZhkxNw0IUv2scXSvBHWGU=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=hD4oN2LBF9JsE6zqzPe6FHba1Eeg2QJZU/rPzBUtoTCxwmw2OzH1po6rF3PtdYfnYzUrUseGJzoDHDbYKhPjMlulUjCtvQKnM4j8docbdyQLKnJbev6llcBI5iEUvCAqfzofovUO/co4cH+jGcEPUarwvgqQQDiXRB1EefxMWM0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=PhlLTzP2; arc=none smtp.client-ip=209.85.218.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="PhlLTzP2" Received: by mail-ej1-f41.google.com with SMTP id a640c23a62f3a-a3e87b2de41so183743066b.2 for ; Tue, 20 Feb 2024 01:27:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421254; x=1709026054; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=qUIZj7JHZQQzmuJwxcBCYLLycwgoQrzQW0HfSgl0F2M=; b=PhlLTzP2F6cx9IyZsRJ+dug7XWbpM2pDUeHK321i44qpUVqxep8ALb3u17wLemUtek c3a+OObF2cfZ6BywWuyAJcNxTdHMOnvpuVsjuwHE4mxzsqD5wVglKejHFkOYFxdiMx9S duNW/uHYdoDp58xrBsnAAHlFXkbfTfICmlWkL5UeU72bwNiuWNaed7NA+tNe5M8g94Fm dcOe1PIWAlTZXs++afMaidfSZLImu13D1UDEBb8Zd9ceQXZBM4Uflc4X0/RM+lv0NtaF 2wSjfN70Xk4daFHsv9agSHFED7r0szhMPEjheET+DFa1lqegbf5XlafDQyLtmfc6JzkY BilA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421254; x=1709026054; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=qUIZj7JHZQQzmuJwxcBCYLLycwgoQrzQW0HfSgl0F2M=; b=bhnUG8KXhIZangTqXGsoSqVO6aX8G++Lr6FogTf+ug6oS2WJVRC8A8k8/+5mcH6pJp iQSQukvXmKFqmgFU813wCV/S/pfanaV1mEsPS/4J8A3tZvHnylDxiddM9bPVtObxrEEh ZhoCL1Wr76E9wyuyTIVpa5iEhwwyG8LQagoO8VrjSpgyHWnSZas2DS0CkiFDeQ+XT0UK fM+Ri7I/N3zeaNmfBaxAhUYCCIIpjpH4V9gDNxaLZA80i3+wEfV7W+yUQgDisWX8CCmy rt9a2HHqbjat/p/Tk1FSA78d/aC6rYAFd2wvoYJGb7sbONv5tVo3JvlptaE1a9CbHOUF 6v7g== X-Forwarded-Encrypted: i=1; AJvYcCX2mC252TjV1VhhLZ5lFM4H+TlRfrUkKQp7pBw+3KjnlEJ4of7qNjfdr1LUnn/6/Uyp6jYbIP9kTyCMfnaJwCUW51AVfshoGD1aKFpg6w== X-Gm-Message-State: AOJu0Yy2nQBif2KDf3BHQFo/iFHu7sTT3dY59S1FBWbYiMfCrkWHV1u4 3v/2IMYCjBsY1VI9dGzRMYKtWRRhtpM4m3yMpwkDMbxzaG3h9NjqLMOAdQJw3w== X-Google-Smtp-Source: AGHT+IFdqEPrvw/m+2sSbOg1414dzXcYlw64hSpUftYqChu8q15/lbYfZWLZr3xxHjkOIFkPX+CszQ== X-Received: by 2002:a17:906:3d41:b0:a3d:b7e1:2670 with SMTP id q1-20020a1709063d4100b00a3db7e12670mr8275844ejf.14.1708421254341; Tue, 20 Feb 2024 01:27:34 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id r18-20020a1709060d5200b00a3d12d84cffsm3752352ejh.167.2024.02.20.01.27.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:27:33 -0800 (PST) Date: Tue, 20 Feb 2024 09:27:30 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 02/11] bpf/selftests: adjust selftests for BPF helper bpf_d_path() Message-ID: <18c7b587d43bbc7e80593bf51ea9d3eb99e47bc1.1708377880.git.mattbobrowski@google.com> References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The BPF helper bpf_d_path() has been modified such that it makes use of probe-read semantics. In turn, the behaviour of the BPF helper bpf_d_path() has slightly changed under certain circumstances, therefore needing to also adjust the backing test suite to account for this. The probe-read based d_path() implementation cannot handle dentries that have their name backed by d_op->d_dname(). For paths containing such dentries, the probe-read based implementation returns -EOPNOTSUPP, so the test suite has been updated to assert this behaviour. Signed-off-by: Matt Bobrowski --- .../testing/selftests/bpf/prog_tests/d_path.c | 84 +++++++++++++++---- .../testing/selftests/bpf/progs/test_d_path.c | 2 +- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/d_path.c b/tools/testing/selftests/bpf/prog_tests/d_path.c index ccc768592e66..d77ae1b1e6ba 100644 --- a/tools/testing/selftests/bpf/prog_tests/d_path.c +++ b/tools/testing/selftests/bpf/prog_tests/d_path.c @@ -6,7 +6,7 @@ #include #define MAX_PATH_LEN 128 -#define MAX_FILES 7 +#define MAX_FILES 8 #include "test_d_path.skel.h" #include "test_d_path_check_rdonly_mem.skel.h" @@ -25,9 +25,15 @@ static int duration; +struct want { + bool err; + long err_code; + char path[MAX_PATH_LEN]; +}; + static struct { __u32 cnt; - char paths[MAX_FILES][MAX_PATH_LEN]; + struct want want[MAX_FILES]; } src; static int set_pathname(int fd, pid_t pid) @@ -35,12 +41,12 @@ static int set_pathname(int fd, pid_t pid) char buf[MAX_PATH_LEN]; snprintf(buf, MAX_PATH_LEN, "/proc/%d/fd/%d", pid, fd); - return readlink(buf, src.paths[src.cnt++], MAX_PATH_LEN); + return readlink(buf, src.want[src.cnt++].path, MAX_PATH_LEN); } static int trigger_fstat_events(pid_t pid) { - int sockfd = -1, procfd = -1, devfd = -1; + int sockfd = -1, procfd = -1, devfd = -1, mntnsfd = -1; int localfd = -1, indicatorfd = -1; int pipefd[2] = { -1, -1 }; struct stat fileStat; @@ -49,10 +55,15 @@ static int trigger_fstat_events(pid_t pid) /* unmountable pseudo-filesystems */ if (CHECK(pipe(pipefd) < 0, "trigger", "pipe failed\n")) return ret; - /* unmountable pseudo-filesystems */ + sockfd = socket(AF_INET, SOCK_STREAM, 0); if (CHECK(sockfd < 0, "trigger", "socket failed\n")) goto out_close; + + mntnsfd = open("/proc/self/ns/mnt", O_RDONLY); + if (CHECK(mntnsfd < 0, "trigger", "mntnsfd failed")) + goto out_close; + /* mountable pseudo-filesystems */ procfd = open("/proc/self/comm", O_RDONLY); if (CHECK(procfd < 0, "trigger", "open /proc/self/comm failed\n")) @@ -69,15 +80,35 @@ static int trigger_fstat_events(pid_t pid) if (CHECK(indicatorfd < 0, "trigger", "open /tmp/ failed\n")) goto out_close; + /* + * With bpf_d_path() being backed by probe-read semantics, we cannot + * safely resolve paths that are comprised of dentries that make use of + * dynamic names. We expect to return -EOPNOTSUPP for such paths. + */ + src.want[src.cnt].err = true; + src.want[src.cnt].err_code = -EOPNOTSUPP; ret = set_pathname(pipefd[0], pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[0]\n")) goto out_close; + + src.want[src.cnt].err = true; + src.want[src.cnt].err_code = -EOPNOTSUPP; ret = set_pathname(pipefd[1], pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[1]\n")) goto out_close; + + src.want[src.cnt].err = true; + src.want[src.cnt].err_code = -EOPNOTSUPP; ret = set_pathname(sockfd, pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for socket\n")) goto out_close; + + src.want[src.cnt].err = true; + src.want[src.cnt].err_code = -EOPNOTSUPP; + ret = set_pathname(mntnsfd, pid); + if (CHECK(ret < 0, "trigger", "set_pathname failed for mntnsfd\n")) + goto out_close; + ret = set_pathname(procfd, pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for proc\n")) goto out_close; @@ -95,6 +126,7 @@ static int trigger_fstat_events(pid_t pid) fstat(pipefd[0], &fileStat); fstat(pipefd[1], &fileStat); fstat(sockfd, &fileStat); + fstat(mntnsfd, &fileStat); fstat(procfd, &fileStat); fstat(devfd, &fileStat); fstat(localfd, &fileStat); @@ -109,6 +141,7 @@ static int trigger_fstat_events(pid_t pid) close(pipefd[0]); close(pipefd[1]); close(sockfd); + close(mntnsfd); close(procfd); close(devfd); close(localfd); @@ -150,24 +183,41 @@ static void test_d_path_basic(void) goto cleanup; for (int i = 0; i < MAX_FILES; i++) { - CHECK(strncmp(src.paths[i], bss->paths_stat[i], MAX_PATH_LEN), - "check", - "failed to get stat path[%d]: %s vs %s\n", - i, src.paths[i], bss->paths_stat[i]); - CHECK(strncmp(src.paths[i], bss->paths_close[i], MAX_PATH_LEN), - "check", - "failed to get close path[%d]: %s vs %s\n", - i, src.paths[i], bss->paths_close[i]); + struct want want = src.want[i]; + + /* + * Assert that we get the correct error code from bpf_d_path() + * when the underlying path contains a dentry that is backed by + * a dynamic name. + */ + if (want.err) { + CHECK(want.err_code != bss->rets_stat[i], "check", + "failed to match stat return[%d]: got=%d, want=%ld [%s]\n", + i, bss->rets_stat[i], want.err_code, + bss->paths_stat[i]); + CHECK(want.err_code != bss->rets_close[i], "check", + "failed to match close return[%d]: got=%d, want=%ld [%s]\n", + i, bss->rets_close[i], want.err_code, + bss->paths_close[i]); + continue; + } + + CHECK(strncmp(want.path, bss->paths_stat[i], MAX_PATH_LEN), + "check", "failed to get stat path[%d]: %s vs %s\n", i, + want.path, bss->paths_stat[i]); + CHECK(strncmp(want.path, bss->paths_close[i], MAX_PATH_LEN), + "check", "failed to get close path[%d]: %s vs %s\n", i, + want.path, bss->paths_close[i]); /* The d_path helper returns size plus NUL char, hence + 1 */ CHECK(bss->rets_stat[i] != strlen(bss->paths_stat[i]) + 1, "check", - "failed to match stat return [%d]: %d vs %zd [%s]\n", - i, bss->rets_stat[i], strlen(bss->paths_stat[i]) + 1, + "failed to match stat return [%d]: %d vs %zd [%s]\n", i, + bss->rets_stat[i], strlen(bss->paths_stat[i]) + 1, bss->paths_stat[i]); CHECK(bss->rets_close[i] != strlen(bss->paths_stat[i]) + 1, "check", - "failed to match stat return [%d]: %d vs %zd [%s]\n", - i, bss->rets_close[i], strlen(bss->paths_close[i]) + 1, + "failed to match stat return [%d]: %d vs %zd [%s]\n", i, + bss->rets_close[i], strlen(bss->paths_close[i]) + 1, bss->paths_stat[i]); } diff --git a/tools/testing/selftests/bpf/progs/test_d_path.c b/tools/testing/selftests/bpf/progs/test_d_path.c index 84e1f883f97b..fc2754f166ec 100644 --- a/tools/testing/selftests/bpf/progs/test_d_path.c +++ b/tools/testing/selftests/bpf/progs/test_d_path.c @@ -5,7 +5,7 @@ #include #define MAX_PATH_LEN 128 -#define MAX_FILES 7 +#define MAX_FILES 8 pid_t my_pid = 0; __u32 cnt_stat = 0; From patchwork Tue Feb 20 09:27:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563734 Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 73EC360DC2 for ; Tue, 20 Feb 2024 09:27:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421264; cv=none; b=dTb7eehMe+N2iByzrgcJqfe0R+gtsUHQoic+K6utuHHPUcXuMxCchbYYMfFnejsUXAzHkBgS5tCVTcoq4BfWMY4tAFLJHXpkz0138otqI0jL3yUYz5wAaeVoeHrSGdH+8Qfl9DGuyRpgHiD98IfDDTlWLRiWNmYAWAywPMgV3oA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421264; c=relaxed/simple; bh=I+cErYdSLg0Qn/bGnm+p1n2X9JUNSmT0do5tne6EpyI=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=NFKtVyv1hF5y5gOdB/bOV1VDhF2lwckGK1fk8Yer4/0iZ15dCdIoWNwmApi2gfrKdL8z/bzNFVRpZiKgHaR4DCXFzJPTSCSWFhQUBMMXeh2q0KQ8aaOoaSbF76A7VrDXC7yLkKcZxoMreFVolvQ7E+rSIBni8oo5ORawC7diNqI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=eXKAvtsT; arc=none smtp.client-ip=209.85.218.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="eXKAvtsT" Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-a3d01a9a9a2so499010766b.1 for ; Tue, 20 Feb 2024 01:27:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421261; x=1709026061; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=Yos5PcM7VN/krEtPgbbzLqvu9MhyDgmtJVHiLz+77YI=; b=eXKAvtsTfT0cChu9u22g354APUtzVRduTiRJvxR9x6as1s4NS4n7/SpYnVEOv0dJPN jBcHeoP4LWqYxW0ecJzbVvQDKpz/8TeAviCbwXWioEFMS68aYPQSgl2LMWr5VDBfvIwl nlnI0UVLFLurmeaHEwCzM+cIfJ3+xZ8N/dipyOAGT16sI8bJui8feNcPteGdu4vuaBLi t6LYUp60aOXAElJET3Fr6z8dcrhA/cA52AAaUfT1PFWVhwiRwgNqg46tUUTcZmc9J8WD 45OwqFAQrt5HhuLVzq+KSC4Kdmai0jkshPu9ZRtD0JCzobrv5XajmqjRr/2IIE8eT1zm LKnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421261; x=1709026061; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Yos5PcM7VN/krEtPgbbzLqvu9MhyDgmtJVHiLz+77YI=; b=EVJOshalpnEB8EgeCA77b/UnswpWv0BhvsqzMHSld9wWrLizqlxegyMI06MPNkHaZ2 w1EuhCTDaOYG4xKO94Cwnz/9H5GyAj6Ko1i0KQSXOGQXtE5CzQqaVBqiPs5ByGk1NiZS fZimByksjMLLjOpmRj17HrNLXBCm538ySq+B/YxlFWWsvNZQwUCtE3jgty8YASN9nYpv V0z3ESANJNWr4qBenz7iDn3eo28Al3wQjCb1is66wDmAZvUPQIkwE/pmZUjlpS6KToaJ MpnEG+mpYWoHvmAckcmg+OXbDOZEJLyWZaWHSNhvWK0Xkzaie8NzBdm68hnZyxA9EGrN wZkA== X-Forwarded-Encrypted: i=1; AJvYcCVjfL1IE1j/UDC6D9DnwNqGf7Fm9iUN937QZUKYPgf8Xobxtqys6dvt2z2AX3tIHz/Xw66fCt2G5sWLizFGAUHVtzAQ+h2x1FNt5RXLoQ== X-Gm-Message-State: AOJu0YwNcXfVEwhQ7+dXXGaAk07SF6JDF/2ruS+MeGRGJtb7Z/DzH8Ik zWvoU3zOMwn7Xah8PdiDDwBeJ9UbAm1OJt2YGjzo/Eu8V3qvsTcYOotvJYIlcg== X-Google-Smtp-Source: AGHT+IGUQRG8YW9LkcPuNFdTNNz7X5KvC++SADFb6lY6crmb2y8Eu/FZHEmtLzaGcgZ/g/7aBkRn0A== X-Received: by 2002:a17:906:ac5:b0:a3e:ab9f:4129 with SMTP id z5-20020a1709060ac500b00a3eab9f4129mr2833910ejf.75.1708421260817; Tue, 20 Feb 2024 01:27:40 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id i18-20020a1709063c5200b00a3d5d8ff745sm3800284ejg.144.2024.02.20.01.27.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:27:40 -0800 (PST) Date: Tue, 20 Feb 2024 09:27:36 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 03/11] bpf: rename fs_kfunc_set_ids to lsm_kfunc_set_ids Message-ID: References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: fs_kfunc_set_ids is rather specific to a single kfunc at the moment. Rename it to something a little more generic such that other future kfuncs restricted to BPF LSM programs can reside in the same set and make use of the same filter. Signed-off-by: Matt Bobrowski --- kernel/trace/bpf_trace.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 12dbd9cef1fa..c45c8d42316c 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1434,7 +1434,7 @@ static int __init bpf_key_sig_kfuncs_init(void) late_initcall(bpf_key_sig_kfuncs_init); #endif /* CONFIG_KEYS */ -/* filesystem kfuncs */ +/* A set of kfuncs that may only be called from BPF LSM programs. */ __bpf_kfunc_start_defs(); /** @@ -1474,31 +1474,33 @@ __bpf_kfunc int bpf_get_file_xattr(struct file *file, const char *name__str, __bpf_kfunc_end_defs(); -BTF_KFUNCS_START(fs_kfunc_set_ids) +BTF_KFUNCS_START(lsm_kfunc_set_ids) BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS) -BTF_KFUNCS_END(fs_kfunc_set_ids) +BTF_KFUNCS_END(lsm_kfunc_set_ids) -static int bpf_get_file_xattr_filter(const struct bpf_prog *prog, u32 kfunc_id) +static int bpf_lsm_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id) { - if (!btf_id_set8_contains(&fs_kfunc_set_ids, kfunc_id)) + if (!btf_id_set8_contains(&lsm_kfunc_set_ids, kfunc_id)) return 0; - /* Only allow to attach from LSM hooks, to avoid recursion */ + /* To avoid recursion, only permit kfuncs included within + * lsm_kfunc_set_ids to be called from BPF LSM programs. + */ return prog->type != BPF_PROG_TYPE_LSM ? -EACCES : 0; } -static const struct btf_kfunc_id_set bpf_fs_kfunc_set = { +static const struct btf_kfunc_id_set bpf_lsm_kfunc_set = { .owner = THIS_MODULE, - .set = &fs_kfunc_set_ids, - .filter = bpf_get_file_xattr_filter, + .set = &lsm_kfunc_set_ids, + .filter = bpf_lsm_kfunc_filter, }; -static int __init bpf_fs_kfuncs_init(void) +static int __init bpf_lsm_kfuncs_init(void) { - return register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fs_kfunc_set); + return register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_lsm_kfunc_set); } -late_initcall(bpf_fs_kfuncs_init); +late_initcall(bpf_lsm_kfuncs_init); static const struct bpf_func_proto * bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) From patchwork Tue Feb 20 09:27:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563735 Received: from mail-ed1-f41.google.com (mail-ed1-f41.google.com [209.85.208.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 455DA5FDD3 for ; Tue, 20 Feb 2024 09:27:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421278; cv=none; b=EzuqNQvVNVyrpHFc0MFGfBQoXlzH+Vp68jRVbDVDVMJmV/XaSBHLM+zeQ3I4sjr14tSSbmh7NjDFHlvBlz0cNpbpUCgoNrXuV1d8Cbt3A/42FKQ1I6U6eCTVH2YlkbnOj9vOqjbEgeLHBHb5SoiJYBgV4feXOTimynvw/IYUs4Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421278; c=relaxed/simple; bh=OZioy8AfLsmSlw0w0r3twrLcp1c+FgadOLiPu1XclVM=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=fxZZ33MWjGWhOBMBsPNi2sv0sSX20GXSAapgU/lYVI2K9m3UgZ80zDHpgnDcRJtBGBfqNNQwXo3lr+RAXxj7Xp3K24xatn8f5AU1zrD4oilalP9OgUd6CjlB4UA7Ide4bR0xVLC2+VbL/MaNHX3HDZfLa503FeI3fqqg+vymaH0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=hVNiM5T3; arc=none smtp.client-ip=209.85.208.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="hVNiM5T3" Received: by mail-ed1-f41.google.com with SMTP id 4fb4d7f45d1cf-55a5e7fa471so5354541a12.1 for ; Tue, 20 Feb 2024 01:27:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421274; x=1709026074; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=mXZ+DN3CcnefV4u4W5SMOCurbndJVv4wj08ijEsPqwU=; b=hVNiM5T3tLpYBBtr1KxqFFMwK/ZwjrMR9qQdzLR4N30JahneU+1pE/JmpVSKADItr7 9bUksLderTjak8+ldH8OQfhWVct35aDklE1j2HgvHR4XsvBNA3EusxAmn/vjtQrE02Xt 3j/bwzQBcY5skH07yrvBRKEveE5UnEpc1zX9laQSjeVZXz+iyGKjKRUv/KJJcIAPcZQj a30j3H3O3u3q8GQ/J2UNDphfZHw8bSSlWxYM+iVKEFdBdloEJjD6sk3Aa6ZLshmKG5xL m26jltMOkP39eqMGiyIZF4zpnBlFXNVprxWBgDwUGteHhS2w2ue0A69uvM4/igxW+dkP DHWg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421274; x=1709026074; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=mXZ+DN3CcnefV4u4W5SMOCurbndJVv4wj08ijEsPqwU=; b=Vk7+lVO01Sms3DmFkyJymOFyJNx+mLGKMppV6aIRMv3NrmBVDzdN8Np7zZDMk2061f hEyjcmsr2jrmi/ZXc7OeKgjN/YusslEHOs2bztna9Oe3zrk9dDSqgzZnx8kTzgPjMuL5 pymxVkamjCv7NqEf++8w8xlvwuvICwmpVdSN8A6z1ul4wnAMakGFIGYNsYT06cy3fL96 WrZ2PvaLLmTsYR5XSid6Bf06Wa5jGBadxohbmfJ+RFh6fBU5yrw45FvgaCuDJmXDKi7r MvKbZwPHlsBqHz1HOZrGP0tJEW44yRGmMobuBg8GohnKMv65QycN+WbgCAw3l5PncdW6 tdrQ== X-Forwarded-Encrypted: i=1; AJvYcCWiGt+eIpm1eM80vMWZt8aoCiyeDu73+1lfEao8IbwYSx6wou6Aitxm6Z6+LX76Qp6WgvR4B9Ppi18qqJhiOPwj1TeKhpdG+JypIQvdEQ== X-Gm-Message-State: AOJu0Yw0Pe5WTK4zGeQ8qME1Q02Co1VrHQJ7sAEXHPqZ0uNMRAHMuivX BtblKtmLQHszZ1hdIhvEbrYl0spKom+p7R/Ugcf7GYG86Lrc6cOYeFiO5evb1Q== X-Google-Smtp-Source: AGHT+IHkFYDXFwT6cS1Y6ESD1QzbPdMU6iw9dKRUM8cEUuLz0d+G3e4wiXXNVR3TuLLPAbfiZ6GnYg== X-Received: by 2002:a05:6402:40c4:b0:563:b7b4:a30e with SMTP id z4-20020a05640240c400b00563b7b4a30emr11299389edb.3.1708421274505; Tue, 20 Feb 2024 01:27:54 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id b2-20020aa7dc02000000b00564cb5a3c7esm338161edu.81.2024.02.20.01.27.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:27:54 -0800 (PST) Date: Tue, 20 Feb 2024 09:27:50 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 04/11] bpf: add new acquire/release BPF kfuncs for mm_struct Message-ID: References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: A BPF LSM program at times will introspect a mm_struct that is associated with a task_struct. In order to perform this reliably, we need introduce a new set of BPF kfuncs that have the ability to acquire and release references on a mm_struct. The following BPF kfuncs have been added in order to support this capability: struct mm_struct *bpf_task_mm_grab(struct task_struct *task); void bpf_mm_drop(struct mm_struct *mm); These newly added mm_struct based BPF kfuncs are simple wrappers around the mmgrab() and mmdrop() in-kernel helpers. Both mmgrab() and mmdrop() are used in favour of their somewhat similar counterparts mmget() and mmput() as they're considered to be the more lightweight variants in comparison i.e. they don't pin the associated address space. Signed-off-by: Matt Bobrowski --- kernel/trace/bpf_trace.c | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index c45c8d42316c..d1d29452dd0c 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1472,10 +1472,53 @@ __bpf_kfunc int bpf_get_file_xattr(struct file *file, const char *name__str, return __vfs_getxattr(dentry, dentry->d_inode, name__str, value, value_len); } +/** + * bpf_task_mm_grab - get a reference on the mm_struct associated with the + * supplied task_struct + * @task: task_struct of which the mm_struct is to be referenced + * + * Grab a reference on the mm_struct associated with the supplied *task*. This + * kfunc will return NULL for threads that do not possess a valid mm_struct, for + * example those that are flagged as PF_KTHREAD. A reference on a mm_struct + * pointer acquired by this kfunc must be released using bpf_mm_drop(). + * + * This helper only pins the underlying mm_struct and not necessarily the + * address space that is associated with the referenced mm_struct that is + * returned from this kfunc. This kfunc internally calls mmgrab(). + * + * Return: A referenced pointer to the mm_struct associated with the supplied + * *task*, or NULL. + */ +__bpf_kfunc struct mm_struct *bpf_task_mm_grab(struct task_struct *task) +{ + struct mm_struct *mm; + + task_lock(task); + mm = task->mm; + if (likely(mm)) + mmgrab(mm); + task_unlock(task); + + return mm; +} + +/** + * bpf_mm_drop - put the reference on the supplied mm_struct + * @mm: mm_struct of which to put the reference on + * + * Put the reference on the supplied *mm*. This kfunc internally calls mmdrop(). + */ +__bpf_kfunc void bpf_mm_drop(struct mm_struct *mm) +{ + mmdrop(mm); +} + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(lsm_kfunc_set_ids) BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS) +BTF_ID_FLAGS(func, bpf_task_mm_grab, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL); +BTF_ID_FLAGS(func, bpf_mm_drop, KF_RELEASE); BTF_KFUNCS_END(lsm_kfunc_set_ids) static int bpf_lsm_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id) From patchwork Tue Feb 20 09:27:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563736 Received: from mail-ej1-f42.google.com (mail-ej1-f42.google.com [209.85.218.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B6C3B5FDB2 for ; Tue, 20 Feb 2024 09:28:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421284; cv=none; b=FvFdljCR38RtBkTf/FzaeJwkCenOlmH6cDx86NDyDf/gvmVteyeFZwTsr3kl//dSNyyeYYNvT9lu7PC5ldeDl7wiG0cIVyxgwJpR/8Sm+Kmu6Xjl223hHa8Wte2fWGGISLF5AfE74C+9pG4MNfuTy/i55A64U/eh0MIbRc+eX1Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421284; c=relaxed/simple; bh=xyujBvXum3UlmVDv38rdAkOo5btSybwxbuNuxnw9+8s=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=ER0CtMDqjhEd1Uf+qTPDzckRwVJlI0Fj594u+Rn+875nve8pxIV+5rh9a+3ZnDBqFm6MnnRw5+bkio+CbULmUGEWxWQ8vEZckA3Z39YSllk0bCyPgD2HuHzzbt+B38W5PHqTTjz/6gNEH8cMsIO1lYaCFwdetke0kiWosc7V+iI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=SoEGGpT/; arc=none smtp.client-ip=209.85.218.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="SoEGGpT/" Received: by mail-ej1-f42.google.com with SMTP id a640c23a62f3a-a3e891b5e4eso206625666b.0 for ; Tue, 20 Feb 2024 01:28:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421281; x=1709026081; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=T8XADQWdbtL6TzlHk6jI8Rohfxav5CYgO71BwjhKPiQ=; b=SoEGGpT/SDbQKrP4MR3A3E9JNwSzXbeoyAObgXnzpYupTk6I9RTUnd84gwGmkOcxWR CyLdt8u+cHJmV35uk70NnCigfzAKOuPUlFhgPndNSIuYEuHNXgsZnr9e0u9D3B3vedHN T4bxOnWDQCOeBzi+WkOldaIzlaOP/Cy+ZnHPSmEy1WAkILVFjG3rKxUXBGHSvZfYIXyV CVYQI8StCjTTLRmNAGhw53ylj2K/Z7YtjtAoPcTMGlojKrE6iWRsSLZqwIoAdNiMFkKF NPpuf52YMPdLEJcIBXU790H9zwxXSDFrlYnKTwikI/JPej0x+YCl+ARLuqe7uQxtYJcq 0oLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421281; x=1709026081; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=T8XADQWdbtL6TzlHk6jI8Rohfxav5CYgO71BwjhKPiQ=; b=XKJvtnuCIifogAaYUlm/klGc5PD0WbB6SacfyEwJ16DmTYFWXcQ8p8SwTIOaLmctLM 12+oFfqaZKrJ2+Ik5DYV48wxcVxMuZNC1UX97ac5Q1hBt73ICtzvyqNeJyaLV3D9XdTH WZuyAkAKfAv1Z10c1jJwv3KT6rvWuHLCDhFhhr/Bn4e4meTDuNPeOFNpHu0ebTFEX7eM ITqG/PatKaeOxJHObu5d6RVd7jvHUWj1xyj0eU2HMKfguAm+16RUv9m3q0Bb74ywZMPX kt2leXuSc7NmeJ673+bg7TY/pGSkJo0SCcFk6YDexBTxnRLMkUzwUbRRVWEXUZ10ENQR gBqg== X-Forwarded-Encrypted: i=1; AJvYcCU5+DdoelA1hj8DpCW3jrxlL5F5nV+CB++k8ef7c2Gu3cDlv0DAeIUX6RMOEfdZAG5/atcc0iXaifx/66nvl/by3PMAZICKqtSxRs7tHQ== X-Gm-Message-State: AOJu0YwnM7MKeiWca1Co+EYmtnPi4I/1+9F6REO/5NTc396Kmer9c/dM i6RWb3yOa9Bh7PGIrINbRZPLZqzCtHWIx+8ofDzsLbfYsqnamTCXE4Utb0KSHw== X-Google-Smtp-Source: AGHT+IG6DBO9pTBCpfeSrUfztxUsQ8peP2QTW/fPaF8CQmyYXocw8drxpjYga4ytiZkuVZEVMSE2Fg== X-Received: by 2002:a17:906:5297:b0:a3d:de7f:2827 with SMTP id c23-20020a170906529700b00a3dde7f2827mr6505802ejm.14.1708421281034; Tue, 20 Feb 2024 01:28:01 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id gc24-20020a170906c8d800b00a3e4d2d99adsm2870810ejb.219.2024.02.20.01.28.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:28:00 -0800 (PST) Date: Tue, 20 Feb 2024 09:27:56 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 05/11] bpf/selftests: add selftests for mm_struct acquire/release BPF kfuncs Message-ID: <2f5099cd6b2ec1594c1215f15f7a484e4989315e.1708377880.git.mattbobrowski@google.com> References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add a new mm_kfunc test suite that is responsible for verifying the behaviour of the newly added mm_struct based BPF kfuncs. As of now, these selftests cover the operability of the following: struct mm_struct *bpf_task_mm_grab(struct task_struct *task); void bpf_mm_drop(struct mm_struct *mm); Signed-off-by: Matt Bobrowski --- .../selftests/bpf/prog_tests/mm_kfunc.c | 48 ++++++++ .../selftests/bpf/progs/mm_kfunc_common.h | 19 ++++ .../selftests/bpf/progs/mm_kfunc_failure.c | 103 ++++++++++++++++++ .../selftests/bpf/progs/mm_kfunc_success.c | 30 +++++ 4 files changed, 200 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/mm_kfunc.c create mode 100644 tools/testing/selftests/bpf/progs/mm_kfunc_common.h create mode 100644 tools/testing/selftests/bpf/progs/mm_kfunc_failure.c create mode 100644 tools/testing/selftests/bpf/progs/mm_kfunc_success.c diff --git a/tools/testing/selftests/bpf/prog_tests/mm_kfunc.c b/tools/testing/selftests/bpf/prog_tests/mm_kfunc.c new file mode 100644 index 000000000000..aece5c25486d --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/mm_kfunc.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#define _GNU_SOURCE +#include + +#include "mm_kfunc_failure.skel.h" +#include "mm_kfunc_success.skel.h" + +static void run_test(const char *prog_name) +{ + struct bpf_link *link; + struct bpf_program *prog; + struct mm_kfunc_success *skel; + + skel = mm_kfunc_success__open_and_load(); + if (!ASSERT_OK_PTR(skel, "mm_kfunc_success__open_and_load")) + return; + + link = NULL; + prog = bpf_object__find_program_by_name(skel->obj, prog_name); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) + goto cleanup; + + link = bpf_program__attach(prog); + ASSERT_OK_PTR(link, "bpf_program__attach"); +cleanup: + bpf_link__destroy(link); + mm_kfunc_success__destroy(skel); +} + +static const char * const success_tests[] = { + "task_mm_grab_drop_from_argument", + "task_mm_acquire_release_from_current", +}; + +void test_mm_kfunc(void) +{ + int i = 0; + + for (; i < ARRAY_SIZE(success_tests); i++) { + if (!test__start_subtest(success_tests[i])) + continue; + run_test(success_tests[i]); + } + + RUN_TESTS(mm_kfunc_failure); +} diff --git a/tools/testing/selftests/bpf/progs/mm_kfunc_common.h b/tools/testing/selftests/bpf/progs/mm_kfunc_common.h new file mode 100644 index 000000000000..043d74d4148b --- /dev/null +++ b/tools/testing/selftests/bpf/progs/mm_kfunc_common.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#ifndef _MM_KFUNC_COMMON_H +#define _MM_KFUNC_COMMON_H + +#include +#include +#include +#include + +#include "bpf_misc.h" + +struct mm_struct *bpf_task_mm_grab(struct task_struct *task) __ksym; +void bpf_mm_drop(struct mm_struct *mm) __ksym; + +char _license[] SEC("license") = "GPL"; + +#endif /* _MM_KFUNC_COMMON_H */ diff --git a/tools/testing/selftests/bpf/progs/mm_kfunc_failure.c b/tools/testing/selftests/bpf/progs/mm_kfunc_failure.c new file mode 100644 index 000000000000..d818dfcab20e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/mm_kfunc_failure.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#include "mm_kfunc_common.h" + +SEC("lsm.s/file_open") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +int BPF_PROG(task_mm_grab_null_kfunc) +{ + struct mm_struct *acquired; + + /* Can't pass a NULL pointer to bpf_task_mm_grab(). */ + acquired = bpf_task_mm_grab(NULL); + if (!acquired) + return 0; + bpf_mm_drop(acquired); + + return 0; +} + +SEC("lsm/task_free") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(task_mm_grab_from_lsm_task_free_kfunc, struct task_struct *task) +{ + struct mm_struct *acquired; + + /* The task_struct supplied to this LSM hook isn't trusted. */ + acquired = bpf_task_mm_grab(task); + if (!acquired) + return 0; + bpf_mm_drop(acquired); + + return 0; +} + +SEC("lsm.s/task_alloc") +__failure __msg("arg#0 pointer type STRUCT task_struct must point") +int BPF_PROG(task_mm_grab_fp_kfunc, struct task_struct *task, u64 clone_flags) +{ + struct task_struct *fp; + struct mm_struct *acquired; + + fp = (struct task_struct *)&clone_flags; + /* Can't pass random frame pointer to bpf_task_mm_grab(). */ + acquired = bpf_task_mm_grab(fp); + if (!acquired) + return 0; + bpf_mm_drop(acquired); + + return 0; +} + +SEC("lsm.s/task_alloc") +__failure __msg("Unreleased reference") +int BPF_PROG(task_mm_grab_unreleased_kfunc, struct task_struct *task) +{ + struct mm_struct *acquired; + + acquired = bpf_task_mm_grab(task); + __sink(acquired); + + /* Acquired but never released. */ + return 0; +} + +SEC("lsm.s/task_alloc") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(task_mm_drop_untrusted_kfunc, struct task_struct *task) +{ + struct mm_struct *acquired; + + /* task->mm from struct task_struct yields an untrusted pointer. */ + acquired = task->mm; + if (!acquired) + return 0; + bpf_mm_drop(acquired); + + return 0; +} + +SEC("lsm/vm_enough_memory") +__failure __msg("release kernel function bpf_mm_drop expects") +int BPF_PROG(mm_drop_unacquired_kfunc, struct mm_struct *mm) +{ + /* Can't release an unacquired pointer. */ + bpf_mm_drop(mm); + + return 0; +} + +SEC("lsm/vm_enough_memory") +__failure __msg("arg#0 pointer type STRUCT mm_struct must point") +int BPF_PROG(mm_drop_fp_kfunc, struct mm_struct *mm, long pages) +{ + struct mm_struct *fp; + + fp = (struct mm_struct *)&pages; + + /* Can't release random frame pointer. */ + bpf_mm_drop(fp); + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/mm_kfunc_success.c b/tools/testing/selftests/bpf/progs/mm_kfunc_success.c new file mode 100644 index 000000000000..5400abd2ee2d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/mm_kfunc_success.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#include "mm_kfunc_common.h" + +SEC("lsm.s/task_alloc") +int BPF_PROG(task_mm_grab_drop_from_argument, struct task_struct *task) +{ + struct mm_struct *acquired; + + acquired = bpf_task_mm_grab(task); + if (!acquired) + return 0; + bpf_mm_drop(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +int BPF_PROG(task_mm_acquire_release_from_current) +{ + struct mm_struct *acquired; + + acquired = bpf_task_mm_grab(bpf_get_current_task_btf()); + if (!acquired) + return 0; + bpf_mm_drop(acquired); + + return 0; +} From patchwork Tue Feb 20 09:28:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563737 Received: from mail-ej1-f53.google.com (mail-ej1-f53.google.com [209.85.218.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C56235FDCC for ; Tue, 20 Feb 2024 09:28:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421291; cv=none; b=nPi1aN+lSZpN5BewTW46CRLlpevTFkIBbjwow7xwYabQmbRx6ByKQVqPatPBi5G0pVYsxSr5gGwZUywTZfS7TBVHrzMJTO0gH3blp6vPBQNPvX0FmK1ZMXzMNcjR9sNVEqM/7ZkTGsHtHvMGOsdL6hGUD7mMBRfKOO8fLEg2MEc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421291; c=relaxed/simple; bh=m3Sucw8QzaWz8TlW7E5NBXxd2VvBAO6oCXEQxTpnqy0=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=KwFz0AYSYKqQ1btk4sSt2NP4bYAyd9vP4v65/vcpzzMAY1wJ2JaDIZq8/iRaURJrhOJtxu39hv9zrzulnZwHlRiKsud5OwuVHdAjavwNknKtexn9offwdJb6U15n3qBTJZHfjU1giZ9oqowxU7Fp4c+xbWv3dZ+z6bW8KqklK9M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=KuFLbdM7; arc=none smtp.client-ip=209.85.218.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="KuFLbdM7" Received: by mail-ej1-f53.google.com with SMTP id a640c23a62f3a-a3eafbcb1c5so183197866b.0 for ; Tue, 20 Feb 2024 01:28:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421288; x=1709026088; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=67zqLp2NujpZSzgMSsWNOorMz98+x6ajQiomKeMyjqI=; b=KuFLbdM7OB3YQcN2Zj8Z8NoEYHuwMpUlG2aQAHTVg5iTSOoN7FQcPwmrDUfbuL5oZ2 PoaLtXL8LZ20pDPl6XaSWdefR1W9lr+KKxQ/k9D+wVP0QtpTkjYvj5SW2tqgJdJ0pH1b KK/RuHqXgUN+zUJB48A9fw/Se0NUhtHCyoFNXxGa2npNTP6e+X9AmWFGQfhZPDoMhz2H vqShghL+q1akr8i50eXlmzCYl3MUX6/E74VvXNdB2NEjuMdOKJIzw3Iw7QimbppMolUF ZAkrT8Jpy6H+bA3bD9fI71b0te4p2UtDNvdcgOoWpQiDasMIvGIQQQ0zVS4qx0+sh/X0 NLDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421288; x=1709026088; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=67zqLp2NujpZSzgMSsWNOorMz98+x6ajQiomKeMyjqI=; b=hanJOw+706DSRAZUfGkg2SgpqEDJigM/W7qCQRqP9HbjqSwbrvk2sKTjT3kho/ARGc Sld4/RRTqkIG+mu3tcWnvAT+pwvajhtUAyxh1EM0DJuIKEXLFHRfiXGNJGA91jOhntVz slJjOPYVNMDEomjzofl97xKX3RF7NtfATZ/34RjAj+H4pWmyAOf7HwdIkj6cs1+oAEQ2 EupjjQw7wm5is8ia15hBR8Ivo9lS1ULdwfzta/CoqeU5H49EHvAhmMwYizgmb3ddsWkW wNXZtni4y68uKgFlLFoyU1vIXxZ1FGO13K5onUYTUwqcML6Y42MPKo2BfpL3TeTr12A+ aEZg== X-Forwarded-Encrypted: i=1; AJvYcCUEgAZyD6CxA7bWqSe12Ul/J7WYqJ15id66uTK3p9eiUQPm5NZFlDJQVeC8zhlXxLOPx3p7n5JR7FG6rCvDInJoEEcN+9CnH2Dnt2jVtQ== X-Gm-Message-State: AOJu0Yyzi2/ZMG4/8SA7UpZRLUMjQMqK3El17l9wEOab4KF2X4xL8LEh RHH9yNzZt29mB98GqGZ5CLDXndRl0pWkxxXjHez7W/E4oGI5Vj60DSCZWVlznA== X-Google-Smtp-Source: AGHT+IFq7qmlWCK24e4E6KTGZnpAt6adAuskCSHyttRxhx9iO9yWyKJ9cRUIq+6/bnV17X5RcOQRwQ== X-Received: by 2002:a17:906:528d:b0:a3e:cab2:f776 with SMTP id c13-20020a170906528d00b00a3ecab2f776mr2895034ejm.15.1708421287989; Tue, 20 Feb 2024 01:28:07 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id vw15-20020a170907a70f00b00a3cf7711d40sm3789110ejc.131.2024.02.20.01.28.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:28:07 -0800 (PST) Date: Tue, 20 Feb 2024 09:28:03 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 06/11] bpf: add new acquire/release based BPF kfuncs for exe_file Message-ID: References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: It's common for BPF LSM programs to perform the following struct walk current->mm->exe_file and subsequently operate on fields of the backing struct file. At times, some of these operations involve passing a exe_file's field on to BPF helpers and such i.e. bpf_d_path(¤t->mm->exe_file->f_path). However, doing this isn't necessarily always reliable as the backing struct file that exe_file is pointing may be in the midst of being torn down and handing anything contained within this file to BPF helpers and such can lead to memory corruption issues [0]. To alleviate possibly operating on semi-torn down instances of current->mm->exe_file we introduce a set of BPF kfuncs that will allow BPF LSM program to reliably acquire a reference on a current->mm->exe_file. The following new BPF kfuncs have been added: struct file *bpf_get_task_exe_file(struct task_struct *task); struct file *bpf_get_mm_exe_file(struct mm_struct *mm); void bpf_put_file(struct file *f); Internally, these new BPF kfuncs simply call the pre-existing in-kernel functions get_task_exe_file(), get_mm_exe_file(), and fput() accordingly. Note that we explicitly do not rely on the use of very low-level in-kernel functions like get_file_rcu() and get_file_active() to acquire a reference on current->mm->exe_file and such. This is super subtle code and we probably want to avoid exposing any such subtleties to BPF in the form of BPF kfuncs. Additionally, the usage of a double pointer i.e. struct file **, isn't something that the BPF verifier currently recognizes nor has any intention to recognize for the foreseeable future. [0] https://lore.kernel.org/bpf/CAG48ez0ppjcT=QxU-jtCUfb5xQb3mLr=5FcwddF_VKfEBPs_Dg@mail.gmail.com/ Signed-off-by: Matt Bobrowski --- kernel/trace/bpf_trace.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index d1d29452dd0c..fbb252ad1d40 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1513,12 +1513,61 @@ __bpf_kfunc void bpf_mm_drop(struct mm_struct *mm) mmdrop(mm); } +/** + * bpf_get_task_exe_file - get a reference on a mm's exe_file for the supplied + * task_struct + * @task: task_struct of which the mm's exe_file to get a reference on + * + * Get a reference on a mm's exe_file that is associated with the supplied + * *task*. A reference on a file pointer acquired using this kfunc must be + * released using bpf_put_file(). + * + * Return: A referenced file pointer to the supplied *task* mm's exe_file, or + * NULL. + */ +__bpf_kfunc struct file *bpf_get_task_exe_file(struct task_struct *task) +{ + return get_task_exe_file(task); +} + +/** + * bpf_get_mm_exe_file - get a reference on the exe_file for the supplied + * mm_struct. + * @mm: mm_struct of which the exe_file to get a reference on + * + * Get a reference on the supplued *mm* exe_file. A reference on a file pointer + * acquired using this kfunc must be released using bpf_put_file(). + * + * Return: A referenced file pointer to the exe_file for the supplied *mm*, or + * NULL. + */ +__bpf_kfunc struct file *bpf_get_mm_exe_file(struct mm_struct *mm) +{ + return get_mm_exe_file(mm); +} + +/** + * bpf_put_file - put the reference on the supplied file + * @f: file of which to put a reference on + * + * Put a reference on the supplied *f*. + */ +__bpf_kfunc void bpf_put_file(struct file *f) +{ + fput(f); +} + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(lsm_kfunc_set_ids) BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS) BTF_ID_FLAGS(func, bpf_task_mm_grab, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL); BTF_ID_FLAGS(func, bpf_mm_drop, KF_RELEASE); +BTF_ID_FLAGS(func, bpf_get_task_exe_file, + KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_get_mm_exe_file, + KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE | KF_SLEEPABLE) BTF_KFUNCS_END(lsm_kfunc_set_ids) static int bpf_lsm_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id) From patchwork Tue Feb 20 09:28:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563738 Received: from mail-ed1-f45.google.com (mail-ed1-f45.google.com [209.85.208.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F2B55FDC6 for ; Tue, 20 Feb 2024 09:28:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421298; cv=none; b=ZGlQMpmfYkkvQH0i94yhjA9D0WUPbwtk3Ym8Q7R9R7diBB/NGWq9m8gBFytdsjUBMkH01EHLFuFQv+Dx57S3rPcRY0kdGLODWlPJEWgWPuHb0JQQqxjkIxRl99iPUM2X2ZBkrL5tPwm+F5fpSh9W18ZGWggKMvPoZ2VmFsrnAKo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421298; c=relaxed/simple; bh=Z0nB72JxcKjIXXvJDvWsGLXhIPmER9IAfA2zYyBQDjE=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=jF85FhHFHv67wkvbdwxS7XQW/aqMERCwXERVYdG4HqB9CiAzQmSAUk5pOSWIj7y1c5c0tIZTitQaUIoJV/+Wa7tCk9zzWpn7iN6Q/t0nkHXHnmgB1YgPonx9PZGJSL1Y6pHiX2a5d6m1uoVU7rTxvs56ZxGVv9pXAFb3PGhAR98= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=KTZ1Oxza; arc=none smtp.client-ip=209.85.208.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="KTZ1Oxza" Received: by mail-ed1-f45.google.com with SMTP id 4fb4d7f45d1cf-563e330351dso4311890a12.0 for ; Tue, 20 Feb 2024 01:28:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421294; x=1709026094; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=Ww1kRCbb77gPR6bbg0oXjgtFW9i+IxSISo3GWSzvNhk=; b=KTZ1Oxzavw7+iHL1mBcvja4KAXeTDROMF59KEDdcAVhypaFsszlo6UOtQEGJLdY9NV KcYPk+7DtogbF9xYQ8KXBGhMgGisyhpc/t+l0tcA1okQEstOJ0kuunD22/HlddRJyiJH Z+V04Yc51Vr3XGAG3BJJQ4kHnt5VmQbOEfvei8FLIvAOdKBkJUig1Q3a4zK11M9I/vBA HfvSwnzzXu/0eFy7PJ9ZJvtQq3mbEybudM/inlPAKGRphzv6eGzt9TUHYLB03XlvFhMl Q6DhaC2dSHse4xlOM+ip175QKG5Rhj2sUWU8pAF2Ky5idhGCYwhakCgZgAUK89IgYrXP QiOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421294; x=1709026094; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Ww1kRCbb77gPR6bbg0oXjgtFW9i+IxSISo3GWSzvNhk=; b=BET+sv64deBIEvTT8lPxNsf+iAAOlDOnADRjgCmZvTJz5NZdDTBn3Qy0mbSDBweImd GRfRQyDxckMXmR2pu6EWwmyedoI+X3j4Yc4C7uPzURNyQrpU/tqpsOkvfWHfoHFS96id 4F30DVkxp1XNpv1scXjDCU/bytDXZ83ipxIesdpjC+HxLqvEfQhTg+PY7TovBd6eoGTh FdEBB/55nhcvh1XOrs8TpKDV0od6mZAvbLDzV/va9NBpFVSZZ3UtJF81GkTG4gZDx8La pujLH8V0RbCUhSaXnqB2Kib0A66AHSKSN5t7N5bzFrBgKR+o6+4Q3LDfu0pZSJ8VEw6O EA+Q== X-Forwarded-Encrypted: i=1; AJvYcCXB9p7I9x+9AS/8ITq17JKodduknbO59vjIJBwh9DTjwrzzDPrSXuCBpWgrgtRxkp/pkdAmigF3XP2txPom0yDYC+n2RJ0z8YRPBcr9tA== X-Gm-Message-State: AOJu0Yw6TZ9EBOiO6hjHwpNxGgSqshNSfvGP5RQaqqszHT/+DaJLAC6N QBz+HHjWtHbevshuiPTSngERoD0eHCXbNrb0O/ok3gG2yMzh7Gg8A/udO+gCbg== X-Google-Smtp-Source: AGHT+IFBzsGQ6n9VgZgbPf9DtIsSJDiR8P+32R2NW+JannbmTLotC54Na1fk3iFKaIff0u+7p0GHLw== X-Received: by 2002:aa7:c655:0:b0:561:548e:e4c4 with SMTP id z21-20020aa7c655000000b00561548ee4c4mr10341708edr.19.1708421294265; Tue, 20 Feb 2024 01:28:14 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id el14-20020a056402360e00b0055fba4996d9sm3461914edb.71.2024.02.20.01.28.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:28:13 -0800 (PST) Date: Tue, 20 Feb 2024 09:28:10 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 07/11] bpf/selftests: add selftests for exe_file acquire/release BPF kfuncs Message-ID: References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add a new exe_file_kfunc test suite that is responsible for verifying the behaviour of the newly added exe_file based BPF kfuncs. For now, this new exe_file_kfunc test suite covers the following BPF kfuncs: struct file *bpf_get_task_exe_file(struct task_struct *task); struct file *bpf_get_mm_exe_file(struct mm_struct *mm); void bpf_put_file(struct file *f); Signed-off-by: Matt Bobrowski --- .../selftests/bpf/prog_tests/exe_file_kfunc.c | 49 +++++ .../bpf/progs/exe_file_kfunc_common.h | 23 +++ .../bpf/progs/exe_file_kfunc_failure.c | 181 ++++++++++++++++++ .../bpf/progs/exe_file_kfunc_success.c | 52 +++++ 4 files changed, 305 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/exe_file_kfunc.c create mode 100644 tools/testing/selftests/bpf/progs/exe_file_kfunc_common.h create mode 100644 tools/testing/selftests/bpf/progs/exe_file_kfunc_failure.c create mode 100644 tools/testing/selftests/bpf/progs/exe_file_kfunc_success.c diff --git a/tools/testing/selftests/bpf/prog_tests/exe_file_kfunc.c b/tools/testing/selftests/bpf/prog_tests/exe_file_kfunc.c new file mode 100644 index 000000000000..5900c1d4e820 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/exe_file_kfunc.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#define _GNU_SOURCE +#include + +#include "exe_file_kfunc_failure.skel.h" +#include "exe_file_kfunc_success.skel.h" + +static void run_test(const char *prog_name) +{ + struct bpf_link *link; + struct bpf_program *prog; + struct exe_file_kfunc_success *skel; + + skel = exe_file_kfunc_success__open_and_load(); + if (!ASSERT_OK_PTR(skel, "file_kfunc_success__open_and_load")) + return; + + link = NULL; + prog = bpf_object__find_program_by_name(skel->obj, prog_name); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) + goto cleanup; + + link = bpf_program__attach(prog); + ASSERT_OK_PTR(link, "bpf_program__attach"); +cleanup: + bpf_link__destroy(link); + exe_file_kfunc_success__destroy(skel); +} + +static const char * const success_tests[] = { + "get_task_exe_file_and_put_kfunc_from_current", + "get_task_exe_file_and_put_kfunc_from_argument", + "get_mm_exe_file_and_put_kfunc_from_current", +}; + +void test_exe_file_kfunc(void) +{ + int i = 0; + + for (; i < ARRAY_SIZE(success_tests); i++) { + if (!test__start_subtest(success_tests[i])) + continue; + run_test(success_tests[i]); + } + + RUN_TESTS(exe_file_kfunc_failure); +} diff --git a/tools/testing/selftests/bpf/progs/exe_file_kfunc_common.h b/tools/testing/selftests/bpf/progs/exe_file_kfunc_common.h new file mode 100644 index 000000000000..6623bcc130c3 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/exe_file_kfunc_common.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#ifndef _FILE_KFUNC_COMMON_H +#define _FILE_KFUNC_COMMON_H + +#include +#include +#include +#include + +#include "bpf_misc.h" + +struct mm_struct *bpf_task_mm_grab(struct task_struct *task) __ksym; +void bpf_mm_drop(struct mm_struct *mm) __ksym; + +struct file *bpf_get_task_exe_file(struct task_struct *task) __ksym; +struct file *bpf_get_mm_exe_file(struct mm_struct *mm) __ksym; +void bpf_put_file(struct file *f) __ksym; + +char _license[] SEC("license") = "GPL"; + +#endif /* _FILE_KFUNC_COMMON_H */ diff --git a/tools/testing/selftests/bpf/progs/exe_file_kfunc_failure.c b/tools/testing/selftests/bpf/progs/exe_file_kfunc_failure.c new file mode 100644 index 000000000000..8a4464481531 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/exe_file_kfunc_failure.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#include "exe_file_kfunc_common.h" + +SEC("lsm.s/file_open") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +int BPF_PROG(get_task_exe_file_kfunc_null) +{ + struct file *acquired; + + /* Can't pass a NULL pointer to bpf_get_task_exe_file(). */ + acquired = bpf_get_task_exe_file(NULL); + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +int BPF_PROG(get_mm_exe_file_kfunc_null) +{ + struct file *acquired; + + /* Can't pass a NULL pointer to bpf_get_mm_exe_file(). */ + acquired = bpf_get_mm_exe_file(NULL); + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/inode_getxattr") +__failure __msg("arg#0 pointer type STRUCT task_struct must point to scalar, or struct with scalar") +int BPF_PROG(get_task_exe_file_kfunc_fp) +{ + u64 x; + struct file *acquired; + struct task_struct *fp; + + fp = (struct task_struct *)&x; + /* Can't pass random frame pointer to bpf_get_task_exe_file(). */ + acquired = bpf_get_task_exe_file(fp); + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/inode_getxattr") +__failure __msg("arg#0 pointer type STRUCT mm_struct must point to scalar, or struct with scalar") +int BPF_PROG(get_mm_exe_file_kfunc_fp) +{ + int x; + struct file *acquired; + struct mm_struct *fp; + + fp = (struct mm_struct *)&x; + /* Can't pass random frame pointer to bpf_get_mm_exe_file(). */ + acquired = bpf_get_mm_exe_file(fp); + if (!acquired) + return 0; + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(get_task_exe_file_kfunc_untrusted) +{ + struct file *acquired; + struct task_struct *parent; + + /* Walking a trusted struct task_struct returned from + * bpf_get_current_task_btf() yields an untrusted pointer. */ + parent = bpf_get_current_task_btf()->parent; + /* Can't pass untrusted pointer to bpf_get_task_exe_file(). */ + acquired = bpf_get_task_exe_file(parent); + if (!acquired) + return 0; + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(get_mm_exe_file_kfunc_untrusted) +{ + struct file *acquired; + struct mm_struct *mm; + + /* Walking a struct task_struct obtained from bpf_get_current_task_btf() + * yields an untrusted pointer. */ + mm = bpf_get_current_task_btf()->mm; + /* Can't pass untrusted pointer to bpf_get_mm_exe_file(). */ + acquired = bpf_get_mm_exe_file(mm); + if (!acquired) + return 0; + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("Unreleased reference") +int BPF_PROG(get_task_exe_file_kfunc_unreleased) +{ + struct file *acquired; + + acquired = bpf_get_task_exe_file(bpf_get_current_task_btf()); + if (!acquired) + return 0; + __sink(acquired); + + /* Acquired but never released. */ + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("Unreleased reference") +int BPF_PROG(get_mm_exe_file_kfunc_unreleased) +{ + struct file *acquired; + struct mm_struct *mm; + + mm = bpf_task_mm_grab(bpf_get_current_task_btf()); + if (!mm) + return 0; + + acquired = bpf_get_mm_exe_file(mm); + if (!acquired) { + bpf_mm_drop(mm); + return 0; + } + __sink(acquired); + bpf_mm_drop(mm); + + /* Acquired but never released. */ + return 0; +} + +SEC("lsm/file_open") +__failure __msg("program must be sleepable to call sleepable kfunc bpf_put_file") +int BPF_PROG(put_file_kfunc_not_sleepable, struct file *f) +{ + struct file *acquired; + + acquired = bpf_get_task_exe_file(bpf_get_current_task_btf()); + if (!acquired) + return 0; + + /* Can't call bpf_put_file() from non-sleepable BPF program. */ + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("release kernel function bpf_put_file expects") +int BPF_PROG(put_file_kfunc_unacquired, struct file *f) +{ + /* Can't release an unacquired pointer. */ + bpf_put_file(f); + + return 0; +} + +SEC("tp_btf/task_newtask") +__failure __msg("calling kernel function bpf_get_task_exe_file is not allowed") +int BPF_PROG(get_task_exe_file_kfunc_not_lsm_prog, struct task_struct *task) +{ + struct file *acquired; + + /* bpf_get_task_exe_file() can only be called from BPF LSM program. */ + acquired = bpf_get_task_exe_file(bpf_get_current_task_btf()); + if (!acquired) + return 0; + bpf_put_file(acquired); + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/exe_file_kfunc_success.c b/tools/testing/selftests/bpf/progs/exe_file_kfunc_success.c new file mode 100644 index 000000000000..ae789cb0a9ae --- /dev/null +++ b/tools/testing/selftests/bpf/progs/exe_file_kfunc_success.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#include "exe_file_kfunc_common.h" + +SEC("lsm.s/file_open") +int BPF_PROG(get_task_exe_file_and_put_kfunc_from_current) +{ + struct file *acquired; + + acquired = bpf_get_task_exe_file(bpf_get_current_task_btf()); + if (!acquired) + return 0; + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/task_alloc") +int BPF_PROG(get_task_exe_file_and_put_kfunc_from_argument, + struct task_struct *task) +{ + struct file *acquired; + + acquired = bpf_get_task_exe_file(task); + if (!acquired) + return 0; + bpf_put_file(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +int BPF_PROG(get_mm_exe_file_and_put_kfunc_from_current) +{ + struct file *acquired; + struct mm_struct *mm; + + mm = bpf_task_mm_grab(bpf_get_current_task_btf()); + if (!mm) + return 0; + + acquired = bpf_get_mm_exe_file(mm); + if (!acquired) { + bpf_mm_drop(mm); + return 0; + } + bpf_put_file(acquired); + bpf_mm_drop(mm); + + return 0; +} From patchwork Tue Feb 20 09:28:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563739 Received: from mail-ed1-f54.google.com (mail-ed1-f54.google.com [209.85.208.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 959285F47D for ; Tue, 20 Feb 2024 09:28:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421310; cv=none; b=cgBV0t4n1/0TkYvpn25fyhwmV6kQJ8dMcNWF/l76iQCcDSVgDYhFbDrq6r+rqJ4CtUGcuHrWDeSI6CYyYcudvZ07ugdZ1I0AK7bV/jOGhqyCBTHLV9i05eOdXtZt9oV9XYgXDEGjjIl+dXE3tCAhsZPt+TEZuzpvzML1jWiLSh4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421310; c=relaxed/simple; bh=EhRdG8Bffj4HR/2Z9RI+Xs1DgKmtukN31L0orRuOgMI=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=IQnjGzpzmlJrcY2m+leC1+REP3P/SO0xaQWqVBo3gmjSHhgOlPCmjH1Nc1ordR9oMZ3NaaP26vJ6tUeu6iCCcBVX18TfaeSiRXv2hwytpV9UDg1sDLWNbrNHw72pfXewto7LXFia0IWL7WSiXmiwL7dAHiAmvss7uoK7PmRkmI8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=1noG1LsA; arc=none smtp.client-ip=209.85.208.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="1noG1LsA" Received: by mail-ed1-f54.google.com with SMTP id 4fb4d7f45d1cf-55f50cf2021so7162383a12.1 for ; Tue, 20 Feb 2024 01:28:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421307; x=1709026107; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=YNhsno5HhiSi6Kp2q/Iucw8xWVpCBEX2HNzCiTZBy3o=; b=1noG1LsA+TZSfMTt51IPdqAzLW4use5siGY7tO8jp1nc3mCXHDN39aQ5H8X7Qfiztb wBV5ZJ8rrk+o04D77w5XPeB2NyPJfKQF34a5ewm/CUcwAPpAN9nn8aRN8jMSJXLFNUBs NU4LpMyJLnQK7kw1LvaTD1L8KgoKfUfeVNwfH9p9TGwThQiSwQZF20peCW4gl2yLYfNP o8eUNGSjgo5LMhE+0qX2sfAWxVoSM9va6Sxi7p0SBjt5UD7g2Lam7mtiLzZzoLxHgSN0 Rju54j/NrTHQoNUd6hHDv/I7neNN0qaYxeFf8eQAYZ8VVqdHg7QyQX/WBW5HY/xKwtSK ZJ0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421307; x=1709026107; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=YNhsno5HhiSi6Kp2q/Iucw8xWVpCBEX2HNzCiTZBy3o=; b=BFhzlWqeAdMuypAM6feoH0AlxghdWyc+qd3ZuENa5JMBZ/25Z+81i9Px3ob39OBQuM ywlU8X7htnP8OmDJJTIElzKsrZ/1JbeKIGtnaceEGhVBi2ICffg0Eg5rOba5zYA9ixh0 2t7KkaNg7wt7zHwD+q5s3sLlXp6UaSS8uFLyKA4VspHvLCOQZun3MUxlRbcm2/t5ZJ9n 7MLskElnMSbgjkcoQ2nimpFESia9M0Hr6WHuWEaKuU0ApDsJzBN35/Y5OqB9tMg6144l p4Ff/1/TPJ7CMl7MmHhFyxY2SX3VvZzl934HHyBwgNTLIxpMNFyMRCPzxKuctbcs0Y07 OrEw== X-Forwarded-Encrypted: i=1; AJvYcCUAfbtpJmx+2gZqPJXJwklo/wzI/rxBhTvqsim79gzJ8vF8F/bhty7XAcOlVDA55p+U1yuWAuItw3tqFqK3TnPRXTO4pLznETH9/AzhoA== X-Gm-Message-State: AOJu0YwyFxgCAJkUu+78vCq466sxdrNnaPmXZ7S/+SEF1gCHUvG+M6i5 AEoOLwZUPaeQ0/AsYS/P8EDN7n8wu0BZwOfbMMW8Gx98tJ8C0Do674uY1AoHEQ== X-Google-Smtp-Source: AGHT+IG8xJfeMBOIFOzJE04kz5nK7k/hdFcuo9pPdlEXe65Ue0XcRKNWu/hcJDmHHreDuWqSzOqkHg== X-Received: by 2002:aa7:d892:0:b0:564:50c7:20d with SMTP id u18-20020aa7d892000000b0056450c7020dmr4066362edq.34.1708421306801; Tue, 20 Feb 2024 01:28:26 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id cf28-20020a0564020b9c00b00564761ca19fsm1784597edb.29.2024.02.20.01.28.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:28:26 -0800 (PST) Date: Tue, 20 Feb 2024 09:28:22 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 08/11] bpf: add acquire/release based BPF kfuncs for fs_struct's paths Message-ID: <33108b72903162baa8eb39e047e6a9f50a890a2b.1708377880.git.mattbobrowski@google.com> References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add the ability to obtain a reference on a common set of path's that are associated with a task_struct's fs_struct. Both fs_struct's root and pwd paths are commonly operated on in BPF LSM programs and at times handed off to BPF helpers and such. There needs to be a mechanism that supports BPF LSM programs to obtain stable handle to such in-kernel structures. We provide that mechanism through the introduction of the following new BPF kfuncs: struct path *bpf_get_task_fs_root(struct task_struct *task); struct path *bpf_get_task_fs_pwd(struct task_struct *task); void bpf_put_path(struct path *path); Signed-off-by: Matt Bobrowski --- kernel/trace/bpf_trace.c | 83 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index fbb252ad1d40..2bb7766337ca 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1557,6 +1558,83 @@ __bpf_kfunc void bpf_put_file(struct file *f) fput(f); } +/** + * bpf_get_task_fs_root - get a reference on the fs_struct's root for the + * supplied task_struct + * @task: task_struct of which the fs_struct's root path to get a reference on + * + * Get a reference on the root path associated with the supplied *task*. The + * referenced path retruned from this kfunc must be released using + * bpf_put_path(). + * + * Return: A referenced path pointer to the fs_struct's root of the supplied + * *task*, or NULL. + */ +__bpf_kfunc struct path *bpf_get_task_fs_root(struct task_struct *task) +{ + struct path *root; + struct fs_struct *fs; + + task_lock(task); + fs = task->fs; + if (unlikely(fs)) { + task_unlock(task); + return NULL; + } + + spin_lock(&fs->lock); + root = &fs->root; + path_get(root); + spin_unlock(&fs->lock); + task_unlock(task); + + return root; +} + +/** + * bpf_get_task_fs_pwd - get a reference on the fs_struct's pwd for the supplied + * task_struct + * @task: task_struct of which the fs_struct's pwd path to get a reference on + * + * Get a reference on the pwd path associated with the supplied *task*. A + * referenced path returned from this kfunc must be released using + * bpf_put_path(). + * + * Return: A referenced path pointer to the fs_struct's pwd of the supplied + * *task*, or NULL. + */ +__bpf_kfunc struct path *bpf_get_task_fs_pwd(struct task_struct *task) +{ + struct path *pwd; + struct fs_struct *fs; + + task_lock(task); + fs = task->fs; + if (unlikely(fs)) { + task_unlock(task); + return NULL; + } + + spin_lock(&fs->lock); + pwd = &fs->pwd; + path_get(pwd); + spin_unlock(&fs->lock); + task_unlock(task); + + return pwd; +} + +/** + * bpf_put_path - put the reference on the supplied path + * @path: path of which to put a reference on + * + * Put a reference on the supplied *path*. + */ +__bpf_kfunc void bpf_put_path(struct path *path) +{ + path_put(path); +} + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(lsm_kfunc_set_ids) @@ -1568,6 +1646,11 @@ BTF_ID_FLAGS(func, bpf_get_task_exe_file, BTF_ID_FLAGS(func, bpf_get_mm_exe_file, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE | KF_SLEEPABLE) +BTF_ID_FLAGS(func, bpf_get_task_fs_root, + KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_get_task_fs_pwd, + KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_put_path, KF_RELEASE | KF_SLEEPABLE) BTF_KFUNCS_END(lsm_kfunc_set_ids) static int bpf_lsm_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id) From patchwork Tue Feb 20 09:28:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563740 Received: from mail-ed1-f44.google.com (mail-ed1-f44.google.com [209.85.208.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C2454612CC for ; Tue, 20 Feb 2024 09:28:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421316; cv=none; b=cBl9NLGq4fW3ou39zHJl43tKwcpgIX2OVJXKHgofvm21AshuTQnjd5A+qrvjMeI+YubD99RdAFQFIvBePf+LnY0V0HmBBQnpLTKZbIxAblSUNKzxypMybfNC9RurrUtW1VQcUmrM+EWzyOd/gAJyAhoGx8xbu5dd/1y+l5eaRq8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421316; c=relaxed/simple; bh=SUs4twjkG/NT+xQtrF7hqn8/N6GJKznJtsrDmd2mx84=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=KWs+udxbpA6xBqPxJXRVYB24yXO6N4PeuXUxgyQ5bcSPDWtPpQQiJogkHdxoeZ6VANfkEShjyTDhPiYzupv89aSOcZXVD8jqpRNGNcZAYoNy1jThq74oSuNZHyHyNBiwT/QeT9LB/jE22AeBQ0uKmlSIZv3P8ipAMkJLK7sqWHY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=hklmhTHp; arc=none smtp.client-ip=209.85.208.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="hklmhTHp" Received: by mail-ed1-f44.google.com with SMTP id 4fb4d7f45d1cf-564a53b8133so1682114a12.0 for ; Tue, 20 Feb 2024 01:28:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421313; x=1709026113; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=Gkg6jmWVd42dKRaH6Zp1yxuMwQVLzUgdMybGYokBaX8=; b=hklmhTHphS1H3PiSZ40iFSPA81eKwX01ygXWYrRoilt2BArKKn4C335rV0IRjV2p9W zYjl4OyVDlLduWzOlBjmxLY5AVg6TElfFroJg2D3k3Ea4Qw9kKQ2jpkqzyomS/kZwF9f cabC8GT/FXH+N5l9NfNTQ51kGjxjdWlpfoKhjUfDmTT3l/vTXdXnD+/22Sr7orZPXkMy QHs/1NQiTQBN3P1hHO771RnfvATJLyYvjTiNfmjd8Sk7+XGShd1H4jb3G6zDspglizQ2 0phCSS00BFOxUs+Mc/t2CU4j7ImXfpG2YRLekdjmOvPK2+Gt2o8+aG9rVfQCoer7+3wN Z29A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421313; x=1709026113; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Gkg6jmWVd42dKRaH6Zp1yxuMwQVLzUgdMybGYokBaX8=; b=P03A+ql6EubCrfXPmNkbgTNpoKDGFFX/jmN2QudQZSbapLDW+cBJIxNtZH5+daW+j8 5xb21Zio5ZGbyLIc+jJ9aRJE2SxcJHBeJvmCovZge/vT0tspKV4skfXLRyHsfh3UhVTm k1aK5i9JbA59U9+4cZd7evGTM2ts+Rl0pYKa1xCiFYiLGD3GhSNN2yti+NtGpGqyrUJY qqZQRZQGIhLFTGaAmdUlj3k2QKSEyciX0zHLTWm7EUP00G23ZVP9tPOK7yDtrrpt4C/3 qzBSUd/Dm03W1u0MoWTwehHcEfs4I36Zyf5CgPSb/Kuqg1i/kbRe+vC9e1HyRbrNyhF4 hoUg== X-Forwarded-Encrypted: i=1; AJvYcCWYWzfAw0Z+66CZufTO8NAVIxWPo8KDtPg1KcN3b6JcS8htOkMbY6gIDGQdVPc5gqxhBLwwlrUTegN/DOlqj3De+8rCo361IZ/Oyq4aSw== X-Gm-Message-State: AOJu0YxuZ5cygq9JpSYdk0vj1baXOTNsVfbva3rGwXRQ8qz4QmbsaCvw WFLqeu0wqYTbRQ3JIeImSTd6oZBSNQ9MXj34u/yqrvQR2kV3b+QCCLf3/bm3ZQ== X-Google-Smtp-Source: AGHT+IEKYq2YhQbsGw9If+Nmvq/U37VhRsQ4MwUOAmeLljjhyFDj3agKWJkWI5zBOj37js1/VglOnA== X-Received: by 2002:a17:906:378e:b0:a3e:fce7:9393 with SMTP id n14-20020a170906378e00b00a3efce79393mr645681ejc.10.1708421312983; Tue, 20 Feb 2024 01:28:32 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id rs6-20020a170907890600b00a3e43b7e7b4sm3019627ejc.143.2024.02.20.01.28.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:28:32 -0800 (PST) Date: Tue, 20 Feb 2024 09:28:28 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 09/11] bpf/selftests: add selftests for root/pwd path based BPF kfuncs Message-ID: <0306f0c54b37afa67ab896d796ac150c90c027ea.1708377880.git.mattbobrowski@google.com> References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Add a new path_kfunc test suite that is responsible for verifiying the operability of the newly added root/pwd path based BPF kfuncs. This test suite covers the following BPF kfuncs: struct path *bpf_get_task_fs_root(struct task_struct *task); struct path *bpf_get_task_fs_pwd(struct task_struct *task); void bpf_put_path(struct path *path); Signed-off-by: Matt Bobrowski --- .../selftests/bpf/prog_tests/path_kfunc.c | 48 ++++++++ .../selftests/bpf/progs/path_kfunc_common.h | 20 +++ .../selftests/bpf/progs/path_kfunc_failure.c | 114 ++++++++++++++++++ .../selftests/bpf/progs/path_kfunc_success.c | 30 +++++ 4 files changed, 212 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/path_kfunc.c create mode 100644 tools/testing/selftests/bpf/progs/path_kfunc_common.h create mode 100644 tools/testing/selftests/bpf/progs/path_kfunc_failure.c create mode 100644 tools/testing/selftests/bpf/progs/path_kfunc_success.c diff --git a/tools/testing/selftests/bpf/prog_tests/path_kfunc.c b/tools/testing/selftests/bpf/prog_tests/path_kfunc.c new file mode 100644 index 000000000000..9a8701a7999c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/path_kfunc.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Google LLC. */ + +#define _GNU_SOURCE +#include + +#include "path_kfunc_failure.skel.h" +#include "path_kfunc_success.skel.h" + +static void run_test(const char *prog_name) +{ + struct bpf_link *link; + struct bpf_program *prog; + struct path_kfunc_success *skel; + + skel = path_kfunc_success__open_and_load(); + if (!ASSERT_OK_PTR(skel, "path_kfunc_success__open_and_load")) + return; + + link = NULL; + prog = bpf_object__find_program_by_name(skel->obj, prog_name); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) + goto cleanup; + + link = bpf_program__attach(prog); + ASSERT_OK_PTR(link, "bpf_program__attach"); +cleanup: + bpf_link__destroy(link); + path_kfunc_success__destroy(skel); +} + +static const char * const success_tests[] = { + "get_task_fs_root_and_put_from_current", + "get_task_fs_pwd_and_put_from_current", +}; + +void test_path_kfunc(void) +{ + int i = 0; + + for (; i < ARRAY_SIZE(success_tests); i++) { + if (!test__start_subtest(success_tests[i])) + continue; + run_test(success_tests[i]); + } + + RUN_TESTS(path_kfunc_failure); +} diff --git a/tools/testing/selftests/bpf/progs/path_kfunc_common.h b/tools/testing/selftests/bpf/progs/path_kfunc_common.h new file mode 100644 index 000000000000..837dc03c136d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/path_kfunc_common.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Google LLC. */ + +#ifndef _PATH_KFUNC_COMMON_H +#define _PATH_KFUNC_COMMON_H + +#include +#include +#include +#include + +#include "bpf_misc.h" + +char _license[] SEC("license") = "GPL"; + +struct path *bpf_get_task_fs_root(struct task_struct *task) __ksym; +struct path *bpf_get_task_fs_pwd(struct task_struct *task) __ksym; +void bpf_put_path(struct path *path) __ksym; + +#endif /* _PATH_KFUNC_COMMON_H */ diff --git a/tools/testing/selftests/bpf/progs/path_kfunc_failure.c b/tools/testing/selftests/bpf/progs/path_kfunc_failure.c new file mode 100644 index 000000000000..a28797e245e3 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/path_kfunc_failure.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Google LLC. */ + +#include "path_kfunc_common.h" + +SEC("lsm.s/file_open") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +int BPF_PROG(get_task_fs_root_kfunc_null) +{ + struct path *acquired; + + /* Can't pass a NULL pointer to bpf_get_task_fs_root(). */ + acquired = bpf_get_task_fs_root(NULL); + if (!acquired) + return 0; + bpf_put_path(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +int BPF_PROG(get_task_fs_pwd_kfunc_null) +{ + struct path *acquired; + + /* Can't pass a NULL pointer to bpf_get_task_fs_pwd(). */ + acquired = bpf_get_task_fs_pwd(NULL); + if (!acquired) + return 0; + bpf_put_path(acquired); + + return 0; +} + +SEC("lsm.s/task_alloc") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(get_task_fs_root_kfunc_untrusted, struct task_struct *task) +{ + struct path *acquired; + struct task_struct *parent; + + /* Walking the struct task_struct will yield an untrusted pointer. */ + parent = task->parent; + if (!parent) + return 0; + + acquired = bpf_get_task_fs_root(parent); + if (!acquired) + return 0; + bpf_put_path(acquired); + + return 0; +} + +SEC("lsm.s/task_alloc") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(get_task_fs_pwd_kfunc_untrusted, struct task_struct *task) +{ + struct path *acquired; + struct task_struct *parent; + + /* Walking the struct task_struct will yield an untrusted pointer. */ + parent = task->parent; + if (!parent) + return 0; + + acquired = bpf_get_task_fs_pwd(parent); + if (!acquired) + return 0; + bpf_put_path(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("Unreleased reference") +int BPF_PROG(get_task_fs_root_kfunc_unreleased) +{ + struct path *acquired; + + acquired = bpf_get_task_fs_root(bpf_get_current_task_btf()); + if (!acquired) + return 0; + __sink(acquired); + + /* Acquired but never released. */ + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("Unreleased reference") +int BPF_PROG(get_task_fs_pwd_kfunc_unreleased) +{ + struct path *acquired; + + acquired = bpf_get_task_fs_pwd(bpf_get_current_task_btf()); + if (!acquired) + return 0; + __sink(acquired); + + /* Acquired but never released. */ + return 0; +} + +SEC("lsm.s/inode_getattr") +__failure __msg("release kernel function bpf_put_path expects refcounted PTR_TO_BTF_ID") +int BPF_PROG(put_path_kfunc_unacquired, struct path *path) +{ + /* Can't release an unacquired pointer. */ + bpf_put_path(path); + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/path_kfunc_success.c b/tools/testing/selftests/bpf/progs/path_kfunc_success.c new file mode 100644 index 000000000000..8fc8e3c51405 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/path_kfunc_success.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Google LLC. */ + +#include "path_kfunc_common.h" + +SEC("lsm.s/file_open") +int BPF_PROG(get_task_fs_root_and_put_from_current) +{ + struct path *acquired; + + acquired = bpf_get_task_fs_root(bpf_get_current_task_btf()); + if (!acquired) + return 0; + bpf_put_path(acquired); + + return 0; +} + +SEC("lsm.s/file_open") +int BPF_PROG(get_task_fs_pwd_and_put_from_current) +{ + struct path *acquired; + + acquired = bpf_get_task_fs_pwd(bpf_get_current_task_btf()); + if (!acquired) + return 0; + bpf_put_path(acquired); + + return 0; +} From patchwork Tue Feb 20 09:28:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563741 Received: from mail-ed1-f44.google.com (mail-ed1-f44.google.com [209.85.208.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0FECE60DD4 for ; Tue, 20 Feb 2024 09:28:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421322; cv=none; b=lENyWV8SXgDp2k8Ah6dD1vy8aU1J7cIAY8G+kYYHm0nrvMXB6VIQdDEI8xzWyyXYx9z3h30gVytGCyJg/mDrEKfkOnO1T094RlnNdXFd7GPgKqWPYw7IntXTX9bbHGNEO1K1YPr57aRlAnH0tsKgEEYP0JGRr9jK97qRYv272j4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421322; c=relaxed/simple; bh=B0wfWCclmrTNKw8t5WQOMXI4ZoGVKDEJu3DZO62q57k=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=lxwBTaaofP5t/uElmItNIfubYsdcv47hx9Tw2pnAVfV6fPmhNB93gKsLx7Dy4YYJdWrb7u8OS35DiuVOjj8rN1wa7cyt1SSpnEwiKrjudCFbNhaznLgdl3b6uTAa7aTaYGBzSUi9/imxozknUeXLyL3mzLhPil7p4W+x7v4uaQQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=SEGU1oF3; arc=none smtp.client-ip=209.85.208.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="SEGU1oF3" Received: by mail-ed1-f44.google.com with SMTP id 4fb4d7f45d1cf-5645960cd56so2922569a12.1 for ; Tue, 20 Feb 2024 01:28:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421319; x=1709026119; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=oxaMZcDKEkY7wflrO9M/nsmbkLRY7k3BJEAicWcKejI=; b=SEGU1oF3rDdvPqD8mC7dU+hhSA1dRtXkroqVxYfXB7cI0p2TwyUYNn1S8kMCTZD3ve GN4xhojgIKrvnwvsx+XN05TIE02ttDzOSFE1jJp22tivUlTjCMn2e8ToMPTVtVlRse2d vRcVl2oYGvB1eERdRykxURxNdpzKSoHmWEIcTwTl4Rjh5iifKL/AaLlnIU6txnfVNdx/ pcKa0LAtP+sGB9EKnHDsF7LbZKjx87z7wODlK5ohMOAkg3E9TnW9Dvx0Jj2so0f62xcL G548vK4lGil9EeUb0CZBHS9DzgoNqhGKV0vDh0uaR0z6+H1xxv3nKYDQCNTiGfDxhw6z HroA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421319; x=1709026119; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=oxaMZcDKEkY7wflrO9M/nsmbkLRY7k3BJEAicWcKejI=; b=fYyQgIRfyYbG44NGfw1aS0pU13uDsuW9OPzFzjl+QNb8SzLD9/08pQBqmSCwGnjRfU Sec6bi1GrASsdONI14B4xaZyQwF19aS5xjbwIERuDvdMN4tPZsJgrL+CH2T/w81qVaRr op3aKDqLSBtDVTeuWmXLk2h+2212eIy5nD1TS0vfmUeiNHIE22qwNgQtKcYQxv0yWhiF ho0LCZtvTXeBnPNFWZK9nD7ftk5h0rz7lHnjLAzwZ40nOQO5DlWoCig//wvCg20DNxYk gS3m4sO09wipYKBMqtjuzhJla9FkdjDViUooOsF/RS3yztXPuk8iA4uU3WJh4AJm1+FU 8k+A== X-Forwarded-Encrypted: i=1; AJvYcCUrxJesTIS3P+g/5Igff+ve2tvIKqfK+l3FKYFL6S38meQn2kZUY//kASqFd65rOVjN1UdKYdk/Yx+OcsBP2QfjL9tfeGy14w7SuA/+Lw== X-Gm-Message-State: AOJu0YxPR9YJBQI6Pi0CA6tRRRAnsoHKFnlIeSI/sEZBobQu3sPhYkmG NO29FV6fDggTgt5q/Gnp9oQABIHr1Gw0XkO0tCiHOtPt9pF+TIeKLXOkM6DdIA== X-Google-Smtp-Source: AGHT+IHOBu+/5v68Q4wEQvOl52ps73P98rLT4hw71J9hPjcmK9E4xRz5ROknH+/Xu0kNrWHfG8P7aA== X-Received: by 2002:aa7:d997:0:b0:564:71d1:6cbd with SMTP id u23-20020aa7d997000000b0056471d16cbdmr3536021eds.14.1708421319547; Tue, 20 Feb 2024 01:28:39 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id h10-20020a0564020e0a00b005641bab8db3sm3286601edh.86.2024.02.20.01.28.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:28:39 -0800 (PST) Date: Tue, 20 Feb 2024 09:28:35 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 10/11] bpf: add trusted d_path() based BPF kfunc bpf_path_d_path() Message-ID: <46200bbaa6eae2131abed97f1a51991207eeb071.1708377880.git.mattbobrowski@google.com> References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: The legacy bpf_d_path() helper didn't operate on trusted pointer arguments, therefore under certain circumstances was susceptible to memory corruption issues [0]. This new d_path() based BPF kfunc bpf_path_d_path() makes use of trusted pointer arguments and therefore is subject to the BPF verifier constraints associated with KF_TRUSTED_ARGS semantics. Making use of such trusted pointer semantics will allow d_path() to be called safely from the contexts of a BPF program. For now, we restrict bpf_path_d_path() to BPF LSM program types, but this may be relaxed in the future. [0] https://lore.kernel.org/bpf/CAG48ez0ppjcT=QxU-jtCUfb5xQb3mLr=5FcwddF_VKfEBPs_Dg@mail.gmail.com/ Signed-off-by: Matt Bobrowski --- kernel/trace/bpf_trace.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 2bb7766337ca..57a7b4aae8d5 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1635,6 +1635,36 @@ __bpf_kfunc void bpf_put_path(struct path *path) path_put(path); } +/** + * bpf_path_d_path - resolve the pathname for a given path + * @path: path to resolve the pathname for + * @buf: buffer to return the resolved path value in + * @buflen: length of the supplied buffer + * + * Resolve the pathname for the supplied trusted *path* in *buf*. This kfunc is + * the trusted/safer variant of the legacy bpf_d_path() helper. + * + * Return: A strictly positive integer corresponding to the length of the string + * representing the resolved pathname, including the NUL termination + * character. On error, a negative integer is returned. + */ +__bpf_kfunc int bpf_path_d_path(struct path *path, char *buf, int buflen) +{ + int len; + char *ret; + + if (buflen <= 0) + return -EINVAL; + + ret = d_path(path, buf, buflen); + if (IS_ERR(ret)) + return PTR_ERR(ret); + + len = buf + buflen - ret; + memmove(buf, ret, len); + return len; +} + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(lsm_kfunc_set_ids) @@ -1651,6 +1681,7 @@ BTF_ID_FLAGS(func, bpf_get_task_fs_root, BTF_ID_FLAGS(func, bpf_get_task_fs_pwd, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_put_path, KF_RELEASE | KF_SLEEPABLE) +BTF_ID_FLAGS(func, bpf_path_d_path, KF_TRUSTED_ARGS | KF_SLEEPABLE) BTF_KFUNCS_END(lsm_kfunc_set_ids) static int bpf_lsm_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id) From patchwork Tue Feb 20 09:28:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Bobrowski X-Patchwork-Id: 13563742 Received: from mail-ed1-f41.google.com (mail-ed1-f41.google.com [209.85.208.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5E42964CD0 for ; Tue, 20 Feb 2024 09:28:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421329; cv=none; b=PjY3ULZLmk3CRo6ynX4XT1oW+aJzUCo+8JvsXniYfFwjH+tzh8Sq9EDn9ETf3icpPaov3OymKkhHcxDx3tDHQYbT9MY4sUaJzTNQT4XDkN5McRZlZ4r3MixDV/cQsez0mP8zLvDoM9kyXXvMTWE01GvY4E03XuDJIwvAbT+c0oo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421329; c=relaxed/simple; bh=aENrpF6P2Li0J5c9iKSwwW15d0q+FsSRPaXVDh8H5nQ=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=HEHgZTJ7WvR8H/tGJfgECGt+czR84Kl5fydWfjfek/iFqVOdJBLzzuYQnoWnT+S0sa6K5Mvv52xM51bJS48to5roiObozxoWhRS8MZsTlsXdyp7xRmrJyyFv1XVr3imjjnc+a+/ELyR0M4mwSXb/KTF48WGO0MWsWlkyWDJhnkY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=CyMHfHEA; arc=none smtp.client-ip=209.85.208.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="CyMHfHEA" Received: by mail-ed1-f41.google.com with SMTP id 4fb4d7f45d1cf-563e6131140so4746554a12.2 for ; Tue, 20 Feb 2024 01:28:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708421326; x=1709026126; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=v+EkyM++YIrsW/V5CCx1zZ3Et3tMoJsoGeRD8+dlvMk=; b=CyMHfHEA/byw8Dq9IjsgKZ8V1uOLV9vb5FG9tH4AKug0FpQGiPnZ/GW26R+LjF5jW3 1eO7+w9G4NoedRF7guSE/m/L+eONSbmmsxpH29OV8xsCLxG4ELqfN42GHCS0AQInTquY EDJbuLX+Wd1/K4pdzThzdjqc8I4+7xISUcf8w/FxSmPBbNo2cu2nBeuDiUZ+8D469v4O v3ARr/UcBUdtdvpAJB8sV5/Z79s1HpRj6rWogYg/UIdzW4PW8SCSilWTuJIdU+ey8V4B RlkxEgCFbr3YmvGY/vaMMUV16Tm6JeriMr9unKYS4V1E0kA0vaz9Jxlwln+KWc5lf1u+ 59nQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708421326; x=1709026126; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=v+EkyM++YIrsW/V5CCx1zZ3Et3tMoJsoGeRD8+dlvMk=; b=uTrNcbi0ZnZQ7fTV6aX8wu8GafkVleGUhiI5FciLP1JQLqXENeYyENVPseT7zkp24t eLVj6AGO2h2PVD0rUSjvBlhQ8DKrqjoEtypTQd7FgyIvPYLPEudWaO+y67yjFPbMr2K1 E3KCfgsK6Q/9vTlRlJujH0lZoshSO3KEdiSPRsyafzTeO6jWQ0O4hk5pSMdBQ7+5hTM7 3GVDUm0iaJzG6z0Jvgg6cS06ulRLBVAf4U+Jyx7obAEJ3EGJdV2X7dMwn0DTxNrVF2oP B1pMkNCscuKloY4vwLIvg7FiXzPdlXGHhgQUPvQIeyb6ArEIHQa5wDPpFPRhTfVs77hh wcAg== X-Forwarded-Encrypted: i=1; AJvYcCXZg9+JVzfBRXRlgR2vh6WtUzXDDP+cEe1PXsqFeeB0ro0LBuNzcWfOSKCuk0ZX+aZhPH4GPCtgmsABZ+YqE7Qe7PX/gzJDf7KOp89s+g== X-Gm-Message-State: AOJu0YwsfGa/kFxiVUiEuqfigzsPmG9POgjTyO4tXPYC1InJEmwCUdhF eUXEcm5bpV7RdSq65H63f4X98pbi5u79+MhxHEPalwgifePHCO25L5jsCRcM45qXJb8aukTrCrE aAw== X-Google-Smtp-Source: AGHT+IHWimJH/1mUsRr2jPvB6bYFOCJPTwnQWpocgIsq4PW29tPp7dLuh4wwcUsYAGpjbODnAgOU2g== X-Received: by 2002:aa7:c493:0:b0:564:d24c:64b5 with SMTP id m19-20020aa7c493000000b00564d24c64b5mr597501edq.26.1708421325557; Tue, 20 Feb 2024 01:28:45 -0800 (PST) Received: from google.com (229.112.91.34.bc.googleusercontent.com. [34.91.112.229]) by smtp.gmail.com with ESMTPSA id l15-20020a056402124f00b00564c8800f66sm373671edw.14.2024.02.20.01.28.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Feb 2024 01:28:45 -0800 (PST) Date: Tue, 20 Feb 2024 09:28:41 +0000 From: Matt Bobrowski To: bpf@vger.kernel.org Cc: ast@kernel.org, andrii@kernel.org, kpsingh@google.com, jannh@google.com, jolsa@kernel.org, daniel@iogearbox.net, brauner@kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH bpf-next 11/11] bpf/selftests: adapt selftests test_d_path for BPF kfunc bpf_path_d_path() Message-ID: <7e27b0d22d89253243fc676a6cd675e0e8ea93b1.1708377880.git.mattbobrowski@google.com> References: Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: Adapt the existing test_d_path test suite to cover the operability of the newly added trusted d_path() based BPF kfunc bpf_path_d_path(). Signed-off-by: Matt Bobrowski --- .../testing/selftests/bpf/prog_tests/d_path.c | 106 ++++++++++++++++-- .../selftests/bpf/progs/d_path_common.h | 34 ++++++ .../bpf/progs/d_path_kfunc_failure.c | 66 +++++++++++ .../bpf/progs/d_path_kfunc_success.c | 25 +++++ .../testing/selftests/bpf/progs/test_d_path.c | 20 +--- .../bpf/progs/test_d_path_check_rdonly_mem.c | 6 +- .../bpf/progs/test_d_path_check_types.c | 6 +- 7 files changed, 222 insertions(+), 41 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/d_path_common.h create mode 100644 tools/testing/selftests/bpf/progs/d_path_kfunc_failure.c create mode 100644 tools/testing/selftests/bpf/progs/d_path_kfunc_success.c diff --git a/tools/testing/selftests/bpf/prog_tests/d_path.c b/tools/testing/selftests/bpf/prog_tests/d_path.c index d77ae1b1e6ba..893324d4d59f 100644 --- a/tools/testing/selftests/bpf/prog_tests/d_path.c +++ b/tools/testing/selftests/bpf/prog_tests/d_path.c @@ -11,6 +11,8 @@ #include "test_d_path.skel.h" #include "test_d_path_check_rdonly_mem.skel.h" #include "test_d_path_check_types.skel.h" +#include "d_path_kfunc_failure.skel.h" +#include "d_path_kfunc_success.skel.h" /* sys_close_range is not around for long time, so let's * make sure we can call it on systems with older glibc @@ -44,7 +46,7 @@ static int set_pathname(int fd, pid_t pid) return readlink(buf, src.want[src.cnt++].path, MAX_PATH_LEN); } -static int trigger_fstat_events(pid_t pid) +static int trigger_fstat_events(pid_t pid, bool want_error) { int sockfd = -1, procfd = -1, devfd = -1, mntnsfd = -1; int localfd = -1, indicatorfd = -1; @@ -85,25 +87,25 @@ static int trigger_fstat_events(pid_t pid) * safely resolve paths that are comprised of dentries that make use of * dynamic names. We expect to return -EOPNOTSUPP for such paths. */ - src.want[src.cnt].err = true; + src.want[src.cnt].err = want_error; src.want[src.cnt].err_code = -EOPNOTSUPP; ret = set_pathname(pipefd[0], pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[0]\n")) goto out_close; - src.want[src.cnt].err = true; + src.want[src.cnt].err = want_error; src.want[src.cnt].err_code = -EOPNOTSUPP; ret = set_pathname(pipefd[1], pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for pipe[1]\n")) goto out_close; - src.want[src.cnt].err = true; + src.want[src.cnt].err = want_error; src.want[src.cnt].err_code = -EOPNOTSUPP; ret = set_pathname(sockfd, pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for socket\n")) goto out_close; - src.want[src.cnt].err = true; + src.want[src.cnt].err = want_error; src.want[src.cnt].err_code = -EOPNOTSUPP; ret = set_pathname(mntnsfd, pid); if (CHECK(ret < 0, "trigger", "set_pathname failed for mntnsfd\n")) @@ -151,12 +153,19 @@ static int trigger_fstat_events(pid_t pid) return ret; } -static void test_d_path_basic(void) +static void test_bpf_d_path_basic(void) { struct test_d_path__bss *bss; struct test_d_path *skel; int err; + /* + * Carrying global state across test function invocations is super + * gross, but it was late and I was tired and I just wanted to get the + * darn test working. Zero'ing this out was a simple no brainer. + */ + memset(&src, 0, sizeof(src)); + skel = test_d_path__open_and_load(); if (CHECK(!skel, "setup", "d_path skeleton failed\n")) goto cleanup; @@ -168,7 +177,7 @@ static void test_d_path_basic(void) bss = skel->bss; bss->my_pid = getpid(); - err = trigger_fstat_events(bss->my_pid); + err = trigger_fstat_events(bss->my_pid, /*want_error=*/true); if (err < 0) goto cleanup; @@ -225,7 +234,7 @@ static void test_d_path_basic(void) test_d_path__destroy(skel); } -static void test_d_path_check_rdonly_mem(void) +static void test_bpf_d_path_check_rdonly_mem(void) { struct test_d_path_check_rdonly_mem *skel; @@ -235,7 +244,7 @@ static void test_d_path_check_rdonly_mem(void) test_d_path_check_rdonly_mem__destroy(skel); } -static void test_d_path_check_types(void) +static void test_bpf_d_path_check_types(void) { struct test_d_path_check_types *skel; @@ -245,14 +254,87 @@ static void test_d_path_check_types(void) test_d_path_check_types__destroy(skel); } +static struct bpf_path_d_path_t { + const char *prog_name; +} success_test_cases[] = { + { + .prog_name = "path_d_path_from_path_argument", + }, +}; + +static void test_bpf_path_d_path(struct bpf_path_d_path_t *t) +{ + int i, ret; + struct bpf_link *link; + struct bpf_program *prog; + struct d_path_kfunc_success__bss *bss; + struct d_path_kfunc_success *skel; + + /* + * Carrying global state across function invocations is super gross, but + * it was late and I was tired and I just wanted to get the darn test + * working. Zero'ing this out was a simple no brainer. + */ + memset(&src, 0, sizeof(src)); + + skel = d_path_kfunc_success__open(); + if (!ASSERT_OK_PTR(skel, "d_path_kfunc_success__open")) + return; + + bss = skel->bss; + bss->my_pid = getpid(); + + ret = d_path_kfunc_success__load(skel); + if (CHECK(ret, "setup", "d_path_kfunc_success__load\n")) + goto cleanup; + + link = NULL; + prog = bpf_object__find_program_by_name(skel->obj, t->prog_name); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) + goto cleanup; + + link = bpf_program__attach(prog); + if (!ASSERT_OK_PTR(link, "bpf_program__attach")) + goto cleanup; + + ret = trigger_fstat_events(bss->my_pid, /*want_error=*/false); + if (ret < 0) + goto cleanup; + + for (i = 0; i < MAX_FILES; i++) { + struct want want = src.want[i]; + CHECK(strncmp(want.path, bss->paths_stat[i], MAX_PATH_LEN), + "check", "failed to get stat path[%d]: %s vs %s\n", i, + want.path, bss->paths_stat[i]); + CHECK(bss->rets_stat[i] != strlen(bss->paths_stat[i]) + 1, + "check", + "failed to match stat return [%d]: %d vs %zd [%s]\n", + i, bss->rets_stat[i], strlen(bss->paths_stat[i]) + 1, + bss->paths_stat[i]); + } +cleanup: + bpf_link__destroy(link); + d_path_kfunc_success__destroy(skel); +} + void test_d_path(void) { + int i = 0; + if (test__start_subtest("basic")) - test_d_path_basic(); + test_bpf_d_path_basic(); if (test__start_subtest("check_rdonly_mem")) - test_d_path_check_rdonly_mem(); + test_bpf_d_path_check_rdonly_mem(); if (test__start_subtest("check_alloc_mem")) - test_d_path_check_types(); + test_bpf_d_path_check_types(); + + for (; i < ARRAY_SIZE(success_test_cases); i++) { + if (!test__start_subtest(success_test_cases[i].prog_name)) + continue; + test_bpf_path_d_path(&success_test_cases[i]); + } + + RUN_TESTS(d_path_kfunc_failure); } diff --git a/tools/testing/selftests/bpf/progs/d_path_common.h b/tools/testing/selftests/bpf/progs/d_path_common.h new file mode 100644 index 000000000000..42d0a28a94ea --- /dev/null +++ b/tools/testing/selftests/bpf/progs/d_path_common.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#ifndef _D_PATH_COMMON_H +#define _D_PATH_COMMON_H + +#include +#include +#include + +#include "bpf_misc.h" + +#define MAX_PATH_LEN 128 +#define MAX_FILES 8 + +int bpf_path_d_path(struct path *path, char *buf, int buflen) __ksym; + +pid_t my_pid = 0; + +__u32 cnt_stat = 0; +__u32 cnt_close = 0; + +char paths_stat[MAX_FILES][MAX_PATH_LEN] = {}; +char paths_close[MAX_FILES][MAX_PATH_LEN] = {}; + +int rets_stat[MAX_FILES] = {}; +int rets_close[MAX_FILES] = {}; + +int called_stat = 0; +int called_close = 0; + +char _license[] SEC("license") = "GPL"; + +#endif /* _D_PATH_COMMON_H */ diff --git a/tools/testing/selftests/bpf/progs/d_path_kfunc_failure.c b/tools/testing/selftests/bpf/progs/d_path_kfunc_failure.c new file mode 100644 index 000000000000..9da5f0d395c9 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/d_path_kfunc_failure.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#include "d_path_common.h" + +char buf[MAX_PATH_LEN] = {}; + +SEC("lsm.s/file_open") +__failure __msg("Possibly NULL pointer passed to trusted arg0") +int BPF_PROG(path_d_path_kfunc_null) +{ + /* Can't pass NULL value to bpf_path_d_path() kfunc. */ + bpf_path_d_path(NULL, buf, sizeof(buf)); + return 0; +} + +SEC("fentry/vfs_open") +__failure __msg("calling kernel function bpf_path_d_path is not allowed") +int BPF_PROG(path_d_path_kfunc_non_lsm, struct path *path, struct file *f) +{ + /* Calling bpf_path_d_path() kfunc from a non-sleepable and non-LSM + * based program isn't permitted. + */ + bpf_path_d_path(path, buf, sizeof(buf)); + return 0; +} + +SEC("lsm.s/task_alloc") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(path_d_path_kfunc_untrusted_from_argument, struct task_struct *task) +{ + struct path *root; + + /* Walking a trusted argument yields an untrusted pointer. */ + root = &task->fs->root; + bpf_path_d_path(root, buf, sizeof(buf)); + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("R1 must be referenced or trusted") +int BPF_PROG(path_d_path_kfunc_untrusted_from_current) +{ + struct path *pwd; + struct task_struct *current; + + current = bpf_get_current_task_btf(); + /* Walking a trusted pointer returned from bpf_get_current_task_btf() + * yields and untrusted pointer. */ + pwd = ¤t->fs->pwd; + bpf_path_d_path(pwd, buf, sizeof(buf)); + return 0; +} + +SEC("lsm.s/file_open") +__failure __msg("R1 must have zero offset when passed to release func or trusted arg to kfunc") +int BPF_PROG(path_d_path_kfunc_trusted_variable_offset, struct file *file) +{ + /* Passing variable offsets from a trusted aren't supported just yet, + * despite being perfectly OK i.e. file->f_path. Once the BPF verifier + * has been updated to handle this case, this test can be removed. For + * now, ensure we reject the BPF program upon load if this is attempted. + */ + bpf_path_d_path(&file->f_path, buf, sizeof(buf)); + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/d_path_kfunc_success.c b/tools/testing/selftests/bpf/progs/d_path_kfunc_success.c new file mode 100644 index 000000000000..72d1a64618d1 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/d_path_kfunc_success.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Google LLC. */ + +#include "d_path_common.h" + +SEC("lsm.s/inode_getattr") +int BPF_PROG(path_d_path_from_path_argument, struct path *path) +{ + u32 cnt = cnt_stat; + int ret; + pid_t pid; + + pid = bpf_get_current_pid_tgid() >> 32; + if (pid != my_pid) + return 0; + + if (cnt >= MAX_FILES) + return 0; + + ret = bpf_path_d_path(path, paths_stat[cnt], MAX_PATH_LEN); + rets_stat[cnt] = ret; + cnt_stat++; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/test_d_path.c b/tools/testing/selftests/bpf/progs/test_d_path.c index fc2754f166ec..5bdfa4abb5f6 100644 --- a/tools/testing/selftests/bpf/progs/test_d_path.c +++ b/tools/testing/selftests/bpf/progs/test_d_path.c @@ -1,22 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include "vmlinux.h" -#include -#include - -#define MAX_PATH_LEN 128 -#define MAX_FILES 8 - -pid_t my_pid = 0; -__u32 cnt_stat = 0; -__u32 cnt_close = 0; -char paths_stat[MAX_FILES][MAX_PATH_LEN] = {}; -char paths_close[MAX_FILES][MAX_PATH_LEN] = {}; -int rets_stat[MAX_FILES] = {}; -int rets_close[MAX_FILES] = {}; - -int called_stat = 0; -int called_close = 0; +#include "d_path_common.h" SEC("fentry/security_inode_getattr") int BPF_PROG(prog_stat, struct path *path, struct kstat *stat, @@ -61,5 +45,3 @@ int BPF_PROG(prog_close, struct file *file, void *id) cnt_close++; return 0; } - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_d_path_check_rdonly_mem.c b/tools/testing/selftests/bpf/progs/test_d_path_check_rdonly_mem.c index 27c27cff6a3a..76654dbf637e 100644 --- a/tools/testing/selftests/bpf/progs/test_d_path_check_rdonly_mem.c +++ b/tools/testing/selftests/bpf/progs/test_d_path_check_rdonly_mem.c @@ -1,9 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2022 Google */ -#include "vmlinux.h" -#include -#include +#include "d_path_common.h" extern const int bpf_prog_active __ksym; @@ -24,5 +22,3 @@ int BPF_PROG(d_path_check_rdonly_mem, struct path *path, struct kstat *stat, } return 0; } - -char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_d_path_check_types.c b/tools/testing/selftests/bpf/progs/test_d_path_check_types.c index 7e02b7361307..c722754aedb0 100644 --- a/tools/testing/selftests/bpf/progs/test_d_path_check_types.c +++ b/tools/testing/selftests/bpf/progs/test_d_path_check_types.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include "vmlinux.h" -#include -#include +#include "d_path_common.h" extern const int bpf_prog_active __ksym; @@ -28,5 +26,3 @@ int BPF_PROG(d_path_check_rdonly_mem, struct path *path, struct kstat *stat, } return 0; } - -char _license[] SEC("license") = "GPL";