public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] fs: Replace user_access_{begin/end} by scoped user access
@ 2026-03-10 14:40 Christophe Leroy (CS GROUP)
  2026-03-10 22:10 ` kernel test robot
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Christophe Leroy (CS GROUP) @ 2026-03-10 14:40 UTC (permalink / raw)
  To: Alexander Viro, Christian Brauner, Jan Kara, Linus Torvalds,
	Thomas Gleixner, David Laight
  Cc: Christophe Leroy (CS GROUP), linux-fsdevel, linux-kernel

Scoped user access reduces code complexity and seamlessly bring
masked user access on architectures that support it.

Replace user_access_begin/user_access_end blocks in fs by
scoped user access.

Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
---
 fs/readdir.c | 92 +++++++++++++++++++++-------------------------------
 fs/select.c  | 33 ++++++++-----------
 2 files changed, 50 insertions(+), 75 deletions(-)

diff --git a/fs/readdir.c b/fs/readdir.c
index 73707b6816e9..3ebe4adbe36c 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -198,18 +198,15 @@ static bool fillonedir(struct dir_context *ctx, const char *name, int namlen,
 	}
 	buf->result++;
 	dirent = buf->dirent;
-	if (!user_write_access_begin(dirent,
+	scoped_user_write_access_size(dirent,
 			(unsigned long)(dirent->d_name + namlen + 1) -
-				(unsigned long)dirent))
-		goto efault;
-	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
-	unsafe_put_user(offset, &dirent->d_offset, efault_end);
-	unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
-	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
-	user_write_access_end();
+				(unsigned long)dirent, efault) {
+		unsafe_put_user(d_ino, &dirent->d_ino, efault);
+		unsafe_put_user(offset, &dirent->d_offset, efault);
+		unsafe_put_user(namlen, &dirent->d_namlen, efault);
+		unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
+	}
 	return true;
-efault_end:
-	user_write_access_end();
 efault:
 	buf->result = -EFAULT;
 	return false;
@@ -287,23 +284,19 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen,
 		return false;
 	dirent = buf->current_dir;
 	prev = (void __user *) dirent - prev_reclen;
-	if (!user_write_access_begin(prev, reclen + prev_reclen))
-		goto efault;
-
-	/* This might be 'dirent->d_off', but if so it will get overwritten */
-	unsafe_put_user(offset, &prev->d_off, efault_end);
-	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
-	unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
-	unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
-	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
-	user_write_access_end();
+	scoped_user_write_access_size(prev, reclen + prev_reclen, efault) {
+		/* This might be 'dirent->d_off', but if so it will get overwritten */
+		unsafe_put_user(offset, &prev->d_off, efault);
+		unsafe_put_user(d_ino, &dirent->d_ino, efault);
+		unsafe_put_user(reclen, &dirent->d_reclen, efault);
+		unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault);
+		unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
+	}
 
 	buf->current_dir = (void __user *)dirent + reclen;
 	buf->prev_reclen = reclen;
 	ctx->count -= reclen;
 	return true;
-efault_end:
-	user_write_access_end();
 efault:
 	buf->error = -EFAULT;
 	return false;
@@ -371,24 +364,20 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen,
 		return false;
 	dirent = buf->current_dir;
 	prev = (void __user *)dirent - prev_reclen;
-	if (!user_write_access_begin(prev, reclen + prev_reclen))
-		goto efault;
-
-	/* This might be 'dirent->d_off', but if so it will get overwritten */
-	unsafe_put_user(offset, &prev->d_off, efault_end);
-	unsafe_put_user(ino, &dirent->d_ino, efault_end);
-	unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
-	unsafe_put_user(d_type, &dirent->d_type, efault_end);
-	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
-	user_write_access_end();
+	scoped_user_write_access_size(prev, reclen + prev_reclen, efault) {
+		/* This might be 'dirent->d_off', but if so it will get overwritten */
+		unsafe_put_user(offset, &prev->d_off, efault);
+		unsafe_put_user(ino, &dirent->d_ino, efault);
+		unsafe_put_user(reclen, &dirent->d_reclen, efault);
+		unsafe_put_user(d_type, &dirent->d_type, efault);
+		unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
+	}
 
 	buf->prev_reclen = reclen;
 	buf->current_dir = (void __user *)dirent + reclen;
 	ctx->count -= reclen;
 	return true;
 
-efault_end:
-	user_write_access_end();
 efault:
 	buf->error = -EFAULT;
 	return false;
@@ -460,18 +449,15 @@ static bool compat_fillonedir(struct dir_context *ctx, const char *name,
 	}
 	buf->result++;
 	dirent = buf->dirent;
-	if (!user_write_access_begin(dirent,
+	scoped_user_write_access_size(dirent,
 			(unsigned long)(dirent->d_name + namlen + 1) -
-				(unsigned long)dirent))
-		goto efault;
-	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
-	unsafe_put_user(offset, &dirent->d_offset, efault_end);
-	unsafe_put_user(namlen, &dirent->d_namlen, efault_end);
-	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
-	user_write_access_end();
+				(unsigned long)dirent), efault) {
+		unsafe_put_user(d_ino, &dirent->d_ino, efault);
+		unsafe_put_user(offset, &dirent->d_offset, efault);
+		unsafe_put_user(namlen, &dirent->d_namlen, efault);
+		unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
+	}
 	return true;
-efault_end:
-	user_write_access_end();
 efault:
 	buf->result = -EFAULT;
 	return false;
@@ -543,22 +529,18 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen
 		return false;
 	dirent = buf->current_dir;
 	prev = (void __user *) dirent - prev_reclen;
-	if (!user_write_access_begin(prev, reclen + prev_reclen))
-		goto efault;
-
-	unsafe_put_user(offset, &prev->d_off, efault_end);
-	unsafe_put_user(d_ino, &dirent->d_ino, efault_end);
-	unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
-	unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
-	unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
-	user_write_access_end();
+	scoped_user_write_access_size(prev, reclen + prev_reclen, efault);
+		unsafe_put_user(offset, &prev->d_off, efault);
+		unsafe_put_user(d_ino, &dirent->d_ino, efault);
+		unsafe_put_user(reclen, &dirent->d_reclen, efault);
+		unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault);
+		unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
+	}
 
 	buf->prev_reclen = reclen;
 	buf->current_dir = (void __user *)dirent + reclen;
 	ctx->count -= reclen;
 	return true;
-efault_end:
-	user_write_access_end();
 efault:
 	buf->error = -EFAULT;
 	return false;
diff --git a/fs/select.c b/fs/select.c
index e0244dbe4429..7cf80568ff78 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -1004,17 +1004,17 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
 	fdcount = do_poll(head, &table, end_time);
 	poll_freewait(&table);
 
-	if (!user_write_access_begin(ufds, nfds * sizeof(*ufds)))
-		goto out_fds;
+	scoped_user_write_access_size(ufds, nfds * sizeof(*ufds), out_fds) {
+		struct pollfd __user *_ufds = ufds;
 
-	for (walk = head; walk; walk = walk->next) {
-		struct pollfd *fds = walk->entries;
-		unsigned int j;
+		for (walk = head; walk; walk = walk->next) {
+			struct pollfd *fds = walk->entries;
+			unsigned int j;
 
-		for (j = walk->len; j; fds++, ufds++, j--)
-			unsafe_put_user(fds->revents, &ufds->revents, Efault);
-  	}
-	user_write_access_end();
+			for (j = walk->len; j; fds++, _ufds++, j--)
+				unsafe_put_user(fds->revents, &_ufds->revents, out_fds);
+		}
+	}
 
 	err = fdcount;
 out_fds:
@@ -1026,11 +1026,6 @@ static int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
 	}
 
 	return err;
-
-Efault:
-	user_write_access_end();
-	err = -EFAULT;
-	goto out_fds;
 }
 
 static long do_restart_poll(struct restart_block *restart_block)
@@ -1338,15 +1333,13 @@ static inline int get_compat_sigset_argpack(struct compat_sigset_argpack *to,
 					    struct compat_sigset_argpack __user *from)
 {
 	if (from) {
-		if (!user_read_access_begin(from, sizeof(*from)))
-			return -EFAULT;
-		unsafe_get_user(to->p, &from->p, Efault);
-		unsafe_get_user(to->size, &from->size, Efault);
-		user_read_access_end();
+		scoped_user_read_access(from, Efault) {
+			unsafe_get_user(to->p, &from->p, Efault);
+			unsafe_get_user(to->size, &from->size, Efault);
+		}
 	}
 	return 0;
 Efault:
-	user_read_access_end();
 	return -EFAULT;
 }
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] fs: Replace user_access_{begin/end} by scoped user access
  2026-03-10 14:40 [PATCH] fs: Replace user_access_{begin/end} by scoped user access Christophe Leroy (CS GROUP)
@ 2026-03-10 22:10 ` kernel test robot
  2026-03-10 23:01 ` kernel test robot
  2026-03-11  0:27 ` kernel test robot
  2 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-03-10 22:10 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP), Alexander Viro, Christian Brauner,
	Jan Kara, Linus Torvalds, Thomas Gleixner, David Laight
  Cc: oe-kbuild-all, LKML, Christophe Leroy (CS GROUP), linux-fsdevel

Hi Christophe,

kernel test robot noticed the following build errors:

[auto build test ERROR on brauner-vfs/vfs.all]
[also build test ERROR on linus/master v7.0-rc3 next-20260310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Christophe-Leroy-CS-GROUP/fs-Replace-user_access_-begin-end-by-scoped-user-access/20260310-230227
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link:    https://lore.kernel.org/r/5021aa325554b3d2437341514ab0a2977e158274.1773153431.git.chleroy%40kernel.org
patch subject: [PATCH] fs: Replace user_access_{begin/end} by scoped user access
config: x86_64-defconfig (https://download.01.org/0day-ci/archive/20260311/202603110628.zpGycSV5-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260311/202603110628.zpGycSV5-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603110628.zpGycSV5-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   fs/readdir.c: In function 'compat_fillonedir':
>> fs/readdir.c:454:54: error: macro "scoped_user_write_access_size" requires 3 arguments, but only 2 given
     454 |                                 (unsigned long)dirent), efault) {
         |                                                      ^
   In file included from include/linux/sched/task.h:13,
                    from include/linux/sched/signal.h:9,
                    from include/linux/rcuwait.h:6,
                    from include/linux/mm.h:37,
                    from fs/readdir.c:12:
   include/linux/uaccess.h:778:9: note: macro "scoped_user_write_access_size" defined here
     778 | #define scoped_user_write_access_size(udst, size, elbl)                 \
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> fs/readdir.c:452:9: error: 'scoped_user_write_access_size' undeclared (first use in this function)
     452 |         scoped_user_write_access_size(dirent,
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   fs/readdir.c:452:9: note: each undeclared identifier is reported only once for each function it appears in
>> fs/readdir.c:454:57: error: 'efault' undeclared (first use in this function)
     454 |                                 (unsigned long)dirent), efault) {
         |                                                         ^~~~~~
>> fs/readdir.c:454:55: warning: left-hand operand of comma expression has no effect [-Wunused-value]
     454 |                                 (unsigned long)dirent), efault) {
         |                                                       ^
>> fs/readdir.c:454:63: error: expected ';' before ')' token
     454 |                                 (unsigned long)dirent), efault) {
         |                                                               ^
         |                                                               ;
>> fs/readdir.c:454:63: error: expected statement before ')' token
   fs/readdir.c: In function 'compat_filldir':
>> include/linux/uaccess.h:744:17: warning: this 'for' clause does not guard... [-Wmisleading-indentation]
     744 |                 for (const auto uptr  __cleanup(__scoped_user_##mode##_access_end) = \
         |                 ^~~
   include/linux/uaccess.h:779:9: note: in expansion of macro '__scoped_user_access'
     779 |         __scoped_user_access(write, udst, size, elbl)
         |         ^~~~~~~~~~~~~~~~~~~~
   fs/readdir.c:532:9: note: in expansion of macro 'scoped_user_write_access_size'
     532 |         scoped_user_write_access_size(prev, reclen + prev_reclen, efault);
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/uaccess.h:616:1: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'
     616 | do {                                                    \
         | ^~
   fs/readdir.c:533:17: note: in expansion of macro 'unsafe_put_user'
     533 |                 unsafe_put_user(offset, &prev->d_off, efault);
         |                 ^~~~~~~~~~~~~~~
   In file included from include/linux/uaccess.h:13:
>> arch/x86/include/asm/uaccess.h:471:26: error: label 'efault' used but not defined
     471 | #define __m(x) (*(struct __large_struct __user *)(x))
         |                          ^~~~~~~~~~~~~~
   arch/x86/include/asm/uaccess.h:482:36: note: in expansion of macro '__m'
     482 |                 : : ltype(x), "m" (__m(addr))                           \
         |                                    ^~~
   arch/x86/include/asm/uaccess.h:146:9: note: in expansion of macro '__put_user_goto'
     146 |         __put_user_goto(x, ptr, "q", "er", label)
         |         ^~~~~~~~~~~~~~~
   arch/x86/include/asm/uaccess.h:248:17: note: in expansion of macro '__put_user_goto_u64'
     248 |                 __put_user_goto_u64(__x, __ptr, label);                 \
         |                 ^~~~~~~~~~~~~~~~~~~
   arch/x86/include/asm/uaccess.h:532:9: note: in expansion of macro '__put_user_size'
     532 |         __put_user_size((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), label)
         |         ^~~~~~~~~~~~~~~
   include/linux/uaccess.h:618:9: note: in expansion of macro 'arch_unsafe_put_user'
     618 |         arch_unsafe_put_user(x, ptr, local_label);      \
         |         ^~~~~~~~~~~~~~~~~~~~
   arch/x86/include/asm/uaccess.h:603:17: note: in expansion of macro 'unsafe_put_user'
     603 |                 unsafe_put_user(*(type *)(src),(type __user *)(dst),label);     \
         |                 ^~~~~~~~~~~~~~~
   arch/x86/include/asm/uaccess.h:617:9: note: in expansion of macro 'unsafe_copy_loop'
     617 |         unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label);   \
         |         ^~~~~~~~~~~~~~~~
   fs/readdir.c:81:9: note: in expansion of macro 'unsafe_copy_to_user'
      81 |         unsafe_copy_to_user(dst, src, len, label);              \
         |         ^~~~~~~~~~~~~~~~~~~
   fs/readdir.c:537:17: note: in expansion of macro 'unsafe_copy_dirent_name'
     537 |                 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
         |                 ^~~~~~~~~~~~~~~~~~~~~~~
   fs/readdir.c: At top level:
>> fs/readdir.c:540:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before '->' token
     540 |         buf->prev_reclen = reclen;
         |            ^~
   fs/readdir.c:541:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before '->' token
     541 |         buf->current_dir = (void __user *)dirent + reclen;
         |            ^~
   fs/readdir.c:542:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before '->' token
     542 |         ctx->count -= reclen;
         |            ^~
>> fs/readdir.c:543:9: error: expected identifier or '(' before 'return'
     543 |         return true;
         |         ^~~~~~
>> fs/readdir.c:544:7: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token
     544 | efault:
         |       ^
   fs/readdir.c:546:9: error: expected identifier or '(' before 'return'
     546 |         return false;
         |         ^~~~~~
>> fs/readdir.c:547:1: error: expected identifier or '(' before '}' token
     547 | }
         | ^
   fs/readdir.c: In function 'compat_filldir':
>> fs/readdir.c:538:9: warning: control reaches end of non-void function [-Wreturn-type]
     538 |         }
         |         ^


vim +/scoped_user_write_access_size +454 fs/readdir.c

   430	
   431	static bool compat_fillonedir(struct dir_context *ctx, const char *name,
   432				     int namlen, loff_t offset, u64 ino,
   433				     unsigned int d_type)
   434	{
   435		struct compat_readdir_callback *buf =
   436			container_of(ctx, struct compat_readdir_callback, ctx);
   437		struct compat_old_linux_dirent __user *dirent;
   438		compat_ulong_t d_ino;
   439	
   440		if (buf->result)
   441			return false;
   442		buf->result = verify_dirent_name(name, namlen);
   443		if (buf->result)
   444			return false;
   445		d_ino = ino;
   446		if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
   447			buf->result = -EOVERFLOW;
   448			return false;
   449		}
   450		buf->result++;
   451		dirent = buf->dirent;
 > 452		scoped_user_write_access_size(dirent,
   453				(unsigned long)(dirent->d_name + namlen + 1) -
 > 454					(unsigned long)dirent), efault) {
   455			unsafe_put_user(d_ino, &dirent->d_ino, efault);
   456			unsafe_put_user(offset, &dirent->d_offset, efault);
   457			unsafe_put_user(namlen, &dirent->d_namlen, efault);
   458			unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
   459		}
   460		return true;
   461	efault:
   462		buf->result = -EFAULT;
   463		return false;
   464	}
   465	
   466	COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
   467			struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
   468	{
   469		int error;
   470		CLASS(fd_pos, f)(fd);
   471		struct compat_readdir_callback buf = {
   472			.ctx.actor = compat_fillonedir,
   473			.ctx.count = 1, /* Hint to fs: just one entry. */
   474			.dirent = dirent
   475		};
   476	
   477		if (fd_empty(f))
   478			return -EBADF;
   479	
   480		error = iterate_dir(fd_file(f), &buf.ctx);
   481		if (buf.result)
   482			error = buf.result;
   483	
   484		return error;
   485	}
   486	
   487	struct compat_linux_dirent {
   488		compat_ulong_t	d_ino;
   489		compat_ulong_t	d_off;
   490		unsigned short	d_reclen;
   491		char		d_name[];
   492	};
   493	
   494	struct compat_getdents_callback {
   495		struct dir_context ctx;
   496		struct compat_linux_dirent __user *current_dir;
   497		int prev_reclen;
   498		int error;
   499	};
   500	
   501	static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen,
   502			loff_t offset, u64 ino, unsigned int d_type)
   503	{
   504		struct compat_linux_dirent __user *dirent, *prev;
   505		struct compat_getdents_callback *buf =
   506			container_of(ctx, struct compat_getdents_callback, ctx);
   507		compat_ulong_t d_ino;
   508		int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
   509			namlen + 2, sizeof(compat_long_t));
   510		int prev_reclen;
   511		unsigned int flags = d_type;
   512	
   513		BUILD_BUG_ON(FILLDIR_FLAG_NOINTR & S_DT_MASK);
   514		d_type &= S_DT_MASK;
   515	
   516		buf->error = verify_dirent_name(name, namlen);
   517		if (unlikely(buf->error))
   518			return false;
   519		buf->error = -EINVAL;	/* only used if we fail.. */
   520		if (reclen > ctx->count)
   521			return false;
   522		d_ino = ino;
   523		if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
   524			buf->error = -EOVERFLOW;
   525			return false;
   526		}
   527		prev_reclen = buf->prev_reclen;
   528		if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current))
   529			return false;
   530		dirent = buf->current_dir;
   531		prev = (void __user *) dirent - prev_reclen;
   532		scoped_user_write_access_size(prev, reclen + prev_reclen, efault);
   533			unsafe_put_user(offset, &prev->d_off, efault);
   534			unsafe_put_user(d_ino, &dirent->d_ino, efault);
   535			unsafe_put_user(reclen, &dirent->d_reclen, efault);
   536			unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault);
   537			unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
 > 538		}
   539	
 > 540		buf->prev_reclen = reclen;
 > 541		buf->current_dir = (void __user *)dirent + reclen;
   542		ctx->count -= reclen;
 > 543		return true;
 > 544	efault:
   545		buf->error = -EFAULT;
 > 546		return false;
 > 547	}
   548	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] fs: Replace user_access_{begin/end} by scoped user access
  2026-03-10 14:40 [PATCH] fs: Replace user_access_{begin/end} by scoped user access Christophe Leroy (CS GROUP)
  2026-03-10 22:10 ` kernel test robot
@ 2026-03-10 23:01 ` kernel test robot
  2026-03-11  0:27 ` kernel test robot
  2 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-03-10 23:01 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP), Alexander Viro, Christian Brauner,
	Jan Kara, Linus Torvalds, Thomas Gleixner, David Laight
  Cc: oe-kbuild-all, LKML, Christophe Leroy (CS GROUP), linux-fsdevel

Hi Christophe,

kernel test robot noticed the following build errors:

[auto build test ERROR on brauner-vfs/vfs.all]
[also build test ERROR on linus/master v7.0-rc3 next-20260310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Christophe-Leroy-CS-GROUP/fs-Replace-user_access_-begin-end-by-scoped-user-access/20260310-230227
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link:    https://lore.kernel.org/r/5021aa325554b3d2437341514ab0a2977e158274.1773153431.git.chleroy%40kernel.org
patch subject: [PATCH] fs: Replace user_access_{begin/end} by scoped user access
config: powerpc64-allnoconfig-bpf (https://download.01.org/0day-ci/archive/20260310/202603102326.JZ7c6Opr-lkp@intel.com/config)
compiler: powerpc64-linux-gnu-gcc (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260310/202603102326.JZ7c6Opr-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603102326.JZ7c6Opr-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   fs/readdir.c: In function 'compat_fillonedir':
>> fs/readdir.c:454:54: error: macro "scoped_user_write_access_size" requires 3 arguments, but only 2 given
     454 |                                 (unsigned long)dirent), efault) {
         |                                                      ^
   In file included from ./include/linux/sched/task.h:13,
                    from ./include/linux/sched/signal.h:9,
                    from ./include/linux/rcuwait.h:6,
                    from ./include/linux/mm.h:37,
                    from fs/readdir.c:12:
   ./include/linux/uaccess.h:778:9: note: macro "scoped_user_write_access_size" defined here
     778 | #define scoped_user_write_access_size(udst, size, elbl)                 \
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> fs/readdir.c:452:9: error: 'scoped_user_write_access_size' undeclared (first use in this function)
     452 |         scoped_user_write_access_size(dirent,
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   fs/readdir.c:452:9: note: each undeclared identifier is reported only once for each function it appears in
>> fs/readdir.c:454:57: error: 'efault' undeclared (first use in this function)
     454 |                                 (unsigned long)dirent), efault) {
         |                                                         ^~~~~~
>> fs/readdir.c:454:55: warning: left-hand operand of comma expression has no effect [-Wunused-value]
     454 |                                 (unsigned long)dirent), efault) {
         |                                                       ^
>> fs/readdir.c:454:63: error: expected ';' before ')' token
     454 |                                 (unsigned long)dirent), efault) {
         |                                                               ^
         |                                                               ;
>> fs/readdir.c:454:63: error: expected statement before ')' token
   fs/readdir.c: In function 'compat_filldir':
>> ./include/linux/uaccess.h:744:17: warning: this 'for' clause does not guard... [-Wmisleading-indentation]
     744 |                 for (const auto uptr  __cleanup(__scoped_user_##mode##_access_end) = \
         |                 ^~~
   ./include/linux/uaccess.h:779:9: note: in expansion of macro '__scoped_user_access'
     779 |         __scoped_user_access(write, udst, size, elbl)
         |         ^~~~~~~~~~~~~~~~~~~~
   fs/readdir.c:532:9: note: in expansion of macro 'scoped_user_write_access_size'
     532 |         scoped_user_write_access_size(prev, reclen + prev_reclen, efault);
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   ./include/linux/uaccess.h:616:1: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'
     616 | do {                                                    \
         | ^~
   fs/readdir.c:533:17: note: in expansion of macro 'unsafe_put_user'
     533 |                 unsafe_put_user(offset, &prev->d_off, efault);
         |                 ^~~~~~~~~~~~~~~
>> fs/readdir.c:537:17: error: label 'efault' used but not defined
     537 |                 unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
         |                 ^~~~~~~~~~~~~~~~~~~~~~~
   fs/readdir.c: At top level:
>> fs/readdir.c:540:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before '->' token
     540 |         buf->prev_reclen = reclen;
         |            ^~
   fs/readdir.c:541:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before '->' token
     541 |         buf->current_dir = (void __user *)dirent + reclen;
         |            ^~
   fs/readdir.c:542:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before '->' token
     542 |         ctx->count -= reclen;
         |            ^~
>> fs/readdir.c:543:9: error: expected identifier or '(' before 'return'
     543 |         return true;
         |         ^~~~~~
>> fs/readdir.c:544:7: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token
     544 | efault:
         |       ^
   fs/readdir.c:546:9: error: expected identifier or '(' before 'return'
     546 |         return false;
         |         ^~~~~~
>> fs/readdir.c:547:1: error: expected identifier or '(' before '}' token
     547 | }
         | ^
   fs/readdir.c: In function 'compat_filldir':
>> fs/readdir.c:538:9: warning: control reaches end of non-void function [-Wreturn-type]
     538 |         }
         |         ^


vim +/scoped_user_write_access_size +454 fs/readdir.c

   430	
   431	static bool compat_fillonedir(struct dir_context *ctx, const char *name,
   432				     int namlen, loff_t offset, u64 ino,
   433				     unsigned int d_type)
   434	{
   435		struct compat_readdir_callback *buf =
   436			container_of(ctx, struct compat_readdir_callback, ctx);
   437		struct compat_old_linux_dirent __user *dirent;
   438		compat_ulong_t d_ino;
   439	
   440		if (buf->result)
   441			return false;
   442		buf->result = verify_dirent_name(name, namlen);
   443		if (buf->result)
   444			return false;
   445		d_ino = ino;
   446		if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
   447			buf->result = -EOVERFLOW;
   448			return false;
   449		}
   450		buf->result++;
   451		dirent = buf->dirent;
 > 452		scoped_user_write_access_size(dirent,
   453				(unsigned long)(dirent->d_name + namlen + 1) -
 > 454					(unsigned long)dirent), efault) {
   455			unsafe_put_user(d_ino, &dirent->d_ino, efault);
   456			unsafe_put_user(offset, &dirent->d_offset, efault);
   457			unsafe_put_user(namlen, &dirent->d_namlen, efault);
   458			unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
   459		}
   460		return true;
   461	efault:
   462		buf->result = -EFAULT;
   463		return false;
   464	}
   465	
   466	COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
   467			struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
   468	{
   469		int error;
   470		CLASS(fd_pos, f)(fd);
   471		struct compat_readdir_callback buf = {
   472			.ctx.actor = compat_fillonedir,
   473			.ctx.count = 1, /* Hint to fs: just one entry. */
   474			.dirent = dirent
   475		};
   476	
   477		if (fd_empty(f))
   478			return -EBADF;
   479	
   480		error = iterate_dir(fd_file(f), &buf.ctx);
   481		if (buf.result)
   482			error = buf.result;
   483	
   484		return error;
   485	}
   486	
   487	struct compat_linux_dirent {
   488		compat_ulong_t	d_ino;
   489		compat_ulong_t	d_off;
   490		unsigned short	d_reclen;
   491		char		d_name[];
   492	};
   493	
   494	struct compat_getdents_callback {
   495		struct dir_context ctx;
   496		struct compat_linux_dirent __user *current_dir;
   497		int prev_reclen;
   498		int error;
   499	};
   500	
   501	static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen,
   502			loff_t offset, u64 ino, unsigned int d_type)
   503	{
   504		struct compat_linux_dirent __user *dirent, *prev;
   505		struct compat_getdents_callback *buf =
   506			container_of(ctx, struct compat_getdents_callback, ctx);
   507		compat_ulong_t d_ino;
   508		int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
   509			namlen + 2, sizeof(compat_long_t));
   510		int prev_reclen;
   511		unsigned int flags = d_type;
   512	
   513		BUILD_BUG_ON(FILLDIR_FLAG_NOINTR & S_DT_MASK);
   514		d_type &= S_DT_MASK;
   515	
   516		buf->error = verify_dirent_name(name, namlen);
   517		if (unlikely(buf->error))
   518			return false;
   519		buf->error = -EINVAL;	/* only used if we fail.. */
   520		if (reclen > ctx->count)
   521			return false;
   522		d_ino = ino;
   523		if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
   524			buf->error = -EOVERFLOW;
   525			return false;
   526		}
   527		prev_reclen = buf->prev_reclen;
   528		if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current))
   529			return false;
   530		dirent = buf->current_dir;
   531		prev = (void __user *) dirent - prev_reclen;
   532		scoped_user_write_access_size(prev, reclen + prev_reclen, efault);
   533			unsafe_put_user(offset, &prev->d_off, efault);
   534			unsafe_put_user(d_ino, &dirent->d_ino, efault);
   535			unsafe_put_user(reclen, &dirent->d_reclen, efault);
   536			unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault);
 > 537			unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
 > 538		}
   539	
 > 540		buf->prev_reclen = reclen;
   541		buf->current_dir = (void __user *)dirent + reclen;
   542		ctx->count -= reclen;
 > 543		return true;
 > 544	efault:
   545		buf->error = -EFAULT;
   546		return false;
 > 547	}
   548	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] fs: Replace user_access_{begin/end} by scoped user access
  2026-03-10 14:40 [PATCH] fs: Replace user_access_{begin/end} by scoped user access Christophe Leroy (CS GROUP)
  2026-03-10 22:10 ` kernel test robot
  2026-03-10 23:01 ` kernel test robot
@ 2026-03-11  0:27 ` kernel test robot
  2 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-03-11  0:27 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP), Alexander Viro, Christian Brauner,
	Jan Kara, Linus Torvalds, Thomas Gleixner, David Laight
  Cc: oe-kbuild-all, LKML, Christophe Leroy (CS GROUP), linux-fsdevel

Hi Christophe,

kernel test robot noticed the following build errors:

[auto build test ERROR on brauner-vfs/vfs.all]
[also build test ERROR on linus/master v7.0-rc3 next-20260310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Christophe-Leroy-CS-GROUP/fs-Replace-user_access_-begin-end-by-scoped-user-access/20260310-230227
base:   https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link:    https://lore.kernel.org/r/5021aa325554b3d2437341514ab0a2977e158274.1773153431.git.chleroy%40kernel.org
patch subject: [PATCH] fs: Replace user_access_{begin/end} by scoped user access
config: x86_64-randconfig-161-20260311 (https://download.01.org/0day-ci/archive/20260311/202603110842.VJ27Z6FK-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
smatch: v0.5.0-9004-gb810ac53
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260311/202603110842.VJ27Z6FK-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603110842.VJ27Z6FK-lkp@intel.com/

All errors (new ones prefixed by >>):

>> fs/readdir.c:454:26: error: too few arguments provided to function-like macro invocation
     454 |                                 (unsigned long)dirent), efault) {
         |                                                      ^
   include/linux/uaccess.h:778:9: note: macro 'scoped_user_write_access_size' defined here
     778 | #define scoped_user_write_access_size(udst, size, elbl)                 \
         |         ^
>> fs/readdir.c:452:2: error: use of undeclared identifier 'scoped_user_write_access_size'; did you mean '__scoped_user_write_access_end'?
     452 |         scoped_user_write_access_size(dirent,
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |         __scoped_user_write_access_end
   include/linux/uaccess.h:658:29: note: '__scoped_user_write_access_end' declared here
     658 | static __always_inline void __scoped_user_write_access_end(const void *p)
         |                             ^
>> fs/readdir.c:454:35: error: expected ';' after expression
     454 |                                 (unsigned long)dirent), efault) {
         |                                                               ^
         |                                                               ;
>> fs/readdir.c:454:29: error: use of undeclared identifier 'efault'
     454 |                                 (unsigned long)dirent), efault) {
         |                                                         ^
>> fs/readdir.c:454:35: error: expected expression
     454 |                                 (unsigned long)dirent), efault) {
         |                                                               ^
>> fs/readdir.c:532:60: error: use of undeclared label 'efault'
     532 |         scoped_user_write_access_size(prev, reclen + prev_reclen, efault);
         |                                                                   ^
>> fs/readdir.c:540:2: error: unknown type name 'buf'
     540 |         buf->prev_reclen = reclen;
         |         ^
>> fs/readdir.c:540:5: error: expected identifier or '('
     540 |         buf->prev_reclen = reclen;
         |            ^
   fs/readdir.c:541:2: error: unknown type name 'buf'
     541 |         buf->current_dir = (void __user *)dirent + reclen;
         |         ^
   fs/readdir.c:541:5: error: expected identifier or '('
     541 |         buf->current_dir = (void __user *)dirent + reclen;
         |            ^
>> fs/readdir.c:542:2: error: unknown type name 'ctx'
     542 |         ctx->count -= reclen;
         |         ^
   fs/readdir.c:542:5: error: expected identifier or '('
     542 |         ctx->count -= reclen;
         |            ^
   fs/readdir.c:543:2: error: expected identifier or '('
     543 |         return true;
         |         ^
>> fs/readdir.c:544:1: error: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int]
     544 | efault:
         | ^
         | int
>> fs/readdir.c:544:7: error: expected ';' after top level declarator
     544 | efault:
         |       ^
         |       ;
   fs/readdir.c:545:2: error: unknown type name 'buf'
     545 |         buf->error = -EFAULT;
         |         ^
   fs/readdir.c:545:5: error: expected identifier or '('
     545 |         buf->error = -EFAULT;
         |            ^
   fs/readdir.c:546:2: error: expected identifier or '('
     546 |         return false;
         |         ^
>> fs/readdir.c:547:1: error: extraneous closing brace ('}')
     547 | }
         | ^
   19 errors generated.


vim +454 fs/readdir.c

   430	
   431	static bool compat_fillonedir(struct dir_context *ctx, const char *name,
   432				     int namlen, loff_t offset, u64 ino,
   433				     unsigned int d_type)
   434	{
   435		struct compat_readdir_callback *buf =
   436			container_of(ctx, struct compat_readdir_callback, ctx);
   437		struct compat_old_linux_dirent __user *dirent;
   438		compat_ulong_t d_ino;
   439	
   440		if (buf->result)
   441			return false;
   442		buf->result = verify_dirent_name(name, namlen);
   443		if (buf->result)
   444			return false;
   445		d_ino = ino;
   446		if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
   447			buf->result = -EOVERFLOW;
   448			return false;
   449		}
   450		buf->result++;
   451		dirent = buf->dirent;
 > 452		scoped_user_write_access_size(dirent,
   453				(unsigned long)(dirent->d_name + namlen + 1) -
 > 454					(unsigned long)dirent), efault) {
   455			unsafe_put_user(d_ino, &dirent->d_ino, efault);
   456			unsafe_put_user(offset, &dirent->d_offset, efault);
   457			unsafe_put_user(namlen, &dirent->d_namlen, efault);
   458			unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
   459		}
   460		return true;
   461	efault:
   462		buf->result = -EFAULT;
   463		return false;
   464	}
   465	
   466	COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
   467			struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
   468	{
   469		int error;
   470		CLASS(fd_pos, f)(fd);
   471		struct compat_readdir_callback buf = {
   472			.ctx.actor = compat_fillonedir,
   473			.ctx.count = 1, /* Hint to fs: just one entry. */
   474			.dirent = dirent
   475		};
   476	
   477		if (fd_empty(f))
   478			return -EBADF;
   479	
   480		error = iterate_dir(fd_file(f), &buf.ctx);
   481		if (buf.result)
   482			error = buf.result;
   483	
   484		return error;
   485	}
   486	
   487	struct compat_linux_dirent {
   488		compat_ulong_t	d_ino;
   489		compat_ulong_t	d_off;
   490		unsigned short	d_reclen;
   491		char		d_name[];
   492	};
   493	
   494	struct compat_getdents_callback {
   495		struct dir_context ctx;
   496		struct compat_linux_dirent __user *current_dir;
   497		int prev_reclen;
   498		int error;
   499	};
   500	
   501	static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen,
   502			loff_t offset, u64 ino, unsigned int d_type)
   503	{
   504		struct compat_linux_dirent __user *dirent, *prev;
   505		struct compat_getdents_callback *buf =
   506			container_of(ctx, struct compat_getdents_callback, ctx);
   507		compat_ulong_t d_ino;
   508		int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
   509			namlen + 2, sizeof(compat_long_t));
   510		int prev_reclen;
   511		unsigned int flags = d_type;
   512	
   513		BUILD_BUG_ON(FILLDIR_FLAG_NOINTR & S_DT_MASK);
   514		d_type &= S_DT_MASK;
   515	
   516		buf->error = verify_dirent_name(name, namlen);
   517		if (unlikely(buf->error))
   518			return false;
   519		buf->error = -EINVAL;	/* only used if we fail.. */
   520		if (reclen > ctx->count)
   521			return false;
   522		d_ino = ino;
   523		if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
   524			buf->error = -EOVERFLOW;
   525			return false;
   526		}
   527		prev_reclen = buf->prev_reclen;
   528		if (!(flags & FILLDIR_FLAG_NOINTR) && prev_reclen && signal_pending(current))
   529			return false;
   530		dirent = buf->current_dir;
   531		prev = (void __user *) dirent - prev_reclen;
 > 532		scoped_user_write_access_size(prev, reclen + prev_reclen, efault);
   533			unsafe_put_user(offset, &prev->d_off, efault);
   534			unsafe_put_user(d_ino, &dirent->d_ino, efault);
   535			unsafe_put_user(reclen, &dirent->d_reclen, efault);
   536			unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault);
   537			unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault);
   538		}
   539	
 > 540		buf->prev_reclen = reclen;
   541		buf->current_dir = (void __user *)dirent + reclen;
 > 542		ctx->count -= reclen;
   543		return true;
 > 544	efault:
   545		buf->error = -EFAULT;
   546		return false;
 > 547	}
   548	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-03-11  0:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-10 14:40 [PATCH] fs: Replace user_access_{begin/end} by scoped user access Christophe Leroy (CS GROUP)
2026-03-10 22:10 ` kernel test robot
2026-03-10 23:01 ` kernel test robot
2026-03-11  0:27 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox