Re: [PATCH v2 3/3] pidfs: implement file handle support

Amir Goldstein
2024-11-14T07:08:05Z

On Wed, Nov 13, 2024 at 7:11 PM Erin Shepherd <erin.shepherd@e43.eu> wrote:
>
> On 64-bit platforms, userspace can read the pidfd's inode in order to
> get a never-repeated PID identifier. On 32-bit platforms this identifier
> is not exposed, as inodes are limited to 32 bits. Instead expose the
> identifier via export_fh, which makes it available to userspace via
> name_to_handle_at
>
> In addition we implement fh_to_dentry, which allows userspace to
> recover a pidfd from a PID file handle.

"In addition" is a good indication that a separate patch was a good idea..

>
> We stash the process' PID in the root pid namespace inside the handle,
> and use that to recover the pid (validating that pid->ino matches the
> value in the handle, i.e. that the pid has not been reused).
>
> We use the root namespace in order to ensure that file handles can be
> moved across namespaces; however, we validate that the PID exists in
> the current namespace before returning the inode.
>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>

This patch has changed enough that you should not have kept my RVB.

BTW, please refrain from using the same subject for the cover letter and
a single patch. They are not the same thing, so if they get the same
name, one of them has an inaccurate description.

> Signed-off-by: Erin Shepherd <erin.shepherd@e43.eu>
> ---
> fs/pidfs.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 61 insertions(+), 1 deletion(-)
>
> diff --git a/fs/pidfs.c b/fs/pidfs.c
> index 80675b6bf88459c22787edaa68db360bdc0d0782..0684a9b8fe71c5205fb153b2714bc9c672045fd5 100644
> --- a/fs/pidfs.c
> +++ b/fs/pidfs.c
> @@ -1,5 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0
> #include <linux/anon_inodes.h>
> +#include <linux/exportfs.h>
> #include <linux/file.h>
> #include <linux/fs.h>
> #include <linux/magic.h>
> @@ -347,11 +348,69 @@ static const struct dentry_operations pidfs_dentry_operations = {
> .d_prune = stashed_dentry_prune,
> };
>
> +#define PIDFD_FID_LEN 3
> +
> +struct pidfd_fid {
> + u64 ino;
> + s32 pid;
> +} __packed;
> +
> +static int pidfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
> + struct inode *parent)
> +{
> + struct pid *pid = inode->i_private;
> + struct pidfd_fid *fid = (struct pidfd_fid *)fh;
> +
> + if (*max_len < PIDFD_FID_LEN) {
> + *max_len = PIDFD_FID_LEN;
> + return FILEID_INVALID;
> + }
> +
> + fid->ino = pid->ino;
> + fid->pid = pid_nr(pid);
> + *max_len = PIDFD_FID_LEN;
> + return FILEID_INO64_GEN;
> +}
> +
> +static struct dentry *pidfs_fh_to_dentry(struct super_block *sb,
> + struct fid *gen_fid,
> + int fh_len, int fh_type)
> +{
> + int ret;
> + struct path path;
> + struct pidfd_fid *fid = (struct pidfd_fid *)gen_fid;
> + struct pid *pid;
> +
> + if (fh_type != FILEID_INO64_GEN || fh_len < PIDFD_FID_LEN)
> + return NULL;
> +
> + scoped_guard(rcu) {
> + pid = find_pid_ns(fid->pid, &init_pid_ns);
> + if (!pid || pid->ino != fid->ino || pid_vnr(pid) == 0)
> + return NULL;
> +
> + pid = get_pid(pid);
> + }
> +
> + ret = path_from_stashed(&pid->stashed, pidfs_mnt, pid, &path);
> + if (ret < 0)
> + return ERR_PTR(ret);

How come no need to put_pid() in case of error?

> +
> + mntput(path.mnt);
> + return path.dentry;
> +}
> +
> +static const struct export_operations pidfs_export_operations = {
> + .encode_fh = pidfs_encode_fh,
> + .fh_to_dentry = pidfs_fh_to_dentry,
> + .flags = EXPORT_OP_UNRESTRICTED_OPEN,
> +};
> +
> static int pidfs_init_inode(struct inode *inode, void *data)
> {
> inode->i_private = data;
> inode->i_flags |= S_PRIVATE;
> - inode->i_mode |= S_IRWXU;
> + inode->i_mode |= S_IRWXU | S_IRWXG | S_IRWXO;

This change is not explained.
Why is it here?

Thanks,
Amir.