#topicpath
* fanotify - filesystem wide access notification [#p264c25b]
From Linux kernel-2.6.36

:IPA Report(japanese)|
http://www.ipa.go.jp/security/fy22/reports/tech1-tg/b_03.html

:Kernel ML - fanotify: the fscking all notification system|
http://lwn.net/Articles/339253/

:Kernel ML - fanotify - overall design before I start sending patcheFri, (24 Jul 2009 16:13:4)|
http://lwn.net/Articles/343346/

:multi-thread opening file hangs when fanotify is on(Sep 27 2011 at 9:15)|
http://stackoverflow.com/questions/7566755/multi-thread-opening-file-hangs-when-fanotify-is-on

:Kernel ML -[PATCH] fanotify: to differ file access event from different threads|
https://lkml.org/lkml/2011/11/17/101

** Version ? [#i9a594cd]
|~Kernel|~Meta data Version|h
|2.6.36 => 2.6.36-4|Version 2|
|2.6.37|Version 3|
|2.6.38|Version 3|
|2.6.39rc1|Version 3|


**Example [#i02fc2a9]
for Kernel-2.6.36~
from git://git.kernel.org/pub/scm/linux/kernel/git/agruen/fanotify-example.git/

*** Kernel-2.6.36 [#b8d5fc77]
fanotify.h - metadata virsion 2
 #ifndef _LINUX_FANOTIFY_H
 #define _LINUX_FANOTIFY_H
 
 #include <linux/types.h>
 
 /* the following events that user-space can register for */
 #define FAN_ACCESS		0x00000001	/* File was accessed */
 #define FAN_MODIFY		0x00000002	/* File was modified */
 #define FAN_CLOSE_WRITE		0x00000008	/* Unwrittable file closed */
 #define FAN_CLOSE_NOWRITE	0x00000010	/* Writtable file closed */
 #define FAN_OPEN		0x00000020	/* File was opened */  
 
 #define FAN_EVENT_ON_CHILD	0x08000000	/* interested in child events */ 
 
 /* FIXME currently Q's have no limit.... */
 #define FAN_Q_OVERFLOW		0x00004000	/* Event queued overflowed */
 
 #define FAN_OPEN_PERM		0x00010000	/* File open in perm check */
 #define FAN_ACCESS_PERM		0x00020000	/* File accessed in perm check */ 
 
 /* helper events */
 #define FAN_CLOSE		(FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
 
 /* flags used for fanotify_init() */
 #define FAN_CLOEXEC		0x00000001
 #define FAN_NONBLOCK		0x00000002
 
 #define FAN_ALL_INIT_FLAGS	(FAN_CLOEXEC | FAN_NONBLOCK) 
 
 /* flags used for fanotify_modify_mark() */
 #define FAN_MARK_ADD		0x00000001
 #define FAN_MARK_REMOVE		0x00000002
 #define FAN_MARK_DONT_FOLLOW	0x00000004
 #define FAN_MARK_ONLYDIR	0x00000008
 #define FAN_MARK_MOUNT		0x00000010
 #define FAN_MARK_IGNORED_MASK	0x00000020
 #define FAN_MARK_IGNORED_SURV_MODIFY	0x00000040
 #define FAN_MARK_FLUSH		0x00000080 
 
 #define FAN_ALL_MARK_FLAGS	(FAN_MARK_ADD |\ 
 				 FAN_MARK_REMOVE |\ 
 				 FAN_MARK_DONT_FOLLOW |\
 				 FAN_MARK_ONLYDIR |\
 				 FAN_MARK_MOUNT |\
 				 FAN_MARK_IGNORED_MASK |\
 				 FAN_MARK_IGNORED_SURV_MODIFY)
 
 /*
  * All of the events - we build the list by hand so that we can add flags in
  * the future and not break backward compatibility.  Apps will get only the
  * events that they originally wanted.  Be sure to add new events here!
  */
 #define FAN_ALL_EVENTS (FAN_ACCESS |\ 
 			FAN_MODIFY |\
 			FAN_CLOSE |\
 			FAN_OPEN)
 
 /*
  * All events which require a permission response from userspace
  */
 #define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\
 			     FAN_ACCESS_PERM)
 
 #define FAN_ALL_OUTGOING_EVENTS	(FAN_ALL_EVENTS |\
 				 FAN_ALL_PERM_EVENTS |\
 				 FAN_Q_OVERFLOW)
 
 #define FANOTIFY_METADATA_VERSION	2
 
 struct fanotify_event_metadata {
 	__u32 event_len;
 	__u32 vers;
 	__u64 mask;
 	__s32 fd;
 	__s32 pid;
 } __attribute__ ((packed));
 
 struct fanotify_response {
 	__s32 fd;
 	__u32 response;
 } __attribute__ ((packed));
 
 /* Legit userspace responses to a _PERM event */
 #define FAN_ALLOW	0x01
 #define FAN_DENY	0x02 
 
 /* Helper functions to deal with fanotify_event_metadata buffers */
 #define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
 
 #define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \
 				   (struct fanotify_event_metadata*)(((char *)(meta)) + \
 				   (meta)->event_len))
 
 #define FAN_EVENT_OK(meta, len)	((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \
 				(long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
 				(long)(meta)->event_len <= (long)(len))
 
 #endif /* _LINUX_FANOTIFY_H */

*** Kernel-2.6.37 , 38 , 39rc1 [#hfb00185]
fanotify.h - metadata virsion 3
 #ifndef _LINUX_FANOTIFY_H
 #define _LINUX_FANOTIFY_H
 
 #include <linux/types.h>
 
 /* the following events that user-space can register for */
 #define FAN_ACCESS              0x00000001      /* File was accessed */
 #define FAN_MODIFY              0x00000002      /* File was modified */
 #define FAN_CLOSE_WRITE         0x00000008      /* Writtable file closed */
 #define FAN_CLOSE_NOWRITE       0x00000010      /* Unwrittable file closed */
 #define FAN_OPEN                0x00000020      /* File was opened */
 
 #define FAN_Q_OVERFLOW          0x00004000      /* Event queued overflowed */
 
 #define FAN_OPEN_PERM           0x00010000      /* File open in perm check */
 #define FAN_ACCESS_PERM         0x00020000      /* File accessed in perm check */
 
 #define FAN_ONDIR               0x40000000      /* event occurred against dir */
 
 #define FAN_EVENT_ON_CHILD      0x08000000      /* interested in child events */ 
 
 /* helper events */
 #define FAN_CLOSE               (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close  */
 
 /* flags used for fanotify_init() */
 #define FAN_CLOEXEC             0x00000001
 #define FAN_NONBLOCK            0x00000002
 
 /* These are NOT bitwise flags.  Both bits are used togther.  */
 #define FAN_CLASS_NOTIF         0x00000000
 #define FAN_CLASS_CONTENT       0x00000004
 #define FAN_CLASS_PRE_CONTENT   0x00000008
 #define FAN_ALL_CLASS_BITS      (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \
                                  FAN_CLASS_PRE_CONTENT)
 
 #define FAN_UNLIMITED_QUEUE     0x00000010
 #define FAN_UNLIMITED_MARKS     0x00000020
 
 #define FAN_ALL_INIT_FLAGS      (FAN_CLOEXEC | FAN_NONBLOCK | \
                                  FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\
                                  FAN_UNLIMITED_MARKS)
 
 /* flags used for fanotify_modify_mark() */
 #define FAN_MARK_ADD            0x00000001
 #define FAN_MARK_REMOVE         0x00000002
 #define FAN_MARK_DONT_FOLLOW    0x00000004
 #define FAN_MARK_ONLYDIR        0x00000008
 #define FAN_MARK_MOUNT          0x00000010
 #define FAN_MARK_IGNORED_MASK   0x00000020
 #define FAN_MARK_IGNORED_SURV_MODIFY    0x00000040
 #define FAN_MARK_FLUSH          0x00000080
 #ifdef __KERNEL__
 /* not valid from userspace, only kernel internal */
 #define FAN_MARK_ONDIR          0x00000100
 #endif
 
 #define FAN_ALL_MARK_FLAGS      (FAN_MARK_ADD |\
                                  FAN_MARK_REMOVE |\
                                  FAN_MARK_DONT_FOLLOW |\
                                  FAN_MARK_ONLYDIR |\
                                  FAN_MARK_MOUNT |\
                                  FAN_MARK_IGNORED_MASK |\
                                  FAN_MARK_IGNORED_SURV_MODIFY |\
                                  FAN_MARK_FLUSH) 
 
 /*
  * All of the events - we build the list by hand so that we can add flags in
  * the future and not break backward compatibility.  Apps will get only the
  * events that they originally wanted.  Be sure to add new events here! 
  */
 #define FAN_ALL_EVENTS (FAN_ACCESS |\
                         FAN_MODIFY |\
                         FAN_CLOSE |\
                         FAN_OPEN)
 
 /*
  * All events which require a permission response from userspace
  */
 #define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\
                              FAN_ACCESS_PERM)
 
 #define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\
                                  FAN_ALL_PERM_EVENTS |\
                                  FAN_Q_OVERFLOW)
 
 #define FANOTIFY_METADATA_VERSION       3 
 
 struct fanotify_event_metadata {
         __u32 event_len;
         __u8 vers;
         __u8 reserved;
         __u16 metadata_len;
         __aligned_u64 mask;
         __s32 fd;
         __s32 pid;
 };
 
 struct fanotify_response {
         __s32 fd;
         __u32 response;
 };
 
 /* Legit userspace responses to a _PERM event */
 #define FAN_ALLOW       0x01
 #define FAN_DENY        0x02
 /* No fd set in event */
 #define FAN_NOFD        -1
 
 /* Helper functions to deal with fanotify_event_metadata buffers */
 #define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
 
 #define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \
                                    (struct fanotify_event_metadata*)(((char *)(meta)) + \
                                   (meta)->event_len))
 
 #define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN &&  \
                                 (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
                                 (long)(meta)->event_len <= (long)(len))
 
 #endif /* _LINUX_FANOTIFY_H */

*** Diff of fanotify.h [#y070f4ae]
 --- fanotify_2636.h     2011-04-05 17:18:01.509828000 +0900
 +++ fanotify_2639rc1.h  2011-04-05 16:42:44.475277000 +0900
 @@ -6,18 +6,19 @@
  /* the following events that user-space can register for */
  #define FAN_ACCESS             0x00000001      /* File was accessed */
  #define FAN_MODIFY             0x00000002      /* File was modified */
 -#define FAN_CLOSE_WRITE                0x00000008      /* Unwrittable file  closed */
 +#define FAN_CLOSE_WRITE                0x00000008      /* Writtable file closed  */
 -#define FAN_CLOSE_NOWRITE      0x00000010      /* Writtable file closed */
 +#define FAN_CLOSE_NOWRITE      0x00000010      /* Unwrittable file closed */
  #define FAN_OPEN               0x00000020      /* File was opened */ 
 
 
  #define FAN_ACCESS_PERM                0x00020000      /* File accessed in perm  check */
 
 +#define FAN_ONDIR              0x40000000      /* event occurred against dir */
 
  /* helper events */
  #define FAN_CLOSE              (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close  */ 
 
 @@ -25,7 +26,19 @@
  #define FAN_CLOEXEC            0x00000001
  #define FAN_NONBLOCK           0x00000002
 
 +/* These are NOT bitwise flags.  Both bits are used togther.  */
 +#define FAN_CLASS_NOTIF                0x00000000
 +#define FAN_CLASS_CONTENT      0x00000004
 +#define FAN_CLASS_PRE_CONTENT  0x00000008
 +#define FAN_ALL_CLASS_BITS     (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \
 +                                FAN_CLASS_PRE_CONTENT)
 +
 +#define FAN_UNLIMITED_QUEUE    0x00000010
 +#define FAN_UNLIMITED_MARKS    0x00000020
 +
 
 -#define FAN_ALL_INIT_FLAGS     (FAN_CLOEXEC | FAN_NONBLOCK)
 +#define FAN_ALL_INIT_FLAGS     (FAN_CLOEXEC | FAN_NONBLOCK | \
 +                                FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\
 +                                FAN_UNLIMITED_MARKS)
  /* flags used for fanotify_modify_mark() */
  #define FAN_MARK_ADD           0x00000001
 @@ -36,6 +49,10 @@
  #define FAN_MARK_IGNORED_MASK  0x00000020
  #define FAN_MARK_IGNORED_SURV_MODIFY   0x00000040
  #define FAN_MARK_FLUSH         0x00000080
 +#ifdef __KERNEL__
 +/* not valid from userspace, only kernel internal */
 +#define FAN_MARK_ONDIR         0x00000100
 +#endif
 
  #define FAN_ALL_MARK_FLAGS     (FAN_MARK_ADD |\
                                  FAN_MARK_REMOVE |\
 @@ -43,7 +60,8 @@
                                  FAN_MARK_ONLYDIR |\
                                  FAN_MARK_MOUNT |\
                                  FAN_MARK_IGNORED_MASK |\
 -                                FAN_MARK_IGNORED_SURV_MODIFY)
 +                                FAN_MARK_IGNORED_SURV_MODIFY |\
 +                                FAN_MARK_FLUSH)
 
  /*
   * All of the events - we build the list by hand so that we can add flags in
 @@ -65,24 +83,28 @@
                                  FAN_ALL_PERM_EVENTS |\
                                  FAN_Q_OVERFLOW) 
 
 -#define FANOTIFY_METADATA_VERSION      2
 +#define FANOTIFY_METADATA_VERSION      3
 
  struct fanotify_event_metadata {
         __u32 event_len;
 -       __u32 vers;
 +       __u8 vers;
 +       __u8 reserved;
 +       __u16 metadata_len;
 -       __u64 mask;
 +       __aligned_u64 mask;
         __s32 fd;
         __s32 pid;
 -} __attribute__ ((packed));
 +};
  
  struct fanotify_response {
         __s32 fd;
         __u32 response;
 -} __attribute__ ((packed));
 +};
 
  /* Legit userspace responses to a _PERM event */
  #define FAN_ALLOW      0x01
  #define FAN_DENY       0x02
 +/* No fd set in event */
 +#define FAN_NOFD       -1
 
  /* Helper functions to deal with fanotify_event_metadata buffers */
  #define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))








*** EXAMPLE CODE for metadata version 2 [#a377a109]
for Kernel-2.6.36~
from git://git.kernel.org/pub/scm/linux/kernel/git/agruen/fanotify-example.git/

fanotify.c
 #define _ATFILE_SOURCE
 #include <errno.h>
 #include <inttypes.h>
 #include <fcntl.h>
 #include <linux/limits.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/select.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include <linux/fanotify.h> 
 
 #include "fanotify-syscalllib.h" 
 
 #define FANOTIFY_ARGUMENTS "cfhmn"
 
 int mark_object(int fan_fd, const char *path, int fd, uint64_t mask, unsigned int flags)
 {
 	return fanotify_mark(fan_fd, flags, mask, fd, path);
 }
 
 int set_ignored_mask(int fan_fd, int fd, uint64_t mask)
 { 
 	unsigned int flags = (FAN_MARK_ADD | FAN_MARK_IGNORED_MASK);
 
 	return mark_object(fan_fd, NULL, fd, mask, flags);
 }
 
 int handle_perm(int fan_fd, struct fanotify_event_metadata *metadata)
 { 
 	struct fanotify_response response_struct;
 	int ret;
 
 	response_struct.fd = metadata->fd;
 	response_struct.response = FAN_ALLOW;
 
 	ret = write(fan_fd, &response_struct, sizeof(response_struct));
 	if (ret < 0)
 		return ret;
 
	return 0;
 }
 
 void synopsis(const char *progname, int status)
 { 
 	FILE *file = status ? stderr : stdout;
 
 	fprintf(file, "USAGE: %s [-" FANOTIFY_ARGUMENTS "] "
 		"[-o {open,close,access,modify,open_perm,access_perm}] "
 		"file ...\n"
 		"-c: learn about events on children of a directory (not decendants)\n"
 		"-f: set premptive ignores (go faster)\n"
 		"-h: this help screen\n"
 		"-m: place mark on the whole mount point, not just the inode\n"
 		"-n: do not ignore repeated permission checks\n"
 		"-s N: sleep N seconds before replying to perm events\n",
 		progname);
 	exit(status);
 }
 
 int main(int argc, char *argv[])
 { 
	int opt;
 	int fan_fd;
 	uint64_t fan_mask = FAN_OPEN | FAN_CLOSE | FAN_ACCESS | FAN_MODIFY;
 	unsigned int mark_flags = FAN_MARK_ADD;
 	bool opt_child, opt_on_mount, opt_fast, opt_ignore_perm;
 	int opt_sleep;
 	ssize_t len;
 	char buf[4096];
 	fd_set rfds;
 
 
 	opt_child = opt_on_mount = opt_fast = false;
 	opt_ignore_perm = true;
 	opt_sleep = 0;
 
 	while ((opt = getopt(argc, argv, "o:s:"FANOTIFY_ARGUMENTS)) != -1) { 
		switch(opt) {
 			case 'o': {
				char *str, *tok;
 
 				fan_mask = 0;
 				str = optarg;
 				while ((tok = strtok(str, ",")) != NULL) {
 					str = NULL;
 					if (strcmp(tok, "open") == 0)
  						fan_mask |= FAN_OPEN;
 					else if (strcmp(tok, "close") == 0)
 						fan_mask |= FAN_CLOSE;
 					else if (strcmp(tok, "access") == 0)
 						fan_mask |= FAN_ACCESS;
 					else if (strcmp(tok, "modify") == 0)
 						fan_mask |= FAN_MODIFY;
 					else if (strcmp(tok, "open_perm") == 0)
 						fan_mask |= FAN_OPEN_PERM;
 					else if (strcmp(tok, "access_perm") == 0)
 						fan_mask |= FAN_ACCESS_PERM;
 					else
 						synopsis(argv[0], 1);
				}
 				break;
 			}
 			case 'c':
 				opt_child = true;
 				break;
 			case 'f':
				opt_fast = true;
 				opt_ignore_perm = false;
 				break;
 			case 'm':
    				opt_on_mount = true;
 				break;
			case 'n':
  				opt_fast = false;
 				opt_ignore_perm = false;
 				break;
 			case 's':
 				opt_sleep = atoi(optarg);
 				break;
 			case 'h':
 				synopsis(argv[0], 0);
			default:  /* '?' */
  				synopsis(argv[0], 1);
		}
 	}
 	if (optind == argc)
 		synopsis(argv[0], 1);
 
 	if (opt_child)
 		fan_mask |= FAN_EVENT_ON_CHILD;
 
 	if (opt_on_mount)
 		mark_flags |= FAN_MARK_MOUNT;
 
 	fan_fd = fanotify_init(0, O_RDONLY | O_LARGEFILE);
 	if (fan_fd < 0)
 		goto fail;
 
 	for (; optind < argc; optind++)
  		if (mark_object(fan_fd, argv[optind], AT_FDCWD, fan_mask, m uark_flags) != 0)
 			goto fail;
 
 	FD_ZERO(&rfds);
 	FD_SET(fan_fd, &rfds);
 
	if (select(fan_fd+1, &rfds, NULL, NULL, NULL) < 0)
 		goto fail;
 
 	while ((len = read(fan_fd, buf, sizeof(buf))) > 0) {
 		struct fanotify_event_metadata *metadata;
 
 		metadata = (void *)buf;
 		while(FAN_EVENT_OK(metadata, len)) {
 			if (metadata->vers != FANOTIFY_METADATA_VERSION) {
				fprintf(stderr, "%s: fanotify version mismatch"
 						" (%d != %d)\n",
 					argv[0], metadata->vers,
 					FANOTIFY_METADATA_VERSION);
 				return 1;
 			}
 
			if (metadata->fd >= 0 &&
 			    opt_fast &&
 			    set_ignored_mask(fan_fd, metadata->fd,
 					     FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS))
 				goto fail;
 
 			if (metadata->fd >= 0) {
 				char path[PATH_MAX];
 				int path_len;
 
 				sprintf(path, "/proc/self/fd/%d", metadata->fd);
				path_len = readlink(path, path, sizeof(path)-1);
 				if (path_len < 0)
 					goto fail;
 				path[path_len] = '\0';
 				printf("%s:", path);
 			} else
 				printf("?:");
 
 			printf(" pid=%ld", (long)metadata->pid);
 
 			if (metadata->mask & FAN_ACCESS)
 				printf(" access");
 			if (metadata->mask & FAN_OPEN)
 				printf(" open");
 			if (metadata->mask & FAN_MODIFY)
 				printf(" modify");
 			if (metadata->mask & FAN_CLOSE) {
 				if (metadata->mask & FAN_CLOSE_WRITE)
 					printf(" close(writable)");
 				else
					printf(" close");
 			}
 			if (metadata->mask & FAN_OPEN_PERM)
 				printf(" open_perm");
 			if (metadata->mask & FAN_ACCESS_PERM)
 				printf(" access_perm");
 			if (metadata->mask & FAN_ALL_PERM_EVENTS) {
 				if (opt_sleep)
 					sleep(opt_sleep);
 
 				if (handle_perm(fan_fd, metadata))
 					goto fail;
				if (metadata->fd >= 0 &&
 				    opt_ignore_perm &&
 				    set_ignored_mask(fan_fd, metadata->fd,
 						     metadata->mask))
 					goto fail;
 			}
 
 			printf("\n");
 			fflush(stdout);
 
 			if (metadata->fd >= 0 && close(metadata->fd) != 0)
 				goto fail;
 			metadata = FAN_EVENT_NEXT(metadata, len);
  		}
  		if (select(fan_fd+1, &rfds, NULL, NULL, NULL) < 0)
  			goto fail;
  	}
  	if (len < 0)
  		goto fail;
  	return 0;
  
  fail:
  	fprintf(stderr, "%s\n", strerror(errno));
  	return 1;
  }

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS