diff mbox series

[v2,13/16] fanotify: report name info for FAN_DIR_MODIFY event

Message ID 20200217131455.31107-14-amir73il@gmail.com (mailing list archive)
State New, archived
Headers show
Series Fanotify event with name info | expand

Commit Message

Amir Goldstein Feb. 17, 2020, 1:14 p.m. UTC
Report event FAN_DIR_MODIFY with name in a variable length record similar
to how fid's are reported.  With name info reporting implemented, setting
FAN_DIR_MODIFY in mark mask is now allowed.

When events are reported with name, the reported fid identifies the
directory and the name follows the fid. The info record type for this
event info is FAN_EVENT_INFO_TYPE_DFID_NAME.

For now, all reported events have at most one info record which is
either FAN_EVENT_INFO_TYPE_FID or FAN_EVENT_INFO_TYPE_DFID_NAME (for
FAN_DIR_MODIFY).  Later on, events "on child" will report both records.

There are several ways that an application can use this information:

1. When watching a single directory, the name is always relative to
the watched directory, so application need to fstatat(2) the name
relative to the watched directory.

2. When watching a set of directories, the application could keep a map
of dirfd for all watched directories and hash the map by fid obtained
with name_to_handle_at(2).  When getting a name event, the fid in the
event info could be used to lookup the base dirfd in the map and then
call fstatat(2) with that dirfd.

3. When watching a filesystem (FAN_MARK_FILESYSTEM) or a large set of
directories, the application could use open_by_handle_at(2) with the fid
in event info to obtain dirfd for the directory where event happened and
call fstatat(2) with this dirfd.

The last option scales better for a large number of watched directories.
The first two options may be available in the future also for non
privileged fanotify watchers, because open_by_handle_at(2) requires
the CAP_DAC_READ_SEARCH capability.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/notify/fanotify/fanotify.c      |   2 +-
 fs/notify/fanotify/fanotify_user.c | 120 ++++++++++++++++++++++-------
 include/linux/fanotify.h           |   3 +-
 include/uapi/linux/fanotify.h      |   1 +
 4 files changed, 98 insertions(+), 28 deletions(-)

Comments

kernel test robot Feb. 19, 2020, 9:43 a.m. UTC | #1
Hi Amir,

I love your patch! Perhaps something to improve:

[auto build test WARNING on 11a48a5a18c63fd7621bb050228cebf13566e4d8]

url:    https://github.com/0day-ci/linux/commits/Amir-Goldstein/Fanotify-event-with-name-info/20200219-160517
base:    11a48a5a18c63fd7621bb050228cebf13566e4d8
config: c6x-randconfig-a001-20200219 (attached as .config)
compiler: c6x-elf-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=c6x 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify/fanotify/fanotify_user.c:3:
   fs/notify/fanotify/fanotify_user.c: In function 'copy_info_to_user':
>> fs/notify/fanotify/fanotify_user.c:238:11: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'size_t {aka unsigned int}' [-Wformat=]
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
              ^
   include/linux/printk.h:288:21: note: in definition of macro 'pr_fmt'
    #define pr_fmt(fmt) fmt
                        ^~~
   include/linux/dynamic_debug.h:143:2: note: in expansion of macro '__dynamic_func_call'
     __dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:153:2: note: in expansion of macro '_dynamic_func_call'
     _dynamic_func_call(fmt, __dynamic_pr_debug,  \
     ^~~~~~~~~~~~~~~~~~
   include/linux/printk.h:335:2: note: in expansion of macro 'dynamic_pr_debug'
     dynamic_pr_debug(fmt, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:11: warning: format '%lu' expects argument of type 'long unsigned int', but argument 5 has type 'size_t {aka unsigned int}' [-Wformat=]
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
              ^
   include/linux/printk.h:288:21: note: in definition of macro 'pr_fmt'
    #define pr_fmt(fmt) fmt
                        ^~~
   include/linux/dynamic_debug.h:143:2: note: in expansion of macro '__dynamic_func_call'
     __dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:153:2: note: in expansion of macro '_dynamic_func_call'
     _dynamic_func_call(fmt, __dynamic_pr_debug,  \
     ^~~~~~~~~~~~~~~~~~
   include/linux/printk.h:335:2: note: in expansion of macro 'dynamic_pr_debug'
     dynamic_pr_debug(fmt, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:11: warning: format '%lu' expects argument of type 'long unsigned int', but argument 6 has type 'size_t {aka unsigned int}' [-Wformat=]
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
              ^
   include/linux/printk.h:288:21: note: in definition of macro 'pr_fmt'
    #define pr_fmt(fmt) fmt
                        ^~~
   include/linux/dynamic_debug.h:143:2: note: in expansion of macro '__dynamic_func_call'
     __dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:153:2: note: in expansion of macro '_dynamic_func_call'
     _dynamic_func_call(fmt, __dynamic_pr_debug,  \
     ^~~~~~~~~~~~~~~~~~
   include/linux/printk.h:335:2: note: in expansion of macro 'dynamic_pr_debug'
     dynamic_pr_debug(fmt, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:11: warning: format '%lu' expects argument of type 'long unsigned int', but argument 7 has type 'size_t {aka unsigned int}' [-Wformat=]
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
              ^
   include/linux/printk.h:288:21: note: in definition of macro 'pr_fmt'
    #define pr_fmt(fmt) fmt
                        ^~~
   include/linux/dynamic_debug.h:143:2: note: in expansion of macro '__dynamic_func_call'
     __dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~~~~
   include/linux/dynamic_debug.h:153:2: note: in expansion of macro '_dynamic_func_call'
     _dynamic_func_call(fmt, __dynamic_pr_debug,  \
     ^~~~~~~~~~~~~~~~~~
   include/linux/printk.h:335:2: note: in expansion of macro 'dynamic_pr_debug'
     dynamic_pr_debug(fmt, ##__VA_ARGS__)
     ^~~~~~~~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~

vim +238 fs/notify/fanotify/fanotify_user.c

   224	
   225	static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
   226				     struct fanotify_fid *fid, const struct qstr *name,
   227				     char __user *buf, size_t count)
   228	{
   229		struct fanotify_event_info_fid info = { };
   230		struct file_handle handle = { };
   231		unsigned char bounce[max(FANOTIFY_INLINE_FH_LEN, DNAME_INLINE_LEN)];
   232		const unsigned char *data;
   233		size_t fh_len = fh->len;
   234		size_t name_len = name ? name->len : 0;
   235		size_t info_len = fanotify_fid_info_len(fh_len, name_len);
   236		size_t len = info_len;
   237	
 > 238		pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
   239			 __func__, fh_len, name_len, info_len, count);
   240	
   241		if (!fh_len || (name && !name_len))
   242			return 0;
   243	
   244		if (WARN_ON_ONCE(len < sizeof(info) || len > count))
   245			return -EFAULT;
   246	
   247		/*
   248		 * Copy event info fid header followed by vaiable sized file handle
   249		 * and optionally followed by vaiable sized filename.
   250		 */
   251		info.hdr.info_type = name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME :
   252						FAN_EVENT_INFO_TYPE_FID;
   253		info.hdr.len = len;
   254		info.fsid = *fsid;
   255		if (copy_to_user(buf, &info, sizeof(info)))
   256			return -EFAULT;
   257	
   258		buf += sizeof(info);
   259		len -= sizeof(info);
   260		if (WARN_ON_ONCE(len < sizeof(handle)))
   261			return -EFAULT;
   262	
   263		handle.handle_type = fh->type;
   264		handle.handle_bytes = fh_len;
   265		if (copy_to_user(buf, &handle, sizeof(handle)))
   266			return -EFAULT;
   267	
   268		buf += sizeof(handle);
   269		len -= sizeof(handle);
   270		if (WARN_ON_ONCE(len < fh_len))
   271			return -EFAULT;
   272	
   273		/*
   274		 * For an inline fh and inline file name, copy through stack to exclude
   275		 * the copy from usercopy hardening protections.
   276		 */
   277		data = fanotify_fid_fh(fid, fh_len);
   278		if (fh_len <= FANOTIFY_INLINE_FH_LEN) {
   279			memcpy(bounce, data, fh_len);
   280			data = bounce;
   281		}
   282		if (copy_to_user(buf, data, fh_len))
   283			return -EFAULT;
   284	
   285		buf += fh_len;
   286		len -= fh_len;
   287	
   288		if (name_len) {
   289			/* Copy the filename with terminating null */
   290			name_len++;
   291			if (WARN_ON_ONCE(len < name_len))
   292				return -EFAULT;
   293	
   294			data = name->name;
   295			if (name_len <= DNAME_INLINE_LEN) {
   296				memcpy(bounce, data, name_len);
   297				data = bounce;
   298			}
   299			if (copy_to_user(buf, data, name_len))
   300				return -EFAULT;
   301	
   302			buf += name_len;
   303			len -= name_len;
   304		}
   305	
   306		/* Pad with 0's */
   307		WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN);
   308		if (len > 0 && clear_user(buf, len))
   309			return -EFAULT;
   310	
   311		return info_len;
   312	}
   313	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Feb. 19, 2020, 10:17 a.m. UTC | #2
Hi Amir,

I love your patch! Perhaps something to improve:

[auto build test WARNING on 11a48a5a18c63fd7621bb050228cebf13566e4d8]

url:    https://github.com/0day-ci/linux/commits/Amir-Goldstein/Fanotify-event-with-name-info/20200219-160517
base:    11a48a5a18c63fd7621bb050228cebf13566e4d8
config: microblaze-randconfig-a001-20200219 (attached as .config)
compiler: microblaze-linux-gcc (GCC) 7.5.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.5.0 make.cross ARCH=microblaze 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify/fanotify/fanotify_user.c:3:
   fs/notify/fanotify/fanotify_user.c: In function 'copy_info_to_user':
>> include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:25: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
                          ~~^
                          %u
   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify/fanotify/fanotify_user.c:3:
   include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:38: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
                                       ~~^
                                       %u
   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify/fanotify/fanotify_user.c:3:
   include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 5 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:52: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
                                                     ~~^
                                                     %u
   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify/fanotify/fanotify_user.c:3:
   include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 6 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify/fanotify/fanotify_user.c:238:63: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
--
   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify//fanotify/fanotify_user.c:3:
   fs/notify//fanotify/fanotify_user.c: In function 'copy_info_to_user':
>> include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 3 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:25: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
                          ~~^
                          %u
   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify//fanotify/fanotify_user.c:3:
   include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 4 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:38: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
                                       ~~^
                                       %u
   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify//fanotify/fanotify_user.c:3:
   include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 5 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:52: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
                                                     ~~^
                                                     %u
   In file included from include/linux/kernel.h:15:0,
                    from include/linux/list.h:9,
                    from include/linux/preempt.h:11,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/fcntl.h:5,
                    from fs/notify//fanotify/fanotify_user.c:3:
   include/linux/kern_levels.h:5:18: warning: format '%lu' expects argument of type 'long unsigned int', but argument 6 has type 'size_t {aka unsigned int}' [-Wformat=]
    #define KERN_SOH "\001"  /* ASCII Start Of Header */
                     ^
   include/linux/printk.h:137:10: note: in definition of macro 'no_printk'
      printk(fmt, ##__VA_ARGS__);  \
             ^~~
   include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
    #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
                       ^~~~~~~~
   include/linux/printk.h:341:12: note: in expansion of macro 'KERN_DEBUG'
     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
               ^~~~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:2: note: in expansion of macro 'pr_debug'
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
     ^~~~~~~~
   fs/notify//fanotify/fanotify_user.c:238:63: note: format string is defined here
     pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",

vim +5 include/linux/kern_levels.h

314ba3520e513a Joe Perches 2012-07-30  4  
04d2c8c83d0e3a Joe Perches 2012-07-30 @5  #define KERN_SOH	"\001"		/* ASCII Start Of Header */
04d2c8c83d0e3a Joe Perches 2012-07-30  6  #define KERN_SOH_ASCII	'\001'
04d2c8c83d0e3a Joe Perches 2012-07-30  7  

:::::: The code at line 5 was first introduced by commit
:::::: 04d2c8c83d0e3ac5f78aeede51babb3236200112 printk: convert the format for KERN_<LEVEL> to a 2 byte pattern

:::::: TO: Joe Perches <joe@perches.com>
:::::: CC: Linus Torvalds <torvalds@linux-foundation.org>

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
Amir Goldstein Feb. 19, 2020, 11:22 a.m. UTC | #3
On Mon, Feb 17, 2020 at 3:15 PM Amir Goldstein <amir73il@gmail.com> wrote:
>
> Report event FAN_DIR_MODIFY with name in a variable length record similar
> to how fid's are reported.  With name info reporting implemented, setting
> FAN_DIR_MODIFY in mark mask is now allowed.
>
> When events are reported with name, the reported fid identifies the
> directory and the name follows the fid. The info record type for this
> event info is FAN_EVENT_INFO_TYPE_DFID_NAME.
>
> For now, all reported events have at most one info record which is
> either FAN_EVENT_INFO_TYPE_FID or FAN_EVENT_INFO_TYPE_DFID_NAME (for
> FAN_DIR_MODIFY).  Later on, events "on child" will report both records.
>
> There are several ways that an application can use this information:
>
> 1. When watching a single directory, the name is always relative to
> the watched directory, so application need to fstatat(2) the name
> relative to the watched directory.
>
> 2. When watching a set of directories, the application could keep a map
> of dirfd for all watched directories and hash the map by fid obtained
> with name_to_handle_at(2).  When getting a name event, the fid in the
> event info could be used to lookup the base dirfd in the map and then
> call fstatat(2) with that dirfd.
>
> 3. When watching a filesystem (FAN_MARK_FILESYSTEM) or a large set of
> directories, the application could use open_by_handle_at(2) with the fid
> in event info to obtain dirfd for the directory where event happened and
> call fstatat(2) with this dirfd.
>
> The last option scales better for a large number of watched directories.
> The first two options may be available in the future also for non
> privileged fanotify watchers, because open_by_handle_at(2) requires
> the CAP_DAC_READ_SEARCH capability.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>  fs/notify/fanotify/fanotify.c      |   2 +-
>  fs/notify/fanotify/fanotify_user.c | 120 ++++++++++++++++++++++-------
>  include/linux/fanotify.h           |   3 +-
>  include/uapi/linux/fanotify.h      |   1 +
>  4 files changed, 98 insertions(+), 28 deletions(-)
>
> diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
> index fc75dc53a218..b651c18d3a93 100644
> --- a/fs/notify/fanotify/fanotify.c
> +++ b/fs/notify/fanotify/fanotify.c
> @@ -478,7 +478,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
>         BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
>         BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
>
> -       BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19);
> +       BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20);
>
>         mask = fanotify_group_event_mask(group, iter_info, mask, data,
>                                          data_type);
> diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
> index 284f3548bb79..a1bafc21ebbb 100644
> --- a/fs/notify/fanotify/fanotify_user.c
> +++ b/fs/notify/fanotify/fanotify_user.c
> @@ -51,20 +51,32 @@ struct kmem_cache *fanotify_name_event_cachep __read_mostly;
>  struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
>
>  #define FANOTIFY_EVENT_ALIGN 4
> +#define FANOTIFY_INFO_HDR_LEN \
> +       (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle))
>
> -static int fanotify_fid_info_len(struct fanotify_fid_hdr *fh)
> +static int fanotify_fid_info_len(int fh_len, int name_len)
>  {
> -       return roundup(sizeof(struct fanotify_event_info_fid) +
> -                      sizeof(struct file_handle) + fh->len,
> -                      FANOTIFY_EVENT_ALIGN);
> +       int info_len = fh_len;
> +
> +       if (name_len)
> +               info_len += name_len + 1;
> +
> +       return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN);
>  }
>
>  static int fanotify_event_info_len(struct fanotify_event *event)
>  {
> -       if (!fanotify_event_has_fid(event))
> -               return 0;
> +       int info_len = 0;
> +
> +       if (fanotify_event_has_fid(event))
> +               info_len += fanotify_fid_info_len(event->fh.len, 0);
> +
> +       if (fanotify_event_has_dfid_name(event)) {
> +               info_len += fanotify_fid_info_len(event->dfh.len,
> +                                       fanotify_event_name_len(event));
> +       }
>
> -       return fanotify_fid_info_len(&event->fh);
> +       return info_len;
>  }
>
>  /*
> @@ -210,23 +222,34 @@ static int process_access_response(struct fsnotify_group *group,
>         return -ENOENT;
>  }
>
> -static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
> -                           struct fanotify_fid *fid, char __user *buf)
> +static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
> +                            struct fanotify_fid *fid, const struct qstr *name,
> +                            char __user *buf, size_t count)
>  {
>         struct fanotify_event_info_fid info = { };
>         struct file_handle handle = { };
> -       unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *data;
> +       unsigned char bounce[max(FANOTIFY_INLINE_FH_LEN, DNAME_INLINE_LEN)];
> +       const unsigned char *data;
>         size_t fh_len = fh->len;
> -       size_t len = fanotify_fid_info_len(fh);
> +       size_t name_len = name ? name->len : 0;
> +       size_t info_len = fanotify_fid_info_len(fh_len, name_len);
> +       size_t len = info_len;
> +
> +       pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
> +                __func__, fh_len, name_len, info_len, count);
>

Changed all %lu above to %zu to print size_t without a warning.

Thanks kbuild test robot,
Amir.
Michael Kerrisk (man-pages) April 16, 2020, 12:16 p.m. UTC | #4
Hello Amir,

On Mon, 17 Feb 2020 at 15:10, Amir Goldstein <amir73il@gmail.com> wrote:
>
> Report event FAN_DIR_MODIFY with name in a variable length record similar
> to how fid's are reported.  With name info reporting implemented, setting
> FAN_DIR_MODIFY in mark mask is now allowed.

I see this was merged for 5.7. Would you be able to send a man-pages
patch that documents this new feature please.

Cheers,

Michael

>
> When events are reported with name, the reported fid identifies the
> directory and the name follows the fid. The info record type for this
> event info is FAN_EVENT_INFO_TYPE_DFID_NAME.
>
> For now, all reported events have at most one info record which is
> either FAN_EVENT_INFO_TYPE_FID or FAN_EVENT_INFO_TYPE_DFID_NAME (for
> FAN_DIR_MODIFY).  Later on, events "on child" will report both records.
>
> There are several ways that an application can use this information:
>
> 1. When watching a single directory, the name is always relative to
> the watched directory, so application need to fstatat(2) the name
> relative to the watched directory.
>
> 2. When watching a set of directories, the application could keep a map
> of dirfd for all watched directories and hash the map by fid obtained
> with name_to_handle_at(2).  When getting a name event, the fid in the
> event info could be used to lookup the base dirfd in the map and then
> call fstatat(2) with that dirfd.
>
> 3. When watching a filesystem (FAN_MARK_FILESYSTEM) or a large set of
> directories, the application could use open_by_handle_at(2) with the fid
> in event info to obtain dirfd for the directory where event happened and
> call fstatat(2) with this dirfd.
>
> The last option scales better for a large number of watched directories.
> The first two options may be available in the future also for non
> privileged fanotify watchers, because open_by_handle_at(2) requires
> the CAP_DAC_READ_SEARCH capability.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>  fs/notify/fanotify/fanotify.c      |   2 +-
>  fs/notify/fanotify/fanotify_user.c | 120 ++++++++++++++++++++++-------
>  include/linux/fanotify.h           |   3 +-
>  include/uapi/linux/fanotify.h      |   1 +
>  4 files changed, 98 insertions(+), 28 deletions(-)
>
> diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
> index fc75dc53a218..b651c18d3a93 100644
> --- a/fs/notify/fanotify/fanotify.c
> +++ b/fs/notify/fanotify/fanotify.c
> @@ -478,7 +478,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
>         BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
>         BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
>
> -       BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19);
> +       BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20);
>
>         mask = fanotify_group_event_mask(group, iter_info, mask, data,
>                                          data_type);
> diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
> index 284f3548bb79..a1bafc21ebbb 100644
> --- a/fs/notify/fanotify/fanotify_user.c
> +++ b/fs/notify/fanotify/fanotify_user.c
> @@ -51,20 +51,32 @@ struct kmem_cache *fanotify_name_event_cachep __read_mostly;
>  struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
>
>  #define FANOTIFY_EVENT_ALIGN 4
> +#define FANOTIFY_INFO_HDR_LEN \
> +       (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle))
>
> -static int fanotify_fid_info_len(struct fanotify_fid_hdr *fh)
> +static int fanotify_fid_info_len(int fh_len, int name_len)
>  {
> -       return roundup(sizeof(struct fanotify_event_info_fid) +
> -                      sizeof(struct file_handle) + fh->len,
> -                      FANOTIFY_EVENT_ALIGN);
> +       int info_len = fh_len;
> +
> +       if (name_len)
> +               info_len += name_len + 1;
> +
> +       return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN);
>  }
>
>  static int fanotify_event_info_len(struct fanotify_event *event)
>  {
> -       if (!fanotify_event_has_fid(event))
> -               return 0;
> +       int info_len = 0;
> +
> +       if (fanotify_event_has_fid(event))
> +               info_len += fanotify_fid_info_len(event->fh.len, 0);
> +
> +       if (fanotify_event_has_dfid_name(event)) {
> +               info_len += fanotify_fid_info_len(event->dfh.len,
> +                                       fanotify_event_name_len(event));
> +       }
>
> -       return fanotify_fid_info_len(&event->fh);
> +       return info_len;
>  }
>
>  /*
> @@ -210,23 +222,34 @@ static int process_access_response(struct fsnotify_group *group,
>         return -ENOENT;
>  }
>
> -static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
> -                           struct fanotify_fid *fid, char __user *buf)
> +static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
> +                            struct fanotify_fid *fid, const struct qstr *name,
> +                            char __user *buf, size_t count)
>  {
>         struct fanotify_event_info_fid info = { };
>         struct file_handle handle = { };
> -       unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *data;
> +       unsigned char bounce[max(FANOTIFY_INLINE_FH_LEN, DNAME_INLINE_LEN)];
> +       const unsigned char *data;
>         size_t fh_len = fh->len;
> -       size_t len = fanotify_fid_info_len(fh);
> +       size_t name_len = name ? name->len : 0;
> +       size_t info_len = fanotify_fid_info_len(fh_len, name_len);
> +       size_t len = info_len;
> +
> +       pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
> +                __func__, fh_len, name_len, info_len, count);
>
> -       if (!len)
> +       if (!fh_len || (name && !name_len))
>                 return 0;
>
> -       if (WARN_ON_ONCE(len < sizeof(info) + sizeof(handle) + fh_len))
> +       if (WARN_ON_ONCE(len < sizeof(info) || len > count))
>                 return -EFAULT;
>
> -       /* Copy event info fid header followed by vaiable sized file handle */
> -       info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
> +       /*
> +        * Copy event info fid header followed by vaiable sized file handle
> +        * and optionally followed by vaiable sized filename.
> +        */
> +       info.hdr.info_type = name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME :
> +                                       FAN_EVENT_INFO_TYPE_FID;
>         info.hdr.len = len;
>         info.fsid = *fsid;
>         if (copy_to_user(buf, &info, sizeof(info)))
> @@ -234,6 +257,9 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
>
>         buf += sizeof(info);
>         len -= sizeof(info);
> +       if (WARN_ON_ONCE(len < sizeof(handle)))
> +               return -EFAULT;
> +
>         handle.handle_type = fh->type;
>         handle.handle_bytes = fh_len;
>         if (copy_to_user(buf, &handle, sizeof(handle)))
> @@ -241,9 +267,12 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
>
>         buf += sizeof(handle);
>         len -= sizeof(handle);
> +       if (WARN_ON_ONCE(len < fh_len))
> +               return -EFAULT;
> +
>         /*
> -        * For an inline fh, copy through stack to exclude the copy from
> -        * usercopy hardening protections.
> +        * For an inline fh and inline file name, copy through stack to exclude
> +        * the copy from usercopy hardening protections.
>          */
>         data = fanotify_fid_fh(fid, fh_len);
>         if (fh_len <= FANOTIFY_INLINE_FH_LEN) {
> @@ -253,14 +282,33 @@ static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
>         if (copy_to_user(buf, data, fh_len))
>                 return -EFAULT;
>
> -       /* Pad with 0's */
>         buf += fh_len;
>         len -= fh_len;
> +
> +       if (name_len) {
> +               /* Copy the filename with terminating null */
> +               name_len++;
> +               if (WARN_ON_ONCE(len < name_len))
> +                       return -EFAULT;
> +
> +               data = name->name;
> +               if (name_len <= DNAME_INLINE_LEN) {
> +                       memcpy(bounce, data, name_len);
> +                       data = bounce;
> +               }
> +               if (copy_to_user(buf, data, name_len))
> +                       return -EFAULT;
> +
> +               buf += name_len;
> +               len -= name_len;
> +       }
> +
> +       /* Pad with 0's */
>         WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN);
>         if (len > 0 && clear_user(buf, len))
>                 return -EFAULT;
>
> -       return 0;
> +       return info_len;
>  }
>
>  static ssize_t copy_event_to_user(struct fsnotify_group *group,
> @@ -282,12 +330,12 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
>         metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS;
>         metadata.pid = pid_vnr(event->pid);
>
> -       if (fanotify_event_has_path(event)) {
> +       if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
> +               metadata.event_len += fanotify_event_info_len(event);
> +       } else if (fanotify_event_has_path(event)) {
>                 fd = create_fd(group, event, &f);
>                 if (fd < 0)
>                         return fd;
> -       } else if (fanotify_event_has_fid(event)) {
> -               metadata.event_len += fanotify_event_info_len(event);
>         }
>         metadata.fd = fd;
>
> @@ -302,16 +350,36 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
>         if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN))
>                 goto out_close_fd;
>
> +       buf += FAN_EVENT_METADATA_LEN;
> +       count -= FAN_EVENT_METADATA_LEN;
> +
>         if (fanotify_is_perm_event(event->mask))
>                 FANOTIFY_PE(fsn_event)->fd = fd;
>
> -       if (fanotify_event_has_path(event)) {
> +       if (f)
>                 fd_install(fd, f);
> -       } else if (fanotify_event_has_fid(event)) {
> -               ret = copy_fid_to_user(&event->fsid, &event->fh, &event->fid,
> -                                      buf + FAN_EVENT_METADATA_LEN);
> +
> +       /* Event info records order is: dir fid + name, child fid */
> +       if (fanotify_event_has_dfid_name(event)) {
> +               struct fanotify_name_event *fne = FANOTIFY_NE(fsn_event);
> +
> +               ret = copy_info_to_user(&event->fsid, &event->dfh, &fne->dfid,
> +                                       &fne->name, buf, count);
>                 if (ret < 0)
>                         return ret;
> +
> +               buf += ret;
> +               count -= ret;
> +       }
> +
> +       if (fanotify_event_has_fid(event)) {
> +               ret = copy_info_to_user(&event->fsid, &event->fh, &event->fid,
> +                                       NULL, buf, count);
> +               if (ret < 0)
> +                       return ret;
> +
> +               buf += ret;
> +               count -= ret;
>         }
>
>         return metadata.event_len;
> diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
> index b79fa9bb7359..3049a6c06d9e 100644
> --- a/include/linux/fanotify.h
> +++ b/include/linux/fanotify.h
> @@ -47,7 +47,8 @@
>   * Directory entry modification events - reported only to directory
>   * where entry is modified and not to a watching parent.
>   */
> -#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE)
> +#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE | \
> +                                FAN_DIR_MODIFY)
>
>  /* Events that can only be reported with data type FSNOTIFY_EVENT_INODE */
>  #define FANOTIFY_INODE_EVENTS  (FANOTIFY_DIRENT_EVENTS | \
> diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
> index 615fa2c87179..2b56e194b858 100644
> --- a/include/uapi/linux/fanotify.h
> +++ b/include/uapi/linux/fanotify.h
> @@ -117,6 +117,7 @@ struct fanotify_event_metadata {
>  };
>
>  #define FAN_EVENT_INFO_TYPE_FID                1
> +#define FAN_EVENT_INFO_TYPE_DFID_NAME  2
>
>  /* Variable length info record following event metadata */
>  struct fanotify_event_info_header {
> --
> 2.17.1
>
Jan Kara April 20, 2020, 3:53 p.m. UTC | #5
On Thu 16-04-20 14:16:40, Michael Kerrisk (man-pages) wrote:
> Hello Amir,
> 
> On Mon, 17 Feb 2020 at 15:10, Amir Goldstein <amir73il@gmail.com> wrote:
> >
> > Report event FAN_DIR_MODIFY with name in a variable length record similar
> > to how fid's are reported.  With name info reporting implemented, setting
> > FAN_DIR_MODIFY in mark mask is now allowed.
> 
> I see this was merged for 5.7. Would you be able to send a man-pages
> patch that documents this new feature please.

I know that Amir has the manpage ready. I'm not sure when he plans to
submit it.

								Honza
Amir Goldstein April 20, 2020, 6:45 p.m. UTC | #6
On Thu, Apr 16, 2020 at 3:16 PM Michael Kerrisk (man-pages)
<mtk.manpages@gmail.com> wrote:
>
> Hello Amir,
>
> On Mon, 17 Feb 2020 at 15:10, Amir Goldstein <amir73il@gmail.com> wrote:
> >
> > Report event FAN_DIR_MODIFY with name in a variable length record similar
> > to how fid's are reported.  With name info reporting implemented, setting
> > FAN_DIR_MODIFY in mark mask is now allowed.
>
> I see this was merged for 5.7. Would you be able to send a man-pages
> patch that documents this new feature please.
>

Sorry, I missed your email.
Just posted the patches.
I never know when in development cycle you expect to get the man page patches...

Thanks,
Amir.
Michael Kerrisk (man-pages) April 20, 2020, 6:47 p.m. UTC | #7
On Mon, 20 Apr 2020 at 20:45, Amir Goldstein <amir73il@gmail.com> wrote:
>
> On Thu, Apr 16, 2020 at 3:16 PM Michael Kerrisk (man-pages)
> <mtk.manpages@gmail.com> wrote:
> >
> > Hello Amir,
> >
> > On Mon, 17 Feb 2020 at 15:10, Amir Goldstein <amir73il@gmail.com> wrote:
> > >
> > > Report event FAN_DIR_MODIFY with name in a variable length record similar
> > > to how fid's are reported.  With name info reporting implemented, setting
> > > FAN_DIR_MODIFY in mark mask is now allowed.
> >
> > I see this was merged for 5.7. Would you be able to send a man-pages
> > patch that documents this new feature please.
> >
>
> Sorry, I missed your email.
> Just posted the patches.
> I never know when in development cycle you expect to get the man page patches...

Ideally,m the manual page patches are posted in parallel with the
kernel patches, with a note saying that the featur eis not yet merged.

Thanks,

Michael
diff mbox series

Patch

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index fc75dc53a218..b651c18d3a93 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -478,7 +478,7 @@  static int fanotify_handle_event(struct fsnotify_group *group,
 	BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
 	BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
 
-	BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19);
+	BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20);
 
 	mask = fanotify_group_event_mask(group, iter_info, mask, data,
 					 data_type);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 284f3548bb79..a1bafc21ebbb 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -51,20 +51,32 @@  struct kmem_cache *fanotify_name_event_cachep __read_mostly;
 struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
 
 #define FANOTIFY_EVENT_ALIGN 4
+#define FANOTIFY_INFO_HDR_LEN \
+	(sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle))
 
-static int fanotify_fid_info_len(struct fanotify_fid_hdr *fh)
+static int fanotify_fid_info_len(int fh_len, int name_len)
 {
-	return roundup(sizeof(struct fanotify_event_info_fid) +
-		       sizeof(struct file_handle) + fh->len,
-		       FANOTIFY_EVENT_ALIGN);
+	int info_len = fh_len;
+
+	if (name_len)
+		info_len += name_len + 1;
+
+	return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN);
 }
 
 static int fanotify_event_info_len(struct fanotify_event *event)
 {
-	if (!fanotify_event_has_fid(event))
-		return 0;
+	int info_len = 0;
+
+	if (fanotify_event_has_fid(event))
+		info_len += fanotify_fid_info_len(event->fh.len, 0);
+
+	if (fanotify_event_has_dfid_name(event)) {
+		info_len += fanotify_fid_info_len(event->dfh.len,
+					fanotify_event_name_len(event));
+	}
 
-	return fanotify_fid_info_len(&event->fh);
+	return info_len;
 }
 
 /*
@@ -210,23 +222,34 @@  static int process_access_response(struct fsnotify_group *group,
 	return -ENOENT;
 }
 
-static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
-			    struct fanotify_fid *fid, char __user *buf)
+static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
+			     struct fanotify_fid *fid, const struct qstr *name,
+			     char __user *buf, size_t count)
 {
 	struct fanotify_event_info_fid info = { };
 	struct file_handle handle = { };
-	unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *data;
+	unsigned char bounce[max(FANOTIFY_INLINE_FH_LEN, DNAME_INLINE_LEN)];
+	const unsigned char *data;
 	size_t fh_len = fh->len;
-	size_t len = fanotify_fid_info_len(fh);
+	size_t name_len = name ? name->len : 0;
+	size_t info_len = fanotify_fid_info_len(fh_len, name_len);
+	size_t len = info_len;
+
+	pr_debug("%s: fh_len=%lu name_len=%lu, info_len=%lu, count=%lu\n",
+		 __func__, fh_len, name_len, info_len, count);
 
-	if (!len)
+	if (!fh_len || (name && !name_len))
 		return 0;
 
-	if (WARN_ON_ONCE(len < sizeof(info) + sizeof(handle) + fh_len))
+	if (WARN_ON_ONCE(len < sizeof(info) || len > count))
 		return -EFAULT;
 
-	/* Copy event info fid header followed by vaiable sized file handle */
-	info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
+	/*
+	 * Copy event info fid header followed by vaiable sized file handle
+	 * and optionally followed by vaiable sized filename.
+	 */
+	info.hdr.info_type = name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME :
+					FAN_EVENT_INFO_TYPE_FID;
 	info.hdr.len = len;
 	info.fsid = *fsid;
 	if (copy_to_user(buf, &info, sizeof(info)))
@@ -234,6 +257,9 @@  static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
 
 	buf += sizeof(info);
 	len -= sizeof(info);
+	if (WARN_ON_ONCE(len < sizeof(handle)))
+		return -EFAULT;
+
 	handle.handle_type = fh->type;
 	handle.handle_bytes = fh_len;
 	if (copy_to_user(buf, &handle, sizeof(handle)))
@@ -241,9 +267,12 @@  static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
 
 	buf += sizeof(handle);
 	len -= sizeof(handle);
+	if (WARN_ON_ONCE(len < fh_len))
+		return -EFAULT;
+
 	/*
-	 * For an inline fh, copy through stack to exclude the copy from
-	 * usercopy hardening protections.
+	 * For an inline fh and inline file name, copy through stack to exclude
+	 * the copy from usercopy hardening protections.
 	 */
 	data = fanotify_fid_fh(fid, fh_len);
 	if (fh_len <= FANOTIFY_INLINE_FH_LEN) {
@@ -253,14 +282,33 @@  static int copy_fid_to_user(__kernel_fsid_t *fsid, struct fanotify_fid_hdr *fh,
 	if (copy_to_user(buf, data, fh_len))
 		return -EFAULT;
 
-	/* Pad with 0's */
 	buf += fh_len;
 	len -= fh_len;
+
+	if (name_len) {
+		/* Copy the filename with terminating null */
+		name_len++;
+		if (WARN_ON_ONCE(len < name_len))
+			return -EFAULT;
+
+		data = name->name;
+		if (name_len <= DNAME_INLINE_LEN) {
+			memcpy(bounce, data, name_len);
+			data = bounce;
+		}
+		if (copy_to_user(buf, data, name_len))
+			return -EFAULT;
+
+		buf += name_len;
+		len -= name_len;
+	}
+
+	/* Pad with 0's */
 	WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN);
 	if (len > 0 && clear_user(buf, len))
 		return -EFAULT;
 
-	return 0;
+	return info_len;
 }
 
 static ssize_t copy_event_to_user(struct fsnotify_group *group,
@@ -282,12 +330,12 @@  static ssize_t copy_event_to_user(struct fsnotify_group *group,
 	metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS;
 	metadata.pid = pid_vnr(event->pid);
 
-	if (fanotify_event_has_path(event)) {
+	if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
+		metadata.event_len += fanotify_event_info_len(event);
+	} else if (fanotify_event_has_path(event)) {
 		fd = create_fd(group, event, &f);
 		if (fd < 0)
 			return fd;
-	} else if (fanotify_event_has_fid(event)) {
-		metadata.event_len += fanotify_event_info_len(event);
 	}
 	metadata.fd = fd;
 
@@ -302,16 +350,36 @@  static ssize_t copy_event_to_user(struct fsnotify_group *group,
 	if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN))
 		goto out_close_fd;
 
+	buf += FAN_EVENT_METADATA_LEN;
+	count -= FAN_EVENT_METADATA_LEN;
+
 	if (fanotify_is_perm_event(event->mask))
 		FANOTIFY_PE(fsn_event)->fd = fd;
 
-	if (fanotify_event_has_path(event)) {
+	if (f)
 		fd_install(fd, f);
-	} else if (fanotify_event_has_fid(event)) {
-		ret = copy_fid_to_user(&event->fsid, &event->fh, &event->fid,
-				       buf + FAN_EVENT_METADATA_LEN);
+
+	/* Event info records order is: dir fid + name, child fid */
+	if (fanotify_event_has_dfid_name(event)) {
+		struct fanotify_name_event *fne = FANOTIFY_NE(fsn_event);
+
+		ret = copy_info_to_user(&event->fsid, &event->dfh, &fne->dfid,
+					&fne->name, buf, count);
 		if (ret < 0)
 			return ret;
+
+		buf += ret;
+		count -= ret;
+	}
+
+	if (fanotify_event_has_fid(event)) {
+		ret = copy_info_to_user(&event->fsid, &event->fh, &event->fid,
+					NULL, buf, count);
+		if (ret < 0)
+			return ret;
+
+		buf += ret;
+		count -= ret;
 	}
 
 	return metadata.event_len;
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index b79fa9bb7359..3049a6c06d9e 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -47,7 +47,8 @@ 
  * Directory entry modification events - reported only to directory
  * where entry is modified and not to a watching parent.
  */
-#define FANOTIFY_DIRENT_EVENTS	(FAN_MOVE | FAN_CREATE | FAN_DELETE)
+#define FANOTIFY_DIRENT_EVENTS	(FAN_MOVE | FAN_CREATE | FAN_DELETE | \
+				 FAN_DIR_MODIFY)
 
 /* Events that can only be reported with data type FSNOTIFY_EVENT_INODE */
 #define FANOTIFY_INODE_EVENTS	(FANOTIFY_DIRENT_EVENTS | \
diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
index 615fa2c87179..2b56e194b858 100644
--- a/include/uapi/linux/fanotify.h
+++ b/include/uapi/linux/fanotify.h
@@ -117,6 +117,7 @@  struct fanotify_event_metadata {
 };
 
 #define FAN_EVENT_INFO_TYPE_FID		1
+#define FAN_EVENT_INFO_TYPE_DFID_NAME	2
 
 /* Variable length info record following event metadata */
 struct fanotify_event_info_header {