Re: [PATCH 4/4] pidfs: implement fh_to_dentry

From: Amir Goldstein
Date: Wed Nov 13 2024 - 03:01:46 EST


On Wed, Nov 13, 2024 at 1:34 AM Jeff Layton <jlayton@xxxxxxxxxx> wrote:
>
> On Fri, 2024-11-01 at 13:54 +0000, Erin Shepherd wrote:
> > This enables userspace to use name_to_handle_at to recover a pidfd
> > to a process.
> >
> > 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.
> >
> > Signed-off-by: Erin Shepherd <erin.shepherd@xxxxxx>
> > ---
> > fs/pidfs.c | 50 +++++++++++++++++++++++++++++++++++++++++++-------
> > 1 file changed, 43 insertions(+), 7 deletions(-)
> >
> > diff --git a/fs/pidfs.c b/fs/pidfs.c
> > index c8e7e9011550..2d66610ef385 100644
> > --- a/fs/pidfs.c
> > +++ b/fs/pidfs.c
> > @@ -348,23 +348,59 @@ static const struct dentry_operations pidfs_dentry_operations = {
> > .d_prune = stashed_dentry_prune,
> > };
> >
> > -static int pidfs_encode_fh(struct inode *inode, __u32 *fh, int *max_len,
> > +#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;
> > -
> > - if (*max_len < 2) {
> > - *max_len = 2;
> > + struct pidfd_fid *fid = (struct pidfd_fid *)fh;
> > +
> > + if (*max_len < PIDFD_FID_LEN) {
> > + *max_len = PIDFD_FID_LEN;
> > return FILEID_INVALID;
> > }
> >
> > - *max_len = 2;
> > - *(u64 *)fh = pid->ino;
> > - return FILEID_KERNFS;
> > + fid->ino = pid->ino;
> > + fid->pid = pid_nr(pid);
>
> I worry a little here. A container being able to discover its pid in
> the root namespace seems a little sketchy. This makes that fairly
> simple to figure out.
>
> Maybe generate a random 32 bit value at boot time, and then xor that
> into this? Then you could just reverse that and look up the pid.
>

I don't like playing pseudo cryptographic games, we are not
crypto experts so we are bound to lose in this game.

My thinking is the other way around -
- encode FILEID_INO32_GEN with pid_nr + i_generation
- pid_nr is obviously not unique across pidns and reusable
but that makes it just like i_ino across filesystems
- the resulting file handle is thus usable only in the pidns where
it was encoded - is that a bad thing?

Erin,

You write that "To ensure file handles are invariant and can move
between pid namespaces, we stash a pid from the initial namespace
inside the file handle."

Why is it a requirement for userspace that pidfs file handles are
invariant to pidns?

Thanks,
Amir.