cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

audit_fsnotify.c (5351B)


      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, 0);
    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		return 0;
    165
    166	if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) {
    167		if (audit_compare_dname_path(dname, audit_mark->path, AUDIT_NAME_FULL))
    168			return 0;
    169		audit_update_mark(audit_mark, inode);
    170	} else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF)) {
    171		audit_autoremove_mark_rule(audit_mark);
    172	}
    173
    174	return 0;
    175}
    176
    177static const struct fsnotify_ops audit_mark_fsnotify_ops = {
    178	.handle_inode_event = audit_mark_handle_event,
    179	.free_mark = audit_fsnotify_free_mark,
    180};
    181
    182static int __init audit_fsnotify_init(void)
    183{
    184	audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops,
    185						    FSNOTIFY_GROUP_DUPS);
    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);