summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Grubb <sgrubb@redhat.com>2017-10-02 20:21:39 -0400
committerJan Kara <jack@suse.cz>2017-10-10 07:18:06 -0400
commitde8cd83e91bc3ee212b3e6ec6e4283af9e4ab269 (patch)
tree06e8053d973743baf71afe8e347fc91df7b05c13
parent8a5776a5f49812d29fe4b2d0a2d71675c3facf3f (diff)
audit: Record fanotify access control decisions
The fanotify interface allows user space daemons to make access control decisions. Under common criteria requirements, we need to optionally record decisions based on policy. This patch adds a bit mask, FAN_AUDIT, that a user space daemon can 'or' into the response decision which will tell the kernel that it made a decision and record it. It would be used something like this in user space code: response.response = FAN_DENY | FAN_AUDIT; write(fd, &response, sizeof(struct fanotify_response)); When the syscall ends, the audit system will record the decision as a AUDIT_FANOTIFY auxiliary record to denote that the reason this event occurred is the result of an access control decision from fanotify rather than DAC or MAC policy. A sample event looks like this: type=PATH msg=audit(1504310584.332:290): item=0 name="./evil-ls" inode=1319561 dev=fc:03 mode=0100755 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_t:s0 nametype=NORMAL type=CWD msg=audit(1504310584.332:290): cwd="/home/sgrubb" type=SYSCALL msg=audit(1504310584.332:290): arch=c000003e syscall=2 success=no exit=-1 a0=32cb3fca90 a1=0 a2=43 a3=8 items=1 ppid=901 pid=959 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts1 ses=3 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t: s0-s0:c0.c1023 key=(null) type=FANOTIFY msg=audit(1504310584.332:290): resp=2 Prior to using the audit flag, the developer needs to call fanotify_init or'ing in FAN_ENABLE_AUDIT to ensure that the kernel supports auditing. The calling process must also have the CAP_AUDIT_WRITE capability. Signed-off-by: sgrubb <sgrubb@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/notify/fanotify/fanotify.c8
-rw-r--r--fs/notify/fanotify/fanotify_user.c16
-rw-r--r--fs/notify/fdinfo.c3
-rw-r--r--include/linux/audit.h10
-rw-r--r--include/linux/fsnotify_backend.h1
-rw-r--r--include/uapi/linux/audit.h1
-rw-r--r--include/uapi/linux/fanotify.h3
-rw-r--r--kernel/auditsc.c6
8 files changed, 46 insertions, 2 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 2fa99aeaa095..1968d21a3f37 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -9,6 +9,7 @@
9#include <linux/sched/user.h> 9#include <linux/sched/user.h>
10#include <linux/types.h> 10#include <linux/types.h>
11#include <linux/wait.h> 11#include <linux/wait.h>
12#include <linux/audit.h>
12 13
13#include "fanotify.h" 14#include "fanotify.h"
14 15
@@ -78,7 +79,7 @@ static int fanotify_get_response(struct fsnotify_group *group,
78 fsnotify_finish_user_wait(iter_info); 79 fsnotify_finish_user_wait(iter_info);
79out: 80out:
80 /* userspace responded, convert to something usable */ 81 /* userspace responded, convert to something usable */
81 switch (event->response) { 82 switch (event->response & ~FAN_AUDIT) {
82 case FAN_ALLOW: 83 case FAN_ALLOW:
83 ret = 0; 84 ret = 0;
84 break; 85 break;
@@ -86,6 +87,11 @@ out:
86 default: 87 default:
87 ret = -EPERM; 88 ret = -EPERM;
88 } 89 }
90
91 /* Check if the response should be audited */
92 if (event->response & FAN_AUDIT)
93 audit_fanotify(event->response & ~FAN_AUDIT);
94
89 event->response = 0; 95 event->response = 0;
90 96
91 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__, 97 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 907a481ac781..0455ea729384 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -179,7 +179,7 @@ static int process_access_response(struct fsnotify_group *group,
179 * userspace can send a valid response or we will clean it up after the 179 * userspace can send a valid response or we will clean it up after the
180 * timeout 180 * timeout
181 */ 181 */
182 switch (response) { 182 switch (response & ~FAN_AUDIT) {
183 case FAN_ALLOW: 183 case FAN_ALLOW:
184 case FAN_DENY: 184 case FAN_DENY:
185 break; 185 break;
@@ -190,6 +190,9 @@ static int process_access_response(struct fsnotify_group *group,
190 if (fd < 0) 190 if (fd < 0)
191 return -EINVAL; 191 return -EINVAL;
192 192
193 if ((response & FAN_AUDIT) && !group->fanotify_data.audit)
194 return -EINVAL;
195
193 event = dequeue_event(group, fd); 196 event = dequeue_event(group, fd);
194 if (!event) 197 if (!event)
195 return -ENOENT; 198 return -ENOENT;
@@ -721,7 +724,11 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
721 if (!capable(CAP_SYS_ADMIN)) 724 if (!capable(CAP_SYS_ADMIN))
722 return -EPERM; 725 return -EPERM;
723 726
727#ifdef CONFIG_AUDITSYSCALL
728 if (flags & ~(FAN_ALL_INIT_FLAGS | FAN_ENABLE_AUDIT))
729#else
724 if (flags & ~FAN_ALL_INIT_FLAGS) 730 if (flags & ~FAN_ALL_INIT_FLAGS)
731#endif
725 return -EINVAL; 732 return -EINVAL;
726 733
727 if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS) 734 if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS)
@@ -805,6 +812,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
805 group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS; 812 group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS;
806 } 813 }
807 814
815 if (flags & FAN_ENABLE_AUDIT) {
816 fd = -EPERM;
817 if (!capable(CAP_AUDIT_WRITE))
818 goto out_destroy_group;
819 group->fanotify_data.audit = true;
820 }
821
808 fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); 822 fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
809 if (fd < 0) 823 if (fd < 0)
810 goto out_destroy_group; 824 goto out_destroy_group;
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c
index dd63aa9a6f9a..645ab561e790 100644
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -156,6 +156,9 @@ void fanotify_show_fdinfo(struct seq_file *m, struct file *f)
156 if (group->fanotify_data.max_marks == UINT_MAX) 156 if (group->fanotify_data.max_marks == UINT_MAX)
157 flags |= FAN_UNLIMITED_MARKS; 157 flags |= FAN_UNLIMITED_MARKS;
158 158
159 if (group->fanotify_data.audit)
160 flags |= FAN_ENABLE_AUDIT;
161
159 seq_printf(m, "fanotify flags:%x event-flags:%x\n", 162 seq_printf(m, "fanotify flags:%x event-flags:%x\n",
160 flags, group->fanotify_data.f_flags); 163 flags, group->fanotify_data.f_flags);
161 164
diff --git a/include/linux/audit.h b/include/linux/audit.h
index cb708eb8accc..d66220dac364 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -356,6 +356,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
356extern void __audit_log_capset(const struct cred *new, const struct cred *old); 356extern void __audit_log_capset(const struct cred *new, const struct cred *old);
357extern void __audit_mmap_fd(int fd, int flags); 357extern void __audit_mmap_fd(int fd, int flags);
358extern void __audit_log_kern_module(char *name); 358extern void __audit_log_kern_module(char *name);
359extern void __audit_fanotify(unsigned int response);
359 360
360static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) 361static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
361{ 362{
@@ -452,6 +453,12 @@ static inline void audit_log_kern_module(char *name)
452 __audit_log_kern_module(name); 453 __audit_log_kern_module(name);
453} 454}
454 455
456static inline void audit_fanotify(unsigned int response)
457{
458 if (!audit_dummy_context())
459 __audit_fanotify(response);
460}
461
455extern int audit_n_rules; 462extern int audit_n_rules;
456extern int audit_signals; 463extern int audit_signals;
457#else /* CONFIG_AUDITSYSCALL */ 464#else /* CONFIG_AUDITSYSCALL */
@@ -568,6 +575,9 @@ static inline void audit_log_kern_module(char *name)
568{ 575{
569} 576}
570 577
578static inline void audit_fanotify(unsigned int response)
579{ }
580
571static inline void audit_ptrace(struct task_struct *t) 581static inline void audit_ptrace(struct task_struct *t)
572{ } 582{ }
573#define audit_n_rules 0 583#define audit_n_rules 0
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index c6c69318752b..4a474f972910 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -190,6 +190,7 @@ struct fsnotify_group {
190 int f_flags; 190 int f_flags;
191 unsigned int max_marks; 191 unsigned int max_marks;
192 struct user_struct *user; 192 struct user_struct *user;
193 bool audit;
193 } fanotify_data; 194 } fanotify_data;
194#endif /* CONFIG_FANOTIFY */ 195#endif /* CONFIG_FANOTIFY */
195 }; 196 };
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 0714a66f0e0c..221f8b7f01b2 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -112,6 +112,7 @@
112#define AUDIT_FEATURE_CHANGE 1328 /* audit log listing feature changes */ 112#define AUDIT_FEATURE_CHANGE 1328 /* audit log listing feature changes */
113#define AUDIT_REPLACE 1329 /* Replace auditd if this packet unanswerd */ 113#define AUDIT_REPLACE 1329 /* Replace auditd if this packet unanswerd */
114#define AUDIT_KERN_MODULE 1330 /* Kernel Module events */ 114#define AUDIT_KERN_MODULE 1330 /* Kernel Module events */
115#define AUDIT_FANOTIFY 1331 /* Fanotify access decision */
115 116
116#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ 117#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
117#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ 118#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h
index 030508d195d3..5dda19a9a947 100644
--- a/include/uapi/linux/fanotify.h
+++ b/include/uapi/linux/fanotify.h
@@ -35,6 +35,7 @@
35 35
36#define FAN_UNLIMITED_QUEUE 0x00000010 36#define FAN_UNLIMITED_QUEUE 0x00000010
37#define FAN_UNLIMITED_MARKS 0x00000020 37#define FAN_UNLIMITED_MARKS 0x00000020
38#define FAN_ENABLE_AUDIT 0x00000040
38 39
39#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ 40#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \
40 FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\ 41 FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\
@@ -99,6 +100,8 @@ struct fanotify_response {
99/* Legit userspace responses to a _PERM event */ 100/* Legit userspace responses to a _PERM event */
100#define FAN_ALLOW 0x01 101#define FAN_ALLOW 0x01
101#define FAN_DENY 0x02 102#define FAN_DENY 0x02
103#define FAN_AUDIT 0x10 /* Bit mask to create audit record for result */
104
102/* No fd set in event */ 105/* No fd set in event */
103#define FAN_NOFD -1 106#define FAN_NOFD -1
104 107
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ecc23e25c9eb..9c723e978245 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2390,6 +2390,12 @@ void __audit_log_kern_module(char *name)
2390 context->type = AUDIT_KERN_MODULE; 2390 context->type = AUDIT_KERN_MODULE;
2391} 2391}
2392 2392
2393void __audit_fanotify(unsigned int response)
2394{
2395 audit_log(current->audit_context, GFP_KERNEL,
2396 AUDIT_FANOTIFY, "resp=%u", response);
2397}
2398
2393static void audit_log_task(struct audit_buffer *ab) 2399static void audit_log_task(struct audit_buffer *ab)
2394{ 2400{
2395 kuid_t auid, uid; 2401 kuid_t auid, uid;