LCOV - code coverage report
Current view: top level - fs/notify/fanotify - fanotify.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 0 124 0.0 %
Date: 2020-09-30 20:25:40 Functions: 0 10 0.0 %
Branches: 0 116 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : #include <linux/fanotify.h>
       3                 :            : #include <linux/fdtable.h>
       4                 :            : #include <linux/fsnotify_backend.h>
       5                 :            : #include <linux/init.h>
       6                 :            : #include <linux/jiffies.h>
       7                 :            : #include <linux/kernel.h> /* UINT_MAX */
       8                 :            : #include <linux/mount.h>
       9                 :            : #include <linux/sched.h>
      10                 :            : #include <linux/sched/user.h>
      11                 :            : #include <linux/sched/signal.h>
      12                 :            : #include <linux/types.h>
      13                 :            : #include <linux/wait.h>
      14                 :            : #include <linux/audit.h>
      15                 :            : #include <linux/sched/mm.h>
      16                 :            : #include <linux/statfs.h>
      17                 :            : 
      18                 :            : #include "fanotify.h"
      19                 :            : 
      20                 :          0 : static bool should_merge(struct fsnotify_event *old_fsn,
      21                 :            :                          struct fsnotify_event *new_fsn)
      22                 :            : {
      23                 :            :         struct fanotify_event *old, *new;
      24                 :            : 
      25                 :            :         pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn);
      26                 :            :         old = FANOTIFY_E(old_fsn);
      27                 :            :         new = FANOTIFY_E(new_fsn);
      28                 :            : 
      29   [ #  #  #  # ]:          0 :         if (old_fsn->objectid != new_fsn->objectid || old->pid != new->pid ||
      30         [ #  # ]:          0 :             old->fh_type != new->fh_type || old->fh_len != new->fh_len)
      31                 :            :                 return false;
      32                 :            : 
      33         [ #  # ]:          0 :         if (fanotify_event_has_path(old)) {
      34   [ #  #  #  # ]:          0 :                 return old->path.mnt == new->path.mnt &&
      35                 :          0 :                         old->path.dentry == new->path.dentry;
      36         [ #  # ]:          0 :         } else if (fanotify_event_has_fid(old)) {
      37                 :            :                 /*
      38                 :            :                  * We want to merge many dirent events in the same dir (i.e.
      39                 :            :                  * creates/unlinks/renames), but we do not want to merge dirent
      40                 :            :                  * events referring to subdirs with dirent events referring to
      41                 :            :                  * non subdirs, otherwise, user won't be able to tell from a
      42                 :            :                  * mask FAN_CREATE|FAN_DELETE|FAN_ONDIR if it describes mkdir+
      43                 :            :                  * unlink pair or rmdir+create pair of events.
      44                 :            :                  */
      45   [ #  #  #  # ]:          0 :                 return (old->mask & FS_ISDIR) == (new->mask & FS_ISDIR) &&
      46                 :          0 :                         fanotify_fid_equal(&old->fid, &new->fid, old->fh_len);
      47                 :            :         }
      48                 :            : 
      49                 :            :         /* Do not merge events if we failed to encode fid */
      50                 :            :         return false;
      51                 :            : }
      52                 :            : 
      53                 :            : /* and the list better be locked by something too! */
      54                 :          0 : static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
      55                 :            : {
      56                 :            :         struct fsnotify_event *test_event;
      57                 :            :         struct fanotify_event *new;
      58                 :            : 
      59                 :            :         pr_debug("%s: list=%p event=%p\n", __func__, list, event);
      60                 :            :         new = FANOTIFY_E(event);
      61                 :            : 
      62                 :            :         /*
      63                 :            :          * Don't merge a permission event with any other event so that we know
      64                 :            :          * the event structure we have created in fanotify_handle_event() is the
      65                 :            :          * one we should check for permission response.
      66                 :            :          */
      67                 :            :         if (fanotify_is_perm_event(new->mask))
      68                 :            :                 return 0;
      69                 :            : 
      70         [ #  # ]:          0 :         list_for_each_entry_reverse(test_event, list, list) {
      71         [ #  # ]:          0 :                 if (should_merge(test_event, event)) {
      72                 :          0 :                         FANOTIFY_E(test_event)->mask |= new->mask;
      73                 :          0 :                         return 1;
      74                 :            :                 }
      75                 :            :         }
      76                 :            : 
      77                 :            :         return 0;
      78                 :            : }
      79                 :            : 
      80                 :            : /*
      81                 :            :  * Wait for response to permission event. The function also takes care of
      82                 :            :  * freeing the permission event (or offloads that in case the wait is canceled
      83                 :            :  * by a signal). The function returns 0 in case access got allowed by userspace,
      84                 :            :  * -EPERM in case userspace disallowed the access, and -ERESTARTSYS in case
      85                 :            :  * the wait got interrupted by a signal.
      86                 :            :  */
      87                 :            : static int fanotify_get_response(struct fsnotify_group *group,
      88                 :            :                                  struct fanotify_perm_event *event,
      89                 :            :                                  struct fsnotify_iter_info *iter_info)
      90                 :            : {
      91                 :            :         int ret;
      92                 :            : 
      93                 :            :         pr_debug("%s: group=%p event=%p\n", __func__, group, event);
      94                 :            : 
      95                 :            :         ret = wait_event_killable(group->fanotify_data.access_waitq,
      96                 :            :                                   event->state == FAN_EVENT_ANSWERED);
      97                 :            :         /* Signal pending? */
      98                 :            :         if (ret < 0) {
      99                 :            :                 spin_lock(&group->notification_lock);
     100                 :            :                 /* Event reported to userspace and no answer yet? */
     101                 :            :                 if (event->state == FAN_EVENT_REPORTED) {
     102                 :            :                         /* Event will get freed once userspace answers to it */
     103                 :            :                         event->state = FAN_EVENT_CANCELED;
     104                 :            :                         spin_unlock(&group->notification_lock);
     105                 :            :                         return ret;
     106                 :            :                 }
     107                 :            :                 /* Event not yet reported? Just remove it. */
     108                 :            :                 if (event->state == FAN_EVENT_INIT)
     109                 :            :                         fsnotify_remove_queued_event(group, &event->fae.fse);
     110                 :            :                 /*
     111                 :            :                  * Event may be also answered in case signal delivery raced
     112                 :            :                  * with wakeup. In that case we have nothing to do besides
     113                 :            :                  * freeing the event and reporting error.
     114                 :            :                  */
     115                 :            :                 spin_unlock(&group->notification_lock);
     116                 :            :                 goto out;
     117                 :            :         }
     118                 :            : 
     119                 :            :         /* userspace responded, convert to something usable */
     120                 :            :         switch (event->response & ~FAN_AUDIT) {
     121                 :            :         case FAN_ALLOW:
     122                 :            :                 ret = 0;
     123                 :            :                 break;
     124                 :            :         case FAN_DENY:
     125                 :            :         default:
     126                 :            :                 ret = -EPERM;
     127                 :            :         }
     128                 :            : 
     129                 :            :         /* Check if the response should be audited */
     130                 :            :         if (event->response & FAN_AUDIT)
     131                 :            :                 audit_fanotify(event->response & ~FAN_AUDIT);
     132                 :            : 
     133                 :            :         pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
     134                 :            :                  group, event, ret);
     135                 :            : out:
     136                 :            :         fsnotify_destroy_event(group, &event->fae.fse);
     137                 :            : 
     138                 :            :         return ret;
     139                 :            : }
     140                 :            : 
     141                 :            : /*
     142                 :            :  * This function returns a mask for an event that only contains the flags
     143                 :            :  * that have been specifically requested by the user. Flags that may have
     144                 :            :  * been included within the event mask, but have not been explicitly
     145                 :            :  * requested by the user, will not be present in the returned mask.
     146                 :            :  */
     147                 :          0 : static u32 fanotify_group_event_mask(struct fsnotify_group *group,
     148                 :            :                                      struct fsnotify_iter_info *iter_info,
     149                 :            :                                      u32 event_mask, const void *data,
     150                 :            :                                      int data_type)
     151                 :            : {
     152                 :            :         __u32 marks_mask = 0, marks_ignored_mask = 0;
     153                 :            :         __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS;
     154                 :            :         const struct path *path = data;
     155                 :            :         struct fsnotify_mark *mark;
     156                 :            :         int type;
     157                 :            : 
     158                 :            :         pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
     159                 :            :                  __func__, iter_info->report_mask, event_mask, data, data_type);
     160                 :            : 
     161         [ #  # ]:          0 :         if (!FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
     162                 :            :                 /* Do we have path to open a file descriptor? */
     163         [ #  # ]:          0 :                 if (data_type != FSNOTIFY_EVENT_PATH)
     164                 :            :                         return 0;
     165                 :            :                 /* Path type events are only relevant for files and dirs */
     166   [ #  #  #  # ]:          0 :                 if (!d_is_reg(path->dentry) && !d_can_lookup(path->dentry))
     167                 :            :                         return 0;
     168                 :            :         }
     169                 :            : 
     170         [ #  # ]:          0 :         fsnotify_foreach_obj_type(type) {
     171         [ #  # ]:          0 :                 if (!fsnotify_iter_should_report_type(iter_info, type))
     172                 :          0 :                         continue;
     173                 :          0 :                 mark = iter_info->marks[type];
     174                 :            : 
     175                 :            :                 /* Apply ignore mask regardless of ISDIR and ON_CHILD flags */
     176                 :          0 :                 marks_ignored_mask |= mark->ignored_mask;
     177                 :            : 
     178                 :            :                 /*
     179                 :            :                  * If the event is on dir and this mark doesn't care about
     180                 :            :                  * events on dir, don't send it!
     181                 :            :                  */
     182   [ #  #  #  # ]:          0 :                 if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR))
     183                 :          0 :                         continue;
     184                 :            : 
     185                 :            :                 /*
     186                 :            :                  * If the event is for a child and this mark doesn't care about
     187                 :            :                  * events on a child, don't send it!
     188                 :            :                  */
     189   [ #  #  #  # ]:          0 :                 if (event_mask & FS_EVENT_ON_CHILD &&
     190         [ #  # ]:          0 :                     (type != FSNOTIFY_OBJ_TYPE_INODE ||
     191                 :          0 :                      !(mark->mask & FS_EVENT_ON_CHILD)))
     192                 :          0 :                         continue;
     193                 :            : 
     194                 :          0 :                 marks_mask |= mark->mask;
     195                 :            :         }
     196                 :            : 
     197                 :          0 :         test_mask = event_mask & marks_mask & ~marks_ignored_mask;
     198                 :            : 
     199                 :            :         /*
     200                 :            :          * dirent modification events (create/delete/move) do not carry the
     201                 :            :          * child entry name/inode information. Instead, we report FAN_ONDIR
     202                 :            :          * for mkdir/rmdir so user can differentiate them from creat/unlink.
     203                 :            :          *
     204                 :            :          * For backward compatibility and consistency, do not report FAN_ONDIR
     205                 :            :          * to user in legacy fanotify mode (reporting fd) and report FAN_ONDIR
     206                 :            :          * to user in FAN_REPORT_FID mode for all event types.
     207                 :            :          */
     208         [ #  # ]:          0 :         if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
     209                 :            :                 /* Do not report FAN_ONDIR without any event */
     210         [ #  # ]:          0 :                 if (!(test_mask & ~FAN_ONDIR))
     211                 :            :                         return 0;
     212                 :            :         } else {
     213                 :            :                 user_mask &= ~FAN_ONDIR;
     214                 :            :         }
     215                 :            : 
     216                 :          0 :         return test_mask & user_mask;
     217                 :            : }
     218                 :            : 
     219                 :          0 : static int fanotify_encode_fid(struct fanotify_event *event,
     220                 :            :                                struct inode *inode, gfp_t gfp,
     221                 :            :                                __kernel_fsid_t *fsid)
     222                 :            : {
     223                 :            :         struct fanotify_fid *fid = &event->fid;
     224                 :            :         int dwords, bytes = 0;
     225                 :            :         int err, type;
     226                 :            : 
     227                 :          0 :         fid->ext_fh = NULL;
     228                 :          0 :         dwords = 0;
     229                 :            :         err = -ENOENT;
     230                 :          0 :         type = exportfs_encode_inode_fh(inode, NULL, &dwords, NULL);
     231         [ #  # ]:          0 :         if (!dwords)
     232                 :            :                 goto out_err;
     233                 :            : 
     234                 :          0 :         bytes = dwords << 2;
     235         [ #  # ]:          0 :         if (bytes > FANOTIFY_INLINE_FH_LEN) {
     236                 :            :                 /* Treat failure to allocate fh as failure to allocate event */
     237                 :            :                 err = -ENOMEM;
     238                 :          0 :                 fid->ext_fh = kmalloc(bytes, gfp);
     239         [ #  # ]:          0 :                 if (!fid->ext_fh)
     240                 :            :                         goto out_err;
     241                 :            :         }
     242                 :            : 
     243                 :          0 :         type = exportfs_encode_inode_fh(inode, fanotify_fid_fh(fid, bytes),
     244                 :            :                                         &dwords, NULL);
     245                 :            :         err = -EINVAL;
     246   [ #  #  #  # ]:          0 :         if (!type || type == FILEID_INVALID || bytes != dwords << 2)
     247                 :            :                 goto out_err;
     248                 :            : 
     249                 :          0 :         fid->fsid = *fsid;
     250                 :          0 :         event->fh_len = bytes;
     251                 :            : 
     252                 :          0 :         return type;
     253                 :            : 
     254                 :            : out_err:
     255         [ #  # ]:          0 :         pr_warn_ratelimited("fanotify: failed to encode fid (fsid=%x.%x, "
     256                 :            :                             "type=%d, bytes=%d, err=%i)\n",
     257                 :            :                             fsid->val[0], fsid->val[1], type, bytes, err);
     258                 :          0 :         kfree(fid->ext_fh);
     259                 :          0 :         fid->ext_fh = NULL;
     260                 :          0 :         event->fh_len = 0;
     261                 :            : 
     262                 :          0 :         return FILEID_INVALID;
     263                 :            : }
     264                 :            : 
     265                 :            : /*
     266                 :            :  * The inode to use as identifier when reporting fid depends on the event.
     267                 :            :  * Report the modified directory inode on dirent modification events.
     268                 :            :  * Report the "victim" inode otherwise.
     269                 :            :  * For example:
     270                 :            :  * FS_ATTRIB reports the child inode even if reported on a watched parent.
     271                 :            :  * FS_CREATE reports the modified dir inode and not the created inode.
     272                 :            :  */
     273                 :            : static struct inode *fanotify_fid_inode(struct inode *to_tell, u32 event_mask,
     274                 :            :                                         const void *data, int data_type)
     275                 :            : {
     276         [ #  # ]:          0 :         if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS)
     277                 :            :                 return to_tell;
     278         [ #  # ]:          0 :         else if (data_type == FSNOTIFY_EVENT_INODE)
     279                 :            :                 return (struct inode *)data;
     280         [ #  # ]:          0 :         else if (data_type == FSNOTIFY_EVENT_PATH)
     281                 :          0 :                 return d_inode(((struct path *)data)->dentry);
     282                 :            :         return NULL;
     283                 :            : }
     284                 :            : 
     285                 :          0 : struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
     286                 :            :                                             struct inode *inode, u32 mask,
     287                 :            :                                             const void *data, int data_type,
     288                 :            :                                             __kernel_fsid_t *fsid)
     289                 :            : {
     290                 :            :         struct fanotify_event *event = NULL;
     291                 :            :         gfp_t gfp = GFP_KERNEL_ACCOUNT;
     292                 :            :         struct inode *id = fanotify_fid_inode(inode, mask, data, data_type);
     293                 :            : 
     294                 :            :         /*
     295                 :            :          * For queues with unlimited length lost events are not expected and
     296                 :            :          * can possibly have security implications. Avoid losing events when
     297                 :            :          * memory is short. For the limited size queues, avoid OOM killer in the
     298                 :            :          * target monitoring memcg as it may have security repercussion.
     299                 :            :          */
     300         [ #  # ]:          0 :         if (group->max_events == UINT_MAX)
     301                 :            :                 gfp |= __GFP_NOFAIL;
     302                 :            :         else
     303                 :            :                 gfp |= __GFP_RETRY_MAYFAIL;
     304                 :            : 
     305                 :            :         /* Whoever is interested in the event, pays for the allocation. */
     306                 :          0 :         memalloc_use_memcg(group->memcg);
     307                 :            : 
     308                 :            :         if (fanotify_is_perm_event(mask)) {
     309                 :            :                 struct fanotify_perm_event *pevent;
     310                 :            : 
     311                 :            :                 pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
     312                 :            :                 if (!pevent)
     313                 :            :                         goto out;
     314                 :            :                 event = &pevent->fae;
     315                 :            :                 pevent->response = 0;
     316                 :            :                 pevent->state = FAN_EVENT_INIT;
     317                 :            :                 goto init;
     318                 :            :         }
     319                 :          0 :         event = kmem_cache_alloc(fanotify_event_cachep, gfp);
     320         [ #  # ]:          0 :         if (!event)
     321                 :            :                 goto out;
     322                 :            : init: __maybe_unused
     323                 :            :         /*
     324                 :            :          * Use the victim inode instead of the watching inode as the id for
     325                 :            :          * event queue, so event reported on parent is merged with event
     326                 :            :          * reported on child when both directory and child watches exist.
     327                 :            :          */
     328                 :          0 :         fsnotify_init_event(&event->fse, (unsigned long)id);
     329                 :          0 :         event->mask = mask;
     330         [ #  # ]:          0 :         if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
     331                 :          0 :                 event->pid = get_pid(task_pid(current));
     332                 :            :         else
     333                 :          0 :                 event->pid = get_pid(task_tgid(current));
     334                 :          0 :         event->fh_len = 0;
     335   [ #  #  #  # ]:          0 :         if (id && FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
     336                 :            :                 /* Report the event without a file identifier on encode error */
     337                 :          0 :                 event->fh_type = fanotify_encode_fid(event, id, gfp, fsid);
     338         [ #  # ]:          0 :         } else if (data_type == FSNOTIFY_EVENT_PATH) {
     339                 :          0 :                 event->fh_type = FILEID_ROOT;
     340                 :          0 :                 event->path = *((struct path *)data);
     341                 :          0 :                 path_get(&event->path);
     342                 :            :         } else {
     343                 :          0 :                 event->fh_type = FILEID_INVALID;
     344                 :          0 :                 event->path.mnt = NULL;
     345                 :          0 :                 event->path.dentry = NULL;
     346                 :            :         }
     347                 :            : out:
     348                 :            :         memalloc_unuse_memcg();
     349                 :          0 :         return event;
     350                 :            : }
     351                 :            : 
     352                 :            : /*
     353                 :            :  * Get cached fsid of the filesystem containing the object from any connector.
     354                 :            :  * All connectors are supposed to have the same fsid, but we do not verify that
     355                 :            :  * here.
     356                 :            :  */
     357                 :          0 : static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
     358                 :            : {
     359                 :            :         int type;
     360                 :            :         __kernel_fsid_t fsid = {};
     361                 :            : 
     362         [ #  # ]:          0 :         fsnotify_foreach_obj_type(type) {
     363                 :            :                 struct fsnotify_mark_connector *conn;
     364                 :            : 
     365         [ #  # ]:          0 :                 if (!fsnotify_iter_should_report_type(iter_info, type))
     366                 :          0 :                         continue;
     367                 :            : 
     368                 :          0 :                 conn = READ_ONCE(iter_info->marks[type]->connector);
     369                 :            :                 /* Mark is just getting destroyed or created? */
     370         [ #  # ]:          0 :                 if (!conn)
     371                 :          0 :                         continue;
     372         [ #  # ]:          0 :                 if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID))
     373                 :          0 :                         continue;
     374                 :            :                 /* Pairs with smp_wmb() in fsnotify_add_mark_list() */
     375                 :          0 :                 smp_rmb();
     376                 :          0 :                 fsid = conn->fsid;
     377   [ #  #  #  #  :          0 :                 if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
          #  #  #  #  #  
                      # ]
     378                 :          0 :                         continue;
     379                 :          0 :                 return fsid;
     380                 :            :         }
     381                 :            : 
     382                 :          0 :         return fsid;
     383                 :            : }
     384                 :            : 
     385                 :          0 : static int fanotify_handle_event(struct fsnotify_group *group,
     386                 :            :                                  struct inode *inode,
     387                 :            :                                  u32 mask, const void *data, int data_type,
     388                 :            :                                  const struct qstr *file_name, u32 cookie,
     389                 :            :                                  struct fsnotify_iter_info *iter_info)
     390                 :            : {
     391                 :            :         int ret = 0;
     392                 :            :         struct fanotify_event *event;
     393                 :            :         struct fsnotify_event *fsn_event;
     394                 :          0 :         __kernel_fsid_t fsid = {};
     395                 :            : 
     396                 :            :         BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
     397                 :            :         BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
     398                 :            :         BUILD_BUG_ON(FAN_ATTRIB != FS_ATTRIB);
     399                 :            :         BUILD_BUG_ON(FAN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE);
     400                 :            :         BUILD_BUG_ON(FAN_CLOSE_WRITE != FS_CLOSE_WRITE);
     401                 :            :         BUILD_BUG_ON(FAN_OPEN != FS_OPEN);
     402                 :            :         BUILD_BUG_ON(FAN_MOVED_TO != FS_MOVED_TO);
     403                 :            :         BUILD_BUG_ON(FAN_MOVED_FROM != FS_MOVED_FROM);
     404                 :            :         BUILD_BUG_ON(FAN_CREATE != FS_CREATE);
     405                 :            :         BUILD_BUG_ON(FAN_DELETE != FS_DELETE);
     406                 :            :         BUILD_BUG_ON(FAN_DELETE_SELF != FS_DELETE_SELF);
     407                 :            :         BUILD_BUG_ON(FAN_MOVE_SELF != FS_MOVE_SELF);
     408                 :            :         BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD);
     409                 :            :         BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
     410                 :            :         BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
     411                 :            :         BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
     412                 :            :         BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR);
     413                 :            :         BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
     414                 :            :         BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
     415                 :            : 
     416                 :            :         BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19);
     417                 :            : 
     418                 :          0 :         mask = fanotify_group_event_mask(group, iter_info, mask, data,
     419                 :            :                                          data_type);
     420         [ #  # ]:          0 :         if (!mask)
     421                 :            :                 return 0;
     422                 :            : 
     423                 :            :         pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,
     424                 :            :                  mask);
     425                 :            : 
     426                 :            :         if (fanotify_is_perm_event(mask)) {
     427                 :            :                 /*
     428                 :            :                  * fsnotify_prepare_user_wait() fails if we race with mark
     429                 :            :                  * deletion.  Just let the operation pass in that case.
     430                 :            :                  */
     431                 :            :                 if (!fsnotify_prepare_user_wait(iter_info))
     432                 :            :                         return 0;
     433                 :            :         }
     434                 :            : 
     435         [ #  # ]:          0 :         if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
     436                 :          0 :                 fsid = fanotify_get_fsid(iter_info);
     437                 :            :                 /* Racing with mark destruction or creation? */
     438   [ #  #  #  # ]:          0 :                 if (!fsid.val[0] && !fsid.val[1])
     439                 :            :                         return 0;
     440                 :            :         }
     441                 :            : 
     442                 :          0 :         event = fanotify_alloc_event(group, inode, mask, data, data_type,
     443                 :            :                                      &fsid);
     444                 :            :         ret = -ENOMEM;
     445         [ #  # ]:          0 :         if (unlikely(!event)) {
     446                 :            :                 /*
     447                 :            :                  * We don't queue overflow events for permission events as
     448                 :            :                  * there the access is denied and so no event is in fact lost.
     449                 :            :                  */
     450                 :            :                 if (!fanotify_is_perm_event(mask))
     451                 :            :                         fsnotify_queue_overflow(group);
     452                 :            :                 goto finish;
     453                 :            :         }
     454                 :            : 
     455                 :          0 :         fsn_event = &event->fse;
     456                 :          0 :         ret = fsnotify_add_event(group, fsn_event, fanotify_merge);
     457         [ #  # ]:          0 :         if (ret) {
     458                 :            :                 /* Permission events shouldn't be merged */
     459   [ #  #  #  # ]:          0 :                 BUG_ON(ret == 1 && mask & FANOTIFY_PERM_EVENTS);
     460                 :            :                 /* Our event wasn't used in the end. Free it. */
     461                 :          0 :                 fsnotify_destroy_event(group, fsn_event);
     462                 :            : 
     463                 :            :                 ret = 0;
     464                 :            :         } else if (fanotify_is_perm_event(mask)) {
     465                 :            :                 ret = fanotify_get_response(group, FANOTIFY_PE(fsn_event),
     466                 :            :                                             iter_info);
     467                 :            :         }
     468                 :            : finish:
     469                 :            :         if (fanotify_is_perm_event(mask))
     470                 :            :                 fsnotify_finish_user_wait(iter_info);
     471                 :            : 
     472                 :          0 :         return ret;
     473                 :            : }
     474                 :            : 
     475                 :          0 : static void fanotify_free_group_priv(struct fsnotify_group *group)
     476                 :            : {
     477                 :            :         struct user_struct *user;
     478                 :            : 
     479                 :          0 :         user = group->fanotify_data.user;
     480                 :          0 :         atomic_dec(&user->fanotify_listeners);
     481                 :          0 :         free_uid(user);
     482                 :          0 : }
     483                 :            : 
     484                 :          0 : static void fanotify_free_event(struct fsnotify_event *fsn_event)
     485                 :            : {
     486                 :            :         struct fanotify_event *event;
     487                 :            : 
     488                 :            :         event = FANOTIFY_E(fsn_event);
     489         [ #  # ]:          0 :         if (fanotify_event_has_path(event))
     490                 :          0 :                 path_put(&event->path);
     491         [ #  # ]:          0 :         else if (fanotify_event_has_ext_fh(event))
     492                 :          0 :                 kfree(event->fid.ext_fh);
     493                 :          0 :         put_pid(event->pid);
     494                 :            :         if (fanotify_is_perm_event(event->mask)) {
     495                 :            :                 kmem_cache_free(fanotify_perm_event_cachep,
     496                 :            :                                 FANOTIFY_PE(fsn_event));
     497                 :          0 :                 return;
     498                 :            :         }
     499                 :          0 :         kmem_cache_free(fanotify_event_cachep, event);
     500                 :            : }
     501                 :            : 
     502                 :          0 : static void fanotify_free_mark(struct fsnotify_mark *fsn_mark)
     503                 :            : {
     504                 :          0 :         kmem_cache_free(fanotify_mark_cache, fsn_mark);
     505                 :          0 : }
     506                 :            : 
     507                 :            : const struct fsnotify_ops fanotify_fsnotify_ops = {
     508                 :            :         .handle_event = fanotify_handle_event,
     509                 :            :         .free_group_priv = fanotify_free_group_priv,
     510                 :            :         .free_event = fanotify_free_event,
     511                 :            :         .free_mark = fanotify_free_mark,
     512                 :            : };

Generated by: LCOV version 1.14