All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
To: linux-security-module@vger.kernel.org
Cc: linux-audit@redhat.com
Subject: Re: [PATCH] TaskTracker : Simplified thread information tracker.
Date: Mon, 23 Jun 2014 21:14:35 +0900	[thread overview]
Message-ID: <201406232114.EJD56725.JFOOHQFMFOVSLt@I-love.SAKURA.ne.jp> (raw)
In-Reply-To: <201405232144.JFB30480.OVMOOSFtQJHLFF@I-love.SAKURA.ne.jp>

Any comments on this proposal?

For now this module is occupying the exclusive LSM hook. But since this
module is for tracking per a "struct task_struct" attributes rather than
for making security decisions, I expect that this module can co-exist with
other LSM modules by not occupying the exclusive LSM hook.

Tetsuo Handa wrote:
> Yesterday I went to LinuxCon Japan 2014 and stopped at Red Hat's booth
> and Oracle's booth. I explained about this module ( using page 92 of
> http://I-love.SAKURA.ne.jp/tomoyo/LCJ2014-en.pdf ) and got positive
> responses from persons who have experienced troubleshooting jobs.
> I was convinced that I am not the only person who is bothered by lack of
> process history information in the logs. Therefore, I repost this module
> toward inclusion into mainline Linux kernel.
> 
> Changes from previous version ( http://lwn.net/Articles/575044/ ):
> 
>   (1) Assign a value to "u32 *seclen" in addition to "char *secdata"
>       at security_task_getsecid() hook.
> 
>   (2) Make calculation of time stamp a bit faster.
> 
> Background:
> 
>   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.
> 
>   I sometimes receive "which application triggered the event" questions on RHEL
>   systems. TOMOYO security module can track how the program was executed, but
>   TOMOYO is not yet available in Fedora/RHEL distributions.
> 
>   Although subj= field is added to the audit log if SELinux is not disabled,
>   SELinux is too difficult to customize as fine grained as I expect in order to
>   reflect how the program was executed. Therefore, I'm currently using AKARI
>   and SystemTap for emulating TOMOYO-like tracing.
> 
>   But AKARI and SystemTap do not help unless the kernel module is loaded before
>   the unexpected system event occurs. Generally, the administrator is failing
>   to record the first event, and has to wait for the same event to occur again
>   after loading the kernel module and/or configuring auditing. I came to think
>   that we want a built-in kernel routine which is automatically started upon
>   boot so that we don't fail to record the first event.
> 
> What I did:
> 
>   Assuming that multiple concurrent LSM support comes in the near future,
>   I wrote a trivial LSM module which emits TOMOYO-like information into the
>   audit logs.
> 
> Usage:
> 
>   Just register this LSM module. No configuration is needed. You will get
>   history of current thread in the form of comm name and time stamp pairs
>   in the subj= field of audit logs like examples shown in the patch
>   description.
> ----------
> >From ff68d3a4cd496bd263d2939848777fffc30cbc0b Mon Sep 17 00:00:00 2001
> From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> Date: Fri, 23 May 2014 21:31:56 +0900
> Subject: [PATCH] TaskTracker : Simplified thread information tracker.
> 
> Existing audit logs generated via system call auditing functionality include
> current thread's comm name. But it is not always sufficient for identifying
> which application has requested specific operations because comm name does not
> reflect history of current thread.
> 
> This security module adds functionality for adding current thread's history
> information like TOMOYO security module does, expecting that this module can
> help us getting more information from system call auditing functionality.
> 
>   type=USER_LOGIN msg=audit(1400879947.084:24): pid=4308 uid=0 auid=0 ses=2
>   subj="swapper/0(2014/05/23-21:17:30)=>init(2014/05/23-21:17:33)=>
>   switch_root(2014/05/23-21:17:34)=>init(2014/05/23-21:17:34)=>
>   sh(2014/05/23-21:17:56)=>mingetty(2014/05/23-21:17:56)=>
>   login(2014/05/23-21:19:05)" msg='op=login id=0 exe="/bin/login" hostname=?
>   addr=? terminal=tty1 res=success'
> 
>   type=SYSCALL msg=audit(1400880014.444:26): arch=40000003 syscall=11
>   success=yes exit=0 a0=8140f78 a1=812b7d8 a2=812b248 a3=812b7d8 items=2
>   ppid=4323 pid=4355 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0
>   fsgid=0 tty=pts0 ses=1 comm="tail" exe="/usr/bin/tail"
>   subj="swapper/0(2014/05/23-21:17:30)=>init(2014/05/23-21:17:33)=>
>   switch_root(2014/05/23-21:17:34)=>init(2014/05/23-21:17:34)=>
>   sh(2014/05/23-21:17:37)=>rc(2014/05/23-21:17:37)=>
>   S55sshd(2014/05/23-21:17:53)=>sshd(2014/05/23-21:17:53)=>
>   sshd(2014/05/23-21:18:17)=>bash(2014/05/23-21:18:21)=>
>   tail(2014/05/23-21:20:14)" key=(null)
> 
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
>  security/Kconfig                   |    6 +
>  security/Makefile                  |    2 +
>  security/tasktracker/Kconfig       |   35 +++++
>  security/tasktracker/Makefile      |    1 +
>  security/tasktracker/tasktracker.c |  282 ++++++++++++++++++++++++++++++++++++
>  5 files changed, 326 insertions(+), 0 deletions(-)
>  create mode 100644 security/tasktracker/Kconfig
>  create mode 100644 security/tasktracker/Makefile
>  create mode 100644 security/tasktracker/tasktracker.c
> 
> diff --git a/security/Kconfig b/security/Kconfig
> index beb86b5..14e7d27 100644
> --- a/security/Kconfig
> +++ b/security/Kconfig
> @@ -122,6 +122,7 @@ source security/smack/Kconfig
>  source security/tomoyo/Kconfig
>  source security/apparmor/Kconfig
>  source security/yama/Kconfig
> +source security/tasktracker/Kconfig
>  
>  source security/integrity/Kconfig
>  
> @@ -132,6 +133,7 @@ choice
>  	default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
>  	default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
>  	default DEFAULT_SECURITY_YAMA if SECURITY_YAMA
> +	default DEFAULT_SECURITY_TT if SECURITY_TT
>  	default DEFAULT_SECURITY_DAC
>  
>  	help
> @@ -153,6 +155,9 @@ choice
>  	config DEFAULT_SECURITY_YAMA
>  		bool "Yama" if SECURITY_YAMA=y
>  
> +	config DEFAULT_SECURITY_TT
> +		bool "TaskTracker" if SECURITY_TT=y
> +
>  	config DEFAULT_SECURITY_DAC
>  		bool "Unix Discretionary Access Controls"
>  
> @@ -165,6 +170,7 @@ config DEFAULT_SECURITY
>  	default "tomoyo" if DEFAULT_SECURITY_TOMOYO
>  	default "apparmor" if DEFAULT_SECURITY_APPARMOR
>  	default "yama" if DEFAULT_SECURITY_YAMA
> +	default "tt" if DEFAULT_SECURITY_TT
>  	default "" if DEFAULT_SECURITY_DAC
>  
>  endmenu
> diff --git a/security/Makefile b/security/Makefile
> index 05f1c93..28a90ed 100644
> --- a/security/Makefile
> +++ b/security/Makefile
> @@ -8,6 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK)		+= smack
>  subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
>  subdir-$(CONFIG_SECURITY_APPARMOR)	+= apparmor
>  subdir-$(CONFIG_SECURITY_YAMA)		+= yama
> +subdir-$(CONFIG_SECURITY_TT)		+= tasktracker
>  
>  # always enable default capabilities
>  obj-y					+= commoncap.o
> @@ -22,6 +23,7 @@ obj-$(CONFIG_AUDIT)			+= lsm_audit.o
>  obj-$(CONFIG_SECURITY_TOMOYO)		+= tomoyo/
>  obj-$(CONFIG_SECURITY_APPARMOR)		+= apparmor/
>  obj-$(CONFIG_SECURITY_YAMA)		+= yama/
> +obj-$(CONFIG_SECURITY_TT)		+= tasktracker/
>  obj-$(CONFIG_CGROUP_DEVICE)		+= device_cgroup.o
>  
>  # Object integrity file lists
> diff --git a/security/tasktracker/Kconfig b/security/tasktracker/Kconfig
> new file mode 100644
> index 0000000..6de5354
> --- /dev/null
> +++ b/security/tasktracker/Kconfig
> @@ -0,0 +1,35 @@
> +config SECURITY_TT
> +	bool "TaskTracker support"
> +	depends on SECURITY
> +	default n
> +	help
> +	  Existing audit logs generated via system call auditing functionality
> +	  include current thread's comm name. But it is not always sufficient
> +	  for identifying which application has requested specific operations
> +	  because comm name does not reflect history of current thread.
> +	  
> +	  This security module adds functionality for adding current thread's
> +	  history information like TOMOYO security module does, expecting that
> +	  this module can help us getting more information from system call
> +	  auditing functionality.
> +	  
> +	  If you are unsure how to answer this question, answer N.
> +	  
> +	  Usage:
> +	  
> +	  Just register this module. No configuration is needed.
> +	  
> +	  You will get history of current thread in the form of
> +	  comm name and time stamp pairs in the subj= field of audit logs
> +	  like an example shown below.
> +	  
> +	    type=SYSCALL msg=audit(1400880014.444:26): arch=40000003 syscall=11
> +	    success=yes exit=0 a0=8140f78 a1=812b7d8 a2=812b248 a3=812b7d8
> +	    items=2 ppid=4323 pid=4355 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0
> +	    egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="tail"
> +	    exe="/usr/bin/tail" subj="swapper/0(2014/05/23-21:17:30)=>
> +	    init(2014/05/23-21:17:33)=>switch_root(2014/05/23-21:17:34)=>
> +	    init(2014/05/23-21:17:34)=>sh(2014/05/23-21:17:37)=>
> +	    rc(2014/05/23-21:17:37)=>S55sshd(2014/05/23-21:17:53)=>
> +	    sshd(2014/05/23-21:17:53)=>sshd(2014/05/23-21:18:17)=>
> +	    bash(2014/05/23-21:18:21)=>tail(2014/05/23-21:20:14)" key=(null)
> diff --git a/security/tasktracker/Makefile b/security/tasktracker/Makefile
> new file mode 100644
> index 0000000..15d03ce
> --- /dev/null
> +++ b/security/tasktracker/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_SECURITY_TT) := tasktracker.o
> diff --git a/security/tasktracker/tasktracker.c b/security/tasktracker/tasktracker.c
> new file mode 100644
> index 0000000..ec4eb0c
> --- /dev/null
> +++ b/security/tasktracker/tasktracker.c
> @@ -0,0 +1,282 @@
> +/*
> + * tasktracker.c - Simplified thread information tracker.
> + *
> + * Copyright (C) 2010-2014  Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> + */
> +#include <linux/security.h>
> +#include <linux/binfmts.h>
> +
> +/* Wrapper structure for passing string buffer. */
> +struct tt_record {
> +	char history[1024];
> +};
> +
> +/* Structure for representing YYYY/MM/DD hh/mm/ss. */
> +struct tt_time {
> +	u16 year;
> +	u8 month;
> +	u8 day;
> +	u8 hour;
> +	u8 min;
> +	u8 sec;
> +};
> +
> +/**
> + * tt_get_time - Get current time in YYYY/MM/DD hh/mm/ss format.
> + *
> + * @stamp: Pointer to "struct tt_time".
> + *
> + * Returns nothing.
> + *
> + * This function does not handle Y2038 problem.
> + */
> +static void tt_get_time(struct tt_time *stamp)
> +{
> +	struct timeval tv;
> +	static const u16 tt_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 y = 1970;
> +	u8 m;
> +	bool r;
> +	time_t time;
> +	do_gettimeofday(&tv);
> +	time = tv.tv_sec;
> +	stamp->sec = time % 60;
> +	time /= 60;
> +	stamp->min = time % 60;
> +	time /= 60;
> +	stamp->hour = time % 24;
> +	time /= 24;
> +	if (time >= 16071) {
> +		/* Start from 2014/01/01 rather than 1970/01/01. */
> +		time -= 16071;
> +		y += 44;
> +	}
> +	while (1) {
> +		const unsigned short days = (y & 3) ? 365 : 366;
> +		if (time < days)
> +			break;
> +		time -= days;
> +		y++;
> +	}
> +	r = (y & 3) == 0;
> +	for (m = 0; m < 11 && time >= tt_eom[r][m]; m++)
> +		;
> +	if (m)
> +		time -= tt_eom[r][m - 1];
> +	stamp->year = y;
> +	stamp->month = ++m;
> +	stamp->day = ++time;
> +}
> +
> +/**
> + * tt_update_record - Update "struct tt_record" for given credential.
> + *
> + * @record: Pointer to "struct tt_record".
> + *
> + * Returns nothing.
> + */
> +static void tt_update_record(struct tt_record *record)
> +{
> +	char *cp;
> +	int i;
> +	struct tt_time stamp;
> +	tt_get_time(&stamp);
> +	/*
> +	 * Lockless update because current thread's record is not concurrently
> +	 * accessible, for "struct cred"->security is not visible from other
> +	 * threads because this function is called upon only boot up and
> +	 * successful execve() operation.
> +	 */
> +	cp = record->history;
> +	i = strlen(cp);
> +	while (i >= sizeof(record->history) - (TASK_COMM_LEN * 4 + 30)) {
> +		/*
> +		 * Since this record is not for making security decision,
> +		 * I don't care by-chance matching "=>" in task's commname.
> +		 */
> +		char *cp2 = strstr(cp + 2, "=>");
> +		if (!cp2)
> +			return;
> +		memmove(cp + 1, cp2, strlen(cp2) + 1);
> +		i = strlen(cp);
> +	}
> +	if (!i)
> +		*cp++ = '"';
> +	else {
> +		cp += i - 1;
> +		*cp++ = '=';
> +		*cp++ = '>';
> +	}
> +	/*
> +	 * Lockless read because this is current thread and being unexpectedly
> +	 * modified by other thread is not a fatal problem.
> +	 */
> +	for (i = 0; i < TASK_COMM_LEN; i++) {
> +		const unsigned char c = current->comm[i];
> +		if (!c)
> +			break;
> +		else if (c == '"' || c == '\\' || c < 0x21 || c > 0x7e) {
> +			*cp++ = '\\';
> +			*cp++ = (c >> 6) + '0';
> +			*cp++ = ((c >> 3) & 7) + '0';
> +			*cp++ = (c & 7) + '0';
> +		} else
> +			*cp++ = c;
> +	}
> +	sprintf(cp, "(%04u/%02u/%02u-%02u:%02u:%02u)\"", stamp.year,
> +		stamp.month, stamp.day, stamp.hour, stamp.min, stamp.sec);
> +}
> +
> +/**
> + * tt_find_record - Find "struct tt_record" for given credential.
> + *
> + * @cred: Pointer to "struct cred".
> + *
> + * Returns pointer to "struct tt_record".
> + */
> +static inline struct tt_record *tt_find_record(const struct cred *cred)
> +{
> +	return cred->security;
> +}
> +
> +/**
> + * tt_cred_alloc_blank - Allocate memory for new credentials.
> + *
> + * @new: Pointer to "struct cred".
> + * @gfp: Memory allocation flags.
> + *
> + * Returns 0 on success, negative value otherwise.
> + */
> +static int tt_cred_alloc_blank(struct cred *new, gfp_t gfp)
> +{
> +	new->security = kzalloc(sizeof(struct tt_record), gfp);
> +	return new->security ? 0 : -ENOMEM;
> +}
> +
> +/**
> + * tt_cred_prepare - Allocate memory for new credentials.
> + *
> + * @new: Pointer to "struct cred".
> + * @old: Pointer to "struct cred".
> + * @gfp: Memory allocation flags.
> + *
> + * Returns 0 on success, negative value otherwise.
> + */
> +static int tt_cred_prepare(struct cred *new, const struct cred *old,
> +			   gfp_t gfp)
> +{
> +	if (tt_cred_alloc_blank(new, gfp))
> +		return -ENOMEM;
> +	strcpy(tt_find_record(new)->history, tt_find_record(old)->history);
> +	return 0;
> +}
> +
> +/**
> + * tt_cred_free - Release memory used by credentials.
> + *
> + * @cred: Pointer to "struct cred".
> + *
> + * Returns nothing.
> + */
> +static void tt_cred_free(struct cred *cred)
> +{
> +	kfree(cred->security);
> +}
> +
> +/**
> + * tt_cred_transfer - Transfer "struct tt_record" between credentials.
> + *
> + * @new: Pointer to "struct cred".
> + * @old: Pointer to "struct cred".
> + *
> + * Returns nothing.
> + */
> +static void tt_cred_transfer(struct cred *new, const struct cred *old)
> +{
> +	strcpy(tt_find_record(new)->history, tt_find_record(old)->history);
> +}
> +
> +/**
> + * tt_bprm_committing_creds - A hook which is called when do_execve() succeeded.
> + *
> + * @bprm: Pointer to "struct linux_binprm".
> + *
> + * Returns nothing.
> + */
> +static void tt_bprm_committing_creds(struct linux_binprm *bprm)
> +{
> +	tt_update_record(tt_find_record(bprm->cred));
> +}
> +
> +/**
> + * tt_task_getsecid - Check whether to audit or not.
> + *
> + * @p:     Pointer to "struct task_struct".
> + * @secid: Pointer to flag.
> + */
> +static void tt_task_getsecid(struct task_struct *p, u32 *secid)
> +{
> +	*secid = (p == current);
> +}
> +
> +/**
> + * tt_secid_to_secctx - Allocate memory used for auditing.
> + *
> + * @secid:   Bool flag to allocate.
> + * @secdata: Pointer to allocate memory.
> + * @seclen:  Size of allocated memory.
> + *
> + * Returns 0 on success, -EINVAL otherwise.
> + */
> +static int tt_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> +{
> +	struct tt_record *record;
> +	/* Ignore unless current thread's record is requested. */
> +	if (secid != 1)
> +		return -EINVAL;
> +	/*
> +	 * We don't need to duplicate the string because current thread's
> +	 * record is updated upon only boot up and successful execve()
> +	 * operation, even if current thread's record is shared between
> +	 * multiple threads.
> +	 */
> +	record = tt_find_record(current->real_cred);
> +	*secdata = record->history;
> +	*seclen = strlen(record->history);
> +	return 0;
> +}
> +
> +/* List of hooks. */
> +static struct security_operations tasktracker_ops = {
> +	.name                  = "tt",
> +	.secid_to_secctx       = tt_secid_to_secctx,
> +	.task_getsecid         = tt_task_getsecid,
> +	.cred_prepare          = tt_cred_prepare,
> +	.cred_free             = tt_cred_free,
> +	.cred_alloc_blank      = tt_cred_alloc_blank,
> +	.cred_transfer         = tt_cred_transfer,
> +	.bprm_committing_creds = tt_bprm_committing_creds,
> +};
> +
> +/**
> + * tt_init - Initialize this module.
> + *
> + * Returns 0 on success, panic otherwise.
> + */
> +static int __init tt_init(void)
> +{
> +	struct cred *cred = (struct cred *) current_cred();
> +	if (!security_module_enable(&tasktracker_ops))
> +		return 0;
> +	if (tt_cred_alloc_blank(cred, GFP_ATOMIC) ||
> +	    register_security(&tasktracker_ops))
> +		panic("Failure registering TaskTracker");
> +	tt_update_record(tt_find_record(cred));
> +	pr_info("TaskTracker initialized\n");
> +	return 0;
> +}
> +
> +security_initcall(tt_init);
> -- 
> 1.7.1
> 

  reply	other threads:[~2014-06-23 12:14 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-05-23 12:44 [PATCH] TaskTracker : Simplified thread information tracker Tetsuo Handa
2014-06-23 12:14 ` Tetsuo Handa [this message]
2014-06-24 14:00   ` Steve Grubb
2014-06-26 11:40     ` Tetsuo Handa
2014-09-27  1:02       ` Tetsuo Handa
2014-09-27 13:14         ` Steve Grubb
2014-09-27 15:13           ` Tetsuo Handa
2014-09-27 15:40             ` Steve Grubb
2014-09-28 10:24               ` [PATCH] audit: Emit history of thread's comm name Tetsuo Handa
2014-10-07 21:30             ` [PATCH] TaskTracker : Simplified thread information tracker Richard Guy Briggs
2014-10-10 12:40               ` Tetsuo Handa
2014-10-10 12:49                 ` Richard Guy Briggs
2015-01-04 11:50                   ` Tetsuo Handa
2015-01-05 18:07                     ` Richard Guy Briggs
2015-01-12  6:13                       ` Tetsuo Handa
2015-01-12 15:14                         ` Steve Grubb
2015-01-12 20:51                           ` Paul Moore
2015-01-20 13:20                           ` Tetsuo Handa
2015-01-12 15:21                         ` Richard Guy Briggs
2015-01-19 15:25                     ` Richard Guy Briggs

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=201406232114.EJD56725.JFOOHQFMFOVSLt@I-love.SAKURA.ne.jp \
    --to=penguin-kernel@i-love.sakura.ne.jp \
    --cc=linux-audit@redhat.com \
    --cc=linux-security-module@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.