From mboxrd@z Thu Jan 1 00:00:00 1970 From: Amy Griffis Subject: [PATCH 2/2] audit signal recipients Date: Wed, 14 Feb 2007 13:25:04 -0500 Message-ID: <20070214182504.GB17337@fc.hp.com> References: <20070214182431.GA17337@fc.hp.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Return-path: Received: from mx1.redhat.com (mx1.redhat.com [172.16.48.31]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id l1EIYivq010596 for ; Wed, 14 Feb 2007 13:34:44 -0500 Received: from atlrel6.hp.com (atlrel6.hp.com [156.153.255.205]) by mx1.redhat.com (8.13.1/8.13.1) with ESMTP id l1EIYN0h019213 for ; Wed, 14 Feb 2007 13:34:23 -0500 Received: from smtp1.fc.hp.com (smtp.fc.hp.com [15.15.136.127]) by atlrel6.hp.com (Postfix) with ESMTP id 5E42935DF6 for ; Wed, 14 Feb 2007 13:34:13 -0500 (EST) Received: from ldl.fc.hp.com (ldl.fc.hp.com [15.11.146.30]) by smtp1.fc.hp.com (Postfix) with ESMTP id 3045A133118 for ; Wed, 14 Feb 2007 18:34:13 +0000 (UTC) Received: from localhost (ldl.lart [127.0.0.1]) by ldl.fc.hp.com (Postfix) with ESMTP id 5526339C1BB for ; Wed, 14 Feb 2007 11:33:48 -0700 (MST) Received: from ldl.fc.hp.com ([127.0.0.1]) by localhost (ldl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 32403-03 for ; Wed, 14 Feb 2007 11:33:41 -0700 (MST) Content-Disposition: inline In-Reply-To: <20070214182431.GA17337@fc.hp.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-audit-bounces@redhat.com Errors-To: linux-audit-bounces@redhat.com To: linux-audit@redhat.com List-Id: linux-audit@redhat.com 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 --- 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, §x, &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, §x, &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 8072e56..1a4f602 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -583,6 +583,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) || @@ -592,10 +597,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