linux/kernel/audit_fsnotify.c
<<
>>
Prefs
   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 */
  26struct 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. */
  35static 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)
  40
  41static void audit_fsnotify_mark_free(struct audit_fsnotify_mark *audit_mark)
  42{
  43        kfree(audit_mark->path);
  44        kfree(audit_mark);
  45}
  46
  47static void audit_fsnotify_free_mark(struct fsnotify_mark *mark)
  48{
  49        struct audit_fsnotify_mark *audit_mark;
  50
  51        audit_mark = container_of(mark, struct audit_fsnotify_mark, mark);
  52        audit_fsnotify_mark_free(audit_mark);
  53}
  54
  55char *audit_mark_path(struct audit_fsnotify_mark *mark)
  56{
  57        return mark->path;
  58}
  59
  60int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev)
  61{
  62        if (mark->ino == AUDIT_INO_UNSET)
  63                return 0;
  64        return (mark->ino == ino) && (mark->dev == dev);
  65}
  66
  67static void audit_update_mark(struct audit_fsnotify_mark *audit_mark,
  68                             const struct inode *inode)
  69{
  70        audit_mark->dev = inode ? inode->i_sb->s_dev : AUDIT_DEV_UNSET;
  71        audit_mark->ino = inode ? inode->i_ino : AUDIT_INO_UNSET;
  72}
  73
  74struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len)
  75{
  76        struct audit_fsnotify_mark *audit_mark;
  77        struct path path;
  78        struct dentry *dentry;
  79        struct inode *inode;
  80        int ret;
  81
  82        if (pathname[0] != '/' || pathname[len-1] == '/')
  83                return ERR_PTR(-EINVAL);
  84
  85        dentry = kern_path_locked(pathname, &path);
  86        if (IS_ERR(dentry))
  87                return ERR_CAST(dentry); /* returning an error */
  88        inode = path.dentry->d_inode;
  89        inode_unlock(inode);
  90
  91        audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
  92        if (unlikely(!audit_mark)) {
  93                audit_mark = ERR_PTR(-ENOMEM);
  94                goto out;
  95        }
  96
  97        fsnotify_init_mark(&audit_mark->mark, audit_fsnotify_group);
  98        audit_mark->mark.mask = AUDIT_FS_EVENTS;
  99        audit_mark->path = pathname;
 100        audit_update_mark(audit_mark, dentry->d_inode);
 101        audit_mark->rule = krule;
 102
 103        ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, true);
 104        if (ret < 0) {
 105                fsnotify_put_mark(&audit_mark->mark);
 106                audit_mark = ERR_PTR(ret);
 107        }
 108out:
 109        dput(dentry);
 110        path_put(&path);
 111        return audit_mark;
 112}
 113
 114static 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
 132void audit_remove_mark(struct audit_fsnotify_mark *audit_mark)
 133{
 134        fsnotify_destroy_mark(&audit_mark->mark, audit_fsnotify_group);
 135        fsnotify_put_mark(&audit_mark->mark);
 136}
 137
 138void audit_remove_mark_rule(struct audit_krule *krule)
 139{
 140        struct audit_fsnotify_mark *mark = krule->exe;
 141
 142        audit_remove_mark(mark);
 143}
 144
 145static void audit_autoremove_mark_rule(struct audit_fsnotify_mark *audit_mark)
 146{
 147        struct audit_krule *rule = audit_mark->rule;
 148        struct audit_entry *entry = container_of(rule, struct audit_entry, rule);
 149
 150        audit_mark_log_rule_change(audit_mark, "autoremove_rule");
 151        audit_del_rule(entry);
 152}
 153
 154/* Update mark data in audit rules based on fsnotify events. */
 155static int audit_mark_handle_event(struct fsnotify_mark *inode_mark, u32 mask,
 156                                   struct inode *inode, struct inode *dir,
 157                                   const struct qstr *dname, u32 cookie)
 158{
 159        struct audit_fsnotify_mark *audit_mark;
 160
 161        audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark);
 162
 163        if (WARN_ON_ONCE(inode_mark->group != audit_fsnotify_group) ||
 164            WARN_ON_ONCE(!inode))
 165                return 0;
 166
 167        if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) {
 168                if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL))
 169                        return 0;
 170                audit_update_mark(audit_mark, inode);
 171        } else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF)) {
 172                audit_autoremove_mark_rule(audit_mark);
 173        }
 174
 175        return 0;
 176}
 177
 178static const struct fsnotify_ops audit_mark_fsnotify_ops = {
 179        .handle_inode_event = audit_mark_handle_event,
 180        .free_mark = audit_fsnotify_free_mark,
 181};
 182
 183static int __init audit_fsnotify_init(void)
 184{
 185        audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops);
 186        if (IS_ERR(audit_fsnotify_group)) {
 187                audit_fsnotify_group = NULL;
 188                audit_panic("cannot create audit fsnotify group");
 189        }
 190        return 0;
 191}
 192device_initcall(audit_fsnotify_init);
 193