LCOV - code coverage report
Current view: top level - kernel - audit_fsnotify.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 4 82 4.9 %
Date: 2022-04-01 14:58:12 Functions: 1 9 11.1 %
Branches: 1 39 2.6 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /* audit_fsnotify.c -- tracking inodes
       3                 :            :  *
       4                 :            :  * Copyright 2003-2009,2014-2015 Red Hat, Inc.
       5                 :            :  * Copyright 2005 Hewlett-Packard Development Company, L.P.
       6                 :            :  * Copyright 2005 IBM Corporation
       7                 :            :  */
       8                 :            : 
       9                 :            : #include <linux/kernel.h>
      10                 :            : #include <linux/audit.h>
      11                 :            : #include <linux/kthread.h>
      12                 :            : #include <linux/mutex.h>
      13                 :            : #include <linux/fs.h>
      14                 :            : #include <linux/fsnotify_backend.h>
      15                 :            : #include <linux/namei.h>
      16                 :            : #include <linux/netlink.h>
      17                 :            : #include <linux/sched.h>
      18                 :            : #include <linux/slab.h>
      19                 :            : #include <linux/security.h>
      20                 :            : #include "audit.h"
      21                 :            : 
      22                 :            : /*
      23                 :            :  * this mark lives on the parent directory of the inode in question.
      24                 :            :  * but dev, ino, and path are about the child
      25                 :            :  */
      26                 :            : struct audit_fsnotify_mark {
      27                 :            :         dev_t dev;              /* associated superblock device */
      28                 :            :         unsigned long ino;      /* associated inode number */
      29                 :            :         char *path;             /* insertion path */
      30                 :            :         struct fsnotify_mark mark; /* fsnotify mark on the inode */
      31                 :            :         struct audit_krule *rule;
      32                 :            : };
      33                 :            : 
      34                 :            : /* fsnotify handle. */
      35                 :            : static struct fsnotify_group *audit_fsnotify_group;
      36                 :            : 
      37                 :            : /* fsnotify events we care about. */
      38                 :            : #define AUDIT_FS_EVENTS (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
      39                 :            :                          FS_MOVE_SELF | FS_EVENT_ON_CHILD)
      40                 :            : 
      41                 :          0 : static void audit_fsnotify_mark_free(struct audit_fsnotify_mark *audit_mark)
      42                 :            : {
      43                 :          0 :         kfree(audit_mark->path);
      44                 :          0 :         kfree(audit_mark);
      45                 :            : }
      46                 :            : 
      47                 :          0 : static void audit_fsnotify_free_mark(struct fsnotify_mark *mark)
      48                 :            : {
      49                 :          0 :         struct audit_fsnotify_mark *audit_mark;
      50                 :            : 
      51                 :          0 :         audit_mark = container_of(mark, struct audit_fsnotify_mark, mark);
      52                 :          0 :         audit_fsnotify_mark_free(audit_mark);
      53                 :          0 : }
      54                 :            : 
      55                 :          0 : char *audit_mark_path(struct audit_fsnotify_mark *mark)
      56                 :            : {
      57                 :          0 :         return mark->path;
      58                 :            : }
      59                 :            : 
      60                 :          0 : int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev)
      61                 :            : {
      62         [ #  # ]:          0 :         if (mark->ino == AUDIT_INO_UNSET)
      63                 :            :                 return 0;
      64   [ #  #  #  # ]:          0 :         return (mark->ino == ino) && (mark->dev == dev);
      65                 :            : }
      66                 :            : 
      67                 :          0 : static void audit_update_mark(struct audit_fsnotify_mark *audit_mark,
      68                 :            :                              const struct inode *inode)
      69                 :            : {
      70                 :          0 :         audit_mark->dev = inode ? inode->i_sb->s_dev : AUDIT_DEV_UNSET;
      71   [ #  #  #  # ]:          0 :         audit_mark->ino = inode ? inode->i_ino : AUDIT_INO_UNSET;
      72                 :          0 : }
      73                 :            : 
      74                 :          0 : struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len)
      75                 :            : {
      76                 :          0 :         struct audit_fsnotify_mark *audit_mark;
      77                 :          0 :         struct path path;
      78                 :          0 :         struct dentry *dentry;
      79                 :          0 :         struct inode *inode;
      80                 :          0 :         int ret;
      81                 :            : 
      82   [ #  #  #  # ]:          0 :         if (pathname[0] != '/' || pathname[len-1] == '/')
      83                 :            :                 return ERR_PTR(-EINVAL);
      84                 :            : 
      85                 :          0 :         dentry = kern_path_locked(pathname, &path);
      86         [ #  # ]:          0 :         if (IS_ERR(dentry))
      87                 :            :                 return (void *)dentry; /* returning an error */
      88                 :          0 :         inode = path.dentry->d_inode;
      89                 :          0 :         inode_unlock(inode);
      90                 :            : 
      91                 :          0 :         audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
      92         [ #  # ]:          0 :         if (unlikely(!audit_mark)) {
      93                 :          0 :                 audit_mark = ERR_PTR(-ENOMEM);
      94                 :          0 :                 goto out;
      95                 :            :         }
      96                 :            : 
      97                 :          0 :         fsnotify_init_mark(&audit_mark->mark, audit_fsnotify_group);
      98                 :          0 :         audit_mark->mark.mask = AUDIT_FS_EVENTS;
      99                 :          0 :         audit_mark->path = pathname;
     100         [ #  # ]:          0 :         audit_update_mark(audit_mark, dentry->d_inode);
     101                 :          0 :         audit_mark->rule = krule;
     102                 :            : 
     103                 :          0 :         ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, true);
     104         [ #  # ]:          0 :         if (ret < 0) {
     105                 :          0 :                 fsnotify_put_mark(&audit_mark->mark);
     106                 :          0 :                 audit_mark = ERR_PTR(ret);
     107                 :            :         }
     108                 :          0 : out:
     109                 :          0 :         dput(dentry);
     110                 :          0 :         path_put(&path);
     111                 :          0 :         return audit_mark;
     112                 :            : }
     113                 :            : 
     114                 :            : static void audit_mark_log_rule_change(struct audit_fsnotify_mark *audit_mark, char *op)
     115                 :            : {
     116                 :            :         struct audit_buffer *ab;
     117                 :            :         struct audit_krule *rule = audit_mark->rule;
     118                 :            : 
     119                 :            :         if (!audit_enabled)
     120                 :            :                 return;
     121                 :            :         ab = audit_log_start(audit_context(), GFP_NOFS, AUDIT_CONFIG_CHANGE);
     122                 :            :         if (unlikely(!ab))
     123                 :            :                 return;
     124                 :            :         audit_log_session_info(ab);
     125                 :            :         audit_log_format(ab, " op=%s path=", op);
     126                 :            :         audit_log_untrustedstring(ab, audit_mark->path);
     127                 :            :         audit_log_key(ab, rule->filterkey);
     128                 :            :         audit_log_format(ab, " list=%d res=1", rule->listnr);
     129                 :            :         audit_log_end(ab);
     130                 :            : }
     131                 :            : 
     132                 :          0 : void audit_remove_mark(struct audit_fsnotify_mark *audit_mark)
     133                 :            : {
     134                 :          0 :         fsnotify_destroy_mark(&audit_mark->mark, audit_fsnotify_group);
     135                 :          0 :         fsnotify_put_mark(&audit_mark->mark);
     136                 :          0 : }
     137                 :            : 
     138                 :          0 : void audit_remove_mark_rule(struct audit_krule *krule)
     139                 :            : {
     140                 :          0 :         struct audit_fsnotify_mark *mark = krule->exe;
     141                 :            : 
     142                 :          0 :         audit_remove_mark(mark);
     143                 :          0 : }
     144                 :            : 
     145                 :          0 : static void audit_autoremove_mark_rule(struct audit_fsnotify_mark *audit_mark)
     146                 :            : {
     147                 :          0 :         struct audit_krule *rule = audit_mark->rule;
     148                 :          0 :         struct audit_entry *entry = container_of(rule, struct audit_entry, rule);
     149                 :            : 
     150                 :          0 :         audit_mark_log_rule_change(audit_mark, "autoremove_rule");
     151                 :          0 :         audit_del_rule(entry);
     152                 :          0 : }
     153                 :            : 
     154                 :            : /* Update mark data in audit rules based on fsnotify events. */
     155                 :          0 : static int audit_mark_handle_event(struct fsnotify_group *group,
     156                 :            :                                     struct inode *to_tell,
     157                 :            :                                     u32 mask, const void *data, int data_type,
     158                 :            :                                     const struct qstr *dname, u32 cookie,
     159                 :            :                                     struct fsnotify_iter_info *iter_info)
     160                 :            : {
     161         [ #  # ]:          0 :         struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
     162                 :          0 :         struct audit_fsnotify_mark *audit_mark;
     163                 :          0 :         const struct inode *inode = NULL;
     164                 :            : 
     165                 :          0 :         audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark);
     166                 :            : 
     167         [ #  # ]:          0 :         BUG_ON(group != audit_fsnotify_group);
     168                 :            : 
     169      [ #  #  # ]:          0 :         switch (data_type) {
     170                 :          0 :         case (FSNOTIFY_EVENT_PATH):
     171                 :          0 :                 inode = ((const struct path *)data)->dentry->d_inode;
     172                 :          0 :                 break;
     173                 :            :         case (FSNOTIFY_EVENT_INODE):
     174                 :            :                 inode = (const struct inode *)data;
     175                 :            :                 break;
     176                 :          0 :         default:
     177                 :          0 :                 BUG();
     178                 :            :                 return 0;
     179                 :            :         }
     180                 :            : 
     181         [ #  # ]:          0 :         if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) {
     182         [ #  # ]:          0 :                 if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL))
     183                 :            :                         return 0;
     184         [ #  # ]:          0 :                 audit_update_mark(audit_mark, inode);
     185         [ #  # ]:          0 :         } else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
     186                 :          0 :                 audit_autoremove_mark_rule(audit_mark);
     187                 :            : 
     188                 :            :         return 0;
     189                 :            : }
     190                 :            : 
     191                 :            : static const struct fsnotify_ops audit_mark_fsnotify_ops = {
     192                 :            :         .handle_event = audit_mark_handle_event,
     193                 :            :         .free_mark = audit_fsnotify_free_mark,
     194                 :            : };
     195                 :            : 
     196                 :          3 : static int __init audit_fsnotify_init(void)
     197                 :            : {
     198                 :          3 :         audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops);
     199         [ -  + ]:          3 :         if (IS_ERR(audit_fsnotify_group)) {
     200                 :          0 :                 audit_fsnotify_group = NULL;
     201                 :          0 :                 audit_panic("cannot create audit fsnotify group");
     202                 :            :         }
     203                 :          3 :         return 0;
     204                 :            : }
     205                 :            : device_initcall(audit_fsnotify_init);

Generated by: LCOV version 1.14