[PATCH v5 68/68] sysfs(2): fs_index() argument is _not_ a pathname

Al Viro posted 68 patches 3 weeks, 5 days ago
[PATCH v5 68/68] sysfs(2): fs_index() argument is _not_ a pathname
Posted by Al Viro 3 weeks, 5 days ago
... it's a filesystem type name.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/filesystems.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/fs/filesystems.c b/fs/filesystems.c
index 95e5256821a5..0c7d2b7ac26c 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -132,24 +132,21 @@ EXPORT_SYMBOL(unregister_filesystem);
 static int fs_index(const char __user * __name)
 {
 	struct file_system_type * tmp;
-	struct filename *name;
+	char *name __free(kfree) = strndup_user(__name, PATH_MAX);
 	int err, index;
 
-	name = getname(__name);
-	err = PTR_ERR(name);
 	if (IS_ERR(name))
-		return err;
+		return PTR_ERR(name);
 
 	err = -EINVAL;
 	read_lock(&file_systems_lock);
 	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
-		if (strcmp(tmp->name, name->name) == 0) {
+		if (strcmp(tmp->name, name) == 0) {
 			err = index;
 			break;
 		}
 	}
 	read_unlock(&file_systems_lock);
-	putname(name);
 	return err;
 }
 
-- 
2.47.3
Re: [PATCH v5 68/68] sysfs(2): fs_index() argument is _not_ a pathname
Posted by David Laight 3 weeks, 4 days ago
On Wed, 14 Jan 2026 04:33:10 +0000
Al Viro <viro@zeniv.linux.org.uk> wrote:

> ... it's a filesystem type name.
> 
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
>  fs/filesystems.c | 9 +++------
>  1 file changed, 3 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/filesystems.c b/fs/filesystems.c
> index 95e5256821a5..0c7d2b7ac26c 100644
> --- a/fs/filesystems.c
> +++ b/fs/filesystems.c
> @@ -132,24 +132,21 @@ EXPORT_SYMBOL(unregister_filesystem);
>  static int fs_index(const char __user * __name)
>  {
>  	struct file_system_type * tmp;
> -	struct filename *name;
> +	char *name __free(kfree) = strndup_user(__name, PATH_MAX);
>  	int err, index;
>  
> -	name = getname(__name);
> -	err = PTR_ERR(name);
>  	if (IS_ERR(name))
> -		return err;
> +		return PTR_ERR(name);

Doesn't that end up calling kfree(name) and the check in kfree() doesn't
seem to exclude error values.

Changing:
#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
				(unsigned long)ZERO_SIZE_PTR)
to:
#define ZERO_OR_NULL_PTR(x) (4096 + (unsigned long)(x) <= \
				4096 + (unsigned long)ZERO_SIZE_PTR)
would fix it at minimal cost.

	David


>  
>  	err = -EINVAL;
>  	read_lock(&file_systems_lock);
>  	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
> -		if (strcmp(tmp->name, name->name) == 0) {
> +		if (strcmp(tmp->name, name) == 0) {
>  			err = index;
>  			break;
>  		}
>  	}
>  	read_unlock(&file_systems_lock);
> -	putname(name);
>  	return err;
>  }
>
Re: [PATCH v5 68/68] sysfs(2): fs_index() argument is _not_ a pathname
Posted by Al Viro 3 weeks, 4 days ago
On Wed, Jan 14, 2026 at 10:41:55AM +0000, David Laight wrote:
> On Wed, 14 Jan 2026 04:33:10 +0000
> Al Viro <viro@zeniv.linux.org.uk> wrote:
> 
> > ... it's a filesystem type name.
> > 
> > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> > ---
> >  fs/filesystems.c | 9 +++------
> >  1 file changed, 3 insertions(+), 6 deletions(-)
> > 
> > diff --git a/fs/filesystems.c b/fs/filesystems.c
> > index 95e5256821a5..0c7d2b7ac26c 100644
> > --- a/fs/filesystems.c
> > +++ b/fs/filesystems.c
> > @@ -132,24 +132,21 @@ EXPORT_SYMBOL(unregister_filesystem);
> >  static int fs_index(const char __user * __name)
> >  {
> >  	struct file_system_type * tmp;
> > -	struct filename *name;
> > +	char *name __free(kfree) = strndup_user(__name, PATH_MAX);
> >  	int err, index;
> >  
> > -	name = getname(__name);
> > -	err = PTR_ERR(name);
> >  	if (IS_ERR(name))
> > -		return err;
> > +		return PTR_ERR(name);
> 
> Doesn't that end up calling kfree(name) and the check in kfree() doesn't
> seem to exclude error values.

include/linux/slab.h:523:DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))

kfree() the function won't be even called in that case...
Re: [PATCH v5 68/68] sysfs(2): fs_index() argument is _not_ a pathname
Posted by David Laight 3 weeks, 4 days ago
On Wed, 14 Jan 2026 14:35:55 +0000
Al Viro <viro@zeniv.linux.org.uk> wrote:

> On Wed, Jan 14, 2026 at 10:41:55AM +0000, David Laight wrote:
> > On Wed, 14 Jan 2026 04:33:10 +0000
> > Al Viro <viro@zeniv.linux.org.uk> wrote:
> >   
> > > ... it's a filesystem type name.
> > > 
> > > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> > > ---
> > >  fs/filesystems.c | 9 +++------
> > >  1 file changed, 3 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/fs/filesystems.c b/fs/filesystems.c
> > > index 95e5256821a5..0c7d2b7ac26c 100644
> > > --- a/fs/filesystems.c
> > > +++ b/fs/filesystems.c
> > > @@ -132,24 +132,21 @@ EXPORT_SYMBOL(unregister_filesystem);
> > >  static int fs_index(const char __user * __name)
> > >  {
> > >  	struct file_system_type * tmp;
> > > -	struct filename *name;
> > > +	char *name __free(kfree) = strndup_user(__name, PATH_MAX);
> > >  	int err, index;
> > >  
> > > -	name = getname(__name);
> > > -	err = PTR_ERR(name);
> > >  	if (IS_ERR(name))
> > > -		return err;
> > > +		return PTR_ERR(name);  
> > 
> > Doesn't that end up calling kfree(name) and the check in kfree() doesn't
> > seem to exclude error values.  
> 
> include/linux/slab.h:523:DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T))
> 
> kfree() the function won't be even called in that case...

I wasn't expecting the code to be optimised for the pointer being invalid.

I guess one of the defines does a 'dance' so that the pointer can be returned
without kfree() being called - and that needs a check in the function itself.
(I'm sure I remember something about the compiler optimising at all away.)

Perhaps the test could be:
	if (!statically_true(IS_ERR_OR_NULL(_T)) kfree(_T)
adjusting the check in kfree() to ignore -4096..16 not just 0..16.
That should reduce code size without slowing down the 'normal' paths
and possibly speeding up the error paths.

	David