[PATCH 2/2] audit signal recipients (v2)

Amy Griffis amy.griffis at hp.com
Fri Feb 23 22:51:51 UTC 2007


When auditing syscalls that send signals, log the pid and security
context for each target process. Optimize the data collection by
adding a counter for signal-related rules, and avoiding allocating an
aux struct unless we have more than one target process. Move the
audit_signal_info() hook up in check_kill_permission() so we audit
attempts where permission is denied.

Signed-off-by: Amy Griffis <amy.griffis at hp.com>
---
 include/linux/audit.h |    3 ++
 kernel/audit.h        |   12 ++++---
 kernel/auditfilter.c  |   14 ++++++++-
 kernel/auditsc.c      |   76 ++++++++++++++++++++++++++++++++++++++++++++++--
 kernel/signal.c       |   10 ++++--
 5 files changed, 100 insertions(+), 15 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0194a9b..b1daf3c 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -90,6 +90,7 @@
 #define AUDIT_MQ_GETSETATTR	1315	/* POSIX MQ get/set attribute record type */
 #define AUDIT_KERNEL_OTHER	1316	/* For use by 3rd party modules */
 #define AUDIT_FD_PAIR		1317    /* audit record for pipe/socketpair */
+#define AUDIT_TARGET_PID	1318    /* audit record for a pid arg */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
@@ -443,6 +444,7 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
 	return 0;
 }
 extern int audit_n_rules;
+extern int audit_signals;
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -472,6 +474,7 @@ extern int audit_n_rules;
 #define audit_mq_notify(d,n) ({ 0; })
 #define audit_mq_getsetattr(d,s) ({ 0; })
 #define audit_n_rules 0
+#define audit_signals 0
 #endif
 
 #ifdef CONFIG_AUDIT
diff --git a/kernel/audit.h b/kernel/audit.h
index a337023..36960f7 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -131,17 +131,19 @@ extern void audit_handle_ievent(struct inotify_watch *, u32, u32, u32,
 extern int selinux_audit_rule_update(void);
 
 #ifdef CONFIG_AUDITSYSCALL
-extern void __audit_signal_info(int sig, struct task_struct *t);
-static inline void audit_signal_info(int sig, struct task_struct *t)
+extern int __audit_signal_info(int sig, struct task_struct *t);
+static inline int audit_signal_info(int sig, struct task_struct *t)
 {
-	if (unlikely(audit_pid && t->tgid == audit_pid))
-		__audit_signal_info(sig, t);
+	if (unlikely((audit_pid && t->tgid == audit_pid) ||
+		     (audit_signals && !audit_dummy_context())))
+		return __audit_signal_info(sig, t);
+	return 0;
 }
 extern enum audit_state audit_filter_inodes(struct task_struct *,
 					    struct audit_context *);
 extern void audit_set_auditable(struct audit_context *);
 #else
-#define audit_signal_info(s,t)
+#define audit_signal_info(s,t) AUDIT_DISABLED
 #define audit_filter_inodes(t,c) AUDIT_DISABLED
 #define audit_set_auditable(c)
 #endif
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 3749193..b90d121 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1171,7 +1171,7 @@ static inline int audit_add_rule(struct audit_entry *entry,
 	struct nameidata *ndp, *ndw;
 	int h, err, putnd_needed = 0;
 #ifdef CONFIG_AUDITSYSCALL
-	int dont_count = 0;
+	int i, dont_count = 0;
 
 	/* If either of these, don't count towards total */
 	if (entry->rule.listnr == AUDIT_FILTER_USER ||
@@ -1221,6 +1221,11 @@ static inline int audit_add_rule(struct audit_entry *entry,
 #ifdef CONFIG_AUDITSYSCALL
 	if (!dont_count)
 		audit_n_rules++;
+
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		if ((entry->rule.mask[i] & classes[AUDIT_CLASS_SIGNAL][i]) ||
+		    (entry->rule.mask[i] & classes[AUDIT_CLASS_SIGNAL_32][i]))
+			audit_signals++;
 #endif
 	mutex_unlock(&audit_filter_mutex);
 
@@ -1247,7 +1252,7 @@ static inline int audit_del_rule(struct audit_entry *entry,
 	LIST_HEAD(inotify_list);
 	int h, ret = 0;
 #ifdef CONFIG_AUDITSYSCALL
-	int dont_count = 0;
+	int i, dont_count = 0;
 
 	/* If either of these, don't count towards total */
 	if (entry->rule.listnr == AUDIT_FILTER_USER ||
@@ -1294,6 +1299,11 @@ static inline int audit_del_rule(struct audit_entry *entry,
 #ifdef CONFIG_AUDITSYSCALL
 	if (!dont_count)
 		audit_n_rules--;
+
+	for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+		if ((entry->rule.mask[i] & classes[AUDIT_CLASS_SIGNAL][i]) ||
+		    (entry->rule.mask[i] & classes[AUDIT_CLASS_SIGNAL_32][i]))
+			audit_signals--;
 #endif
 	mutex_unlock(&audit_filter_mutex);
 
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 1b427d9..2da8c2c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -84,6 +84,9 @@ extern int audit_enabled;
 /* number of audit rules */
 int audit_n_rules;
 
+/* determines whether we collect data for signals sent */
+int audit_signals;
+
 /* When fs/namei.c:getname() is called, we store the pointer in name and
  * we don't let putname() free it (instead we free all of the saved
  * pointers at syscall exit time).
@@ -176,6 +179,12 @@ struct audit_aux_data_path {
 	struct vfsmount		*mnt;
 };
 
+struct audit_aux_data_pid {
+	struct audit_aux_data	d;
+	pid_t			opid;
+	u32			osid;
+};
+
 /* The per-task audit context. */
 struct audit_context {
 	int		    dummy;	/* must be the first element */
@@ -204,6 +213,10 @@ struct audit_context {
 	unsigned long	    personality;
 	int		    arch;
 
+				/* optimize collection for single target pid */
+	pid_t		    opid;
+	u32		    osid;
+
 #if AUDIT_DEBUG
 	int		    put_count;
 	int		    ino_count;
@@ -860,6 +873,21 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 		audit_log_format(ab, " key=(null)");
 	audit_log_end(ab);
 
+	if (context->opid) {
+	    char *sectx = NULL;
+	    u32 len;
+
+	    ab = audit_log_start(context, GFP_KERNEL, AUDIT_TARGET_PID);
+	    audit_log_format(ab, "opid=%d ", context->opid);
+	    if (selinux_sid_to_string(context->osid, &sectx, &len)) {
+		    audit_log_format(ab, "osid=%u", context->osid);
+		    call_panic = 2;
+	    } else
+		    audit_log_format(ab, " obj=%s", sectx);
+	    kfree(sectx);
+	    audit_log_end(ab);
+	}
+
 	for (aux = context->aux; aux; aux = aux->next) {
 
 		ab = audit_log_start(context, GFP_KERNEL, aux->type);
@@ -867,6 +895,20 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 			continue; /* audit_panic has been called */
 
 		switch (aux->type) {
+		case AUDIT_TARGET_PID: {
+			struct audit_aux_data_pid *axi = (void *)aux;
+			char *sectx = NULL;
+			u32 len;
+
+			audit_log_format(ab, "opid=%d ", axi->opid);
+			if (selinux_sid_to_string(axi->osid, &sectx, &len)) {
+				audit_log_format(ab, "osid=%u", axi->osid);
+				call_panic = 2;
+			} else
+				audit_log_format(ab, " obj=%s", sectx);
+			kfree(sectx);
+			break; }
+
 		case AUDIT_MQ_OPEN: {
 			struct audit_aux_data_mq_open *axi = (void *)aux;
 			audit_log_format(ab,
@@ -1916,15 +1958,17 @@ int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
  * If the audit subsystem is being terminated, record the task (pid)
  * and uid that is doing that.
  */
-void __audit_signal_info(int sig, struct task_struct *t)
+int __audit_signal_info(int sig, struct task_struct *t)
 {
+	struct audit_aux_data_pid *ax;
+	struct task_struct *tsk = current;
+	struct audit_context *ctx = tsk->audit_context;
 	extern pid_t audit_sig_pid;
 	extern uid_t audit_sig_uid;
 	extern u32 audit_sig_sid;
 
-	if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
-		struct task_struct *tsk = current;
-		struct audit_context *ctx = tsk->audit_context;
+	if (audit_pid && t->tgid == audit_pid &&
+	    (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1)) {
 		audit_sig_pid = tsk->pid;
 		if (ctx)
 			audit_sig_uid = ctx->loginuid;
@@ -1932,4 +1976,28 @@ void __audit_signal_info(int sig, struct task_struct *t)
 			audit_sig_uid = tsk->uid;
 		selinux_get_task_sid(tsk, &audit_sig_sid);
 	}
+
+	if (!audit_signals) /* audit_context checked in wrapper */
+		return 0;
+
+	/* optimize the common case by putting first signal recipient directly
+	 * in audit_context */
+	if (!ctx->opid) {
+		ctx->opid = t->tgid;
+		selinux_get_task_sid(t, &ctx->osid);
+		return 0;
+	}
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax) {
+		return -ENOMEM;
+	}
+
+	ax->opid = t->tgid;
+	selinux_get_task_sid(t, &ax->osid);
+
+	ax->d.type = AUDIT_TARGET_PID;
+	ax->d.next = ctx->aux;
+	ctx->aux = (void *)ax;
+	return 0;
 }
diff --git a/kernel/signal.c b/kernel/signal.c
index e2a7d4b..10c183a 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -607,6 +607,11 @@ static int check_kill_permission(int sig, struct siginfo *info,
 	int error = -EINVAL;
 	if (!valid_signal(sig))
 		return error;
+
+	error = audit_signal_info(sig, t); /* Let audit system see the signal */
+	if (error)
+		return error;
+
 	error = -EPERM;
 	if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
 	    && ((sig != SIGCONT) ||
@@ -616,10 +621,7 @@ static int check_kill_permission(int sig, struct siginfo *info,
 	    && !capable(CAP_KILL))
 		return error;
 
-	error = security_task_kill(t, info, sig, 0);
-	if (!error)
-		audit_signal_info(sig, t); /* Let audit system see the signal */
-	return error;
+	return security_task_kill(t, info, sig, 0);
 }
 
 /* forward decl */
-- 
1.4.4.4




More information about the Linux-audit mailing list