Blame view

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