| .. | .. |
|---|
| 17 | 17 | #include <linux/compat.h> |
|---|
| 18 | 18 | #include <linux/sched/signal.h> |
|---|
| 19 | 19 | #include <linux/memcontrol.h> |
|---|
| 20 | +#include <linux/statfs.h> |
|---|
| 21 | +#include <linux/exportfs.h> |
|---|
| 20 | 22 | |
|---|
| 21 | 23 | #include <asm/ioctls.h> |
|---|
| 22 | 24 | |
|---|
| .. | .. |
|---|
| 44 | 46 | extern const struct fsnotify_ops fanotify_fsnotify_ops; |
|---|
| 45 | 47 | |
|---|
| 46 | 48 | struct kmem_cache *fanotify_mark_cache __read_mostly; |
|---|
| 47 | | -struct kmem_cache *fanotify_event_cachep __read_mostly; |
|---|
| 49 | +struct kmem_cache *fanotify_fid_event_cachep __read_mostly; |
|---|
| 50 | +struct kmem_cache *fanotify_path_event_cachep __read_mostly; |
|---|
| 48 | 51 | struct kmem_cache *fanotify_perm_event_cachep __read_mostly; |
|---|
| 49 | 52 | |
|---|
| 53 | +#define FANOTIFY_EVENT_ALIGN 4 |
|---|
| 54 | +#define FANOTIFY_INFO_HDR_LEN \ |
|---|
| 55 | + (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle)) |
|---|
| 56 | + |
|---|
| 57 | +static int fanotify_fid_info_len(int fh_len, int name_len) |
|---|
| 58 | +{ |
|---|
| 59 | + int info_len = fh_len; |
|---|
| 60 | + |
|---|
| 61 | + if (name_len) |
|---|
| 62 | + info_len += name_len + 1; |
|---|
| 63 | + |
|---|
| 64 | + return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN); |
|---|
| 65 | +} |
|---|
| 66 | + |
|---|
| 67 | +static int fanotify_event_info_len(unsigned int fid_mode, |
|---|
| 68 | + struct fanotify_event *event) |
|---|
| 69 | +{ |
|---|
| 70 | + struct fanotify_info *info = fanotify_event_info(event); |
|---|
| 71 | + int dir_fh_len = fanotify_event_dir_fh_len(event); |
|---|
| 72 | + int fh_len = fanotify_event_object_fh_len(event); |
|---|
| 73 | + int info_len = 0; |
|---|
| 74 | + int dot_len = 0; |
|---|
| 75 | + |
|---|
| 76 | + if (dir_fh_len) { |
|---|
| 77 | + info_len += fanotify_fid_info_len(dir_fh_len, info->name_len); |
|---|
| 78 | + } else if ((fid_mode & FAN_REPORT_NAME) && (event->mask & FAN_ONDIR)) { |
|---|
| 79 | + /* |
|---|
| 80 | + * With group flag FAN_REPORT_NAME, if name was not recorded in |
|---|
| 81 | + * event on a directory, we will report the name ".". |
|---|
| 82 | + */ |
|---|
| 83 | + dot_len = 1; |
|---|
| 84 | + } |
|---|
| 85 | + |
|---|
| 86 | + if (fh_len) |
|---|
| 87 | + info_len += fanotify_fid_info_len(fh_len, dot_len); |
|---|
| 88 | + |
|---|
| 89 | + return info_len; |
|---|
| 90 | +} |
|---|
| 91 | + |
|---|
| 50 | 92 | /* |
|---|
| 51 | | - * Get an fsnotify notification event if one exists and is small |
|---|
| 93 | + * Get an fanotify notification event if one exists and is small |
|---|
| 52 | 94 | * enough to fit in "count". Return an error pointer if the count |
|---|
| 53 | | - * is not large enough. |
|---|
| 54 | | - * |
|---|
| 55 | | - * Called with the group->notification_lock held. |
|---|
| 95 | + * is not large enough. When permission event is dequeued, its state is |
|---|
| 96 | + * updated accordingly. |
|---|
| 56 | 97 | */ |
|---|
| 57 | | -static struct fsnotify_event *get_one_event(struct fsnotify_group *group, |
|---|
| 98 | +static struct fanotify_event *get_one_event(struct fsnotify_group *group, |
|---|
| 58 | 99 | size_t count) |
|---|
| 59 | 100 | { |
|---|
| 60 | | - assert_spin_locked(&group->notification_lock); |
|---|
| 101 | + size_t event_size = FAN_EVENT_METADATA_LEN; |
|---|
| 102 | + struct fanotify_event *event = NULL; |
|---|
| 103 | + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
|---|
| 61 | 104 | |
|---|
| 62 | 105 | pr_debug("%s: group=%p count=%zd\n", __func__, group, count); |
|---|
| 63 | 106 | |
|---|
| 107 | + spin_lock(&group->notification_lock); |
|---|
| 64 | 108 | if (fsnotify_notify_queue_is_empty(group)) |
|---|
| 65 | | - return NULL; |
|---|
| 109 | + goto out; |
|---|
| 66 | 110 | |
|---|
| 67 | | - if (FAN_EVENT_METADATA_LEN > count) |
|---|
| 68 | | - return ERR_PTR(-EINVAL); |
|---|
| 111 | + if (fid_mode) { |
|---|
| 112 | + event_size += fanotify_event_info_len(fid_mode, |
|---|
| 113 | + FANOTIFY_E(fsnotify_peek_first_event(group))); |
|---|
| 114 | + } |
|---|
| 69 | 115 | |
|---|
| 70 | | - /* held the notification_lock the whole time, so this is the |
|---|
| 71 | | - * same event we peeked above */ |
|---|
| 72 | | - return fsnotify_remove_first_event(group); |
|---|
| 116 | + if (event_size > count) { |
|---|
| 117 | + event = ERR_PTR(-EINVAL); |
|---|
| 118 | + goto out; |
|---|
| 119 | + } |
|---|
| 120 | + event = FANOTIFY_E(fsnotify_remove_first_event(group)); |
|---|
| 121 | + if (fanotify_is_perm_event(event->mask)) |
|---|
| 122 | + FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED; |
|---|
| 123 | +out: |
|---|
| 124 | + spin_unlock(&group->notification_lock); |
|---|
| 125 | + return event; |
|---|
| 73 | 126 | } |
|---|
| 74 | 127 | |
|---|
| 75 | | -static int create_fd(struct fsnotify_group *group, |
|---|
| 76 | | - struct fanotify_event_info *event, |
|---|
| 128 | +static int create_fd(struct fsnotify_group *group, struct path *path, |
|---|
| 77 | 129 | struct file **file) |
|---|
| 78 | 130 | { |
|---|
| 79 | 131 | int client_fd; |
|---|
| 80 | 132 | struct file *new_file; |
|---|
| 81 | | - |
|---|
| 82 | | - pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
|---|
| 83 | 133 | |
|---|
| 84 | 134 | client_fd = get_unused_fd_flags(group->fanotify_data.f_flags); |
|---|
| 85 | 135 | if (client_fd < 0) |
|---|
| .. | .. |
|---|
| 89 | 139 | * we need a new file handle for the userspace program so it can read even if it was |
|---|
| 90 | 140 | * originally opened O_WRONLY. |
|---|
| 91 | 141 | */ |
|---|
| 92 | | - /* it's possible this event was an overflow event. in that case dentry and mnt |
|---|
| 93 | | - * are NULL; That's fine, just don't call dentry open */ |
|---|
| 94 | | - if (event->path.dentry && event->path.mnt) |
|---|
| 95 | | - new_file = dentry_open(&event->path, |
|---|
| 96 | | - group->fanotify_data.f_flags | FMODE_NONOTIFY, |
|---|
| 97 | | - current_cred()); |
|---|
| 98 | | - else |
|---|
| 99 | | - new_file = ERR_PTR(-EOVERFLOW); |
|---|
| 142 | + new_file = dentry_open(path, |
|---|
| 143 | + group->fanotify_data.f_flags | FMODE_NONOTIFY, |
|---|
| 144 | + current_cred()); |
|---|
| 100 | 145 | if (IS_ERR(new_file)) { |
|---|
| 101 | 146 | /* |
|---|
| 102 | 147 | * we still send an event even if we can't open the file. this |
|---|
| .. | .. |
|---|
| 114 | 159 | return client_fd; |
|---|
| 115 | 160 | } |
|---|
| 116 | 161 | |
|---|
| 117 | | -static int fill_event_metadata(struct fsnotify_group *group, |
|---|
| 118 | | - struct fanotify_event_metadata *metadata, |
|---|
| 119 | | - struct fsnotify_event *fsn_event, |
|---|
| 120 | | - struct file **file) |
|---|
| 162 | +/* |
|---|
| 163 | + * Finish processing of permission event by setting it to ANSWERED state and |
|---|
| 164 | + * drop group->notification_lock. |
|---|
| 165 | + */ |
|---|
| 166 | +static void finish_permission_event(struct fsnotify_group *group, |
|---|
| 167 | + struct fanotify_perm_event *event, |
|---|
| 168 | + unsigned int response) |
|---|
| 169 | + __releases(&group->notification_lock) |
|---|
| 121 | 170 | { |
|---|
| 122 | | - int ret = 0; |
|---|
| 123 | | - struct fanotify_event_info *event; |
|---|
| 171 | + bool destroy = false; |
|---|
| 124 | 172 | |
|---|
| 125 | | - pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, |
|---|
| 126 | | - group, metadata, fsn_event); |
|---|
| 127 | | - |
|---|
| 128 | | - *file = NULL; |
|---|
| 129 | | - event = container_of(fsn_event, struct fanotify_event_info, fse); |
|---|
| 130 | | - metadata->event_len = FAN_EVENT_METADATA_LEN; |
|---|
| 131 | | - metadata->metadata_len = FAN_EVENT_METADATA_LEN; |
|---|
| 132 | | - metadata->vers = FANOTIFY_METADATA_VERSION; |
|---|
| 133 | | - metadata->reserved = 0; |
|---|
| 134 | | - metadata->mask = fsn_event->mask & FAN_ALL_OUTGOING_EVENTS; |
|---|
| 135 | | - metadata->pid = pid_vnr(event->tgid); |
|---|
| 136 | | - if (unlikely(fsn_event->mask & FAN_Q_OVERFLOW)) |
|---|
| 137 | | - metadata->fd = FAN_NOFD; |
|---|
| 138 | | - else { |
|---|
| 139 | | - metadata->fd = create_fd(group, event, file); |
|---|
| 140 | | - if (metadata->fd < 0) |
|---|
| 141 | | - ret = metadata->fd; |
|---|
| 142 | | - } |
|---|
| 143 | | - |
|---|
| 144 | | - return ret; |
|---|
| 145 | | -} |
|---|
| 146 | | - |
|---|
| 147 | | -static struct fanotify_perm_event_info *dequeue_event( |
|---|
| 148 | | - struct fsnotify_group *group, int fd) |
|---|
| 149 | | -{ |
|---|
| 150 | | - struct fanotify_perm_event_info *event, *return_e = NULL; |
|---|
| 151 | | - |
|---|
| 152 | | - spin_lock(&group->notification_lock); |
|---|
| 153 | | - list_for_each_entry(event, &group->fanotify_data.access_list, |
|---|
| 154 | | - fae.fse.list) { |
|---|
| 155 | | - if (event->fd != fd) |
|---|
| 156 | | - continue; |
|---|
| 157 | | - |
|---|
| 158 | | - list_del_init(&event->fae.fse.list); |
|---|
| 159 | | - return_e = event; |
|---|
| 160 | | - break; |
|---|
| 161 | | - } |
|---|
| 173 | + assert_spin_locked(&group->notification_lock); |
|---|
| 174 | + event->response = response; |
|---|
| 175 | + if (event->state == FAN_EVENT_CANCELED) |
|---|
| 176 | + destroy = true; |
|---|
| 177 | + else |
|---|
| 178 | + event->state = FAN_EVENT_ANSWERED; |
|---|
| 162 | 179 | spin_unlock(&group->notification_lock); |
|---|
| 163 | | - |
|---|
| 164 | | - pr_debug("%s: found return_re=%p\n", __func__, return_e); |
|---|
| 165 | | - |
|---|
| 166 | | - return return_e; |
|---|
| 180 | + if (destroy) |
|---|
| 181 | + fsnotify_destroy_event(group, &event->fae.fse); |
|---|
| 167 | 182 | } |
|---|
| 168 | 183 | |
|---|
| 169 | 184 | static int process_access_response(struct fsnotify_group *group, |
|---|
| 170 | 185 | struct fanotify_response *response_struct) |
|---|
| 171 | 186 | { |
|---|
| 172 | | - struct fanotify_perm_event_info *event; |
|---|
| 187 | + struct fanotify_perm_event *event; |
|---|
| 173 | 188 | int fd = response_struct->fd; |
|---|
| 174 | 189 | int response = response_struct->response; |
|---|
| 175 | 190 | |
|---|
| .. | .. |
|---|
| 191 | 206 | if (fd < 0) |
|---|
| 192 | 207 | return -EINVAL; |
|---|
| 193 | 208 | |
|---|
| 194 | | - if ((response & FAN_AUDIT) && !group->fanotify_data.audit) |
|---|
| 209 | + if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT)) |
|---|
| 195 | 210 | return -EINVAL; |
|---|
| 196 | 211 | |
|---|
| 197 | | - event = dequeue_event(group, fd); |
|---|
| 198 | | - if (!event) |
|---|
| 199 | | - return -ENOENT; |
|---|
| 212 | + spin_lock(&group->notification_lock); |
|---|
| 213 | + list_for_each_entry(event, &group->fanotify_data.access_list, |
|---|
| 214 | + fae.fse.list) { |
|---|
| 215 | + if (event->fd != fd) |
|---|
| 216 | + continue; |
|---|
| 200 | 217 | |
|---|
| 201 | | - event->response = response; |
|---|
| 202 | | - wake_up(&group->fanotify_data.access_waitq); |
|---|
| 218 | + list_del_init(&event->fae.fse.list); |
|---|
| 219 | + finish_permission_event(group, event, response); |
|---|
| 220 | + wake_up(&group->fanotify_data.access_waitq); |
|---|
| 221 | + return 0; |
|---|
| 222 | + } |
|---|
| 223 | + spin_unlock(&group->notification_lock); |
|---|
| 203 | 224 | |
|---|
| 204 | | - return 0; |
|---|
| 225 | + return -ENOENT; |
|---|
| 226 | +} |
|---|
| 227 | + |
|---|
| 228 | +static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, |
|---|
| 229 | + int info_type, const char *name, size_t name_len, |
|---|
| 230 | + char __user *buf, size_t count) |
|---|
| 231 | +{ |
|---|
| 232 | + struct fanotify_event_info_fid info = { }; |
|---|
| 233 | + struct file_handle handle = { }; |
|---|
| 234 | + unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf; |
|---|
| 235 | + size_t fh_len = fh ? fh->len : 0; |
|---|
| 236 | + size_t info_len = fanotify_fid_info_len(fh_len, name_len); |
|---|
| 237 | + size_t len = info_len; |
|---|
| 238 | + |
|---|
| 239 | + pr_debug("%s: fh_len=%zu name_len=%zu, info_len=%zu, count=%zu\n", |
|---|
| 240 | + __func__, fh_len, name_len, info_len, count); |
|---|
| 241 | + |
|---|
| 242 | + if (!fh_len) |
|---|
| 243 | + return 0; |
|---|
| 244 | + |
|---|
| 245 | + if (WARN_ON_ONCE(len < sizeof(info) || len > count)) |
|---|
| 246 | + return -EFAULT; |
|---|
| 247 | + |
|---|
| 248 | + /* |
|---|
| 249 | + * Copy event info fid header followed by variable sized file handle |
|---|
| 250 | + * and optionally followed by variable sized filename. |
|---|
| 251 | + */ |
|---|
| 252 | + switch (info_type) { |
|---|
| 253 | + case FAN_EVENT_INFO_TYPE_FID: |
|---|
| 254 | + case FAN_EVENT_INFO_TYPE_DFID: |
|---|
| 255 | + if (WARN_ON_ONCE(name_len)) |
|---|
| 256 | + return -EFAULT; |
|---|
| 257 | + break; |
|---|
| 258 | + case FAN_EVENT_INFO_TYPE_DFID_NAME: |
|---|
| 259 | + if (WARN_ON_ONCE(!name || !name_len)) |
|---|
| 260 | + return -EFAULT; |
|---|
| 261 | + break; |
|---|
| 262 | + default: |
|---|
| 263 | + return -EFAULT; |
|---|
| 264 | + } |
|---|
| 265 | + |
|---|
| 266 | + info.hdr.info_type = info_type; |
|---|
| 267 | + info.hdr.len = len; |
|---|
| 268 | + info.fsid = *fsid; |
|---|
| 269 | + if (copy_to_user(buf, &info, sizeof(info))) |
|---|
| 270 | + return -EFAULT; |
|---|
| 271 | + |
|---|
| 272 | + buf += sizeof(info); |
|---|
| 273 | + len -= sizeof(info); |
|---|
| 274 | + if (WARN_ON_ONCE(len < sizeof(handle))) |
|---|
| 275 | + return -EFAULT; |
|---|
| 276 | + |
|---|
| 277 | + handle.handle_type = fh->type; |
|---|
| 278 | + handle.handle_bytes = fh_len; |
|---|
| 279 | + if (copy_to_user(buf, &handle, sizeof(handle))) |
|---|
| 280 | + return -EFAULT; |
|---|
| 281 | + |
|---|
| 282 | + buf += sizeof(handle); |
|---|
| 283 | + len -= sizeof(handle); |
|---|
| 284 | + if (WARN_ON_ONCE(len < fh_len)) |
|---|
| 285 | + return -EFAULT; |
|---|
| 286 | + |
|---|
| 287 | + /* |
|---|
| 288 | + * For an inline fh and inline file name, copy through stack to exclude |
|---|
| 289 | + * the copy from usercopy hardening protections. |
|---|
| 290 | + */ |
|---|
| 291 | + fh_buf = fanotify_fh_buf(fh); |
|---|
| 292 | + if (fh_len <= FANOTIFY_INLINE_FH_LEN) { |
|---|
| 293 | + memcpy(bounce, fh_buf, fh_len); |
|---|
| 294 | + fh_buf = bounce; |
|---|
| 295 | + } |
|---|
| 296 | + if (copy_to_user(buf, fh_buf, fh_len)) |
|---|
| 297 | + return -EFAULT; |
|---|
| 298 | + |
|---|
| 299 | + buf += fh_len; |
|---|
| 300 | + len -= fh_len; |
|---|
| 301 | + |
|---|
| 302 | + if (name_len) { |
|---|
| 303 | + /* Copy the filename with terminating null */ |
|---|
| 304 | + name_len++; |
|---|
| 305 | + if (WARN_ON_ONCE(len < name_len)) |
|---|
| 306 | + return -EFAULT; |
|---|
| 307 | + |
|---|
| 308 | + if (copy_to_user(buf, name, name_len)) |
|---|
| 309 | + return -EFAULT; |
|---|
| 310 | + |
|---|
| 311 | + buf += name_len; |
|---|
| 312 | + len -= name_len; |
|---|
| 313 | + } |
|---|
| 314 | + |
|---|
| 315 | + /* Pad with 0's */ |
|---|
| 316 | + WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN); |
|---|
| 317 | + if (len > 0 && clear_user(buf, len)) |
|---|
| 318 | + return -EFAULT; |
|---|
| 319 | + |
|---|
| 320 | + return info_len; |
|---|
| 205 | 321 | } |
|---|
| 206 | 322 | |
|---|
| 207 | 323 | static ssize_t copy_event_to_user(struct fsnotify_group *group, |
|---|
| 208 | | - struct fsnotify_event *event, |
|---|
| 209 | | - char __user *buf) |
|---|
| 324 | + struct fanotify_event *event, |
|---|
| 325 | + char __user *buf, size_t count) |
|---|
| 210 | 326 | { |
|---|
| 211 | | - struct fanotify_event_metadata fanotify_event_metadata; |
|---|
| 212 | | - struct file *f; |
|---|
| 213 | | - int fd, ret; |
|---|
| 327 | + struct fanotify_event_metadata metadata; |
|---|
| 328 | + struct path *path = fanotify_event_path(event); |
|---|
| 329 | + struct fanotify_info *info = fanotify_event_info(event); |
|---|
| 330 | + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
|---|
| 331 | + struct file *f = NULL; |
|---|
| 332 | + int ret, fd = FAN_NOFD; |
|---|
| 333 | + int info_type = 0; |
|---|
| 214 | 334 | |
|---|
| 215 | 335 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
|---|
| 216 | 336 | |
|---|
| 217 | | - ret = fill_event_metadata(group, &fanotify_event_metadata, event, &f); |
|---|
| 218 | | - if (ret < 0) |
|---|
| 219 | | - return ret; |
|---|
| 337 | + metadata.event_len = FAN_EVENT_METADATA_LEN + |
|---|
| 338 | + fanotify_event_info_len(fid_mode, event); |
|---|
| 339 | + metadata.metadata_len = FAN_EVENT_METADATA_LEN; |
|---|
| 340 | + metadata.vers = FANOTIFY_METADATA_VERSION; |
|---|
| 341 | + metadata.reserved = 0; |
|---|
| 342 | + metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; |
|---|
| 343 | + metadata.pid = pid_vnr(event->pid); |
|---|
| 220 | 344 | |
|---|
| 221 | | - fd = fanotify_event_metadata.fd; |
|---|
| 345 | + if (path && path->mnt && path->dentry) { |
|---|
| 346 | + fd = create_fd(group, path, &f); |
|---|
| 347 | + if (fd < 0) |
|---|
| 348 | + return fd; |
|---|
| 349 | + } |
|---|
| 350 | + metadata.fd = fd; |
|---|
| 351 | + |
|---|
| 222 | 352 | ret = -EFAULT; |
|---|
| 223 | | - if (copy_to_user(buf, &fanotify_event_metadata, |
|---|
| 224 | | - fanotify_event_metadata.event_len)) |
|---|
| 353 | + /* |
|---|
| 354 | + * Sanity check copy size in case get_one_event() and |
|---|
| 355 | + * event_len sizes ever get out of sync. |
|---|
| 356 | + */ |
|---|
| 357 | + if (WARN_ON_ONCE(metadata.event_len > count)) |
|---|
| 225 | 358 | goto out_close_fd; |
|---|
| 226 | 359 | |
|---|
| 227 | | - if (fanotify_is_perm_event(event->mask)) |
|---|
| 228 | | - FANOTIFY_PE(event)->fd = fd; |
|---|
| 360 | + if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN)) |
|---|
| 361 | + goto out_close_fd; |
|---|
| 229 | 362 | |
|---|
| 230 | | - if (fd != FAN_NOFD) |
|---|
| 363 | + buf += FAN_EVENT_METADATA_LEN; |
|---|
| 364 | + count -= FAN_EVENT_METADATA_LEN; |
|---|
| 365 | + |
|---|
| 366 | + if (fanotify_is_perm_event(event->mask)) |
|---|
| 367 | + FANOTIFY_PERM(event)->fd = fd; |
|---|
| 368 | + |
|---|
| 369 | + /* Event info records order is: dir fid + name, child fid */ |
|---|
| 370 | + if (fanotify_event_dir_fh_len(event)) { |
|---|
| 371 | + info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : |
|---|
| 372 | + FAN_EVENT_INFO_TYPE_DFID; |
|---|
| 373 | + ret = copy_info_to_user(fanotify_event_fsid(event), |
|---|
| 374 | + fanotify_info_dir_fh(info), |
|---|
| 375 | + info_type, fanotify_info_name(info), |
|---|
| 376 | + info->name_len, buf, count); |
|---|
| 377 | + if (ret < 0) |
|---|
| 378 | + goto out_close_fd; |
|---|
| 379 | + |
|---|
| 380 | + buf += ret; |
|---|
| 381 | + count -= ret; |
|---|
| 382 | + } |
|---|
| 383 | + |
|---|
| 384 | + if (fanotify_event_object_fh_len(event)) { |
|---|
| 385 | + const char *dot = NULL; |
|---|
| 386 | + int dot_len = 0; |
|---|
| 387 | + |
|---|
| 388 | + if (fid_mode == FAN_REPORT_FID || info_type) { |
|---|
| 389 | + /* |
|---|
| 390 | + * With only group flag FAN_REPORT_FID only type FID is |
|---|
| 391 | + * reported. Second info record type is always FID. |
|---|
| 392 | + */ |
|---|
| 393 | + info_type = FAN_EVENT_INFO_TYPE_FID; |
|---|
| 394 | + } else if ((fid_mode & FAN_REPORT_NAME) && |
|---|
| 395 | + (event->mask & FAN_ONDIR)) { |
|---|
| 396 | + /* |
|---|
| 397 | + * With group flag FAN_REPORT_NAME, if name was not |
|---|
| 398 | + * recorded in an event on a directory, report the |
|---|
| 399 | + * name "." with info type DFID_NAME. |
|---|
| 400 | + */ |
|---|
| 401 | + info_type = FAN_EVENT_INFO_TYPE_DFID_NAME; |
|---|
| 402 | + dot = "."; |
|---|
| 403 | + dot_len = 1; |
|---|
| 404 | + } else if ((event->mask & ALL_FSNOTIFY_DIRENT_EVENTS) || |
|---|
| 405 | + (event->mask & FAN_ONDIR)) { |
|---|
| 406 | + /* |
|---|
| 407 | + * With group flag FAN_REPORT_DIR_FID, a single info |
|---|
| 408 | + * record has type DFID for directory entry modification |
|---|
| 409 | + * event and for event on a directory. |
|---|
| 410 | + */ |
|---|
| 411 | + info_type = FAN_EVENT_INFO_TYPE_DFID; |
|---|
| 412 | + } else { |
|---|
| 413 | + /* |
|---|
| 414 | + * With group flags FAN_REPORT_DIR_FID|FAN_REPORT_FID, |
|---|
| 415 | + * a single info record has type FID for event on a |
|---|
| 416 | + * non-directory, when there is no directory to report. |
|---|
| 417 | + * For example, on FAN_DELETE_SELF event. |
|---|
| 418 | + */ |
|---|
| 419 | + info_type = FAN_EVENT_INFO_TYPE_FID; |
|---|
| 420 | + } |
|---|
| 421 | + |
|---|
| 422 | + ret = copy_info_to_user(fanotify_event_fsid(event), |
|---|
| 423 | + fanotify_event_object_fh(event), |
|---|
| 424 | + info_type, dot, dot_len, buf, count); |
|---|
| 425 | + if (ret < 0) |
|---|
| 426 | + goto out_close_fd; |
|---|
| 427 | + |
|---|
| 428 | + buf += ret; |
|---|
| 429 | + count -= ret; |
|---|
| 430 | + } |
|---|
| 431 | + |
|---|
| 432 | + if (f) |
|---|
| 231 | 433 | fd_install(fd, f); |
|---|
| 232 | | - return fanotify_event_metadata.event_len; |
|---|
| 434 | + |
|---|
| 435 | + return metadata.event_len; |
|---|
| 233 | 436 | |
|---|
| 234 | 437 | out_close_fd: |
|---|
| 235 | 438 | if (fd != FAN_NOFD) { |
|---|
| .. | .. |
|---|
| 258 | 461 | size_t count, loff_t *pos) |
|---|
| 259 | 462 | { |
|---|
| 260 | 463 | struct fsnotify_group *group; |
|---|
| 261 | | - struct fsnotify_event *kevent; |
|---|
| 464 | + struct fanotify_event *event; |
|---|
| 262 | 465 | char __user *start; |
|---|
| 263 | 466 | int ret; |
|---|
| 264 | 467 | DEFINE_WAIT_FUNC(wait, woken_wake_function); |
|---|
| .. | .. |
|---|
| 270 | 473 | |
|---|
| 271 | 474 | add_wait_queue(&group->notification_waitq, &wait); |
|---|
| 272 | 475 | while (1) { |
|---|
| 273 | | - spin_lock(&group->notification_lock); |
|---|
| 274 | | - kevent = get_one_event(group, count); |
|---|
| 275 | | - spin_unlock(&group->notification_lock); |
|---|
| 276 | | - |
|---|
| 277 | | - if (IS_ERR(kevent)) { |
|---|
| 278 | | - ret = PTR_ERR(kevent); |
|---|
| 476 | + /* |
|---|
| 477 | + * User can supply arbitrarily large buffer. Avoid softlockups |
|---|
| 478 | + * in case there are lots of available events. |
|---|
| 479 | + */ |
|---|
| 480 | + cond_resched(); |
|---|
| 481 | + event = get_one_event(group, count); |
|---|
| 482 | + if (IS_ERR(event)) { |
|---|
| 483 | + ret = PTR_ERR(event); |
|---|
| 279 | 484 | break; |
|---|
| 280 | 485 | } |
|---|
| 281 | 486 | |
|---|
| 282 | | - if (!kevent) { |
|---|
| 487 | + if (!event) { |
|---|
| 283 | 488 | ret = -EAGAIN; |
|---|
| 284 | 489 | if (file->f_flags & O_NONBLOCK) |
|---|
| 285 | 490 | break; |
|---|
| .. | .. |
|---|
| 295 | 500 | continue; |
|---|
| 296 | 501 | } |
|---|
| 297 | 502 | |
|---|
| 298 | | - ret = copy_event_to_user(group, kevent, buf); |
|---|
| 503 | + ret = copy_event_to_user(group, event, buf, count); |
|---|
| 299 | 504 | if (unlikely(ret == -EOPENSTALE)) { |
|---|
| 300 | 505 | /* |
|---|
| 301 | 506 | * We cannot report events with stale fd so drop it. |
|---|
| .. | .. |
|---|
| 310 | 515 | * Permission events get queued to wait for response. Other |
|---|
| 311 | 516 | * events can be destroyed now. |
|---|
| 312 | 517 | */ |
|---|
| 313 | | - if (!fanotify_is_perm_event(kevent->mask)) { |
|---|
| 314 | | - fsnotify_destroy_event(group, kevent); |
|---|
| 518 | + if (!fanotify_is_perm_event(event->mask)) { |
|---|
| 519 | + fsnotify_destroy_event(group, &event->fse); |
|---|
| 315 | 520 | } else { |
|---|
| 316 | 521 | if (ret <= 0) { |
|---|
| 317 | | - FANOTIFY_PE(kevent)->response = FAN_DENY; |
|---|
| 522 | + spin_lock(&group->notification_lock); |
|---|
| 523 | + finish_permission_event(group, |
|---|
| 524 | + FANOTIFY_PERM(event), FAN_DENY); |
|---|
| 318 | 525 | wake_up(&group->fanotify_data.access_waitq); |
|---|
| 319 | 526 | } else { |
|---|
| 320 | 527 | spin_lock(&group->notification_lock); |
|---|
| 321 | | - list_add_tail(&kevent->list, |
|---|
| 528 | + list_add_tail(&event->fse.list, |
|---|
| 322 | 529 | &group->fanotify_data.access_list); |
|---|
| 323 | 530 | spin_unlock(&group->notification_lock); |
|---|
| 324 | 531 | } |
|---|
| .. | .. |
|---|
| 346 | 553 | |
|---|
| 347 | 554 | group = file->private_data; |
|---|
| 348 | 555 | |
|---|
| 349 | | - if (count > sizeof(response)) |
|---|
| 350 | | - count = sizeof(response); |
|---|
| 556 | + if (count < sizeof(response)) |
|---|
| 557 | + return -EINVAL; |
|---|
| 558 | + |
|---|
| 559 | + count = sizeof(response); |
|---|
| 351 | 560 | |
|---|
| 352 | 561 | pr_debug("%s: group=%p count=%zu\n", __func__, group, count); |
|---|
| 353 | 562 | |
|---|
| .. | .. |
|---|
| 364 | 573 | static int fanotify_release(struct inode *ignored, struct file *file) |
|---|
| 365 | 574 | { |
|---|
| 366 | 575 | struct fsnotify_group *group = file->private_data; |
|---|
| 367 | | - struct fanotify_perm_event_info *event, *next; |
|---|
| 368 | | - struct fsnotify_event *fsn_event; |
|---|
| 369 | 576 | |
|---|
| 370 | 577 | /* |
|---|
| 371 | 578 | * Stop new events from arriving in the notification queue. since |
|---|
| .. | .. |
|---|
| 379 | 586 | * and simulate reply from userspace. |
|---|
| 380 | 587 | */ |
|---|
| 381 | 588 | spin_lock(&group->notification_lock); |
|---|
| 382 | | - list_for_each_entry_safe(event, next, &group->fanotify_data.access_list, |
|---|
| 383 | | - fae.fse.list) { |
|---|
| 384 | | - pr_debug("%s: found group=%p event=%p\n", __func__, group, |
|---|
| 385 | | - event); |
|---|
| 589 | + while (!list_empty(&group->fanotify_data.access_list)) { |
|---|
| 590 | + struct fanotify_perm_event *event; |
|---|
| 386 | 591 | |
|---|
| 592 | + event = list_first_entry(&group->fanotify_data.access_list, |
|---|
| 593 | + struct fanotify_perm_event, fae.fse.list); |
|---|
| 387 | 594 | list_del_init(&event->fae.fse.list); |
|---|
| 388 | | - event->response = FAN_ALLOW; |
|---|
| 595 | + finish_permission_event(group, event, FAN_ALLOW); |
|---|
| 596 | + spin_lock(&group->notification_lock); |
|---|
| 389 | 597 | } |
|---|
| 390 | 598 | |
|---|
| 391 | 599 | /* |
|---|
| .. | .. |
|---|
| 394 | 602 | * response is consumed and fanotify_get_response() returns. |
|---|
| 395 | 603 | */ |
|---|
| 396 | 604 | while (!fsnotify_notify_queue_is_empty(group)) { |
|---|
| 397 | | - fsn_event = fsnotify_remove_first_event(group); |
|---|
| 398 | | - if (!(fsn_event->mask & FAN_ALL_PERM_EVENTS)) { |
|---|
| 605 | + struct fanotify_event *event; |
|---|
| 606 | + |
|---|
| 607 | + event = FANOTIFY_E(fsnotify_remove_first_event(group)); |
|---|
| 608 | + if (!(event->mask & FANOTIFY_PERM_EVENTS)) { |
|---|
| 399 | 609 | spin_unlock(&group->notification_lock); |
|---|
| 400 | | - fsnotify_destroy_event(group, fsn_event); |
|---|
| 401 | | - spin_lock(&group->notification_lock); |
|---|
| 610 | + fsnotify_destroy_event(group, &event->fse); |
|---|
| 402 | 611 | } else { |
|---|
| 403 | | - FANOTIFY_PE(fsn_event)->response = FAN_ALLOW; |
|---|
| 612 | + finish_permission_event(group, FANOTIFY_PERM(event), |
|---|
| 613 | + FAN_ALLOW); |
|---|
| 404 | 614 | } |
|---|
| 615 | + spin_lock(&group->notification_lock); |
|---|
| 405 | 616 | } |
|---|
| 406 | 617 | spin_unlock(&group->notification_lock); |
|---|
| 407 | 618 | |
|---|
| .. | .. |
|---|
| 447 | 658 | .fasync = NULL, |
|---|
| 448 | 659 | .release = fanotify_release, |
|---|
| 449 | 660 | .unlocked_ioctl = fanotify_ioctl, |
|---|
| 450 | | - .compat_ioctl = fanotify_ioctl, |
|---|
| 661 | + .compat_ioctl = compat_ptr_ioctl, |
|---|
| 451 | 662 | .llseek = noop_llseek, |
|---|
| 452 | 663 | }; |
|---|
| 453 | 664 | |
|---|
| 454 | 665 | static int fanotify_find_path(int dfd, const char __user *filename, |
|---|
| 455 | | - struct path *path, unsigned int flags) |
|---|
| 666 | + struct path *path, unsigned int flags, __u64 mask, |
|---|
| 667 | + unsigned int obj_type) |
|---|
| 456 | 668 | { |
|---|
| 457 | 669 | int ret; |
|---|
| 458 | 670 | |
|---|
| .. | .. |
|---|
| 490 | 702 | } |
|---|
| 491 | 703 | |
|---|
| 492 | 704 | /* you can only watch an inode if you have read permissions on it */ |
|---|
| 493 | | - ret = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ); |
|---|
| 705 | + ret = inode_permission(path->dentry->d_inode, MAY_READ); |
|---|
| 706 | + if (ret) { |
|---|
| 707 | + path_put(path); |
|---|
| 708 | + goto out; |
|---|
| 709 | + } |
|---|
| 710 | + |
|---|
| 711 | + ret = security_path_notify(path, mask, obj_type); |
|---|
| 494 | 712 | if (ret) |
|---|
| 495 | 713 | path_put(path); |
|---|
| 714 | + |
|---|
| 496 | 715 | out: |
|---|
| 497 | 716 | return ret; |
|---|
| 498 | 717 | } |
|---|
| 499 | 718 | |
|---|
| 500 | 719 | static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, |
|---|
| 501 | | - __u32 mask, |
|---|
| 502 | | - unsigned int flags, |
|---|
| 503 | | - int *destroy) |
|---|
| 720 | + __u32 mask, unsigned int flags, |
|---|
| 721 | + __u32 umask, int *destroy) |
|---|
| 504 | 722 | { |
|---|
| 505 | 723 | __u32 oldmask = 0; |
|---|
| 506 | 724 | |
|---|
| 725 | + /* umask bits cannot be removed by user */ |
|---|
| 726 | + mask &= ~umask; |
|---|
| 507 | 727 | spin_lock(&fsn_mark->lock); |
|---|
| 508 | 728 | if (!(flags & FAN_MARK_IGNORED_MASK)) { |
|---|
| 509 | | - __u32 tmask = fsn_mark->mask & ~mask; |
|---|
| 510 | | - |
|---|
| 511 | | - if (flags & FAN_MARK_ONDIR) |
|---|
| 512 | | - tmask &= ~FAN_ONDIR; |
|---|
| 513 | | - |
|---|
| 514 | 729 | oldmask = fsn_mark->mask; |
|---|
| 515 | | - fsn_mark->mask = tmask; |
|---|
| 730 | + fsn_mark->mask &= ~mask; |
|---|
| 516 | 731 | } else { |
|---|
| 517 | | - __u32 tmask = fsn_mark->ignored_mask & ~mask; |
|---|
| 518 | | - if (flags & FAN_MARK_ONDIR) |
|---|
| 519 | | - tmask &= ~FAN_ONDIR; |
|---|
| 520 | | - fsn_mark->ignored_mask = tmask; |
|---|
| 732 | + fsn_mark->ignored_mask &= ~mask; |
|---|
| 521 | 733 | } |
|---|
| 522 | | - *destroy = !(fsn_mark->mask | fsn_mark->ignored_mask); |
|---|
| 734 | + /* |
|---|
| 735 | + * We need to keep the mark around even if remaining mask cannot |
|---|
| 736 | + * result in any events (e.g. mask == FAN_ONDIR) to support incremenal |
|---|
| 737 | + * changes to the mask. |
|---|
| 738 | + * Destroy mark when only umask bits remain. |
|---|
| 739 | + */ |
|---|
| 740 | + *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask); |
|---|
| 523 | 741 | spin_unlock(&fsn_mark->lock); |
|---|
| 524 | 742 | |
|---|
| 525 | 743 | return mask & oldmask; |
|---|
| .. | .. |
|---|
| 527 | 745 | |
|---|
| 528 | 746 | static int fanotify_remove_mark(struct fsnotify_group *group, |
|---|
| 529 | 747 | fsnotify_connp_t *connp, __u32 mask, |
|---|
| 530 | | - unsigned int flags) |
|---|
| 748 | + unsigned int flags, __u32 umask) |
|---|
| 531 | 749 | { |
|---|
| 532 | 750 | struct fsnotify_mark *fsn_mark = NULL; |
|---|
| 533 | 751 | __u32 removed; |
|---|
| .. | .. |
|---|
| 541 | 759 | } |
|---|
| 542 | 760 | |
|---|
| 543 | 761 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, |
|---|
| 544 | | - &destroy_mark); |
|---|
| 762 | + umask, &destroy_mark); |
|---|
| 545 | 763 | if (removed & fsnotify_conn_mask(fsn_mark->connector)) |
|---|
| 546 | 764 | fsnotify_recalc_mask(fsn_mark->connector); |
|---|
| 547 | 765 | if (destroy_mark) |
|---|
| .. | .. |
|---|
| 557 | 775 | |
|---|
| 558 | 776 | static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, |
|---|
| 559 | 777 | struct vfsmount *mnt, __u32 mask, |
|---|
| 560 | | - unsigned int flags) |
|---|
| 778 | + unsigned int flags, __u32 umask) |
|---|
| 561 | 779 | { |
|---|
| 562 | 780 | return fanotify_remove_mark(group, &real_mount(mnt)->mnt_fsnotify_marks, |
|---|
| 563 | | - mask, flags); |
|---|
| 781 | + mask, flags, umask); |
|---|
| 782 | +} |
|---|
| 783 | + |
|---|
| 784 | +static int fanotify_remove_sb_mark(struct fsnotify_group *group, |
|---|
| 785 | + struct super_block *sb, __u32 mask, |
|---|
| 786 | + unsigned int flags, __u32 umask) |
|---|
| 787 | +{ |
|---|
| 788 | + return fanotify_remove_mark(group, &sb->s_fsnotify_marks, mask, |
|---|
| 789 | + flags, umask); |
|---|
| 564 | 790 | } |
|---|
| 565 | 791 | |
|---|
| 566 | 792 | static int fanotify_remove_inode_mark(struct fsnotify_group *group, |
|---|
| 567 | 793 | struct inode *inode, __u32 mask, |
|---|
| 568 | | - unsigned int flags) |
|---|
| 794 | + unsigned int flags, __u32 umask) |
|---|
| 569 | 795 | { |
|---|
| 570 | 796 | return fanotify_remove_mark(group, &inode->i_fsnotify_marks, mask, |
|---|
| 571 | | - flags); |
|---|
| 797 | + flags, umask); |
|---|
| 572 | 798 | } |
|---|
| 573 | 799 | |
|---|
| 574 | 800 | static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, |
|---|
| .. | .. |
|---|
| 579 | 805 | |
|---|
| 580 | 806 | spin_lock(&fsn_mark->lock); |
|---|
| 581 | 807 | if (!(flags & FAN_MARK_IGNORED_MASK)) { |
|---|
| 582 | | - __u32 tmask = fsn_mark->mask | mask; |
|---|
| 583 | | - |
|---|
| 584 | | - if (flags & FAN_MARK_ONDIR) |
|---|
| 585 | | - tmask |= FAN_ONDIR; |
|---|
| 586 | | - |
|---|
| 587 | 808 | oldmask = fsn_mark->mask; |
|---|
| 588 | | - fsn_mark->mask = tmask; |
|---|
| 809 | + fsn_mark->mask |= mask; |
|---|
| 589 | 810 | } else { |
|---|
| 590 | | - __u32 tmask = fsn_mark->ignored_mask | mask; |
|---|
| 591 | | - if (flags & FAN_MARK_ONDIR) |
|---|
| 592 | | - tmask |= FAN_ONDIR; |
|---|
| 593 | | - |
|---|
| 594 | | - fsn_mark->ignored_mask = tmask; |
|---|
| 811 | + fsn_mark->ignored_mask |= mask; |
|---|
| 595 | 812 | if (flags & FAN_MARK_IGNORED_SURV_MODIFY) |
|---|
| 596 | 813 | fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; |
|---|
| 597 | 814 | } |
|---|
| .. | .. |
|---|
| 602 | 819 | |
|---|
| 603 | 820 | static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, |
|---|
| 604 | 821 | fsnotify_connp_t *connp, |
|---|
| 605 | | - unsigned int type) |
|---|
| 822 | + unsigned int type, |
|---|
| 823 | + __kernel_fsid_t *fsid) |
|---|
| 606 | 824 | { |
|---|
| 607 | 825 | struct fsnotify_mark *mark; |
|---|
| 608 | 826 | int ret; |
|---|
| .. | .. |
|---|
| 615 | 833 | return ERR_PTR(-ENOMEM); |
|---|
| 616 | 834 | |
|---|
| 617 | 835 | fsnotify_init_mark(mark, group); |
|---|
| 618 | | - ret = fsnotify_add_mark_locked(mark, connp, type, 0); |
|---|
| 836 | + ret = fsnotify_add_mark_locked(mark, connp, type, 0, fsid); |
|---|
| 619 | 837 | if (ret) { |
|---|
| 620 | 838 | fsnotify_put_mark(mark); |
|---|
| 621 | 839 | return ERR_PTR(ret); |
|---|
| .. | .. |
|---|
| 627 | 845 | |
|---|
| 628 | 846 | static int fanotify_add_mark(struct fsnotify_group *group, |
|---|
| 629 | 847 | fsnotify_connp_t *connp, unsigned int type, |
|---|
| 630 | | - __u32 mask, unsigned int flags) |
|---|
| 848 | + __u32 mask, unsigned int flags, |
|---|
| 849 | + __kernel_fsid_t *fsid) |
|---|
| 631 | 850 | { |
|---|
| 632 | 851 | struct fsnotify_mark *fsn_mark; |
|---|
| 633 | 852 | __u32 added; |
|---|
| .. | .. |
|---|
| 635 | 854 | mutex_lock(&group->mark_mutex); |
|---|
| 636 | 855 | fsn_mark = fsnotify_find_mark(connp, group); |
|---|
| 637 | 856 | if (!fsn_mark) { |
|---|
| 638 | | - fsn_mark = fanotify_add_new_mark(group, connp, type); |
|---|
| 857 | + fsn_mark = fanotify_add_new_mark(group, connp, type, fsid); |
|---|
| 639 | 858 | if (IS_ERR(fsn_mark)) { |
|---|
| 640 | 859 | mutex_unlock(&group->mark_mutex); |
|---|
| 641 | 860 | return PTR_ERR(fsn_mark); |
|---|
| .. | .. |
|---|
| 652 | 871 | |
|---|
| 653 | 872 | static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, |
|---|
| 654 | 873 | struct vfsmount *mnt, __u32 mask, |
|---|
| 655 | | - unsigned int flags) |
|---|
| 874 | + unsigned int flags, __kernel_fsid_t *fsid) |
|---|
| 656 | 875 | { |
|---|
| 657 | 876 | return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks, |
|---|
| 658 | | - FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags); |
|---|
| 877 | + FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid); |
|---|
| 878 | +} |
|---|
| 879 | + |
|---|
| 880 | +static int fanotify_add_sb_mark(struct fsnotify_group *group, |
|---|
| 881 | + struct super_block *sb, __u32 mask, |
|---|
| 882 | + unsigned int flags, __kernel_fsid_t *fsid) |
|---|
| 883 | +{ |
|---|
| 884 | + return fanotify_add_mark(group, &sb->s_fsnotify_marks, |
|---|
| 885 | + FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid); |
|---|
| 659 | 886 | } |
|---|
| 660 | 887 | |
|---|
| 661 | 888 | static int fanotify_add_inode_mark(struct fsnotify_group *group, |
|---|
| 662 | 889 | struct inode *inode, __u32 mask, |
|---|
| 663 | | - unsigned int flags) |
|---|
| 890 | + unsigned int flags, __kernel_fsid_t *fsid) |
|---|
| 664 | 891 | { |
|---|
| 665 | 892 | pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); |
|---|
| 666 | 893 | |
|---|
| .. | .. |
|---|
| 671 | 898 | */ |
|---|
| 672 | 899 | if ((flags & FAN_MARK_IGNORED_MASK) && |
|---|
| 673 | 900 | !(flags & FAN_MARK_IGNORED_SURV_MODIFY) && |
|---|
| 674 | | - (atomic_read(&inode->i_writecount) > 0)) |
|---|
| 901 | + inode_is_open_for_write(inode)) |
|---|
| 675 | 902 | return 0; |
|---|
| 676 | 903 | |
|---|
| 677 | 904 | return fanotify_add_mark(group, &inode->i_fsnotify_marks, |
|---|
| 678 | | - FSNOTIFY_OBJ_TYPE_INODE, mask, flags); |
|---|
| 905 | + FSNOTIFY_OBJ_TYPE_INODE, mask, flags, fsid); |
|---|
| 906 | +} |
|---|
| 907 | + |
|---|
| 908 | +static struct fsnotify_event *fanotify_alloc_overflow_event(void) |
|---|
| 909 | +{ |
|---|
| 910 | + struct fanotify_event *oevent; |
|---|
| 911 | + |
|---|
| 912 | + oevent = kmalloc(sizeof(*oevent), GFP_KERNEL_ACCOUNT); |
|---|
| 913 | + if (!oevent) |
|---|
| 914 | + return NULL; |
|---|
| 915 | + |
|---|
| 916 | + fanotify_init_event(oevent, 0, FS_Q_OVERFLOW); |
|---|
| 917 | + oevent->type = FANOTIFY_EVENT_TYPE_OVERFLOW; |
|---|
| 918 | + |
|---|
| 919 | + return &oevent->fse; |
|---|
| 679 | 920 | } |
|---|
| 680 | 921 | |
|---|
| 681 | 922 | /* fanotify syscalls */ |
|---|
| .. | .. |
|---|
| 684 | 925 | struct fsnotify_group *group; |
|---|
| 685 | 926 | int f_flags, fd; |
|---|
| 686 | 927 | struct user_struct *user; |
|---|
| 687 | | - struct fanotify_event_info *oevent; |
|---|
| 928 | + unsigned int fid_mode = flags & FANOTIFY_FID_BITS; |
|---|
| 929 | + unsigned int class = flags & FANOTIFY_CLASS_BITS; |
|---|
| 688 | 930 | |
|---|
| 689 | | - pr_debug("%s: flags=%d event_f_flags=%d\n", |
|---|
| 690 | | - __func__, flags, event_f_flags); |
|---|
| 931 | + pr_debug("%s: flags=%x event_f_flags=%x\n", |
|---|
| 932 | + __func__, flags, event_f_flags); |
|---|
| 691 | 933 | |
|---|
| 692 | 934 | if (!capable(CAP_SYS_ADMIN)) |
|---|
| 693 | 935 | return -EPERM; |
|---|
| 694 | 936 | |
|---|
| 695 | 937 | #ifdef CONFIG_AUDITSYSCALL |
|---|
| 696 | | - if (flags & ~(FAN_ALL_INIT_FLAGS | FAN_ENABLE_AUDIT)) |
|---|
| 938 | + if (flags & ~(FANOTIFY_INIT_FLAGS | FAN_ENABLE_AUDIT)) |
|---|
| 697 | 939 | #else |
|---|
| 698 | | - if (flags & ~FAN_ALL_INIT_FLAGS) |
|---|
| 940 | + if (flags & ~FANOTIFY_INIT_FLAGS) |
|---|
| 699 | 941 | #endif |
|---|
| 700 | 942 | return -EINVAL; |
|---|
| 701 | 943 | |
|---|
| .. | .. |
|---|
| 710 | 952 | default: |
|---|
| 711 | 953 | return -EINVAL; |
|---|
| 712 | 954 | } |
|---|
| 955 | + |
|---|
| 956 | + if (fid_mode && class != FAN_CLASS_NOTIF) |
|---|
| 957 | + return -EINVAL; |
|---|
| 958 | + |
|---|
| 959 | + /* |
|---|
| 960 | + * Child name is reported with parent fid so requires dir fid. |
|---|
| 961 | + * We can report both child fid and dir fid with or without name. |
|---|
| 962 | + */ |
|---|
| 963 | + if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID)) |
|---|
| 964 | + return -EINVAL; |
|---|
| 713 | 965 | |
|---|
| 714 | 966 | user = get_current_user(); |
|---|
| 715 | 967 | if (atomic_read(&user->fanotify_listeners) > FANOTIFY_DEFAULT_MAX_LISTENERS) { |
|---|
| .. | .. |
|---|
| 731 | 983 | } |
|---|
| 732 | 984 | |
|---|
| 733 | 985 | group->fanotify_data.user = user; |
|---|
| 986 | + group->fanotify_data.flags = flags; |
|---|
| 734 | 987 | atomic_inc(&user->fanotify_listeners); |
|---|
| 735 | 988 | group->memcg = get_mem_cgroup_from_mm(current->mm); |
|---|
| 736 | 989 | |
|---|
| 737 | | - oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL); |
|---|
| 738 | | - if (unlikely(!oevent)) { |
|---|
| 990 | + group->overflow_event = fanotify_alloc_overflow_event(); |
|---|
| 991 | + if (unlikely(!group->overflow_event)) { |
|---|
| 739 | 992 | fd = -ENOMEM; |
|---|
| 740 | 993 | goto out_destroy_group; |
|---|
| 741 | 994 | } |
|---|
| 742 | | - group->overflow_event = &oevent->fse; |
|---|
| 743 | 995 | |
|---|
| 744 | 996 | if (force_o_largefile()) |
|---|
| 745 | 997 | event_f_flags |= O_LARGEFILE; |
|---|
| 746 | 998 | group->fanotify_data.f_flags = event_f_flags; |
|---|
| 747 | 999 | init_waitqueue_head(&group->fanotify_data.access_waitq); |
|---|
| 748 | 1000 | INIT_LIST_HEAD(&group->fanotify_data.access_list); |
|---|
| 749 | | - switch (flags & FAN_ALL_CLASS_BITS) { |
|---|
| 1001 | + switch (class) { |
|---|
| 750 | 1002 | case FAN_CLASS_NOTIF: |
|---|
| 751 | 1003 | group->priority = FS_PRIO_0; |
|---|
| 752 | 1004 | break; |
|---|
| .. | .. |
|---|
| 783 | 1035 | fd = -EPERM; |
|---|
| 784 | 1036 | if (!capable(CAP_AUDIT_WRITE)) |
|---|
| 785 | 1037 | goto out_destroy_group; |
|---|
| 786 | | - group->fanotify_data.audit = true; |
|---|
| 787 | 1038 | } |
|---|
| 788 | 1039 | |
|---|
| 789 | 1040 | fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); |
|---|
| .. | .. |
|---|
| 797 | 1048 | return fd; |
|---|
| 798 | 1049 | } |
|---|
| 799 | 1050 | |
|---|
| 1051 | +/* Check if filesystem can encode a unique fid */ |
|---|
| 1052 | +static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid) |
|---|
| 1053 | +{ |
|---|
| 1054 | + __kernel_fsid_t root_fsid; |
|---|
| 1055 | + int err; |
|---|
| 1056 | + |
|---|
| 1057 | + /* |
|---|
| 1058 | + * Make sure path is not in filesystem with zero fsid (e.g. tmpfs). |
|---|
| 1059 | + */ |
|---|
| 1060 | + err = vfs_get_fsid(path->dentry, fsid); |
|---|
| 1061 | + if (err) |
|---|
| 1062 | + return err; |
|---|
| 1063 | + |
|---|
| 1064 | + if (!fsid->val[0] && !fsid->val[1]) |
|---|
| 1065 | + return -ENODEV; |
|---|
| 1066 | + |
|---|
| 1067 | + /* |
|---|
| 1068 | + * Make sure path is not inside a filesystem subvolume (e.g. btrfs) |
|---|
| 1069 | + * which uses a different fsid than sb root. |
|---|
| 1070 | + */ |
|---|
| 1071 | + err = vfs_get_fsid(path->dentry->d_sb->s_root, &root_fsid); |
|---|
| 1072 | + if (err) |
|---|
| 1073 | + return err; |
|---|
| 1074 | + |
|---|
| 1075 | + if (root_fsid.val[0] != fsid->val[0] || |
|---|
| 1076 | + root_fsid.val[1] != fsid->val[1]) |
|---|
| 1077 | + return -EXDEV; |
|---|
| 1078 | + |
|---|
| 1079 | + /* |
|---|
| 1080 | + * We need to make sure that the file system supports at least |
|---|
| 1081 | + * encoding a file handle so user can use name_to_handle_at() to |
|---|
| 1082 | + * compare fid returned with event to the file handle of watched |
|---|
| 1083 | + * objects. However, name_to_handle_at() requires that the |
|---|
| 1084 | + * filesystem also supports decoding file handles. |
|---|
| 1085 | + */ |
|---|
| 1086 | + if (!path->dentry->d_sb->s_export_op || |
|---|
| 1087 | + !path->dentry->d_sb->s_export_op->fh_to_dentry) |
|---|
| 1088 | + return -EOPNOTSUPP; |
|---|
| 1089 | + |
|---|
| 1090 | + return 0; |
|---|
| 1091 | +} |
|---|
| 1092 | + |
|---|
| 1093 | +static int fanotify_events_supported(struct path *path, __u64 mask) |
|---|
| 1094 | +{ |
|---|
| 1095 | + /* |
|---|
| 1096 | + * Some filesystems such as 'proc' acquire unusual locks when opening |
|---|
| 1097 | + * files. For them fanotify permission events have high chances of |
|---|
| 1098 | + * deadlocking the system - open done when reporting fanotify event |
|---|
| 1099 | + * blocks on this "unusual" lock while another process holding the lock |
|---|
| 1100 | + * waits for fanotify permission event to be answered. Just disallow |
|---|
| 1101 | + * permission events for such filesystems. |
|---|
| 1102 | + */ |
|---|
| 1103 | + if (mask & FANOTIFY_PERM_EVENTS && |
|---|
| 1104 | + path->mnt->mnt_sb->s_type->fs_flags & FS_DISALLOW_NOTIFY_PERM) |
|---|
| 1105 | + return -EINVAL; |
|---|
| 1106 | + return 0; |
|---|
| 1107 | +} |
|---|
| 1108 | + |
|---|
| 800 | 1109 | static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, |
|---|
| 801 | 1110 | int dfd, const char __user *pathname) |
|---|
| 802 | 1111 | { |
|---|
| .. | .. |
|---|
| 805 | 1114 | struct fsnotify_group *group; |
|---|
| 806 | 1115 | struct fd f; |
|---|
| 807 | 1116 | struct path path; |
|---|
| 808 | | - u32 valid_mask = FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD; |
|---|
| 1117 | + __kernel_fsid_t __fsid, *fsid = NULL; |
|---|
| 1118 | + u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; |
|---|
| 1119 | + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; |
|---|
| 1120 | + bool ignored = flags & FAN_MARK_IGNORED_MASK; |
|---|
| 1121 | + unsigned int obj_type, fid_mode; |
|---|
| 1122 | + u32 umask = 0; |
|---|
| 809 | 1123 | int ret; |
|---|
| 810 | 1124 | |
|---|
| 811 | 1125 | pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", |
|---|
| .. | .. |
|---|
| 815 | 1129 | if (mask & ((__u64)0xffffffff << 32)) |
|---|
| 816 | 1130 | return -EINVAL; |
|---|
| 817 | 1131 | |
|---|
| 818 | | - if (flags & ~FAN_ALL_MARK_FLAGS) |
|---|
| 1132 | + if (flags & ~FANOTIFY_MARK_FLAGS) |
|---|
| 819 | 1133 | return -EINVAL; |
|---|
| 1134 | + |
|---|
| 1135 | + switch (mark_type) { |
|---|
| 1136 | + case FAN_MARK_INODE: |
|---|
| 1137 | + obj_type = FSNOTIFY_OBJ_TYPE_INODE; |
|---|
| 1138 | + break; |
|---|
| 1139 | + case FAN_MARK_MOUNT: |
|---|
| 1140 | + obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT; |
|---|
| 1141 | + break; |
|---|
| 1142 | + case FAN_MARK_FILESYSTEM: |
|---|
| 1143 | + obj_type = FSNOTIFY_OBJ_TYPE_SB; |
|---|
| 1144 | + break; |
|---|
| 1145 | + default: |
|---|
| 1146 | + return -EINVAL; |
|---|
| 1147 | + } |
|---|
| 1148 | + |
|---|
| 820 | 1149 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { |
|---|
| 821 | | - case FAN_MARK_ADD: /* fallthrough */ |
|---|
| 1150 | + case FAN_MARK_ADD: |
|---|
| 822 | 1151 | case FAN_MARK_REMOVE: |
|---|
| 823 | 1152 | if (!mask) |
|---|
| 824 | 1153 | return -EINVAL; |
|---|
| 825 | 1154 | break; |
|---|
| 826 | 1155 | case FAN_MARK_FLUSH: |
|---|
| 827 | | - if (flags & ~(FAN_MARK_MOUNT | FAN_MARK_FLUSH)) |
|---|
| 1156 | + if (flags & ~(FANOTIFY_MARK_TYPE_BITS | FAN_MARK_FLUSH)) |
|---|
| 828 | 1157 | return -EINVAL; |
|---|
| 829 | 1158 | break; |
|---|
| 830 | 1159 | default: |
|---|
| 831 | 1160 | return -EINVAL; |
|---|
| 832 | 1161 | } |
|---|
| 833 | 1162 | |
|---|
| 834 | | - if (mask & FAN_ONDIR) { |
|---|
| 835 | | - flags |= FAN_MARK_ONDIR; |
|---|
| 836 | | - mask &= ~FAN_ONDIR; |
|---|
| 837 | | - } |
|---|
| 838 | | - |
|---|
| 839 | 1163 | if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) |
|---|
| 840 | | - valid_mask |= FAN_ALL_PERM_EVENTS; |
|---|
| 1164 | + valid_mask |= FANOTIFY_PERM_EVENTS; |
|---|
| 841 | 1165 | |
|---|
| 842 | 1166 | if (mask & ~valid_mask) |
|---|
| 843 | 1167 | return -EINVAL; |
|---|
| 1168 | + |
|---|
| 1169 | + /* Event flags (ONDIR, ON_CHILD) are meaningless in ignored mask */ |
|---|
| 1170 | + if (ignored) |
|---|
| 1171 | + mask &= ~FANOTIFY_EVENT_FLAGS; |
|---|
| 844 | 1172 | |
|---|
| 845 | 1173 | f = fdget(fanotify_fd); |
|---|
| 846 | 1174 | if (unlikely(!f.file)) |
|---|
| .. | .. |
|---|
| 857 | 1185 | * allowed to set permissions events. |
|---|
| 858 | 1186 | */ |
|---|
| 859 | 1187 | ret = -EINVAL; |
|---|
| 860 | | - if (mask & FAN_ALL_PERM_EVENTS && |
|---|
| 1188 | + if (mask & FANOTIFY_PERM_EVENTS && |
|---|
| 861 | 1189 | group->priority == FS_PRIO_0) |
|---|
| 1190 | + goto fput_and_out; |
|---|
| 1191 | + |
|---|
| 1192 | + /* |
|---|
| 1193 | + * Events with data type inode do not carry enough information to report |
|---|
| 1194 | + * event->fd, so we do not allow setting a mask for inode events unless |
|---|
| 1195 | + * group supports reporting fid. |
|---|
| 1196 | + * inode events are not supported on a mount mark, because they do not |
|---|
| 1197 | + * carry enough information (i.e. path) to be filtered by mount point. |
|---|
| 1198 | + */ |
|---|
| 1199 | + fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); |
|---|
| 1200 | + if (mask & FANOTIFY_INODE_EVENTS && |
|---|
| 1201 | + (!fid_mode || mark_type == FAN_MARK_MOUNT)) |
|---|
| 862 | 1202 | goto fput_and_out; |
|---|
| 863 | 1203 | |
|---|
| 864 | 1204 | if (flags & FAN_MARK_FLUSH) { |
|---|
| 865 | 1205 | ret = 0; |
|---|
| 866 | | - if (flags & FAN_MARK_MOUNT) |
|---|
| 1206 | + if (mark_type == FAN_MARK_MOUNT) |
|---|
| 867 | 1207 | fsnotify_clear_vfsmount_marks_by_group(group); |
|---|
| 1208 | + else if (mark_type == FAN_MARK_FILESYSTEM) |
|---|
| 1209 | + fsnotify_clear_sb_marks_by_group(group); |
|---|
| 868 | 1210 | else |
|---|
| 869 | 1211 | fsnotify_clear_inode_marks_by_group(group); |
|---|
| 870 | 1212 | goto fput_and_out; |
|---|
| 871 | 1213 | } |
|---|
| 872 | 1214 | |
|---|
| 873 | | - ret = fanotify_find_path(dfd, pathname, &path, flags); |
|---|
| 1215 | + ret = fanotify_find_path(dfd, pathname, &path, flags, |
|---|
| 1216 | + (mask & ALL_FSNOTIFY_EVENTS), obj_type); |
|---|
| 874 | 1217 | if (ret) |
|---|
| 875 | 1218 | goto fput_and_out; |
|---|
| 876 | 1219 | |
|---|
| 1220 | + if (flags & FAN_MARK_ADD) { |
|---|
| 1221 | + ret = fanotify_events_supported(&path, mask); |
|---|
| 1222 | + if (ret) |
|---|
| 1223 | + goto path_put_and_out; |
|---|
| 1224 | + } |
|---|
| 1225 | + |
|---|
| 1226 | + if (fid_mode) { |
|---|
| 1227 | + ret = fanotify_test_fid(&path, &__fsid); |
|---|
| 1228 | + if (ret) |
|---|
| 1229 | + goto path_put_and_out; |
|---|
| 1230 | + |
|---|
| 1231 | + fsid = &__fsid; |
|---|
| 1232 | + } |
|---|
| 1233 | + |
|---|
| 877 | 1234 | /* inode held in place by reference to path; group by fget on fd */ |
|---|
| 878 | | - if (!(flags & FAN_MARK_MOUNT)) |
|---|
| 1235 | + if (mark_type == FAN_MARK_INODE) |
|---|
| 879 | 1236 | inode = path.dentry->d_inode; |
|---|
| 880 | 1237 | else |
|---|
| 881 | 1238 | mnt = path.mnt; |
|---|
| 882 | 1239 | |
|---|
| 1240 | + /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ |
|---|
| 1241 | + if (mnt || !S_ISDIR(inode->i_mode)) { |
|---|
| 1242 | + mask &= ~FAN_EVENT_ON_CHILD; |
|---|
| 1243 | + umask = FAN_EVENT_ON_CHILD; |
|---|
| 1244 | + /* |
|---|
| 1245 | + * If group needs to report parent fid, register for getting |
|---|
| 1246 | + * events with parent/name info for non-directory. |
|---|
| 1247 | + */ |
|---|
| 1248 | + if ((fid_mode & FAN_REPORT_DIR_FID) && |
|---|
| 1249 | + (flags & FAN_MARK_ADD) && !ignored) |
|---|
| 1250 | + mask |= FAN_EVENT_ON_CHILD; |
|---|
| 1251 | + } |
|---|
| 1252 | + |
|---|
| 883 | 1253 | /* create/update an inode mark */ |
|---|
| 884 | 1254 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { |
|---|
| 885 | 1255 | case FAN_MARK_ADD: |
|---|
| 886 | | - if (flags & FAN_MARK_MOUNT) |
|---|
| 887 | | - ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags); |
|---|
| 1256 | + if (mark_type == FAN_MARK_MOUNT) |
|---|
| 1257 | + ret = fanotify_add_vfsmount_mark(group, mnt, mask, |
|---|
| 1258 | + flags, fsid); |
|---|
| 1259 | + else if (mark_type == FAN_MARK_FILESYSTEM) |
|---|
| 1260 | + ret = fanotify_add_sb_mark(group, mnt->mnt_sb, mask, |
|---|
| 1261 | + flags, fsid); |
|---|
| 888 | 1262 | else |
|---|
| 889 | | - ret = fanotify_add_inode_mark(group, inode, mask, flags); |
|---|
| 1263 | + ret = fanotify_add_inode_mark(group, inode, mask, |
|---|
| 1264 | + flags, fsid); |
|---|
| 890 | 1265 | break; |
|---|
| 891 | 1266 | case FAN_MARK_REMOVE: |
|---|
| 892 | | - if (flags & FAN_MARK_MOUNT) |
|---|
| 893 | | - ret = fanotify_remove_vfsmount_mark(group, mnt, mask, flags); |
|---|
| 1267 | + if (mark_type == FAN_MARK_MOUNT) |
|---|
| 1268 | + ret = fanotify_remove_vfsmount_mark(group, mnt, mask, |
|---|
| 1269 | + flags, umask); |
|---|
| 1270 | + else if (mark_type == FAN_MARK_FILESYSTEM) |
|---|
| 1271 | + ret = fanotify_remove_sb_mark(group, mnt->mnt_sb, mask, |
|---|
| 1272 | + flags, umask); |
|---|
| 894 | 1273 | else |
|---|
| 895 | | - ret = fanotify_remove_inode_mark(group, inode, mask, flags); |
|---|
| 1274 | + ret = fanotify_remove_inode_mark(group, inode, mask, |
|---|
| 1275 | + flags, umask); |
|---|
| 896 | 1276 | break; |
|---|
| 897 | 1277 | default: |
|---|
| 898 | 1278 | ret = -EINVAL; |
|---|
| 899 | 1279 | } |
|---|
| 900 | 1280 | |
|---|
| 1281 | +path_put_and_out: |
|---|
| 901 | 1282 | path_put(&path); |
|---|
| 902 | 1283 | fput_and_out: |
|---|
| 903 | 1284 | fdput(f); |
|---|
| 904 | 1285 | return ret; |
|---|
| 905 | 1286 | } |
|---|
| 906 | 1287 | |
|---|
| 1288 | +#ifndef CONFIG_ARCH_SPLIT_ARG64 |
|---|
| 907 | 1289 | SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags, |
|---|
| 908 | 1290 | __u64, mask, int, dfd, |
|---|
| 909 | 1291 | const char __user *, pathname) |
|---|
| 910 | 1292 | { |
|---|
| 911 | 1293 | return do_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname); |
|---|
| 912 | 1294 | } |
|---|
| 1295 | +#endif |
|---|
| 913 | 1296 | |
|---|
| 914 | | -#ifdef CONFIG_COMPAT |
|---|
| 915 | | -COMPAT_SYSCALL_DEFINE6(fanotify_mark, |
|---|
| 1297 | +#if defined(CONFIG_ARCH_SPLIT_ARG64) || defined(CONFIG_COMPAT) |
|---|
| 1298 | +SYSCALL32_DEFINE6(fanotify_mark, |
|---|
| 916 | 1299 | int, fanotify_fd, unsigned int, flags, |
|---|
| 917 | | - __u32, mask0, __u32, mask1, int, dfd, |
|---|
| 1300 | + SC_ARG64(mask), int, dfd, |
|---|
| 918 | 1301 | const char __user *, pathname) |
|---|
| 919 | 1302 | { |
|---|
| 920 | | - return do_fanotify_mark(fanotify_fd, flags, |
|---|
| 921 | | -#ifdef __BIG_ENDIAN |
|---|
| 922 | | - ((__u64)mask0 << 32) | mask1, |
|---|
| 923 | | -#else |
|---|
| 924 | | - ((__u64)mask1 << 32) | mask0, |
|---|
| 925 | | -#endif |
|---|
| 926 | | - dfd, pathname); |
|---|
| 1303 | + return do_fanotify_mark(fanotify_fd, flags, SC_VAL64(__u64, mask), |
|---|
| 1304 | + dfd, pathname); |
|---|
| 927 | 1305 | } |
|---|
| 928 | 1306 | #endif |
|---|
| 929 | 1307 | |
|---|
| .. | .. |
|---|
| 934 | 1312 | */ |
|---|
| 935 | 1313 | static int __init fanotify_user_setup(void) |
|---|
| 936 | 1314 | { |
|---|
| 1315 | + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 10); |
|---|
| 1316 | + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); |
|---|
| 1317 | + |
|---|
| 937 | 1318 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, |
|---|
| 938 | 1319 | SLAB_PANIC|SLAB_ACCOUNT); |
|---|
| 939 | | - fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC); |
|---|
| 1320 | + fanotify_fid_event_cachep = KMEM_CACHE(fanotify_fid_event, |
|---|
| 1321 | + SLAB_PANIC); |
|---|
| 1322 | + fanotify_path_event_cachep = KMEM_CACHE(fanotify_path_event, |
|---|
| 1323 | + SLAB_PANIC); |
|---|
| 940 | 1324 | if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) { |
|---|
| 941 | 1325 | fanotify_perm_event_cachep = |
|---|
| 942 | | - KMEM_CACHE(fanotify_perm_event_info, SLAB_PANIC); |
|---|
| 1326 | + KMEM_CACHE(fanotify_perm_event, SLAB_PANIC); |
|---|
| 943 | 1327 | } |
|---|
| 944 | 1328 | |
|---|
| 945 | 1329 | return 0; |
|---|