Messages in this thread |  | | Date | Fri, 10 Oct 2014 08:49:23 -0400 | From | Richard Guy Briggs <> | Subject | Re: [PATCH] TaskTracker : Simplified thread information tracker. |
| |
On 14/10/10, Tetsuo Handa wrote: > Steve Grubb wrote: > > Hello, > > > > On Sun, 28 Sep 2014 00:13:14 +0900 > > Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> wrote: > > > Steve Grubb wrote: > > > > On Sat, 27 Sep 2014 10:02:44 +0900 > > > > Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> wrote: > > > > > > > > > May I continue proposing this functionality? > > > > > > > > From the audit perspective, sure. I think we were expecting a > > > > revised patch after the comments. Other groups may have different > > > > thoughts, though. > > > > > > > > -Steve > > > > > > OK, thank you. Before posting a revised patch, can I hear answers > > > about specification questions listed below? > > > > Sure. > > > > > (Q1) Where can I find which bytes in $value need to be escaped when > > > emitting a record like name='$value' ? > > > > I have written a specification that describes how to write well formed > > audit events to help with questions like this. You can find it here: > > > > http://people.redhat.com/sgrubb/audit/audit-events.txt > > > > If you know that a field is under user control, it must be escaped so > > that they cannot try to trick the parser. > > > > > Is 0x20 in $value permitted? > > > > No. That is the separator between fields, so it cannot be allowed. What > > we suggest is to use a dash or hyphen between if you are logging a > > phrase that cannot be altered by the user. For example, you may have an > > op field saying it deleted a rule. You would do it as op=rule-deleted. > > However, we do not suggest that for user controlled fields. Just escape > > it by calling audit_log_untrustedstring() if in the kernel. There are > > examples in the page I mention above. > > > > > (Q2) Does auxiliary record work with only type=SYSCALL case? > > > > Auxiliary records compliment a syscall record by adding extra > > information. PATH, IPC, CWD, and EXECVE are some examples. They get > > emitted in audit_log_exit() if you wanted to look at them in more > > detail. > > > > HTH... > > Richard Guy Briggs wrote: > > On 14/09/28, Tetsuo Handa wrote: > > > (Q2) Does auxiliary record work with only type=SYSCALL case? > > > > Auxiliary records don't work with AUDIT_LOGIN because that record has a > > NULL context. Similarly for core dumps (AUDIT_ANOM_ABEND), AUDIT_SECCOMP, > > configuration changes (AUDIT_CONFIG_CHANGE, AUDIT_FEATURE_CHANGE), most > > (all?) AUDIT_USER_* messages. > > > I see, thank you. > > Although I feel that, from the point of view of troubleshooting, emitting > history of thread's comm name into NULL-context records would help sysadmin > to map login session and operations a user did from that login session, > I'm OK with starting history of thread's comm name as auxiliary records > (i.e. not emitted into NULL-context records). > > Adding LKML for reviewers. What else can I do for merging this patch?
I'm willing to take it with some reflection and no significant objections, in particular from userspace audit. I'll have a closer look at it.
> ---------- > >From 2beb93e870e9c1a6391d8706aa84a608b8353c2a Mon Sep 17 00:00:00 2001 > From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> > Date: Sun, 28 Sep 2014 19:20:16 +0900 > Subject: [PATCH] audit: Emit history of thread's comm name. > > When an unexpected system event (e.g. reboot) occurs, the administrator may > want to identify which application triggered the event. System call auditing > could be used for recording such event. However, the audit log may not be > able to provide sufficient information for identifying the application > because the audit log does not reflect how the program was executed. > > This patch adds ability to trace how the program was executed and emit it > as an auxiliary record in the form of comm name and time stamp pairs as of > execve(). > > type=UNKNOWN[1329] msg=audit(1403741314.019:22): history=' > swapper/0(2014/06/26-09:06:04)=>init(2014/06/26-09:06:10)=> > switch_root(2014/06/26-09:06:13)=>init(2014/06/26-09:06:13)=> > sh(2014/06/26-00:06:27)=>rc(2014/06/26-00:06:27)=> > S55sshd(2014/06/26-00:06:35)=>sshd(2014/06/26-00:06:35)=> > sshd(2014/06/26-00:06:40)=>bash(2014/06/26-00:06:43)=> > tail(2014/06/26-00:08:34)' > > Note that only char < 0x21, char > 0x7e, '\'', '\\' and '=' are escaped > using \ooo style octal value rather than converting all characters to XX > style hexadecimal value. > > Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> > --- > fs/exec.c | 1 + > include/linux/audit.h | 4 ++ > include/linux/init_task.h | 5 ++ > include/linux/sched.h | 3 + > include/uapi/linux/audit.h | 1 + > kernel/audit.c | 1 + > kernel/auditsc.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ > 7 files changed, 128 insertions(+), 0 deletions(-) > > diff --git a/fs/exec.c b/fs/exec.c > index a2b42a9..1e81709 100644 > --- a/fs/exec.c > +++ b/fs/exec.c > @@ -1191,6 +1191,7 @@ void install_exec_creds(struct linux_binprm *bprm) > commit_creds(bprm->cred); > bprm->cred = NULL; > > + audit_update_history(); > /* > * Disable monitoring for regular users > * when executing setuid binaries. Must > diff --git a/include/linux/audit.h b/include/linux/audit.h > index 22cfddb..97d08e1 100644 > --- a/include/linux/audit.h > +++ b/include/linux/audit.h > @@ -206,6 +206,8 @@ static inline void audit_ptrace(struct task_struct *t) > __audit_ptrace(t); > } > > +extern void audit_update_history(void); > + > /* Private API (for audit.c only) */ > extern unsigned int audit_serial(void); > extern int auditsc_get_stamp(struct audit_context *ctx, > @@ -419,6 +421,8 @@ static inline void audit_mmap_fd(int fd, int flags) > { } > static inline void audit_ptrace(struct task_struct *t) > { } > +static inline void audit_update_history(void) > +{ } > #define audit_n_rules 0 > #define audit_signals 0 > #endif /* CONFIG_AUDITSYSCALL */ > diff --git a/include/linux/init_task.h b/include/linux/init_task.h > index 2bb4c4f..7a5695b 100644 > --- a/include/linux/init_task.h > +++ b/include/linux/init_task.h > @@ -98,8 +98,12 @@ extern struct group_info init_groups; > #define INIT_IDS \ > .loginuid = INVALID_UID, \ > .sessionid = (unsigned int)-1, > +extern char init_task_history[]; > +#define INIT_THREAD_HISTORY \ > + .comm_history = init_task_history, > #else > #define INIT_IDS > +#define INIT_THREAD_HISTORY > #endif > > #ifdef CONFIG_TREE_PREEMPT_RCU > @@ -227,6 +231,7 @@ extern struct task_group root_task_group; > INIT_CPUSET_SEQ(tsk) \ > INIT_RT_MUTEXES(tsk) \ > INIT_VTIME(tsk) \ > + INIT_THREAD_HISTORY \ > } > > > diff --git a/include/linux/sched.h b/include/linux/sched.h > index b867a4d..fd3cdaf 100644 > --- a/include/linux/sched.h > +++ b/include/linux/sched.h > @@ -1644,6 +1644,9 @@ struct task_struct { > unsigned int sequential_io; > unsigned int sequential_io_avg; > #endif > +#ifdef CONFIG_AUDITSYSCALL > + char *comm_history; > +#endif > }; > > /* Future-safe accessor for struct task_struct's cpus_allowed. */ > diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h > index 3b9ff33..a6a8ee8 100644 > --- a/include/uapi/linux/audit.h > +++ b/include/uapi/linux/audit.h > @@ -110,6 +110,7 @@ > #define AUDIT_SECCOMP 1326 /* Secure Computing event */ > #define AUDIT_PROCTITLE 1327 /* Proctitle emit event */ > #define AUDIT_FEATURE_CHANGE 1328 /* audit log listing feature changes */ > +#define AUDIT_PROCHISTORY 1329 /* Commname history emit event */ > > #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ > #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ > diff --git a/kernel/audit.c b/kernel/audit.c > index ba2ff5a..252544a 100644 > --- a/kernel/audit.c > +++ b/kernel/audit.c > @@ -1163,6 +1163,7 @@ static int __init audit_init(void) > { > int i; > > + audit_update_history(); > if (audit_initialized == AUDIT_DISABLED) > return 0; > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c > index 21eae3c..2e5ee14 100644 > --- a/kernel/auditsc.c > +++ b/kernel/auditsc.c > @@ -85,6 +85,9 @@ > /* max length to print of cmdline/proctitle value during audit */ > #define MAX_PROCTITLE_AUDIT_LEN 128 > > +/* thread's comm name history length */ > +#define COMM_HISTORY_SIZE 1024 > + > /* number of audit rules */ > int audit_n_rules; > > @@ -950,6 +953,11 @@ int audit_alloc(struct task_struct *tsk) > enum audit_state state; > char *key = NULL; > > + tsk->comm_history = kmemdup(current->comm_history, COMM_HISTORY_SIZE, > + GFP_KERNEL); > + if (!tsk->comm_history) > + return -ENOMEM; > + > if (likely(!audit_ever_enabled)) > return 0; /* Return if not auditing. */ > > @@ -960,6 +968,8 @@ int audit_alloc(struct task_struct *tsk) > } > > if (!(context = audit_alloc_context(state))) { > + kfree(tsk->comm_history); > + tsk->comm_history = NULL; > kfree(key); > audit_log_lost("out of memory in audit_alloc"); > return -ENOMEM; > @@ -1349,6 +1359,17 @@ out: > audit_log_end(ab); > } > > +static void audit_log_history(struct audit_context *context) > +{ > + struct audit_buffer *ab; > + > + ab = audit_log_start(context, GFP_KERNEL, AUDIT_PROCHISTORY); > + if (!ab) > + return; /* audit_panic or being filtered */ > + audit_log_format(ab, "history='%s'", current->comm_history); > + audit_log_end(ab); > +} > + > static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) > { > int i, call_panic = 0; > @@ -1467,6 +1488,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts > } > > audit_log_proctitle(tsk, context); > + audit_log_history(context); > > /* Send end of event record to help user space know we are finished */ > ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE); > @@ -1486,6 +1508,8 @@ void __audit_free(struct task_struct *tsk) > { > struct audit_context *context; > > + kfree(tsk->comm_history); > + tsk->comm_history = NULL; > context = audit_take_context(tsk, 0, 0); > if (!context) > return; > @@ -2503,3 +2527,92 @@ struct list_head *audit_killed_trees(void) > return NULL; > return &ctx->killed_trees; > } > + > +char init_task_history[COMM_HISTORY_SIZE]; > + > +/** > + * audit_update_history - Update current->comm_history field. > + * > + * Returns nothing. > + * > + * Update is done locklessly because current thread's history is updated by > + * only current thread upon boot up and successful execve() operation, and > + * we don't read other thread's history. > + */ > +void audit_update_history(void) > +{ > + static const u16 eom[2][12] = { > + { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, > + { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } > + }; > + u16 year = 1970; > + u16 day; > + u8 month; > + u8 hour; > + u8 minute; > + u8 second; > + bool r; > + time_t now = get_seconds(); > + char *history = current->comm_history; > + int pos = strlen(history); > + > + /* Make some room by truncating old history. */ > + while (pos >= COMM_HISTORY_SIZE - (TASK_COMM_LEN * 4 + 30)) { > + char *cp = strchr(history + 1, '='); > + > + if (unlikely(!cp)) > + return; > + pos -= cp - history; > + memmove(history, cp, pos + 1); > + } > + if (pos) { > + history += pos; > + *history++ = '='; > + *history++ = '>'; > + } > + /* > + * Read locklessly because this is current thread and being > + * unexpectedly modified by other thread is not a fatal problem. > + */ > + for (pos = 0; pos < TASK_COMM_LEN; pos++) { > + const unsigned char c = current->comm[pos]; > + > + if (!c) > + break; > + else if (c == '\'' || c == '\\' || c == '=' || c < 0x21 || > + c > 0x7e) { > + *history++ = '\\'; > + *history++ = (c >> 6) + '0'; > + *history++ = ((c >> 3) & 7) + '0'; > + *history++ = (c & 7) + '0'; > + } else > + *history++ = c; > + } > + /* Append current time in "(YYYY/MM/DD-hh:mm:ss)" format. */ > + second = now % 60; > + now /= 60; > + minute = now % 60; > + now /= 60; > + hour = now % 24; > + day = now / 24; > + if (day >= 16071) { > + /* Start from 2014/01/01 rather than 1970/01/01. */ > + day -= 16071; > + year += 44; > + } > + while (1) { > + const u16 days = (year & 3) ? 365 : 366; > + > + if (day < days) > + break; > + day -= days; > + year++; > + } > + r = (year & 3) == 0; > + for (month = 0; month < 11 && day >= eom[r][month]; month++) > + ; > + if (month) > + day -= eom[r][month - 1]; > + snprintf(history, 22, "(%04u/%02u/%02u-%02u:%02u:%02u)", year, > + month + 1, day + 1, hour, minute, second); > +} > -- > 1.7.1
- RGB
-- Richard Guy Briggs <rbriggs@redhat.com> Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red Hat Remote, Ottawa, Canada Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545
|  |