2024-01-03 15:19:58

by Chuck Lever

[permalink] [raw]
Subject: [PATCH v2 1/2] exportfs: fix the fallback implementation of the get_name export operation

From: Trond Myklebust <[email protected]>

The fallback implementation for the get_name export operation uses
readdir() to try to match the inode number to a filename. That filename
is then used together with lookup_one() to produce a dentry.
A problem arises when we match the '.' or '..' entries, since that
causes lookup_one() to fail. This has sometimes been seen to occur for
filesystems that violate POSIX requirements around uniqueness of inode
numbers, something that is common for snapshot directories.

This patch just ensures that we skip '.' and '..' rather than allowing a
match.

Signed-off-by: Trond Myklebust <[email protected]>
Reviewed-by: Jeff Layton <[email protected]>
Acked-by: Amir Goldstein <[email protected]>
Link: https://lore.kernel.org/linux-nfs/CAOQ4uxiOZobN76OKB-VBNXWeFKVwLW_eK5QtthGyYzWU9mjb7Q@mail.gmail.com/
Signed-off-by: Chuck Lever <[email protected]>
---
fs/exportfs/expfs.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 3ae0154c5680..84af58eaf2ca 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -255,7 +255,9 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
container_of(ctx, struct getdents_callback, ctx);

buf->sequence++;
- if (buf->ino == ino && len <= NAME_MAX) {
+ /* Ignore the '.' and '..' entries */
+ if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
+ buf->ino == ino && len <= NAME_MAX) {
memcpy(buf->name, name, len);
buf->name[len] = '\0';
buf->found = 1;




2024-01-04 07:39:22

by Amir Goldstein

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] exportfs: fix the fallback implementation of the get_name export operation

On Wed, Jan 3, 2024 at 5:19 PM Chuck Lever <[email protected]> wrote:
>
> From: Trond Myklebust <[email protected]>
>
> The fallback implementation for the get_name export operation uses
> readdir() to try to match the inode number to a filename. That filename
> is then used together with lookup_one() to produce a dentry.
> A problem arises when we match the '.' or '..' entries, since that
> causes lookup_one() to fail. This has sometimes been seen to occur for
> filesystems that violate POSIX requirements around uniqueness of inode
> numbers, something that is common for snapshot directories.
>
> This patch just ensures that we skip '.' and '..' rather than allowing a
> match.
>
> Signed-off-by: Trond Myklebust <[email protected]>
> Reviewed-by: Jeff Layton <[email protected]>
> Acked-by: Amir Goldstein <[email protected]>
> Link: https://lore.kernel.org/linux-nfs/CAOQ4uxiOZobN76OKB-VBNXWeFKVwLW_eK5QtthGyYzWU9mjb7Q@mail.gmail.com/
> Signed-off-by: Chuck Lever <[email protected]>
> ---
> fs/exportfs/expfs.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> index 3ae0154c5680..84af58eaf2ca 100644
> --- a/fs/exportfs/expfs.c
> +++ b/fs/exportfs/expfs.c
> @@ -255,7 +255,9 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
> container_of(ctx, struct getdents_callback, ctx);
>
> buf->sequence++;
> - if (buf->ino == ino && len <= NAME_MAX) {
> + /* Ignore the '.' and '..' entries */
> + if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
> + buf->ino == ino && len <= NAME_MAX) {


Thank you for creating the helper, but if you already went to this trouble,
I think it is better to introduce is_dot_dotdot() as a local helper already
in this backportable patch, so that stable kernel code is same as upstream
code (good for future fixes) and then dedupe the local helper with the rest
of the local helpers in patch 2?

Thanks,
Amir.

2024-01-04 14:27:34

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] exportfs: fix the fallback implementation of the get_name export operation

On Thu, Jan 04, 2024 at 09:39:04AM +0200, Amir Goldstein wrote:
> On Wed, Jan 3, 2024 at 5:19 PM Chuck Lever <[email protected]> wrote:
> >
> > From: Trond Myklebust <[email protected]>
> >
> > The fallback implementation for the get_name export operation uses
> > readdir() to try to match the inode number to a filename. That filename
> > is then used together with lookup_one() to produce a dentry.
> > A problem arises when we match the '.' or '..' entries, since that
> > causes lookup_one() to fail. This has sometimes been seen to occur for
> > filesystems that violate POSIX requirements around uniqueness of inode
> > numbers, something that is common for snapshot directories.
> >
> > This patch just ensures that we skip '.' and '..' rather than allowing a
> > match.
> >
> > Signed-off-by: Trond Myklebust <[email protected]>
> > Reviewed-by: Jeff Layton <[email protected]>
> > Acked-by: Amir Goldstein <[email protected]>
> > Link: https://lore.kernel.org/linux-nfs/CAOQ4uxiOZobN76OKB-VBNXWeFKVwLW_eK5QtthGyYzWU9mjb7Q@mail.gmail.com/
> > Signed-off-by: Chuck Lever <[email protected]>
> > ---
> > fs/exportfs/expfs.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > index 3ae0154c5680..84af58eaf2ca 100644
> > --- a/fs/exportfs/expfs.c
> > +++ b/fs/exportfs/expfs.c
> > @@ -255,7 +255,9 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
> > container_of(ctx, struct getdents_callback, ctx);
> >
> > buf->sequence++;
> > - if (buf->ino == ino && len <= NAME_MAX) {
> > + /* Ignore the '.' and '..' entries */
> > + if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
> > + buf->ino == ino && len <= NAME_MAX) {
>
>
> Thank you for creating the helper, but if you already went to this trouble,
> I think it is better to introduce is_dot_dotdot() as a local helper already
> in this backportable patch, so that stable kernel code is same as upstream
> code (good for future fixes) and then dedupe the local helper with the rest
> of the local helpers in patch 2?

There's now no Fixes: nor a Cc: stable on 1/2. You convinced me that
1/2 will not result in any external behavior change.

The upshot is I do not expect 1/2 will be backported, unless I have
grossly misread your emails.


--
Chuck Lever

2024-01-04 17:43:42

by Amir Goldstein

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] exportfs: fix the fallback implementation of the get_name export operation

On Thu, Jan 4, 2024 at 4:27 PM Chuck Lever <[email protected]> wrote:
>
> On Thu, Jan 04, 2024 at 09:39:04AM +0200, Amir Goldstein wrote:
> > On Wed, Jan 3, 2024 at 5:19 PM Chuck Lever <[email protected]> wrote:
> > >
> > > From: Trond Myklebust <[email protected]>
> > >
> > > The fallback implementation for the get_name export operation uses
> > > readdir() to try to match the inode number to a filename. That filename
> > > is then used together with lookup_one() to produce a dentry.
> > > A problem arises when we match the '.' or '..' entries, since that
> > > causes lookup_one() to fail. This has sometimes been seen to occur for
> > > filesystems that violate POSIX requirements around uniqueness of inode
> > > numbers, something that is common for snapshot directories.
> > >
> > > This patch just ensures that we skip '.' and '..' rather than allowing a
> > > match.
> > >
> > > Signed-off-by: Trond Myklebust <[email protected]>
> > > Reviewed-by: Jeff Layton <[email protected]>
> > > Acked-by: Amir Goldstein <[email protected]>
> > > Link: https://lore.kernel.org/linux-nfs/CAOQ4uxiOZobN76OKB-VBNXWeFKVwLW_eK5QtthGyYzWU9mjb7Q@mail.gmail.com/
> > > Signed-off-by: Chuck Lever <[email protected]>
> > > ---
> > > fs/exportfs/expfs.c | 4 +++-
> > > 1 file changed, 3 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
> > > index 3ae0154c5680..84af58eaf2ca 100644
> > > --- a/fs/exportfs/expfs.c
> > > +++ b/fs/exportfs/expfs.c
> > > @@ -255,7 +255,9 @@ static bool filldir_one(struct dir_context *ctx, const char *name, int len,
> > > container_of(ctx, struct getdents_callback, ctx);
> > >
> > > buf->sequence++;
> > > - if (buf->ino == ino && len <= NAME_MAX) {
> > > + /* Ignore the '.' and '..' entries */
> > > + if ((len > 2 || name[0] != '.' || (len == 2 && name[1] != '.')) &&
> > > + buf->ino == ino && len <= NAME_MAX) {
> >
> >
> > Thank you for creating the helper, but if you already went to this trouble,
> > I think it is better to introduce is_dot_dotdot() as a local helper already
> > in this backportable patch, so that stable kernel code is same as upstream
> > code (good for future fixes) and then dedupe the local helper with the rest
> > of the local helpers in patch 2?
>
> There's now no Fixes: nor a Cc: stable on 1/2. You convinced me that
> 1/2 will not result in any external behavior change.
>
> The upshot is I do not expect 1/2 will be backported, unless I have
> grossly misread your emails.
>

It's not what I meant, but I don't want to bother you about this.

I meant patch 1 is backportable:
- adds static is_dot_dotdot() in expfs.c and uses it
- patch 2 the same as you posted, but also removes is_dot_dotdot() from expfs.c

No big deal.
Patch 1, as far as I am concerned, patch 1 can stay as it is

Thanks,
Amir.