Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3383e83 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.infradead.org/users/eparis/notify

* 'for-linus' of git://git.infradead.org/users/eparis/notify:
  fanotify: fill in the metadata_len field on struct fanotify_event_metadata
  fanotify: split version into version and metadata_len
  fanotify: Dont try to open a file descriptor for the overflow event
  fanotify: Introduce FAN_NOFD
  fanotify: do not leak user reference on allocation failure
  inotify: stop kernel memory leak on file creation failure
  fanotify: on group destroy allow all waiters to bypass permission check
  fanotify: Dont allow a mask of 0 if setting or removing a mark
  fanotify: correct broken ref counting in case adding a mark failed
  fanotify: if set by user unset FMODE_NONOTIFY before fsnotify_perm() is called
  fanotify: remove packed from access response message
  fanotify: deny permissions when no event was sent
parents 68a4ec9c 7d131623
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1748,6 +1748,9 @@ struct file *do_filp_open(int dfd, const char *pathname,
	if (!(open_flag & O_CREAT))
		mode = 0;

	/* Must never be set by userspace */
	open_flag &= ~FMODE_NONOTIFY;

	/*
	 * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
	 * check for O_DSYNC if the need any syncing at all we enforce it's
+5 −1
Original line number Diff line number Diff line
@@ -92,7 +92,11 @@ static int fanotify_get_response_from_access(struct fsnotify_group *group,

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

	wait_event(group->fanotify_data.access_waitq, event->response);
	wait_event(group->fanotify_data.access_waitq, event->response ||
				atomic_read(&group->fanotify_data.bypass_perm));

	if (!event->response) /* bypass_perm set */
		return 0;

	/* userspace responded, convert to something usable */
	spin_lock(&event->lock);
+51 −30
Original line number Diff line number Diff line
@@ -106,20 +106,29 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event)
	return client_fd;
}

static ssize_t fill_event_metadata(struct fsnotify_group *group,
static int fill_event_metadata(struct fsnotify_group *group,
				   struct fanotify_event_metadata *metadata,
				   struct fsnotify_event *event)
{
	int ret = 0;

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

	metadata->event_len = FAN_EVENT_METADATA_LEN;
	metadata->metadata_len = FAN_EVENT_METADATA_LEN;
	metadata->vers = FANOTIFY_METADATA_VERSION;
	metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS;
	metadata->pid = pid_vnr(event->tgid);
	if (unlikely(event->mask & FAN_Q_OVERFLOW))
		metadata->fd = FAN_NOFD;
	else {
		metadata->fd = create_fd(group, event);
		if (metadata->fd < 0)
			ret = metadata->fd;
	}

	return metadata->fd;
	return ret;
}

#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
@@ -200,7 +209,7 @@ static int prepare_for_access_response(struct fsnotify_group *group,

	mutex_lock(&group->fanotify_data.access_mutex);

	if (group->fanotify_data.bypass_perm) {
	if (atomic_read(&group->fanotify_data.bypass_perm)) {
		mutex_unlock(&group->fanotify_data.access_mutex);
		kmem_cache_free(fanotify_response_event_cache, re);
		event->response = FAN_ALLOW;
@@ -257,24 +266,34 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,

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

	fd = fill_event_metadata(group, &fanotify_event_metadata, event);
	if (fd < 0)
		return fd;
	ret = fill_event_metadata(group, &fanotify_event_metadata, event);
	if (ret < 0)
		goto out;

	fd = fanotify_event_metadata.fd;
	ret = prepare_for_access_response(group, event, fd);
	if (ret)
		goto out_close_fd;

	ret = -EFAULT;
	if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN))
	if (copy_to_user(buf, &fanotify_event_metadata,
			 fanotify_event_metadata.event_len))
		goto out_kill_access_response;

	return FAN_EVENT_METADATA_LEN;
	return fanotify_event_metadata.event_len;

out_kill_access_response:
	remove_access_response(group, event, fd);
out_close_fd:
	if (fd != FAN_NOFD)
		sys_close(fd);
out:
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
	if (event->mask & FAN_ALL_PERM_EVENTS) {
		event->response = FAN_DENY;
		wake_up(&group->fanotify_data.access_waitq);
	}
#endif
	return ret;
}

@@ -382,7 +401,7 @@ static int fanotify_release(struct inode *ignored, struct file *file)

	mutex_lock(&group->fanotify_data.access_mutex);

	group->fanotify_data.bypass_perm = true;
	atomic_inc(&group->fanotify_data.bypass_perm);

	list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) {
		pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group,
@@ -586,11 +605,10 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
{
	struct fsnotify_mark *fsn_mark;
	__u32 added;
	int ret = 0;

	fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
	if (!fsn_mark) {
		int ret;

		if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
			return -ENOSPC;

@@ -600,17 +618,16 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,

		fsnotify_init_mark(fsn_mark, fanotify_free_mark);
		ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0);
		if (ret) {
			fanotify_free_mark(fsn_mark);
			return ret;
		}
		if (ret)
			goto err;
	}
	added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
	fsnotify_put_mark(fsn_mark);

	if (added & ~mnt->mnt_fsnotify_mask)
		fsnotify_recalc_vfsmount_mask(mnt);

	return 0;
err:
	fsnotify_put_mark(fsn_mark);
	return ret;
}

static int fanotify_add_inode_mark(struct fsnotify_group *group,
@@ -619,6 +636,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,
{
	struct fsnotify_mark *fsn_mark;
	__u32 added;
	int ret = 0;

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

@@ -634,8 +652,6 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,

	fsn_mark = fsnotify_find_inode_mark(group, inode);
	if (!fsn_mark) {
		int ret;

		if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
			return -ENOSPC;

@@ -645,16 +661,16 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group,

		fsnotify_init_mark(fsn_mark, fanotify_free_mark);
		ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0);
		if (ret) {
			fanotify_free_mark(fsn_mark);
			return ret;
		}
		if (ret)
			goto err;
	}
	added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
	fsnotify_put_mark(fsn_mark);

	if (added & ~inode->i_fsnotify_mask)
		fsnotify_recalc_inode_mask(inode);
	return 0;
err:
	fsnotify_put_mark(fsn_mark);
	return ret;
}

/* fanotify syscalls */
@@ -687,8 +703,10 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)

	/* fsnotify_alloc_group takes a ref.  Dropped in fanotify_release */
	group = fsnotify_alloc_group(&fanotify_fsnotify_ops);
	if (IS_ERR(group))
	if (IS_ERR(group)) {
		free_uid(user);
		return PTR_ERR(group);
	}

	group->fanotify_data.user = user;
	atomic_inc(&user->fanotify_listeners);
@@ -698,6 +716,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
	mutex_init(&group->fanotify_data.access_mutex);
	init_waitqueue_head(&group->fanotify_data.access_waitq);
	INIT_LIST_HEAD(&group->fanotify_data.access_list);
	atomic_set(&group->fanotify_data.bypass_perm, 0);
#endif
	switch (flags & FAN_ALL_CLASS_BITS) {
	case FAN_CLASS_NOTIF:
@@ -764,8 +783,10 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
	if (flags & ~FAN_ALL_MARK_FLAGS)
		return -EINVAL;
	switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
	case FAN_MARK_ADD:
	case FAN_MARK_ADD:		/* fallthrough */
	case FAN_MARK_REMOVE:
		if (!mask)
			return -EINVAL;
	case FAN_MARK_FLUSH:
		break;
	default:
+1 −0
Original line number Diff line number Diff line
@@ -752,6 +752,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
	if (ret >= 0)
		return ret;

	fsnotify_put_group(group);
	atomic_dec(&user->inotify_devs);
out_free_uid:
	free_uid(user);
+7 −3
Original line number Diff line number Diff line
@@ -83,11 +83,13 @@
				 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;
	__aligned_u64 mask;
	__s32 fd;
	__s32 pid;
@@ -96,11 +98,13 @@ struct fanotify_event_metadata {
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))
Loading