diff mbox series

f2fs: fix 32-bit linking

Message ID 20190628104007.2721479-1-arnd@arndb.de
State New
Headers show
Series f2fs: fix 32-bit linking | expand

Commit Message

Arnd Bergmann June 28, 2019, 10:39 a.m. UTC
Not all architectures support get_user() with a 64-bit argument:

ERROR: "__get_user_bad" [fs/f2fs/f2fs.ko] undefined!

Use copy_from_user() here, this will always work.

Fixes: d2ae7494d043 ("f2fs: ioctl for removing a range from F2FS")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

---
 fs/f2fs/file.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

-- 
2.20.0

Comments

'Christoph Hellwig' June 28, 2019, 12:44 p.m. UTC | #1
On Fri, Jun 28, 2019 at 12:39:52PM +0200, Arnd Bergmann wrote:
> Not all architectures support get_user() with a 64-bit argument:


Which architectures are still missing?  I think we finally need to
get everyone in line instead of repeatedly working around the lack
of minor arch support.
Arnd Bergmann June 28, 2019, 1:09 p.m. UTC | #2
On Fri, Jun 28, 2019 at 2:44 PM Christoph Hellwig <hch@infradead.org> wrote:
>

> On Fri, Jun 28, 2019 at 12:39:52PM +0200, Arnd Bergmann wrote:

> > Not all architectures support get_user() with a 64-bit argument:

>

> Which architectures are still missing?  I think we finally need to

> get everyone in line instead of repeatedly working around the lack

> of minor arch support.


I came across this on arm-nommu (which disables
CONFIG_CPU_SPECTRE) during randconfig testing.

I don't see an easy way to add this in there, short of rewriting the
whole __get_user_err() function. Any suggestions?

      Arnd
'Christoph Hellwig' June 28, 2019, 1:17 p.m. UTC | #3
On Fri, Jun 28, 2019 at 03:09:47PM +0200, Arnd Bergmann wrote:
> I came across this on arm-nommu (which disables

> CONFIG_CPU_SPECTRE) during randconfig testing.

> 

> I don't see an easy way to add this in there, short of rewriting the

> whole __get_user_err() function. Any suggestions?


Can't we just fall back to using copy_from_user with a little wrapper
that switches based on sizeof()?
Arnd Bergmann June 28, 2019, 2:46 p.m. UTC | #4
On Fri, Jun 28, 2019 at 3:17 PM Christoph Hellwig <hch@infradead.org> wrote:
>

> On Fri, Jun 28, 2019 at 03:09:47PM +0200, Arnd Bergmann wrote:

> > I came across this on arm-nommu (which disables

> > CONFIG_CPU_SPECTRE) during randconfig testing.

> >

> > I don't see an easy way to add this in there, short of rewriting the

> > whole __get_user_err() function. Any suggestions?

>

> Can't we just fall back to using copy_from_user with a little wrapper

> that switches based on sizeof()?


I came up with something now. It's not pretty, but seems to satisfy the
compiler. Not a proper patch yet, but let me know if you find a bug.

This might contain a double uaccess_save_and_enable/uaccess_restore,
not sure how much we care about that.

     Arnd

index 7e0d2727c6b5..c21cdecadf26 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -307,6 +307,7 @@ static inline void set_fs(mm_segment_t fs)
 do {                                                                   \
        unsigned long __gu_addr = (unsigned long)(ptr);                 \
        unsigned long __gu_val;                                         \
+       unsigned long long __gu_val8;                                   \
        unsigned int __ua_flags;                                        \
        __chk_user_ptr(ptr);                                            \
        might_fault();                                                  \
@@ -315,10 +316,13 @@ do {
                         \
        case 1: __get_user_asm_byte(__gu_val, __gu_addr, err);  break;  \
        case 2: __get_user_asm_half(__gu_val, __gu_addr, err);  break;  \
        case 4: __get_user_asm_word(__gu_val, __gu_addr, err);  break;  \
+       case 8: __get_user_asm_dword(__gu_val8, __gu_addr, err);break;  \
        default: (__gu_val) = __get_user_bad();                         \
        }                                                               \
        uaccess_restore(__ua_flags);                                    \
-       (x) = (__typeof__(*(ptr)))__gu_val;                             \
+       (x) = __builtin_choose_expr(sizeof(*(ptr)) == 8,                \
+               (__typeof__(*(ptr)))__gu_val8,                          \
+               (__typeof__(*(ptr)))__gu_val);                          \
 } while (0)

 #define __get_user_asm(x, addr, err, instr)                    \
@@ -373,6 +377,8 @@ do {
                         \
        __get_user_asm(x, addr, err, ldr)
 #endif

+#define __get_user_asm_dword(x, addr, err)                     \
+       do { err = raw_copy_from_user(&x, (void __user *)addr, 8) ?
-EFAULT : 0; } while (0)

 #define __put_user_switch(x, ptr, __err, __fn)                         \
        do {                                                            \
Jaegeuk Kim June 28, 2019, 3:59 p.m. UTC | #5
Hi Arnd,

If you don't mind, can I integrate this into the original patch in the queue?

Thanks,

On 06/28, Arnd Bergmann wrote:
> Not all architectures support get_user() with a 64-bit argument:

> 

> ERROR: "__get_user_bad" [fs/f2fs/f2fs.ko] undefined!

> 

> Use copy_from_user() here, this will always work.

> 

> Fixes: d2ae7494d043 ("f2fs: ioctl for removing a range from F2FS")

> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

> ---

>  fs/f2fs/file.c | 3 ++-

>  1 file changed, 2 insertions(+), 1 deletion(-)

> 

> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c

> index 998affe31419..465853029b8e 100644

> --- a/fs/f2fs/file.c

> +++ b/fs/f2fs/file.c

> @@ -3066,7 +3066,8 @@ static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)

>  	if (f2fs_readonly(sbi->sb))

>  		return -EROFS;

>  

> -	if (get_user(block_count, (__u64 __user *)arg))

> +	if (copy_from_user(&block_count, (void __user *)arg,

> +			   sizeof(block_count)))

>  		return -EFAULT;

>  

>  	ret = f2fs_resize_fs(sbi, block_count);

> -- 

> 2.20.0
Russell King (Oracle) June 28, 2019, 5:58 p.m. UTC | #6
On Fri, Jun 28, 2019 at 04:46:14PM +0200, Arnd Bergmann wrote:
> On Fri, Jun 28, 2019 at 3:17 PM Christoph Hellwig <hch@infradead.org> wrote:

> >

> > On Fri, Jun 28, 2019 at 03:09:47PM +0200, Arnd Bergmann wrote:

> > > I came across this on arm-nommu (which disables

> > > CONFIG_CPU_SPECTRE) during randconfig testing.

> > >

> > > I don't see an easy way to add this in there, short of rewriting the

> > > whole __get_user_err() function. Any suggestions?

> >

> > Can't we just fall back to using copy_from_user with a little wrapper

> > that switches based on sizeof()?

> 

> I came up with something now. It's not pretty, but seems to satisfy the

> compiler. Not a proper patch yet, but let me know if you find a bug.


Have you checked what the behaviour is when "ptr" is a pointer to a
pointer?  I think you'll end up with a compiler warning for every
case, complaining about casting an unsigned long long to a pointer.

> 

> This might contain a double uaccess_save_and_enable/uaccess_restore,

> not sure how much we care about that.

> 

>      Arnd

> 

> index 7e0d2727c6b5..c21cdecadf26 100644

> --- a/arch/arm/include/asm/uaccess.h

> +++ b/arch/arm/include/asm/uaccess.h

> @@ -307,6 +307,7 @@ static inline void set_fs(mm_segment_t fs)

>  do {                                                                   \

>         unsigned long __gu_addr = (unsigned long)(ptr);                 \

>         unsigned long __gu_val;                                         \

> +       unsigned long long __gu_val8;                                   \

>         unsigned int __ua_flags;                                        \

>         __chk_user_ptr(ptr);                                            \

>         might_fault();                                                  \

> @@ -315,10 +316,13 @@ do {

>                          \

>         case 1: __get_user_asm_byte(__gu_val, __gu_addr, err);  break;  \

>         case 2: __get_user_asm_half(__gu_val, __gu_addr, err);  break;  \

>         case 4: __get_user_asm_word(__gu_val, __gu_addr, err);  break;  \

> +       case 8: __get_user_asm_dword(__gu_val8, __gu_addr, err);break;  \

>         default: (__gu_val) = __get_user_bad();                         \

>         }                                                               \

>         uaccess_restore(__ua_flags);                                    \

> -       (x) = (__typeof__(*(ptr)))__gu_val;                             \

> +       (x) = __builtin_choose_expr(sizeof(*(ptr)) == 8,                \

> +               (__typeof__(*(ptr)))__gu_val8,                          \

> +               (__typeof__(*(ptr)))__gu_val);                          \

>  } while (0)

> 

>  #define __get_user_asm(x, addr, err, instr)                    \

> @@ -373,6 +377,8 @@ do {

>                          \

>         __get_user_asm(x, addr, err, ldr)

>  #endif

> 

> +#define __get_user_asm_dword(x, addr, err)                     \

> +       do { err = raw_copy_from_user(&x, (void __user *)addr, 8) ?

> -EFAULT : 0; } while (0)

> 

>  #define __put_user_switch(x, ptr, __err, __fn)                         \

>         do {                                                            \

> 


-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up
Randy Dunlap June 28, 2019, 11:25 p.m. UTC | #7
On 6/28/19 5:44 AM, Christoph Hellwig wrote:
> On Fri, Jun 28, 2019 at 12:39:52PM +0200, Arnd Bergmann wrote:

>> Not all architectures support get_user() with a 64-bit argument:

> 

> Which architectures are still missing?  I think we finally need to

> get everyone in line instead of repeatedly working around the lack

> of minor arch support.

> 


arch/microblaze/include/asm/uaccess.c does not support get_user()
with a size of 8.

-- 
~Randy
Arnd Bergmann July 1, 2019, 2:54 p.m. UTC | #8
On Fri, Jun 28, 2019 at 5:59 PM Jaegeuk Kim <jaegeuk@kernel.org> wrote:
>

> Hi Arnd,

>

> If you don't mind, can I integrate this into the original patch in the queue?


Yes, I think that would be good anyway, it may take a little longer to fix all
the architectures.

        Arnd
Arnd Bergmann July 1, 2019, 2:58 p.m. UTC | #9
On Fri, Jun 28, 2019 at 7:58 PM Russell King - ARM Linux admin
<linux@armlinux.org.uk> wrote:
>

> On Fri, Jun 28, 2019 at 04:46:14PM +0200, Arnd Bergmann wrote:

> > On Fri, Jun 28, 2019 at 3:17 PM Christoph Hellwig <hch@infradead.org> wrote:

> > >

> > > On Fri, Jun 28, 2019 at 03:09:47PM +0200, Arnd Bergmann wrote:

> > > > I came across this on arm-nommu (which disables

> > > > CONFIG_CPU_SPECTRE) during randconfig testing.

> > > >

> > > > I don't see an easy way to add this in there, short of rewriting the

> > > > whole __get_user_err() function. Any suggestions?

> > >

> > > Can't we just fall back to using copy_from_user with a little wrapper

> > > that switches based on sizeof()?

> >

> > I came up with something now. It's not pretty, but seems to satisfy the

> > compiler. Not a proper patch yet, but let me know if you find a bug.

>

> Have you checked what the behaviour is when "ptr" is a pointer to a

> pointer?  I think you'll end up with a compiler warning for every

> case, complaining about casting an unsigned long long to a pointer.


I have built lots of kernels using this patch as a test, though my autobuilder
is currently configured to use clang-8, and other compilers or versions
might show more warnings.

> >         uaccess_restore(__ua_flags);                                    \

> > -       (x) = (__typeof__(*(ptr)))__gu_val;                             \

> > +       (x) = __builtin_choose_expr(sizeof(*(ptr)) == 8,                \

> > +               (__typeof__(*(ptr)))__gu_val8,                          \

> > +               (__typeof__(*(ptr)))__gu_val);                          \

> >  } while (0)


The __builtin_choose_expr() here is supposed to take care of the case
of a pointer type, gcc and clang should both ignore the non-taken
branch and only produce warnings for the case they actually use.

       Arnd
diff mbox series

Patch

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 998affe31419..465853029b8e 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3066,7 +3066,8 @@  static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)
 	if (f2fs_readonly(sbi->sb))
 		return -EROFS;
 
-	if (get_user(block_count, (__u64 __user *)arg))
+	if (copy_from_user(&block_count, (void __user *)arg,
+			   sizeof(block_count)))
 		return -EFAULT;
 
 	ret = f2fs_resize_fs(sbi, block_count);