Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 207696
b: refs/heads/master
c: 9e66e42
h: refs/heads/master
v: v3
  • Loading branch information
Eric Paris committed Jul 28, 2010
1 parent 5fa894c commit 6032ee9
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c4ec54b40d33f8016fea970a383cc584dd0e6019
refs/heads/master: 9e66e4233db9c7e31e9ee706be2c9ddd54cf99b3
14 changes: 14 additions & 0 deletions trunk/fs/notify/fanotify/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,17 @@ config FANOTIFY
the event.

If unsure, say Y.

config FANOTIFY_ACCESS_PERMISSIONS
bool "fanotify permissions checking"
depends on FANOTIFY
depends on SECURITY
default n
---help---
Say Y here is you want fanotify listeners to be able to make permissions
decisions concerning filesystem events. This is used by some fanotify
listeners which need to scan files before allowing the system access to
use those files. This is used by some anti-malware vendors and by some
hierarchical storage managent systems.

If unsure, say N.
54 changes: 50 additions & 4 deletions trunk/fs/notify/fanotify/fanotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
#include <linux/fdtable.h>
#include <linux/fsnotify_backend.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> /* UINT_MAX */
#include <linux/mount.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/wait.h>

static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
{
Expand Down Expand Up @@ -88,10 +91,37 @@ static int fanotify_merge(struct list_head *list,
return ret;
}

#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
static int fanotify_get_response_from_access(struct fsnotify_group *group,
struct fsnotify_event *event)
{
int ret;

pr_debug("%s: group=%p event=%p\n", __func__, group, event);

wait_event(group->fanotify_data.access_waitq, event->response);

/* userspace responded, convert to something usable */
spin_lock(&event->lock);
switch (event->response) {
case FAN_ALLOW:
ret = 0;
break;
case FAN_DENY:
default:
ret = -EPERM;
}
event->response = 0;
spin_unlock(&event->lock);

return ret;
}
#endif

static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
int ret;
struct fsnotify_event *used_event;
struct fsnotify_event *notify_event = NULL;

BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
Expand All @@ -100,15 +130,31 @@ static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_e
BUILD_BUG_ON(FAN_OPEN != FS_OPEN);
BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD);
BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);

pr_debug("%s: group=%p event=%p\n", __func__, group, event);

ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge, (void **)&used_event);
ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge,
(void **)&notify_event);
/* -EEXIST means this event was merged with another, not that it was an error */
if (ret == -EEXIST)
ret = 0;
if (used_event)
fsnotify_put_event(used_event);
if (ret)
goto out;

#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
if (event->mask & FAN_ALL_PERM_EVENTS) {
/* if we merged we need to wait on the new event */
if (notify_event)
event = notify_event;
ret = fanotify_get_response_from_access(group, event);
}
#endif

out:
if (notify_event)
fsnotify_put_event(notify_event);
return ret;
}

Expand Down
5 changes: 5 additions & 0 deletions trunk/fs/notify/fanotify/fanotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,11 @@ SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags,
return PTR_ERR(group);

group->priority = priority;
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
mutex_init(&group->fanotify_data.access_mutex);
init_waitqueue_head(&group->fanotify_data.access_waitq);
INIT_LIST_HEAD(&group->fanotify_data.access_list);
#endif

fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
if (fd < 0)
Expand Down
18 changes: 18 additions & 0 deletions trunk/include/linux/fanotify.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
/* 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 */

Expand Down Expand Up @@ -52,7 +55,14 @@
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 1
Expand All @@ -65,6 +75,10 @@ struct fanotify_event_metadata {
__s64 pid;
} __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))

Expand All @@ -78,5 +92,9 @@ struct fanotify_event_metadata {

#ifdef __KERNEL__

struct fanotify_wait {
struct fsnotify_event *event;
__s32 fd;
};
#endif /* __KERNEL__ */
#endif /* _LINUX_FANOTIFY_H */
12 changes: 12 additions & 0 deletions trunk/include/linux/fsnotify_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,14 @@ struct fsnotify_group {
struct fasync_struct *fa; /* async notification */
struct user_struct *user;
} inotify_data;
#endif
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
struct fanotify_group_private_data {
/* allows a group to block waiting for a userspace response */
struct mutex access_mutex;
struct list_head access_list;
wait_queue_head_t access_waitq;
} fanotify_data;
#endif
};
};
Expand Down Expand Up @@ -227,6 +235,10 @@ struct fsnotify_event {
size_t name_len;
struct pid *tgid;

#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
__u32 response; /* userspace answer to question */
#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */

struct list_head private_data_list; /* groups can store private data here */
};

Expand Down

0 comments on commit 6032ee9

Please sign in to comment.