History

Merge tag 'fsnotify_for_v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull fsnotify updates from Jan Kara: "Support for auditing decisions regarding fanotify permission events" * tag 'fsnotify_for_v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fanotify,audit: Allow audit to use the full permission event response fanotify: define struct members to hold response decision context fanotify: Ensure consistent variable type for response

Linus Torvalds committed 3 years ago

Commit cd776a42 parents 6639c3c 032bffd7 files · +131 −33Browse files

Unified · Split

7 files
  1. fs/notify/fanotify/fanotify.c +6 −2
  2. fs/notify/fanotify/fanotify.h +5 −1
  3. fs/notify/fanotify/fanotify_user.c +66 −22
  4. include/linux/audit.h +5 −4
  5. include/linux/fanotify.h +5 −0
  6. include/uapi/linux/fanotify.h +29 −1
  7. kernel/auditsc.c +15 −3
fs/notify/fanotify/fanotify.c+6−2
@@ -262,7 +262,7 @@ static int fanotify_get_response(struct fsnotify_group *group, · 261 unmodified lines
262262 }
263263
264264 /* userspace responded, convert to something usable */
265− switch (event->response & ~FAN_AUDIT) {
265+ switch (event->response & FANOTIFY_RESPONSE_ACCESS) {
266266 case FAN_ALLOW:
267267 ret = 0;
268268 break;
@@ -273,7 +273,8 @@ static int fanotify_get_response(struct fsnotify_group *group, · 4 unmodified lines
273273
274274 /* Check if the response should be audited */
275275 if (event->response & FAN_AUDIT)
276− audit_fanotify(event->response & ~FAN_AUDIT);
276+ audit_fanotify(event->response & ~FAN_AUDIT,
277+ &event->audit_rule);
277278
278279 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
279280 group, event, ret);
@@ -563,6 +564,9 @@ static struct fanotify_event *fanotify_alloc_perm_event(const struct path *path, · 283 unmodified lines
563564
564565 pevent->fae.type = FANOTIFY_EVENT_TYPE_PATH_PERM;
565566 pevent->response = 0;
567+ pevent->hdr.type = FAN_RESPONSE_INFO_NONE;
568+ pevent->hdr.pad = 0;
569+ pevent->hdr.len = 0;
566570 pevent->state = FAN_EVENT_INIT;
567571 pevent->path = *path;
568572 path_get(path);
fs/notify/fanotify/fanotify.h+5−1
@@ -425,9 +425,13 @@ FANOTIFY_PE(struct fanotify_event *event) · 424 unmodified lines
425425 struct fanotify_perm_event {
426426 struct fanotify_event fae;
427427 struct path path;
428− unsigned short response; /* userspace answer to the event */
428+ u32 response; /* userspace answer to the event */
429429 unsigned short state; /* state of the event */
430430 int fd; /* fd we passed to userspace for this event */
431+ union {
432+ struct fanotify_response_info_header hdr;
433+ struct fanotify_response_info_audit_rule audit_rule;
434+ };
431435 };
432436
433437 static inline struct fanotify_perm_event *
fs/notify/fanotify/fanotify_user.c+66−22
@@ -283,19 +283,42 @@ static int create_fd(struct fsnotify_group *group, const struct path *path, · 282 unmodified lines
283283 return client_fd;
284284 }
285285
286+static int process_access_response_info(const char __user *info,
287+ size_t info_len,
288+ struct fanotify_response_info_audit_rule *friar)
289+{
290+ if (info_len != sizeof(*friar))
291+ return -EINVAL;
292+
293+ if (copy_from_user(friar, info, sizeof(*friar)))
294+ return -EFAULT;
295+
296+ if (friar->hdr.type != FAN_RESPONSE_INFO_AUDIT_RULE)
297+ return -EINVAL;
298+ if (friar->hdr.pad != 0)
299+ return -EINVAL;
300+ if (friar->hdr.len != sizeof(*friar))
301+ return -EINVAL;
302+
303+ return info_len;
304+}
305+
286306 /*
287307 * Finish processing of permission event by setting it to ANSWERED state and
288308 * drop group->notification_lock.
289309 */
290310 static void finish_permission_event(struct fsnotify_group *group,
291− struct fanotify_perm_event *event,
292− unsigned int response)
311+ struct fanotify_perm_event *event, u32 response,
312+ struct fanotify_response_info_audit_rule *friar)
293313 __releases(&group->notification_lock)
294314 {
295315 bool destroy = false;
296316
297317 assert_spin_locked(&group->notification_lock);
298− event->response = response;
318+ event->response = response & ~FAN_INFO;
319+ if (response & FAN_INFO)
320+ memcpy(&event->audit_rule, friar, sizeof(*friar));
321+
299322 if (event->state == FAN_EVENT_CANCELED)
300323 destroy = true;
301324 else
@@ -306,20 +329,27 @@ static void finish_permission_event(struct fsnotify_group *group, · 4 unmodified lines
306329 }
307330
308331 static int process_access_response(struct fsnotify_group *group,
309− struct fanotify_response *response_struct)
332+ struct fanotify_response *response_struct,
333+ const char __user *info,
334+ size_t info_len)
310335 {
311336 struct fanotify_perm_event *event;
312337 int fd = response_struct->fd;
313− int response = response_struct->response;
338+ u32 response = response_struct->response;
339+ int ret = info_len;
340+ struct fanotify_response_info_audit_rule friar;
314341
315− pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
316− fd, response);
342+ pr_debug("%s: group=%p fd=%d response=%u buf=%p size=%zu\n", __func__,
343+ group, fd, response, info, info_len);
317344 /*
318345 * make sure the response is valid, if invalid we do nothing and either
319346 * userspace can send a valid response or we will clean it up after the
320347 * timeout
321348 */
322− switch (response & ~FAN_AUDIT) {
349+ if (response & ~FANOTIFY_RESPONSE_VALID_MASK)
350+ return -EINVAL;
351+
352+ switch (response & FANOTIFY_RESPONSE_ACCESS) {
323353 case FAN_ALLOW:
324354 case FAN_DENY:
325355 break;
@@ -327,10 +357,20 @@ static int process_access_response(struct fsnotify_group *group, · 1 unmodified line
327357 return -EINVAL;
328358 }
329359
330− if (fd < 0)
360+ if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
331361 return -EINVAL;
332362
333− if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
363+ if (response & FAN_INFO) {
364+ ret = process_access_response_info(info, info_len, &friar);
365+ if (ret < 0)
366+ return ret;
367+ if (fd == FAN_NOFD)
368+ return ret;
369+ } else {
370+ ret = 0;
371+ }
372+
373+ if (fd < 0)
334374 return -EINVAL;
335375
336376 spin_lock(&group->notification_lock);
@@ -340,9 +380,9 @@ static int process_access_response(struct fsnotify_group *group, · 3 unmodified lines
340380 continue;
341381
342382 list_del_init(&event->fae.fse.list);
343− finish_permission_event(group, event, response);
383+ finish_permission_event(group, event, response, &friar);
344384 wake_up(&group->fanotify_data.access_waitq);
345− return 0;
385+ return ret;
346386 }
347387 spin_unlock(&group->notification_lock);
348388
@@ -804,7 +844,7 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, · 455 unmodified lines
804844 if (ret <= 0) {
805845 spin_lock(&group->notification_lock);
806846 finish_permission_event(group,
807− FANOTIFY_PERM(event), FAN_DENY);
847+ FANOTIFY_PERM(event), FAN_DENY, NULL);
808848 wake_up(&group->fanotify_data.access_waitq);
809849 } else {
810850 spin_lock(&group->notification_lock);
@@ -827,28 +867,32 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, · 16 unmodified lines
827867
828868 static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
829869 {
830− struct fanotify_response response = { .fd = -1, .response = -1 };
870+ struct fanotify_response response;
831871 struct fsnotify_group *group;
832872 int ret;
873+ const char __user *info_buf = buf + sizeof(struct fanotify_response);
874+ size_t info_len;
833875
834876 if (!IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
835877 return -EINVAL;
836878
837879 group = file->private_data;
838880
881+ pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
882+
839883 if (count < sizeof(response))
840884 return -EINVAL;
841885
842− count = sizeof(response);
843−
844− pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
845−
846− if (copy_from_user(&response, buf, count))
886+ if (copy_from_user(&response, buf, sizeof(response)))
847887 return -EFAULT;
848888
849− ret = process_access_response(group, &response);
889+ info_len = count - sizeof(response);
890+
891+ ret = process_access_response(group, &response, info_buf, info_len);
850892 if (ret < 0)
851893 count = ret;
894+ else
895+ count = sizeof(response) + ret;
852896
853897 return count;
854898 }
@@ -876,7 +920,7 @@ static int fanotify_release(struct inode *ignored, struct file *file) · 21 unmodified lines
876920 event = list_first_entry(&group->fanotify_data.access_list,
877921 struct fanotify_perm_event, fae.fse.list);
878922 list_del_init(&event->fae.fse.list);
879− finish_permission_event(group, event, FAN_ALLOW);
923+ finish_permission_event(group, event, FAN_ALLOW, NULL);
880924 spin_lock(&group->notification_lock);
881925 }
882926
@@ -893,7 +937,7 @@ static int fanotify_release(struct inode *ignored, struct file *file) · 10 unmodified lines
893937 fsnotify_destroy_event(group, fsn_event);
894938 } else {
895939 finish_permission_event(group, FANOTIFY_PERM(event),
896− FAN_ALLOW);
940+ FAN_ALLOW, NULL);
897941 }
898942 spin_lock(&group->notification_lock);
899943 }
include/linux/audit.h+5−4
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <linux/audit_arch.h>
1515 #include <uapi/linux/audit.h>
1616 #include <uapi/linux/netfilter/nf_tables.h>
17+#include <uapi/linux/fanotify.h>
1718
1819 #define AUDIT_INO_UNSET ((unsigned long)-1)
1920 #define AUDIT_DEV_UNSET ((dev_t)-1)
@@ -416,7 +417,7 @@ extern void __audit_log_capset(const struct cred *new, const struct cred *old); · 396 unmodified lines
416417 extern void __audit_mmap_fd(int fd, int flags);
417418 extern void __audit_openat2_how(struct open_how *how);
418419 extern void __audit_log_kern_module(char *name);
419−extern void __audit_fanotify(unsigned int response);
420+extern void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar);
420421 extern void __audit_tk_injoffset(struct timespec64 offset);
421422 extern void __audit_ntp_log(const struct audit_ntp_data *ad);
422423 extern void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
@@ -523,10 +524,10 @@ static inline void audit_log_kern_module(char *name) · 100 unmodified lines
523524 __audit_log_kern_module(name);
524525 }
525526
526−static inline void audit_fanotify(unsigned int response)
527+static inline void audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
527528 {
528529 if (!audit_dummy_context())
529− __audit_fanotify(response);
530+ __audit_fanotify(response, friar);
530531 }
531532
532533 static inline void audit_tk_injoffset(struct timespec64 offset)
@@ -679,7 +680,7 @@ static inline void audit_log_kern_module(char *name) · 146 unmodified lines
679680 {
680681 }
681682
682−static inline void audit_fanotify(unsigned int response)
683+static inline void audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
683684 { }
684685
685686 static inline void audit_tk_injoffset(struct timespec64 offset)
include/linux/fanotify.h+5−0
@@ -122,6 +122,11 @@ · 121 unmodified lines
122122 #define ALL_FANOTIFY_EVENT_BITS (FANOTIFY_OUTGOING_EVENTS | \
123123 FANOTIFY_EVENT_FLAGS)
124124
125+/* These masks check for invalid bits in permission responses. */
126+#define FANOTIFY_RESPONSE_ACCESS (FAN_ALLOW | FAN_DENY)
127+#define FANOTIFY_RESPONSE_FLAGS (FAN_AUDIT | FAN_INFO)
128+#define FANOTIFY_RESPONSE_VALID_MASK (FANOTIFY_RESPONSE_ACCESS | FANOTIFY_RESPONSE_FLAGS)
129+
125130 /* Do not use these old uapi constants internally */
126131 #undef FAN_ALL_CLASS_BITS
127132 #undef FAN_ALL_INIT_FLAGS
include/uapi/linux/fanotify.h+29−1
@@ -188,15 +188,43 @@ struct fanotify_event_info_error { · 187 unmodified lines
188188 __u32 error_count;
189189 };
190190
191+/*
192+ * User space may need to record additional information about its decision.
193+ * The extra information type records what kind of information is included.
194+ * The default is none. We also define an extra information buffer whose
195+ * size is determined by the extra information type.
196+ *
197+ * If the information type is Audit Rule, then the information following
198+ * is the rule number that triggered the user space decision that
199+ * requires auditing.
200+ */
201+
202+#define FAN_RESPONSE_INFO_NONE 0
203+#define FAN_RESPONSE_INFO_AUDIT_RULE 1
204+
191205 struct fanotify_response {
192206 __s32 fd;
193207 __u32 response;
194208 };
195209
210+struct fanotify_response_info_header {
211+ __u8 type;
212+ __u8 pad;
213+ __u16 len;
214+};
215+
216+struct fanotify_response_info_audit_rule {
217+ struct fanotify_response_info_header hdr;
218+ __u32 rule_number;
219+ __u32 subj_trust;
220+ __u32 obj_trust;
221+};
222+
196223 /* Legit userspace responses to a _PERM event */
197224 #define FAN_ALLOW 0x01
198225 #define FAN_DENY 0x02
199−#define FAN_AUDIT 0x10 /* Bit mask to create audit record for result */
226+#define FAN_AUDIT 0x10 /* Bitmask to create audit record for result */
227+#define FAN_INFO 0x20 /* Bitmask to indicate additional information */
200228
201229 /* No fd set in event */
202230 #define FAN_NOFD -1
kernel/auditsc.c+15−3
@@ -64,6 +64,7 @@ · 63 unmodified lines
6464 #include <uapi/linux/limits.h>
6565 #include <uapi/linux/netfilter/nf_tables.h>
6666 #include <uapi/linux/openat2.h> // struct open_how
67+#include <uapi/linux/fanotify.h>
6768
6869 #include "audit.h"
6970
@@ -2877,10 +2878,21 @@ void __audit_log_kern_module(char *name) · 2807 unmodified lines
28772878 context->type = AUDIT_KERN_MODULE;
28782879 }
28792880
2880−void __audit_fanotify(unsigned int response)
2881+void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
28812882 {
2882− audit_log(audit_context(), GFP_KERNEL,
2883− AUDIT_FANOTIFY, "resp=%u", response);
2883+ /* {subj,obj}_trust values are {0,1,2}: no,yes,unknown */
2884+ switch (friar->hdr.type) {
2885+ case FAN_RESPONSE_INFO_NONE:
2886+ audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
2887+ "resp=%u fan_type=%u fan_info=0 subj_trust=2 obj_trust=2",
2888+ response, FAN_RESPONSE_INFO_NONE);
2889+ break;
2890+ case FAN_RESPONSE_INFO_AUDIT_RULE:
2891+ audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
2892+ "resp=%u fan_type=%u fan_info=%X subj_trust=%u obj_trust=%u",
2893+ response, friar->hdr.type, friar->rule_number,
2894+ friar->subj_trust, friar->obj_trust);
2895+ }
28842896 }
28852897
28862898 void __audit_tk_injoffset(struct timespec64 offset)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t