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: 13563720 X-Patchwork-Delegate: bpf@iogearbox.net 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 AFDDA5FDB1 for ; Tue, 20 Feb 2024 09:27:29 +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=1708421251; cv=none; b=lzDLiUHaYqfenmCAjV6YZ1HsNbk1J5oP6pjBIl/aUEuMI4tOrdDt8e6lsFHCOh7H8BrI2OeX0fcP4ePbQ8OU5lQTTy7Rawez154Tol6ECITX/b24LQTZNV3UZSRmjw7CupDQvCQWoJuepPen/XideAWkK7SQqqxNp7mLdch1Apk= 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.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="02+7I3BM" Received: by mail-ej1-f42.google.com with SMTP id a640c23a62f3a-a36126ee41eso688227566b.2 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=wDOJT72iO/ASXFDafqhbMfhnkHdbEPqiHsaRLcWyvImDj6Uou2SyW5yGL0g8WfEVQ6 sWsqbBoeUFh/Mz/pVRU3ew+s5kyAvlFoYqr+x4O8lzU4iwnMXyphs+w9X79i0TAa8OHW 1CAznQQTTvBBot8NoZLRg3b3c78z5FfG5cTqTvYJbfTtmFzaLKD+1cbF8PiJY/hz/jlZ F2MZqkI0oTB1V1ksY2bLTYcuZ1LffAvz6pa0CG0vw/UmBEhpk/NTT/+WkC4lgvEmsoq4 h4kcTN6F0WWaWs4LlNh5GNrcRXEturvA/a6BV+O5xiAFtEZxxfcCZJCX5sdKOTrsn67T sbbw== X-Gm-Message-State: AOJu0YxT49NeowJxqlaZJxKPZ+yrfRUIHeUpLa9uPjTbUK/TziS8LosD L55yz+dQfIMSsCl95Pg4PBdX1+aj1LnpkXYXjY95ECPiR+Fmjw4bWCpFaF7AbHKnVnGin25E7WK kAA== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563721 X-Patchwork-Delegate: bpf@iogearbox.net 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 BA0FE5F875 for ; Tue, 20 Feb 2024 09:27:36 +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=1708421258; cv=none; b=ELLn3sbla5RgmWSFiiS6SjFEHMKIRM6WSJtnUEoVOhsdewrmzTWVxCV6HGb4GP/RQREhEMG81QVYY1uSAOeCzuF0qTmX7qzgI4Qw5fZmGOSB2CBgJlUyRD7lUQthHuriC5Qp63meUkc/ciZd9iZ1CmFOA9xGurZ4ZiOQBre3NGU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421258; 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=FqmPmgPWtklrlNztXNwPsvYLF3gR4f118fiZuxWpuOjpBP3z2reFmPLPat4luL4/NeXJfWGuc1Ijepg1yinvmF3/GtEBCV0XklzZ+NS2HMeftUCEQ3Oy+gKJdrQZ/Dg5HzddBy3LnanfP+SLcweJfXEFQPdkQiLIZTlBUbqNvaY= 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.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="PhlLTzP2" Received: by mail-ej1-f53.google.com with SMTP id a640c23a62f3a-a3eafbcb1c5so183129366b.0 for ; Tue, 20 Feb 2024 01:27:36 -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=t9L6ty6TqljwJ4FT3l1oHLBpsZDemeCj1rDoLPjPpzmO/GFAk315Gk5NzeeR5B+fGS fYJAns3aQh/f+j/l+slNpMVEkU4iFXHOWR1Rv4RUTiieTNoMmiQUHF+neZMx2bLgGvzV i4i4+VDz7T33Z6ND5gTKTHThlHe8dVDyVdOAoPtW8Y85cVYXZJmGefQxkNR7QynpNgdC 4xKohTTOsknvQgqU1JpYQ+DsPRFHMdaO55rCeujh8uWuEWLunLgbAfOSN76H5M32GVaK jIGWnrMo5Itdxmm5j9JwhxMhaj69+NcuwbUHLTQNXx17nOltWXkHJ02XXPDbIbRwFAw7 u6Ww== X-Gm-Message-State: AOJu0YxVkdW/umOoYBN8RKVOy4MKCfx/isRO6wnAC/dYenX9NnKMNNNR VKDxlhJlwpg1dh/T5gf93zjhPodFPD5KINJx10+s9IZ+UTqDMytKRQ1HEungPORjJ+L7OIZzRgL 5Cg== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563722 X-Patchwork-Delegate: bpf@iogearbox.net 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 E546960DD4 for ; Tue, 20 Feb 2024 09:27:42 +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=1708421264; cv=none; b=mDCF9YapFGiYqhyu9jvpsjel6kl/vsavU2jPzyBUIKBvYWu36x/m7egrRv/T6XWy0thxgzaCK4skB3heqb46Qvs16BjtciFfHvIskY4WnKZdzfqFA/xawTAm3u1jTeBJap+tVKwPfxJywNLsrZ8VCAn73MYxFEz5yRzNOLiMSUo= 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.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="eXKAvtsT" Received: by mail-ej1-f53.google.com with SMTP id a640c23a62f3a-a3e550ef31cso239301666b.3 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=hAbHZKh/YmAA81MnjWXVefbnN/MiXGNuYMgzvv6xnk9EMEoL/6ZtfO3X+VNhZ0/GZa eXDeUcriFlGR+Bn8PRqqCpHT3Ee6CZ17M02m5qT0a65xlYoQb1uoiBuc/RA6JT9Bmife Z6FLyBAkFF+Ip7A88E9YnCL8n0aCa7xeShiV784xxL8GxUy7Oibs/kZDllOs9gyZjajg Rn8g2hcgLn2uCLAbfnNt/V/baVujH7Lp5YT+vQBL/KwC19zv/AuqYQ4PnE9odJuHpfFt h+fnwubVSmwJAWCgWEb25StQQMiUFjx8DK+r+AaUT4dotAzmbqTUwAjWjBrpfXkTXiQf RGhA== X-Gm-Message-State: AOJu0Yw22oqkkgowF5qO+M1gAdaXCdAn9LLgi7ZxEtzS2DDSxqmI/I04 yPuY4B2kg4CWFhX2pT8YEXjPgXrM+Nz63n75E/9i+UGpKFTtkU/jPdiw21ySASUXOerm6knKgiI ZjA== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563723 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) (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 81DBD5FDDB for ; Tue, 20 Feb 2024 09:27:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421278; cv=none; b=TIHHeAWcrLluMr7FB9FxiB43ZHx8yJ0mCB/9Xp/5DJBKXzW+3tq0+lMLcoim3Q3K4YsEVINORN8wr48p6IVdX2brPdGYthnpKCfRJ7xsWc97gI/vw7gKgMvOQjMVui9movpkLdOQfuLZ8vCqiGYDfgb+XPgVad7OLqUzQhGv+t4= 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.52 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-f52.google.com with SMTP id 4fb4d7f45d1cf-564a05ab3efso2037816a12.0 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=STYkzn3k/8mkl/XOvD/n84ZhSxqFOmXqmH4YqQUnNFqJT6aBH4mL91OCl6rGbQsK+q OCO7DywOA+jpStHPlJSikvycb9pluc5OfD4XhyWBPNovKv37ptVxGt8wryEWAKZhBblq qcQviDHFFe8f5/oS3KjvwPeWt/l5HM5CcyEsB6oJORiH1K+3iN8Gs5CfixX6ZAE/MEbq h8S2+7Bx557tCSwYaD8UBVXN+4862uWPMLMfcKv3Cx/e4MV3T4mzwHC5jTI0N/s/k19g maDgyYQ9a0pq/f74IT84ANk1SuaM9dINwwjLvHZsDU4jPthsiPLW/291s0SJQ9SGP94Q 1K/A== X-Gm-Message-State: AOJu0Yx+oAihN1soWbx/GDiC/DsTcPFpf4Ct94vWYPgskHW35gvoN9Qv jvc3t3TrD7TPEYig48heLNFlRR9zBIapW8BBw9tx01BTW2Ba4ugl61OLA/tLsTLvd2XXx6na+aA pOQ== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563724 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-ej1-f46.google.com (mail-ej1-f46.google.com [209.85.218.46]) (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 1419E5FDBF for ; Tue, 20 Feb 2024 09:28:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421284; cv=none; b=Lxf2olynfD5xhtq0O3OAfkGOAzE7gvROZeRvjUzAbGzgu9CE9LNEiES+6SJiLa4D3rWGx1Vb+2wEqtXH2tbYJq2jQIBK3lonJZN8DQ8HZM4tUwLiX+b+gFVI2BBnYITzf74ZzT9CpdF3mHSZk2a9gVFJ9Ai0VdeFchdex2/P1os= 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.46 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-f46.google.com with SMTP id a640c23a62f3a-a3e891b5e4eso206626166b.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=n8Ud5172GjrRv0G1mdpDpvcgfarcfuuVLL0ZHkFtJQAzukqAxeti/fS8yFBfl8P7yb JdLYNzl2f4nbR+Z6Jtxq0GgOrniSNj5OOZDy+v/S3+uojKxhm0b/Uka0B3Ixwg8zp3hZ l9EgG57utwFlwyjGC3m1S5eMOBOJSmqWGyGiwGr6A/xLoGk6EdTTffeYeTkZfK86yyQv rnMD+zMEQVodOydmn+ClFQXfZaQrIE8Ymvk8Tt/DlYRByor3jxGS5BkyBgJP/qThdcU4 rAEhqSXgdbeAHRM7nJ7BhLaxW7rmSr1XF7i/L3g/cC1FSXU3O8QcCRsWil6qbnB1eSDR gtvg== X-Gm-Message-State: AOJu0YxUtke9yxpQvELH6ZJqVab0mOHb+HNwySM1314MhJ2lHr0gSg42 uwfAHEvY6lXI3zikLRBMf2hfPvwIYJJGqoKeRydBqfsGeGQnEcenlczDjXGr4joksPAWHoUZpd7 a9g== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563725 X-Patchwork-Delegate: bpf@iogearbox.net 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 EDC855D8E4 for ; Tue, 20 Feb 2024 09:28:09 +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=1708421291; cv=none; b=ZTaTCB0xKfaX5ZttVjfDetMAfeH/WIRVDN+MuIQetECpcs6qCh2Hp8LvwNIU0WWMAVwce0g/OUkWvXEcUKU0gpAAII2QXz3Jmd8nxdzfGiCJDsHq4doNCpbcoQOiHoZ0BKUmen++3O2Bg8a0uwT44Tyi/85GPhmRXRsggqN3IFM= 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.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="KuFLbdM7" Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-a3e87b2de41so183810566b.2 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=lcDBZSAqvBfsBC6yQm0+YWJTIys+MJV1IXpMv2c3uQVqD69phHru39a4iSBI6HTwED N4Na1eAUiUH3aliL9OhTIO20FZRvGgHxyHC+RVZ54yS2J5S7G+B+XGz5iHL0JdSBiY30 Ae0n6Twr87fOuyaBp7sf5zFvviGzzbF4FAJeRgjgmQc5SQWhm/kHFKrvXrxN/NN+UFUE 0nOymR8Ym8EcLpbspEuJsTeGbYUxCr35uPl3J4zFBUmFB3UFVgJbHSdSJwWXAIpsgEvc vtpoRbrMmh1Jgdvd94WoK6AFtd1o7tpRt7PrOG3fF6WSICtQO+KKPqOYX3DlpO4pW6y+ 911g== X-Gm-Message-State: AOJu0YxXoVUnAiBSX9KZodKIPgg9jywTdbWZibPVh5l199LCMuNG7tUH giQYfYkk8agdAgl6cSeKLNwIs0+SaGOVSe/yajbiLTk/fkvSTBgx+UzopTpaZVUlZ7nxKj+WJo5 Egg== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563726 X-Patchwork-Delegate: bpf@iogearbox.net 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 624DF5FDCC for ; Tue, 20 Feb 2024 09:28:16 +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-5649c25369aso2434473a12.2 for ; Tue, 20 Feb 2024 01:28:16 -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=CHoe0Z2rGiPccy6QPWFXiX8l3ALNjj21DAJLt2YskDDso3jDlgUBuug6hmEx5wIr9U 2m1v6l1qm6AIUnaXKddwSQO6pOP0m/G8iqFDjSV2JN4sRirLgwtSGbHHhnP1PeOBF7Ay wL01fk68T8pCGvJ+7HukDFVY95RvQFhfaxHwT84m26/Sbo/24D2NxdO9FqhOnNXYUKk4 I7mPeLZBXzVbu0VU8cW2dx0Sg/xsucm5n4bNS9HRThLBZvnLGu3A71iMwwe/v8mwV7hV 5mU1MyVXHfjmDcoBYY1dHyfrrTtZvUuUzOHzSZZNUJ5dM+3KoSVD4javkg8OlhBqoQD9 RcYg== X-Gm-Message-State: AOJu0YysL6L+P9tTy0PmzodG6CbhqVyooUEV/Zp7kaZrd5V/GBsTiVoW xuxp2z75P6on9KpN6RBnyDmTngWuPSAFg0VJkvMZf+2T8ZYxVGjWfjNHLcm76B6t3m5XnqMpMkv X/g== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563727 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) (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 ED7395FBAD for ; Tue, 20 Feb 2024 09:28:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421310; cv=none; b=H3VSHx2afJiIrmeOauAuwsrYJ+akz8O4+OiGDCq08VZkpbRQtVncYXShoqhN61gc7kKdYkjVLVZLrysaVMUuWByFRCH6hcVea0M8NQrN7Q948R+bcT6BreHuA4z1HCWwq5lDOnIENTMW+Saya8u/q6LVhp6V4Safm2SUvGAsTcc= 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.52 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-f52.google.com with SMTP id 4fb4d7f45d1cf-564d332bd73so322216a12.3 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=UYgYzpgvoLvKhfM0d5LUOdbvJjpLS26En30KO5OFxHZCFf6qZAGr/csi7mvpWR/ELX AQAdwOojZj3UCqvS16+NoMrDOckh3j/0RpPrZ0bZH90EscVGuJupqXX3S+M+0Ks7DG5G h8KXUAydGNzc+4g4S9rz5hihT2bi1vNf4Q9hm6AUZP40Hj2X4FXd+gEk9WGL5s2jCk6+ JVa+eZdCOv2ljZlkD70cUI5EfRNerWRxCIhjcxxQ2LFXFRQACYknhFRUzo/a1xUFcmgK yPvHoBpaOGS4ZIzLo2bFE19kj+WpVk/9LM9nhD8hytT5WyQm7wNcXI15E9OCkWMkxndP 220w== X-Gm-Message-State: AOJu0Yyq5zWmYLhjDvVd8Kedw5dR+Frlt4M8t5bSPTHPQ4Rf+w7jHyfF umxIQ1KrfM0bscd7zP7giwzjmYEstAG6CxSFmfDAHqmw145fS3KEOAh7owdDF1kvbK5+xLloCq3 U4Q== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563728 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-ej1-f51.google.com (mail-ej1-f51.google.com [209.85.218.51]) (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 196AF5FDC9 for ; Tue, 20 Feb 2024 09:28:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421316; cv=none; b=YgcCn/xlyV62jCQwSIOY9giH7wkzIaPD0ekXd6HlMVZHO5du6yXfsGqyynpdUEZpT6QqJntphuIsALwe/s4yUlglMvhuCVivh1Ct/54O5bDvx3bisf0/rtzqy0wnXHPDF81fap3gZpc1WhTeuyaBvuoM1C1mRyj2A0oeN2GjClI= 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.218.51 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-ej1-f51.google.com with SMTP id a640c23a62f3a-a2f22bfb4e6so635032166b.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=cRsoOKEHCEnjdzyIJVXJJbEPWP9fy6S34Yy9L5p9lCKl0kHF+kH2TxgtMmeWQTrB/j Th1ySoA1CrAWHpcvMvXAZFE3OvApHBrXZ1ooA3neTSi1WGQ5b65xi33d6qsG9N2sngI1 Yv1ulo8ZXL9Vklw56LlPYF0VXYBkMRPN5l19PZP9+kt89AvZDZkF8PqK1MsTYrR+Iel9 FC0fM1DeOfkLhy+bD5FVMez9u9kCBiksHHSIvgz1brdr23iVdvV4bgQZ+GjWYu5iiJw6 dWbTVc5cTPuoozlSgEYGjeoEKFEDdd4jvSnQWTpSNs2fA/hggPAIGhv5wzaYMWgihf+n tUhQ== X-Gm-Message-State: AOJu0YwOYLUQ4AT62feeeENYrMuYfEGsWAy9v3ChFhzCyV8zDdKfGwdD Bhm1XwBT8SqTT5PRlpRwLo4sbyEeU4IEHzkvbXBeTbya6O1Dn7Ww8D01M4XFZAnvLPGjRuJOKbD 05Q== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563729 X-Patchwork-Delegate: bpf@iogearbox.net 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 7350964CF3 for ; Tue, 20 Feb 2024 09:28:41 +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=1708421323; cv=none; b=LdOSTQGfQz0FOEYwVMkg0Z0yqdE/ZPsRB17CHyw1dvD5nN6vWlMb4oH3IxJzo3K6DTgeZkjgLol5pwCNb1e3f6eG7xWdIi35hHfA00WijlKiWB/W7W13WuiJ5jMq7W2d+A6Gd2VuQiy61RkOlGL4B7tnvQLwUyB2C6ZYkstpzhA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708421323; c=relaxed/simple; bh=B0wfWCclmrTNKw8t5WQOMXI4ZoGVKDEJu3DZO62q57k=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=VyYrv8GlSYXk+M+WHICsMkhDGK9bd/wn/Ff9fyWYZsAyl05TOt9j4SG8qDRWDk3ppkfwwfmQHbaxR1W4bTsMV3wgz7fi4CYUrF009VzT4kDt1RbVaE/Apw1qb9VKN8hsvSL+g4iaavXuUUYBq5/YFKmCDdZpnviGraTJN9tcn6k= 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.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="SEGU1oF3" Received: by mail-ed1-f54.google.com with SMTP id 4fb4d7f45d1cf-564d9b0e96dso128493a12.2 for ; Tue, 20 Feb 2024 01:28:41 -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=Mfi1WtMmTfx2mN6i3e8awKvcYFpAaIx6DljPOYiR+f/nYdK6Vnz3VyYkdJxiszBlVp ZC/+0x59OyPRfJFkTiis7oGtOnaDidm45IQdoyWfOaoLpedlctYRjGDCEA22znwNiHQ5 8SAJAzJKgZweaDogb7ywRQ/DEHmCnLNd5bRLMqUc9cQUaWfyAWPdA8qr9EQviTxxMJHl DuBJeoz2+SlK1mK7yckfcYYFQfyY/D/NpCQc914+gys1oNtvZ3D6NacPDb9y0GWHymht RGioJ9L8IdSVPHS54Jib2uqymPCFk+KIhuvfiIRlOT7o8H04Ucz06EdMK4C/djJgeCD4 rTOw== X-Gm-Message-State: AOJu0YzJ+jhhvFcBOVcu9ufD4qoXWeDQuZ9o1WbcQmAciSerNtXZ55y/ GPTmH9MPHCd0qtbIWzujMUrHFW1veyKUzsYBVOncGXdyNZKqzS+ADa2ERv8+1bBQcc4yeoHnHyE LmA== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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: 13563730 X-Patchwork-Delegate: bpf@iogearbox.net 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 A8C65657B9 for ; Tue, 20 Feb 2024 09:28:47 +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=1708421329; cv=none; b=rh5eqY8FD0nmPn/NNNeaChRCY2nCM4bghBWtpQGJjRuo5lE79tvJ26F1PC89I4rSHHJJrKkkfdEH+bFKJxHa7h34IXeiiWd2B6yar4t6oJhQGkvt7ArMl+lMBLvJFpBHDgPWe0wXkD1UCtyo6AyWDDqyxw6SRO0ak0wQt2TMvz0= 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.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="CyMHfHEA" Received: by mail-ed1-f45.google.com with SMTP id 4fb4d7f45d1cf-563c0f13cabso6318717a12.3 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=TqAFe2f1jILgrTcJ8wikguxK9dXqsfnMyExRIP6DKsQ/Lhw3Pp3Tfx5jGTmcX14Ggo KSJgfeeXwUtgAz4k0OHnKHG8BCg7G1oDIjbR+A1BwebDCz59PBe9y8MbniOPlck6A914 XCRCwHnWAkOUbiE+uDMWTWdLlmTgJHCb2y0E8fjpzxgdPQKBXSlCiY79pjMrV34QeMg6 XiBJYumciJFA7ILmyNz2uVwjx8b3feH+lZ7VwhmfDW3YxDbOR4gxIFMy212pwI6KBx4/ F9HLHOuHM4F3FrFov8FR8hBGXf3KCtCtUO+bQoWvKL+KnEji9tXFAaooAA+7TvpvTYNG zhQg== X-Gm-Message-State: AOJu0Yy5bnhVMZeHWrjtih93MJNXpw8zvkk1AJGlPRE10peCa62PY0NQ SZx0ytX8fjfqxNm7yQWkfjnKxawkBb5nJ9CiE9fo4IzrfIynhoXZKNqK1WcFndBrJDRzULb8uVE CyQ== 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: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Patchwork-Delegate: bpf@iogearbox.net 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";