diff --git a/ChangeLog b/ChangeLog index fcc3c8a9..702edaaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ - On shutdown when running reports, if trust db empty warn (Nobuhiro Iwamatsu) - Extend state machine to skip opens after exec until dyn linker found - Control filtering of unwanted files in rpm backend with config file +- Add support for logging rule number of decision in the audit event 1.1.7 - Re-add dropped FAN_MARK_MOUNT for monitoring events (Steven Brzozowski) diff --git a/configure.ac b/configure.ac index 92024ce1..a49e3971 100644 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,11 @@ AC_CHECK_PROG([FILE_COMM], "file", "yes", "no") if test "$FILE_COMM" = "no"; then AC_MSG_ERROR([Unable to find the file program need to build magic databases]) fi +AC_CHECK_MEMBER([struct fanotify_response_info_audit_rule.rule_number], + [perm=yes], [perm=no], [[#include ]]) +if test $perm = "yes"; then + AC_DEFINE(FAN_AUDIT_RULE_NUM, 1,[Define if kernel supports audit rule numbers]) +fi echo . echo Checking compiler options diff --git a/src/daemon/notify.c b/src/daemon/notify.c index c280a1f1..d3d9a509 100644 --- a/src/daemon/notify.c +++ b/src/daemon/notify.c @@ -1,6 +1,6 @@ /* * notify.c - functions handle recieving and enqueuing events - * Copyright (c) 2016-18,22 Red Hat Inc. + * Copyright (c) 2016-18,2022-23 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the @@ -350,7 +350,7 @@ static void enqueue_event(const struct fanotify_event_metadata *metadata) // We have to deny. This allows the kernel to free it's // memory related to this request. reply_event also closes // the descriptor, so we don't need to do it here. - reply_event(fd, metadata, FAN_DENY); + reply_event(fd, metadata, FAN_DENY, NULL); msg(LOG_DEBUG, "enqueue error"); } else set_ready(); @@ -392,14 +392,15 @@ void handle_events(void) if (metadata->fd >= 0) { if (metadata->mask & mask) { if (metadata->pid == our_pid) - reply_event(fd, metadata, FAN_ALLOW); + reply_event(fd, metadata, FAN_ALLOW, + NULL); else enqueue_event(metadata); } else { // This should never happen. Reply with deny // which releases the descriptor and kernel // memory. Continue processing what was read. - reply_event(fd, metadata, FAN_DENY); + reply_event(fd, metadata, FAN_DENY, NULL); } } metadata = FAN_EVENT_NEXT(metadata, len); diff --git a/src/library/event.c b/src/library/event.c index 649cb9d6..6bcfe31f 100644 --- a/src/library/event.c +++ b/src/library/event.c @@ -1,6 +1,6 @@ /* * event.c - Functions to access event attributes - * Copyright (c) 2016,2018-20 Red Hat Inc. + * Copyright (c) 2016,2018-20,2023 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the @@ -109,6 +109,7 @@ int new_event(const struct fanotify_event_metadata *m, event_t *e) e->pid = m->pid; e->fd = m->fd; e->type = m->mask & ALL_EVENTS; + e->num = 0; key = compute_subject_key(subj_cache, m->pid); q_node = check_lru_cache(subj_cache, key); diff --git a/src/library/event.h b/src/library/event.h index 56892426..860abbbd 100644 --- a/src/library/event.h +++ b/src/library/event.h @@ -1,6 +1,6 @@ /* * event.h - Header file for event.c - * Copyright (c) 2016,2018-19 Red Hat Inc. + * Copyright (c) 2016,2018-19,2023 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the @@ -37,6 +37,7 @@ typedef struct ev { pid_t pid; int fd; int type; + unsigned num; s_array *s; o_array *o; } event_t; diff --git a/src/library/policy.c b/src/library/policy.c index 4a4f03c9..4a2f9518 100644 --- a/src/library/policy.c +++ b/src/library/policy.c @@ -1,6 +1,6 @@ /* * policy.c - functions that encapsulate the notion of a policy - * Copyright (c) 2016,2019-22 Red Hat + * Copyright (c) 2016,2019-23 Red Hat * All Rights Reserved. * * This software may be freely redistributed and/or modified under the @@ -71,6 +71,13 @@ static const nv_t table[] = { #define F_PERM 32 #define F_COLON 33 +#ifdef FAN_AUDIT_RULE_NUM +struct fan_audit_response +{ + struct fanotify_response r; + struct fanotify_response_info_audit_rule a; +}; +#endif // This function returns 1 on success and 0 on failure static int parsing_obj; @@ -408,6 +415,10 @@ decision_t process_event(event_t *e) (debug > 1 && (results & DENY)) ) log_it2(r ? r->num : 0xFFFFFFFF, results, e); + // Record which rule (rules are 1 based when listed by the cli tool) + if (r) + e->num = r->num + 1; + // If we are not in permissive mode, return any decision if (results != NO_OPINION) return results; @@ -415,14 +426,76 @@ decision_t process_event(event_t *e) return ALLOW; } +#ifdef FAN_AUDIT_RULE_NUM +static int test_info_api(int fd) +{ + int rc; + struct fan_audit_response f; + + f.r.fd = FAN_NOFD; + f.r.response = FAN_DENY | FAN_INFO; + f.a.hdr.type = FAN_RESPONSE_INFO_AUDIT_RULE; + f.a.hdr.pad = 0; + f.a.hdr.len = sizeof(struct fanotify_response_info_audit_rule); + f.a.rule_number = 0; + f.a.subj_trust = 2; + f.a.obj_trust = 2; + rc = write(fd, &f, sizeof(struct fan_audit_response)); + msg(LOG_DEBUG, "Rule number API supported %s", rc < 0 ? "no" : "yes"); + if (rc < 0) + return 0; + else + return 1; +} +#endif + void reply_event(int fd, const struct fanotify_event_metadata *metadata, - unsigned reply) + unsigned reply, event_t *e) { + close(metadata->fd); +#ifdef FAN_AUDIT_RULE_NUM + static int use_new = 2; + if (use_new == 2) + use_new = test_info_api(fd); + if (reply & FAN_AUDIT && use_new) { + struct fan_audit_response f; + subject_attr_t *sn; + object_attr_t *obj; + + f.r.fd = metadata->fd; + f.r.response = reply | FAN_INFO; + f.a.hdr.type = FAN_RESPONSE_INFO_AUDIT_RULE; + f.a.hdr.pad = 0; + f.a.hdr.len = sizeof(struct fanotify_response_info_audit_rule); + if (e) + f.a.rule_number = e->num; + else + f.a.rule_number = 0; + + // Subj trust is rare. See if we have it. + if (e && (sn = subject_access(e->s, SUBJ_TRUST))) { + if (sn) + f.a.subj_trust = sn->val; + else + f.a.subj_trust = 2; + } else + f.a.subj_trust = 2; + // All objects have a trust value + if (e && (obj = get_obj_attr(e, OBJ_TRUST))) { + if (obj) + f.a.obj_trust = obj->val; + else // Only serious errors cause this + f.a.obj_trust = 2; + } else + f.a.obj_trust = 2; + write(fd, &f, sizeof(struct fan_audit_response)); + return; + } +#endif struct fanotify_response response; response.fd = metadata->fd; response.response = reply; - close(metadata->fd); write(fd, &response, sizeof(struct fanotify_response)); } @@ -451,9 +524,11 @@ void make_policy_decision(const struct fanotify_event_metadata *metadata, // If permissive, always allow and honor the audit bit // if not in debug mode if (permissive) - reply_event(fd, metadata,FAN_ALLOW |(decision & AUDIT)); + reply_event(fd, metadata,FAN_ALLOW | (decision & AUDIT), + &e); else - reply_event(fd, metadata, decision & FAN_RESPONSE_MASK); + reply_event(fd, metadata, decision & FAN_RESPONSE_MASK, + &e); } } diff --git a/src/library/policy.h b/src/library/policy.h index 12f112ab..bdaaca0c 100644 --- a/src/library/policy.h +++ b/src/library/policy.h @@ -1,6 +1,6 @@ /* * policy.h - Header file for policy.c - * Copyright (c) 2016,2020 Red Hat + * Copyright (c) 2016,2020,2023 Red Hat * All Rights Reserved. * * This software may be freely redistributed and/or modified under the @@ -64,7 +64,7 @@ int load_config(const conf_t *config); int reload_config(const conf_t *config); decision_t process_event(event_t *e); void reply_event(int fd, const struct fanotify_event_metadata *metadata, - unsigned reply); + unsigned reply, event_t *e); void make_policy_decision(const struct fanotify_event_metadata *metadata, int fd, uint64_t mask); unsigned long getAllowed(void);