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 | FS_EVENT_ON_CHILD)
  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 (void *)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_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        struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
 162        struct audit_fsnotify_mark *audit_mark;
 163        const struct inode *inode = NULL;
 164
 165        audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark);
 166
 167        BUG_ON(group != audit_fsnotify_group);
 168
 169        switch (data_type) {
 170        case (FSNOTIFY_EVENT_PATH):
 171                inode = ((const struct path *)data)->dentry->d_inode;
 172                break;
 173        case (FSNOTIFY_EVENT_INODE):
 174                inode = (const struct inode *)data;
 175                break;
 176        default:
 177                BUG();
 178                return 0;
 179        }
 180
 181        if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) {
 182                if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL))
 183                        return 0;
 184                audit_update_mark(audit_mark, inode);
 185        } else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
 186                audit_autoremove_mark_rule(audit_mark);
 187
 188        return 0;
 189}
 190
 191static const struct fsnotify_ops audit_mark_fsnotify_ops = {
 192        .handle_event = audit_mark_handle_event,
 193        .free_mark = audit_fsnotify_free_mark,
 194};
 195
 196static int __init audit_fsnotify_init(void)
 197{
 198        audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops);
 199        if (IS_ERR(audit_fsnotify_group)) {
 200                audit_fsnotify_group = NULL;
 201                audit_panic("cannot create audit fsnotify group");
 202        }
 203        return 0;
 204}
 205device_initcall(audit_fsnotify_init);
 206