Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jul 2010 18:35:44 GMT
From:      Efstratios Karatzas <gpf@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 181264 for review
Message-ID:  <201007211835.o6LIZicS000451@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@181264?ac=10

Change 181264 by gpf@gpf_desktop on 2010/07/21 18:35:00

	- Now, the audit framework is capable of keeping multiple simultaneous 
	audit records per kernel thread in a simple tree like data structure.
	Done quite some testing and can't seem to trigger any bugs.
	
	Note:
	This will cover most cases, but we may have to provide some 
	modules with an audit record that will be filled by them and then 
	passed to us only for it to be commited to the audit worker. Not 
	sure if this "supplement" will be needed, but hey, this is just 
	my proposed solution to this problem. 
	
	On the good side, the interface is kept exactly the same. On the 
	bad side, we can only have one active audit record at a time.
	(though we could provide a mechanism to temporarily shift up and down 
	the tree if the programmer is really confident about the code flow).

Affected files ...

.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.c#13 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.h#11 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_arg.c#9 edit
.. //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_private.h#10 edit

Differences ...

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.c#13 (text) ====

@@ -221,25 +221,28 @@
 	td = arg;
 	ar = mem;
 	bzero(ar, sizeof(*ar));
-	/* XXXgpf: we should allocate a k_ar, iff we are auditing this event -> todo */
-	ar->k_ar = malloc(sizeof(struct audit_record), M_AUDITRECORD, M_WAITOK);
-	bzero(ar->k_ar, sizeof(struct audit_record));
-	ar->k_ar->ar_magic = AUDIT_RECORD_MAGIC;
-	nanotime(&ar->k_ar->ar_starttime);
+	/* We should allocate a k_ar iff we are auditing this event */
+	if (td->td_pflags & TDP_AUDITREC) {
+		ar->k_ar = malloc(sizeof(struct audit_record), M_AUDITRECORD, M_WAITOK);
+		bzero(ar->k_ar, sizeof(struct audit_record));
+		ar->k_ar->ar_magic = AUDIT_RECORD_MAGIC;
+		nanotime(&ar->k_ar->ar_starttime);
+
+		/*
+		* Export the subject credential.
+		*/
+		cred = td->td_ucred;
+		cru2x(cred, &ar->k_ar->ar_subj_cred);
+		ar->k_ar->ar_subj_ruid = cred->cr_ruid;
+		ar->k_ar->ar_subj_rgid = cred->cr_rgid;
+		ar->k_ar->ar_subj_egid = cred->cr_groups[0];
+		ar->k_ar->ar_subj_auid = cred->cr_audit.ai_auid;
+		ar->k_ar->ar_subj_asid = cred->cr_audit.ai_asid;
+		ar->k_ar->ar_subj_pid = td->td_proc->p_pid;
+		ar->k_ar->ar_subj_amask = cred->cr_audit.ai_mask;
+		ar->k_ar->ar_subj_term_addr = cred->cr_audit.ai_termid;
+	}
 
-	/*
-	 * Export the subject credential.
-	 */
-	cred = td->td_ucred;
-	cru2x(cred, &ar->k_ar->ar_subj_cred);
-	ar->k_ar->ar_subj_ruid = cred->cr_ruid;
-	ar->k_ar->ar_subj_rgid = cred->cr_rgid;
-	ar->k_ar->ar_subj_egid = cred->cr_groups[0];
-	ar->k_ar->ar_subj_auid = cred->cr_audit.ai_auid;
-	ar->k_ar->ar_subj_asid = cred->cr_audit.ai_asid;
-	ar->k_ar->ar_subj_pid = td->td_proc->p_pid;
-	ar->k_ar->ar_subj_amask = cred->cr_audit.ai_mask;
-	ar->k_ar->ar_subj_term_addr = cred->cr_audit.ai_termid;
 	return (0);
 }
 
@@ -400,109 +403,168 @@
 	uma_zfree(audit_record_zone, ar);
 }
 
+/*
+ * Insert the new audit record in the per thread tree structure &
+ * make td_ar point to it
+ */
 void
-audit_commit(struct kaudit_record *ar, int error, int retval)
+audit_tree_insert(struct thread *td, struct kaudit_record *ar)
+{
+	if (ar == NULL)
+		return;
+
+	ar->k_parent = td->td_ar;
+	STAILQ_INIT(&ar->kaudit_children_q);
+	if (td->td_ar != NULL)
+		STAILQ_INSERT_TAIL(&td->td_ar->kaudit_children_q, ar, k_record_q);
+	td->td_ar = ar;
+}
+
+
+/*
+ * Go up on level on the tree hierarchy, restore the audit flag 
+ * to its previous value and make td_ar point to the parent event
+ */
+void
+audit_tree_go_up(struct thread *td)
 {
+	td->td_ar = td->td_ar->k_parent;
+	if (td->td_ar->k_ar == NULL)
+		td->td_pflags &= ~TDP_AUDITREC;
+	else
+		td->td_pflags |= TDP_AUDITREC;
+}
+
+/*
+ * commit the audit events of the tree in preorder & destroy the 
+ * ones we don't commit
+ * 
+ * XXXgpf: The caller needs to hold a lock on audit_mtx. If we don't 
+ * like hogging on the mutex, we can split this function in two.
+ * One will decide which records should be commited and the other, 
+ * which will require the lock, will just commit or destroy each record.
+ */
+void
+audit_tree_commit(struct kaudit_record *ar, int *signal_worker)
+{	
 	au_event_t event;
 	au_class_t class;
 	au_id_t auid;
-	int sorf;
+	int commit, error, retval, sorf;
 	struct au_mask *aumask;
+	struct kaudit_record *child, *tchild;
+
+	commit = 0;
+
+	if (ar->k_ar != NULL) {
+		error = ar->k_ar->ar_errno;
+		retval = ar->k_ar->ar_retval;
+
+		/*
+		 * Decide whether to commit the audit record by checking the error
+		 * value from the system call and using the appropriate audit mask.
+		 */
+		if (ar->k_ar->ar_subj_auid == AU_DEFAUDITID)
+			aumask = &audit_nae_mask;
+		else
+			aumask = &ar->k_ar->ar_subj_amask;
 
-	if (ar == NULL)
-		return;
+		if (error)
+			sorf = AU_PRS_FAILURE;
+		else
+			sorf = AU_PRS_SUCCESS;
+
+		/*
+		 * syscalls.master sometimes contains a prototype event number, which
+		 * we will transform into a more specific event number now that we
+		 * have more complete information gathered during the system call.
+		 */
+		switch(ar->k_ar->ar_event) {
+		case AUE_OPEN_RWTC:
+			ar->k_ar->ar_event = audit_flags_and_error_to_openevent(
+			    ar->k_ar->ar_arg_fflags, error);
+			break;
 
-	/*
-	 * Decide whether to commit the audit record by checking the error
-	 * value from the system call and using the appropriate audit mask.
-	 */
-	if (ar->k_ar->ar_subj_auid == AU_DEFAUDITID)
-		aumask = &audit_nae_mask;
-	else
-		aumask = &ar->k_ar->ar_subj_amask;
+		case AUE_OPENAT_RWTC:
+			ar->k_ar->ar_event = audit_flags_and_error_to_openatevent(
+			    ar->k_ar->ar_arg_fflags, error);
+			break;
 
-	if (error)
-		sorf = AU_PRS_FAILURE;
-	else
-		sorf = AU_PRS_SUCCESS;
+		case AUE_SYSCTL:
+			ar->k_ar->ar_event = audit_ctlname_to_sysctlevent(
+			    ar->k_ar->ar_arg_ctlname, ar->k_ar->ar_valid_arg);
+			break;
 
-	/*
-	 * syscalls.master sometimes contains a prototype event number, which
-	 * we will transform into a more specific event number now that we
-	 * have more complete information gathered during the system call.
-	 */
-	switch(ar->k_ar->ar_event) {
-	case AUE_OPEN_RWTC:
-		ar->k_ar->ar_event = audit_flags_and_error_to_openevent(
-		    ar->k_ar->ar_arg_fflags, error);
-		break;
+		case AUE_AUDITON:
+			/* Convert the auditon() command to an event. */
+			ar->k_ar->ar_event = auditon_command_event(ar->k_ar->ar_arg_cmd);
+			break;
+			
+		case AUE_NFS_OPEN:
+			ar->k_ar->ar_event = audit_flags_to_nfs_openevent(ar->k_ar->ar_arg_fflags);
+			break;
+		}
 
-	case AUE_OPENAT_RWTC:
-		ar->k_ar->ar_event = audit_flags_and_error_to_openatevent(
-		    ar->k_ar->ar_arg_fflags, error);
-		break;
+		auid = ar->k_ar->ar_subj_auid;
+		event = ar->k_ar->ar_event;
+		class = au_event_class(event);
 
-	case AUE_SYSCTL:
-		ar->k_ar->ar_event = audit_ctlname_to_sysctlevent(
-		    ar->k_ar->ar_arg_ctlname, ar->k_ar->ar_valid_arg);
-		break;
+		ar->k_ar_commit |= AR_COMMIT_KERNEL;
+		if (au_preselect(event, class, aumask, sorf) != 0)
+			ar->k_ar_commit |= AR_PRESELECT_TRAIL;
+		if (audit_pipe_preselect(auid, event, class, sorf,
+		    ar->k_ar_commit & AR_PRESELECT_TRAIL) != 0)
+			ar->k_ar_commit |= AR_PRESELECT_PIPE;
+		if ((ar->k_ar_commit & (AR_PRESELECT_TRAIL | AR_PRESELECT_PIPE |
+		    AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE)) == 0)
+			goto out;
 
-	case AUE_AUDITON:
-		/* Convert the auditon() command to an event. */
-		ar->k_ar->ar_event = auditon_command_event(ar->k_ar->ar_arg_cmd);
-		break;
-		
-	case AUE_NFS_OPEN:
-		ar->k_ar->ar_event = audit_flags_to_nfs_openevent(ar->k_ar->ar_arg_fflags);
-		break;
-	}
+		/*
+		 * Note: it could be that some records initiated while audit was
+		 * enabled should still be committed?
+		 */
+		if (audit_suspended || !audit_enabled)
+			goto out;
 
-	auid = ar->k_ar->ar_subj_auid;
-	event = ar->k_ar->ar_event;
-	class = au_event_class(event);
+		commit = 1;
+		*signal_worker = 1;
+		/*
+		 * Constrain the number of committed audit records based on the
+		 * configurable parameter.
+		 */
+		while (audit_q_len >= audit_qctrl.aq_hiwater)
+			cv_wait(&audit_watermark_cv, &audit_mtx);
 
-	ar->k_ar_commit |= AR_COMMIT_KERNEL;
-	if (au_preselect(event, class, aumask, sorf) != 0)
-		ar->k_ar_commit |= AR_PRESELECT_TRAIL;
-	if (audit_pipe_preselect(auid, event, class, sorf,
-	    ar->k_ar_commit & AR_PRESELECT_TRAIL) != 0)
-		ar->k_ar_commit |= AR_PRESELECT_PIPE;
-	if ((ar->k_ar_commit & (AR_PRESELECT_TRAIL | AR_PRESELECT_PIPE |
-	    AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE)) == 0) {
-		mtx_lock(&audit_mtx);
+		TAILQ_INSERT_TAIL(&audit_q, ar, k_q);
+		audit_q_len++;
 		audit_pre_q_len--;
-		mtx_unlock(&audit_mtx);
-		audit_free(ar);
-		return;
 	}
 
-	ar->k_ar->ar_errno = error;
-	ar->k_ar->ar_retval = retval;
-	nanotime(&ar->k_ar->ar_endtime);
-
-	/*
-	 * Note: it could be that some records initiated while audit was
-	 * enabled should still be committed?
-	 */
-	mtx_lock(&audit_mtx);
-	if (audit_suspended || !audit_enabled) {
+out:
+	STAILQ_FOREACH_SAFE(child, &ar->kaudit_children_q, k_record_q, tchild) {
+		audit_tree_commit(child, signal_worker);
+	}
+	
+	/* if we are not commiting this ar, free it */
+	if (commit == 0) {
 		audit_pre_q_len--;
-		mtx_unlock(&audit_mtx);
 		audit_free(ar);
-		return;
 	}
+}
+
+void
+audit_commit(struct kaudit_record *ar)
+{
+	int signal_worker;
 
-	/*
-	 * Constrain the number of committed audit records based on the
-	 * configurable parameter.
-	 */
-	while (audit_q_len >= audit_qctrl.aq_hiwater)
-		cv_wait(&audit_watermark_cv, &audit_mtx);
+	if (ar == NULL)
+		return;
 
-	TAILQ_INSERT_TAIL(&audit_q, ar, k_q);
-	audit_q_len++;
-	audit_pre_q_len--;
-	cv_signal(&audit_worker_cv);
+	signal_worker = 0;
+	mtx_lock(&audit_mtx);	
+	audit_tree_commit(ar, &signal_worker);
+	if (signal_worker != 0)
+		cv_signal(&audit_worker_cv);
 	mtx_unlock(&audit_mtx);
 }
 
@@ -519,11 +581,8 @@
 	au_class_t class;
 	au_event_t event;
 	au_id_t auid;
+	struct kaudit_record *ar;
 
-	KASSERT(td->td_ar == NULL, ("audit_syscall_enter: td->td_ar != NULL"));
-	KASSERT((td->td_pflags & TDP_AUDITREC) == 0,
-	    ("audit_syscall_enter: TDP_AUDITREC set"));
-
 	/*
 	 * In FreeBSD, each ABI has its own system call table, and hence
 	 * mapping of system call codes to audit events.  Convert the code to
@@ -531,6 +590,9 @@
 	 * reference.  In Darwin, there's only one, so we use the global
 	 * symbol for the system call table.  No audit record is generated
 	 * for bad system calls, as no operation has been performed.
+	 * 
+	 * gpf: This doesn't seem ok now that we are keeping state for 
+	 * every event, whether we are auditing it or not.
 	 */
 	if (code >= td->td_proc->p_sysent->sv_size)
 		return;
@@ -572,42 +634,75 @@
 			cv_wait(&audit_fail_cv, &audit_mtx);
 			panic("audit_failing_stop: thread continued");
 		}
-		td->td_ar = audit_new(event, td);
-		if (td->td_ar != NULL)
-			td->td_pflags |= TDP_AUDITREC;
-	} else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) {
-		td->td_ar = audit_new(event, td);
-		if (td->td_ar != NULL)
-			td->td_pflags |= TDP_AUDITREC;
-	} else
+		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_syscall_exit() is called from the return of every system call, or in
- * the event of exit1(), during the execution of exit1().  It is responsible
- * for committing the audit record, if any, along with return condition.
+ * the event of exit1(), during the execution of exit1(). 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.
+ * 
+ * In the event of nfssvc(), we are forced to call audit_syscall_exit() 
+ * before the syscall actually exits because in some cases, it may hang around 
+ * in the kernel as a NFS daemon thread; this can cause problems with the 
+ * auditing of NFS RPCs.
  */
 void
 audit_syscall_exit(int error, struct thread *td)
 {
 	int retval;
 
+	if (td->td_ar == NULL)
+		return;
+
 	/*
-	 * Commit the audit record as desired; once we pass the record into
-	 * audit_commit(), the memory is owned by the audit subsystem.  The
-	 * return value from the system call is stored on the user thread.
+	 * The return value from the system call is stored on the user thread.
 	 * If there was an error, the return value is set to -1, imitating
 	 * the behavior of the cerror routine.
-	 */
+	 */ 
 	if (error)
 		retval = -1;
 	else
 		retval = td->td_retval[0];
 
-	audit_commit(td->td_ar, error, retval);
-	td->td_ar = NULL;
-	td->td_pflags &= ~TDP_AUDITREC;
+	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);
 }
 
 /*
@@ -723,18 +818,13 @@
 	au_event_t event;
 	au_id_t auid;
 	int error;
+	struct kaudit_record *ar;
 
-	KASSERT(td->td_ar == NULL, ("audit_nfs_enter: td->td_ar != NULL"));
-	KASSERT((td->td_pflags & TDP_AUDITREC) == 0,
-	    ("audit_nfs_enter: TDP_AUDITREC set"));
-
 	error = audit_nfs_proc_to_event(proc, &event, nfsprot);
-	if (error) {
-		td->td_ar = NULL;
+	if (error)
 		return;
-	}
-	
-	/* XXXgpf: for debuging, nevermind */
+
+	/* XXXgpf: for debugging, nevermind */
 	printf("audit_nfs_enter: procedure = %d\n"
 	       "audit_nfs_enter: event = %d\n", proc, event);
 	
@@ -771,17 +861,30 @@
 		    priv_check(td, PRIV_AUDIT_FAILSTOP) != 0) {
 			cv_wait(&audit_fail_cv, &audit_mtx);
 			panic("audit_failing_stop: thread continued");
-		}		
-		td->td_ar = audit_new(event, td);		
-		if (td->td_ar != NULL)
-			td->td_pflags |= TDP_AUDITREC;
-	} else if (audit_pipe_preselect(auid, event, class, AU_PRS_BOTH, 0)) {		
-		td->td_ar = audit_new(event, td);
-		if (td->td_ar != NULL)
-			td->td_pflags |= TDP_AUDITREC;
-	} else
+		}
+		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;
-	
+		return;
+	}
+
 	/*
 	 * Write over the credentials that audit_record_ctor() exported.
 	 * These are the credentials of the user that initiated the NFS RPC.
@@ -797,7 +900,7 @@
 	 * td->ar = audit_new(...);
 	 * td->td_ucred = orig_cr;
 	 */
-	if (td->td_ar != NULL && user_cr != NULL) {
+	if (AUDITING_TD(td) && user_cr != NULL) {
 		cru2x(user_cr, &td->td_ar->k_ar->ar_subj_cred);
 		td->td_ar->k_ar->ar_subj_ruid = user_cr->cr_ruid;
 		td->td_ar->k_ar->ar_subj_rgid = user_cr->cr_rgid;
@@ -805,34 +908,47 @@
 	}
 }
 
+
 /*
  * audit_nfs_exit() is called from the return of every NFS pseudo-sys/call 
- * that services an RPC by performing the various vnode operations.
- * It is responsible for committing the audit record, if any, along with 
- * return condition.
+ * that services an RPC by performing the various vnode operations. 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_nfs_exit(int error, struct thread *td)
 {
 	int retval;
+	
+	if (td->td_ar == NULL)
+		return;
+
 	/*
-	 * Commit the audit record as desired; once we pass the record into
-	 * audit_commit(), the memory is owned by the audit subsystem.  The
-	 * return value from the system call is stored on the user thread.
-	 * If there was an error, the return value is set to -1, imitating
-	 * the behavior of the cerror routine.
-	 * 
-	 * gpf: passing retval to audit_commit doesn't make much sense for 
-	 * NFS
+	 * XXXgpf: In the case of NFS RPCs, I don't think we need to worry 
+	 * about retval.
 	 */	
 	if (error)
 		retval = -1;
 	else
 		retval = td->td_retval[0];
 
-	audit_commit(td->td_ar, error, retval);
-	td->td_ar = NULL;
-	td->td_pflags &= ~TDP_AUDITREC;
+	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
@@ -943,5 +1059,9 @@
 	ARG_SET_VALID(ar, ARG_SIGNUM);
 	if (errcode != 0)
 		ret = 1;
-	audit_commit(ar, errcode, ret);
+	AUDIT_ERROR(errcode);
+	AUDIT_RETVAL(ret);
+	AUDIT_ENDTIME();
+	audit_commit(ar);
+	td->td_pflags &= ~TDP_AUDITREC;
 }

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit.h#11 (text) ====

@@ -134,6 +134,9 @@
 void	 audit_arg_lockowner(char *lockowner, u_short len);
 void	 audit_arg_locktype(int locktype);
 void	 audit_arg_clientname(char *clientname, u_short len);
+void	 audit_error(int error);
+void	 audit_retval(int retval);
+void	 audit_endtime(void);
 
 /*
  * Define macros to wrap the audit_arg_* calls by checking the global
@@ -347,13 +350,29 @@
 	}								\
 } while (0)
 
+#define AUDIT_ENDTIME() do {						\
+	if (AUDITING_TD(curthread))					\
+		audit_endtime();					\
+} while (0)								\
+
+#define AUDIT_ERROR(error) do {						\
+	if (AUDITING_TD(curthread))					\
+		audit_error((error));					\
+} while (0)								\
+
+#define AUDIT_RETVAL(retval) do {					\
+	if (AUDITING_TD(curthread))					\
+		audit_retval((retval));					\
+} while (0)								\
+
 /*
- * Wrap the audit_syscall_exit() function so that it is called only when
- * we have a audit record on the thread.  Audit records can persist after
+ * 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_SYSCALL_EXIT(error, td)	do {				\
-	if (td->td_pflags & TDP_AUDITREC)				\
 		audit_syscall_exit(error, td);				\
 } while (0)
 
@@ -363,8 +382,14 @@
 	}								\
 } 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 {				\
-	if (td->td_pflags & TDP_AUDITREC)				\
 		audit_nfs_exit(error, td);				\
 } while (0)
 
@@ -419,6 +444,10 @@
 #define	AUDIT_ARG_VNODE2(vp)
 #define AUDIT_ARG_VTYPE(vtype)
 
+#define AUDIT_ENDTIME()
+#define AUDIT_ERROR(error)
+#define AUDIT_RETVAL(retval)
+
 #define	AUDIT_SYSCALL_ENTER(code, td)
 #define	AUDIT_SYSCALL_EXIT(error, td)
 

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_arg.c#9 (text) ====

@@ -1035,3 +1035,39 @@
 	ar->k_ar->ar_arg_locktype = locktype;
 	ARG_SET_VALID(ar, ARG_LOCKTYPE);
 }
+
+void
+audit_error(int error)
+{
+	struct kaudit_record *ar;
+
+	ar = currecord();
+	if (ar == NULL)
+		return;
+
+	ar->k_ar->ar_errno = error;
+}
+
+void
+audit_retval(int retval)
+{
+	struct kaudit_record *ar;
+
+	ar = currecord();
+	if (ar == NULL)
+		return;
+
+	ar->k_ar->ar_retval = retval;
+}
+
+void
+audit_endtime(void)
+{
+	struct kaudit_record *ar;
+
+	ar = currecord();
+	if (ar == NULL)
+		return;
+	
+	nanotime(&ar->k_ar->ar_endtime);
+}

==== //depot/projects/soc2010/gpf_audit/freebsd/src/sys/security/audit/audit_private.h#10 (text) ====

@@ -315,7 +315,9 @@
 } while (0)
 
 /*
- * In-kernel version of audit record; the basic record plus queue meta-data.
+ * In-kernel version of audit record; the basic record plus queue meta-data,
+ * plus the necessary elements to maintain a tree like structure of multiple
+ * audit records per kernel thread.
  * This record can also have a pointer set to some opaque data that will be
  * passed through to the audit writing mechanism.
  */
@@ -326,6 +328,9 @@
 	u_int				 k_ulen;	/* User data length. */
 	struct uthread			*k_uthread;	/* Audited thread. */
 	TAILQ_ENTRY(kaudit_record)	 k_q;
+	struct kaudit_record 		*k_parent;	/* parent record */
+	STAILQ_ENTRY(kaudit_record) 	 k_record_q;
+	STAILQ_HEAD(kaudit_children_q, kaudit_record) kaudit_children_q; /* queue for children records */
 };
 TAILQ_HEAD(kaudit_queue, kaudit_record);
 
@@ -334,11 +339,18 @@
  * records.
  */
 void			 audit_abort(struct kaudit_record *ar);
-void			 audit_commit(struct kaudit_record *ar, int error,
-			    int retval);
+void			 audit_commit(struct kaudit_record *ar);
 struct kaudit_record	*audit_new(int event, struct thread *td);
 
 /*
+ * Functions to manage the per thread audit record tree structure
+ */
+
+void		audit_tree_commit(struct kaudit_record *ar, int *signal_worker);
+void		audit_tree_go_up(struct thread *td);
+void		audit_tree_insert(struct thread *td, struct kaudit_record *ar);
+
+/*
  * NFS specific stuff
  */
 int			 audit_nfs_proc_to_event(unsigned int proc, au_event_t *event, int nfsprot);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007211835.o6LIZicS000451>