PERFORCE change 186990 for review
Efstratios Karatzas
gpf at FreeBSD.org
Thu Dec 16 22:22:23 UTC 2010
http://p4web.freebsd.org/@@186990?ac=10
Change 186990 by gpf at gpf_desktop on 2010/12/16 22:21:41
first take on auditing firewall events:
- now auditing the enabling/disabling of ipfw
note: perhaps I should add an argument or extra events to
differentiate between packet filtering of ipv4 & ipv6.
Affected files ...
.. //depot/projects/soc2010/gpf_audit/freebsd/src/contrib/openbsm/etc/audit_event#8 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/bsm/audit_kevents.h#6 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/netinet/ipfw/ip_fw_pfil.c#2 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.c#15 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.h#12 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_bsm.c#22 edit
Differences ...
==== //depot/projects/soc2010/gpf_audit/freebsd/src/contrib/openbsm/etc/audit_event#8 (text) ====
@@ -425,6 +425,12 @@
2057:AUE_NFS_OPEN_WTC:nfsrv_open() - write, trunc, creat:fw,fd,fc,fa,fm
2058:AUE_NFS_OPEN_WT:nfsrv_open() - write, trunc:fw,fd,fa,fm
#
+# Firewall Events
+# note: class 'aa' is only temporarily used
+#
+3000:AUE_PFIL_ENABLE:enable packet filtering:aa
+3001:AUE_PFIL_DISABLE:disable packet filtering:aa
+#
# OpenBSM-specific kernel events.
#
43001:AUE_GETFSSTAT:getfsstat(2):fa
==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/bsm/audit_kevents.h#6 (text) ====
@@ -447,6 +447,11 @@
#define AUE_NFS_OPEN_WC 2056
#define AUE_NFS_OPEN_WTC 2057
#define AUE_NFS_OPEN_WT 2058
+/*
+ * Firewall Events
+ */
+#define AUE_PFIL_ENABLE 3000
+#define AUE_PFIL_DISABLE 3001
/*
* Audit event identifiers added as part of OpenBSM, generally corresponding
==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/netinet/ipfw/ip_fw_pfil.c#2 (text+ko) ====
@@ -44,6 +44,7 @@
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/lock.h>
+#include <sys/proc.h>
#include <sys/rwlock.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
@@ -63,6 +64,9 @@
#include <machine/in_cksum.h>
+#include <bsm/audit_kevents.h>
+#include <security/audit/audit.h>
+
static VNET_DEFINE(int, fw_enable) = 1;
#define V_fw_enable VNET(fw_enable)
@@ -334,9 +338,17 @@
if (pfh == NULL)
return ENOENT;
+ if (onoff)
+ AUDIT_PFIL_ENTER(AUE_PFIL_ENABLE, curthread);
+ else
+ AUDIT_PFIL_ENTER(AUE_PFIL_DISABLE, curthread);
+
(void) (onoff ? pfil_add_hook : pfil_remove_hook)
(ipfw_check_hook, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh);
+ AUDIT_ARG_TEXT("ipfw");
+ AUDIT_PFIL_EXIT(0, curthread);
+
return 0;
}
==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.c#15 (text) ====
@@ -901,7 +901,6 @@
}
}
-
/*
* audit_nfs_exit() is called from the return of every NFS pseudo-sys/call
* that services an RPC by performing the various vnode operations. If the
@@ -944,6 +943,118 @@
audit_tree_go_up(td);
}
+/*
+ * audit_pfil_enter is called just before executing a firewall event, whether
+ * that be an administrative or a network event. It is responsible for deciding
+ * whether or not to audit the call (preselection), and if so, allocating a
+ * per-thread audit record. audit_new() will fill in basic thread/credential
+ * properties.
+ */
+void
+audit_pfil_enter(unsigned short event, struct thread *td)
+{
+ struct au_mask *aumask;
+ au_class_t class;
+ au_id_t auid;
+ struct kaudit_record *ar;
+
+ /*
+ * Check which audit mask to use; either the kernel non-attributable
+ * event mask or the process audit mask.
+ */
+ auid = td->td_ucred->cr_audit.ai_auid;
+ if (auid == AU_DEFAUDITID)
+ aumask = &audit_nae_mask;
+ else
+ aumask = &td->td_ucred->cr_audit.ai_mask;
+
+ /*
+ * Allocate an audit record, if preselection allows it, and store in
+ * the thread for later use.
+ */
+ class = au_event_class(event);
+ if (au_preselect(event, class, aumask, AU_PRS_BOTH)) {
+ /*
+ * If we're out of space and need to suspend unprivileged
+ * processes, do that here rather than trying to allocate
+ * another audit record.
+ *
+ * Note: we might wish to be able to continue here in the
+ * future, if the system recovers. That should be possible
+ * by means of checking the condition in a loop around
+ * cv_wait(). It might be desirable to reevaluate whether an
+ * audit record is still required for this event by
+ * re-calling au_preselect().
+ */
+ if (audit_in_failure &&
+ priv_check(td, PRIV_AUDIT_FAILSTOP) != 0) {
+ cv_wait(&audit_fail_cv, &audit_mtx);
+ panic("audit_failing_stop: thread continued");
+ }
+ td->td_pflags |= TDP_AUDITREC;
+ }
+ else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0))
+ td->td_pflags |= TDP_AUDITREC;
+ else
+ td->td_pflags &= ~TDP_AUDITREC;
+
+ /*
+ * We need to keep state, even if we are not auditing this event.
+ * The reason is that that we may encounter another security event,
+ * before this one is over. When we exit from the second event, we
+ * need a way to remember if we were auditing the first event or not.
+ */
+ ar = audit_new(event, td);
+ if (ar != NULL)
+ audit_tree_insert(td, ar);
+ else {
+ audit_commit(td->td_ar);
+ td->td_pflags &= ~TDP_AUDITREC;
+ td->td_ar = NULL;
+ }
+}
+
+/*
+ * audit_pfil_exit() is called from the return of a routine that services
+ * firewall events. If the current event is the root of the audit record
+ * tree structure, this function is responsible for commiting the whole
+ * audit record tree. Otherwise, it stores the return status & endtime;
+ * also it restores the auditing flag and td_ar to reflect the parent audit record.
+ */
+void
+audit_pfil_exit(int error, struct thread *td)
+{
+ int retval;
+
+ if (td->td_ar == NULL)
+ return;
+
+ /*
+ * XXXgpf: In the case of firewall events, I don't think we need to worry
+ * about retval.
+ */
+ if (error)
+ retval = -1;
+ else
+ retval = td->td_retval[0];
+
+ AUDIT_ENDTIME();
+ AUDIT_ERROR(error);
+ AUDIT_RETVAL(retval);
+
+ /*
+ * Commit the audit record tree; once we pass the records into
+ * audit_commit(), the memory is owned by the audit subsystem.
+ */
+ if (td->td_ar->k_parent == NULL) {
+ audit_commit(td->td_ar);
+ td->td_ar = NULL;
+ td->td_pflags &= ~TDP_AUDITREC;
+ }
+ else
+ audit_tree_go_up(td);
+}
+
void
audit_cred_copy(struct ucred *src, struct ucred *dest)
{
==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.h#12 (text) ====
@@ -62,6 +62,9 @@
void audit_nfs_enter(unsigned int proc, struct ucred *user_cr, struct thread *td, int nfsprot);
void audit_nfs_exit(int error, struct thread *td);
+void audit_pfil_enter(unsigned short event, struct thread *td);
+void audit_pfil_exit(int error, struct thread *td);
+
/*
* The remaining kernel functions are conditionally compiled in as they are
* wrapped by a macro, and the macro should be the only place in the source
@@ -371,6 +374,8 @@
* of audit records, make td_ar point someplace else or change the value
* of the thread's auditing flag. Audit records can persist after
* auditing is disabled, so we don't just check audit_enabled here.
+ *
+ * same goes for all the other audit_X_exit() macros
*/
#define AUDIT_SYSCALL_EXIT(error, td) do { \
audit_syscall_exit(error, td); \
@@ -382,17 +387,20 @@
} \
} while (0)
-/*
- * audit_syscall_exit() needs to be called even if we are not auditing
- * this particular event because we may have to commit a whole tree
- * of audit records, make td_ar point someplace else or change the value
- * of the thread's auditing flag. Audit records can persist after
- * auditing is disabled, so we don't just check audit_enabled here.
- */
#define AUDIT_NFS_EXIT(error, td) do { \
audit_nfs_exit(error, td); \
} while (0)
+#define AUDIT_PFIL_ENTER(event, td) do { \
+ if (audit_enabled) { \
+ audit_pfil_enter(event, td); \
+ } \
+} while (0)
+
+#define AUDIT_PFIL_EXIT(error, td) do { \
+ audit_pfil_exit(error, td); \
+} while (0)
+
/*
* A Macro to wrap the audit_sysclose() function.
*/
@@ -456,6 +464,9 @@
#define AUDIT_NFS_ENTER(proc, user_cr, td, prot)
#define AUDIT_NFS_EXIT(error, td)
+#define AUDIT_PFIL_ENTER(event, td)
+#define AUDIT_PFIL_EXIT(error, td)
+
#endif /* AUDIT */
#endif /* !_SECURITY_AUDIT_KERNEL_H_ */
==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_bsm.c#22 (text) ====
@@ -1831,6 +1831,15 @@
}
break;
+ /* FALLTHROUGH */
+ case AUE_PFIL_ENABLE:
+ case AUE_PFIL_DISABLE:
+ if (ARG_IS_VALID(kar, ARG_TEXT)) {
+ tok = au_to_text(ar->ar_arg_text);
+ kau_write(rec, tok);
+ }
+ break;
+
case AUE_WAIT4:
PROCESS_PID_TOKENS(1);
if (ARG_IS_VALID(kar, ARG_VALUE)) {
More information about the p4-projects
mailing list