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