[nf PATCH 1/2] netfilter: nf_tables: Audit log setelem reset
by Phil Sutter
Since set element reset is not integrated into nf_tables' transaction
logic, an explicit log call is needed, similar to NFT_MSG_GETOBJ_RESET
handling.
For the sake of simplicity, catchall element reset will always generate
a dedicated log entry. This relieves nf_tables_dump_set() from having to
adjust the logged element count depending on whether a catchall element
was found or not.
Cc: Richard Guy Briggs <rgb(a)redhat.com>
Fixes: 079cd633219d7 ("netfilter: nf_tables: Introduce NFT_MSG_GETSETELEM_RESET")
Signed-off-by: Phil Sutter <phil(a)nwl.cc>
---
include/linux/audit.h | 1 +
kernel/auditsc.c | 1 +
net/netfilter/nf_tables_api.c | 31 ++++++++++++++++++++++++++++---
3 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 6a3a9e122bb5e..192bf03aacc52 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -117,6 +117,7 @@ enum audit_nfcfgop {
AUDIT_NFT_OP_OBJ_RESET,
AUDIT_NFT_OP_FLOWTABLE_REGISTER,
AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
+ AUDIT_NFT_OP_SETELEM_RESET,
AUDIT_NFT_OP_INVALID,
};
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index addeed3df15d3..38481e3181975 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -143,6 +143,7 @@ static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
{ AUDIT_NFT_OP_OBJ_RESET, "nft_reset_obj" },
{ AUDIT_NFT_OP_FLOWTABLE_REGISTER, "nft_register_flowtable" },
{ AUDIT_NFT_OP_FLOWTABLE_UNREGISTER, "nft_unregister_flowtable" },
+ { AUDIT_NFT_OP_SETELEM_RESET, "nft_reset_setelem" },
{ AUDIT_NFT_OP_INVALID, "nft_invalid" },
};
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 1ddbdca4e47d6..a1218ea4e0c3d 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -102,6 +102,7 @@ static const u8 nft2audit_op[NFT_MSG_MAX] = { // enum nf_tables_msg_types
[NFT_MSG_NEWFLOWTABLE] = AUDIT_NFT_OP_FLOWTABLE_REGISTER,
[NFT_MSG_GETFLOWTABLE] = AUDIT_NFT_OP_INVALID,
[NFT_MSG_DELFLOWTABLE] = AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
+ [NFT_MSG_GETSETELEM_RESET] = AUDIT_NFT_OP_SETELEM_RESET,
};
static void nft_validate_state_update(struct nft_table *table, u8 new_validate_state)
@@ -5661,13 +5662,25 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
return nf_tables_fill_setelem(args->skb, set, elem, args->reset);
}
+static void audit_log_nft_set_reset(const struct nft_table *table,
+ unsigned int base_seq,
+ unsigned int nentries)
+{
+ char *buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, base_seq);
+
+ audit_log_nfcfg(buf, table->family, nentries,
+ AUDIT_NFT_OP_SETELEM_RESET, GFP_ATOMIC);
+ kfree(buf);
+}
+
struct nft_set_dump_ctx {
const struct nft_set *set;
struct nft_ctx ctx;
};
static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
- const struct nft_set *set, bool reset)
+ const struct nft_set *set, bool reset,
+ unsigned int base_seq)
{
struct nft_set_elem_catchall *catchall;
u8 genmask = nft_genmask_cur(net);
@@ -5683,6 +5696,8 @@ static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
elem.priv = catchall->elem;
ret = nf_tables_fill_setelem(skb, set, &elem, reset);
+ if (reset && !ret)
+ audit_log_nft_set_reset(set->table, base_seq, 1);
break;
}
@@ -5762,12 +5777,17 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
set->ops->walk(&dump_ctx->ctx, set, &args.iter);
if (!args.iter.err && args.iter.count == cb->args[0])
- args.iter.err = nft_set_catchall_dump(net, skb, set, reset);
+ args.iter.err = nft_set_catchall_dump(net, skb, set,
+ reset, cb->seq);
rcu_read_unlock();
nla_nest_end(skb, nest);
nlmsg_end(skb, nlh);
+ if (reset && args.iter.count > args.iter.skip)
+ audit_log_nft_set_reset(table, cb->seq,
+ args.iter.count - args.iter.skip);
+
if (args.iter.err && args.iter.err != -EMSGSIZE)
return args.iter.err;
if (args.iter.count == cb->args[0])
@@ -5992,13 +6012,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
struct netlink_ext_ack *extack = info->extack;
u8 genmask = nft_genmask_cur(info->net);
u8 family = info->nfmsg->nfgen_family;
+ int rem, err = 0, nelems = 0;
struct net *net = info->net;
struct nft_table *table;
struct nft_set *set;
struct nlattr *attr;
struct nft_ctx ctx;
bool reset = false;
- int rem, err = 0;
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
genmask, 0);
@@ -6041,8 +6061,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
NL_SET_BAD_ATTR(extack, attr);
break;
}
+ nelems++;
}
+ if (reset)
+ audit_log_nft_set_reset(table, nft_pernet(net)->base_seq,
+ nelems);
+
return err;
}
--
2.41.0
1 year, 3 months
[PATCH] audit: add task history record
by Tetsuo Handa
When an unexpected system event occurs, the administrator may want to
identify which application triggered the event. For example, unexpected
process termination is still a real concern enough to write articles
like https://access.redhat.com/solutions/165993 .
This patch adds a record which emits TOMOYO-like task history information
into the audit logs for better understanding of unexpected system events.
type=UNKNOWN[1340] msg=audit(1691750738.271:108): history="name=swapper/0;pid=1;start=20230811194329=>name=init;pid=1;start=20230811194343=>name=systemd;pid=1;start=20230811194439=>name=sshd;pid=3660;start=20230811104504=>name=sshd;pid=3767;start=20230811104535"
To be able to avoid bloating audit log files due to this information, this
patch uses audit_history= kernel command line parameter that controls max
length of history in bytes (default is 1024, and setting to 0 disables
recording and emitting).
Unlike execve()'s argv record, records in this history information is
emitted as one string in order to reduce bloat of the audit log files.
This information can be split into an array using => as the tokenizer.
But don't expect that you can compare array elements throughout the whole
audit logs by splitting into an array, for old records get removed from
history when history became too long to append the newest record. This
history information is meant to be interpreted by humans rather than be
analyzed by programs.
Signed-off-by: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
---
fs/exec.c | 1 +
include/linux/audit.h | 5 ++
include/linux/sched.h | 1 +
include/uapi/linux/audit.h | 1 +
init/init_task.c | 7 +++
kernel/audit.c | 1 +
kernel/auditsc.c | 108 +++++++++++++++++++++++++++++++++++++
7 files changed, 124 insertions(+)
diff --git a/fs/exec.c b/fs/exec.c
index 1a827d55ba94..5c8776f692c5 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1381,6 +1381,7 @@ int begin_new_exec(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 6a3a9e122bb5..6291d0f76541 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -397,6 +397,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 void __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode);
@@ -701,6 +703,9 @@ static inline void audit_ntp_log(const struct audit_ntp_data *ad)
static inline void audit_ptrace(struct task_struct *t)
{ }
+static inline void audit_update_history(void)
+{ }
+
static inline void audit_log_nfcfg(const char *name, u8 af,
unsigned int nentries,
enum audit_nfcfgop op, gfp_t gfp)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 609bde814cb0..f32076b6b733 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1112,6 +1112,7 @@ struct task_struct {
#ifdef CONFIG_AUDIT
#ifdef CONFIG_AUDITSYSCALL
struct audit_context *audit_context;
+ char *comm_history;
#endif
kuid_t loginuid;
unsigned int sessionid;
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index d676ed2b246e..186c0b5ca1b6 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -122,6 +122,7 @@
#define AUDIT_OPENAT2 1337 /* Record showing openat2 how args */
#define AUDIT_DM_CTRL 1338 /* Device Mapper target control */
#define AUDIT_DM_EVENT 1339 /* Device Mapper events */
+#define AUDIT_PROCHISTORY 1340 /* 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/init/init_task.c b/init/init_task.c
index ff6c4b9bfe6b..e3d481d1b010 100644
--- a/init/init_task.c
+++ b/init/init_task.c
@@ -57,6 +57,10 @@ unsigned long init_shadow_call_stack[SCS_SIZE / sizeof(long)]
};
#endif
+#ifdef CONFIG_AUDITSYSCALL
+extern char init_task_audit_history[];
+#endif
+
/*
* Set up the first task table, touch at your own risk!. Base=0,
* limit=0x1fffff (=2MB)
@@ -137,6 +141,9 @@ struct task_struct init_task
#ifdef CONFIG_AUDIT
.loginuid = INVALID_UID,
.sessionid = AUDIT_SID_UNSET,
+#ifdef CONFIG_AUDITSYSCALL
+ .comm_history = init_task_audit_history,
+#endif
#endif
#ifdef CONFIG_PERF_EVENTS
.perf_event_mutex = __MUTEX_INITIALIZER(init_task.perf_event_mutex),
diff --git a/kernel/audit.c b/kernel/audit.c
index 9bc0b0301198..034952abd83d 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1674,6 +1674,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 addeed3df15d..6f1b124da2fe 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -80,6 +80,9 @@
/* max length to print of cmdline/proctitle value during audit */
#define MAX_PROCTITLE_AUDIT_LEN 128
+/* max length for thread's comm name history */
+static unsigned int audit_history_size __ro_after_init = 1024;
+
/* number of audit rules */
int audit_n_rules;
@@ -1055,6 +1058,12 @@ int audit_alloc(struct task_struct *tsk)
enum audit_state state;
char *key = NULL;
+ if (audit_history_size) {
+ tsk->comm_history = kmemdup(current->comm_history, audit_history_size, GFP_KERNEL);
+ if (!tsk->comm_history)
+ return -ENOMEM;
+ }
+
if (likely(!audit_ever_enabled))
return 0;
@@ -1065,6 +1074,10 @@ int audit_alloc(struct task_struct *tsk)
}
if (!(context = audit_alloc_context(state))) {
+ if (audit_history_size) {
+ kfree(tsk->comm_history);
+ tsk->comm_history = NULL;
+ }
kfree(key);
audit_log_lost("out of memory in audit_alloc");
return -ENOMEM;
@@ -1671,6 +1684,18 @@ static void audit_log_uring(struct audit_context *ctx)
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=");
+ audit_log_untrustedstring(ab, current->comm_history);
+ audit_log_end(ab);
+}
+
static void audit_log_exit(void)
{
int i, call_panic = 0;
@@ -1805,6 +1830,8 @@ static void audit_log_exit(void)
if (context->context == AUDIT_CTX_SYSCALL)
audit_log_proctitle();
+ if (audit_history_size)
+ 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);
@@ -1824,6 +1851,10 @@ void __audit_free(struct task_struct *tsk)
{
struct audit_context *context = tsk->audit_context;
+ if (audit_history_size) {
+ kfree(tsk->comm_history);
+ tsk->comm_history = NULL;
+ }
if (!context)
return;
@@ -3034,3 +3065,80 @@ struct list_head *audit_killed_trees(void)
return NULL;
return &ctx->killed_trees;
}
+
+char init_task_audit_history[4096];
+
+static int __init audit_history_setup(char *str)
+{
+ unsigned int size;
+
+ if (kstrtouint(str, 10, &size))
+ return -EINVAL;
+ if (size > sizeof(init_task_audit_history))
+ size = sizeof(init_task_audit_history);
+ audit_history_size = size;
+ return 0;
+}
+early_param("audit_history", audit_history_setup);
+
+void audit_update_history(void)
+{
+ int i;
+ int required;
+ struct tm tm;
+ char buf[256];
+ char *cp = buf;
+
+ if (!audit_history_size)
+ return;
+
+ cp += snprintf(buf, sizeof(buf) - 1, "name=");
+ for (i = 0; i < TASK_COMM_LEN; i++) {
+ const unsigned char c = current->comm[i];
+
+ if (!c)
+ break;
+ if (isalnum(c) || c == '.' || c == '_' || c == '-' || c == '/') {
+ *cp++ = c;
+ continue;
+ }
+ *cp++ = '\\';
+ *cp++ = (c >> 6) + '0';
+ *cp++ = ((c >> 3) & 7) + '0';
+ *cp++ = (c & 7) + '0';
+ }
+ /* Append PID. */
+ cp += snprintf(cp, buf - cp + sizeof(buf) - 1, ";pid=%u",
+ current->pid);
+ /* Append timestamp. */
+ time64_to_tm(ktime_get_real_seconds(), 0, &tm);
+ cp += snprintf(cp, buf - cp + sizeof(buf) - 1,
+ ";start=%04u%02u%02u%02u%02u%02u", (int) tm.tm_year + 1900,
+ tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
+ tm.tm_sec);
+ /* Terminate the buffer. */
+ if (cp >= buf + sizeof(buf))
+ cp = buf + sizeof(buf) - 1;
+ *cp = '\0';
+ required = cp - buf + 1;
+ /* Make some room by truncating old history. */
+ cp = current->comm_history;
+ i = strlen(cp);
+ while (i + required >= audit_history_size - 3) {
+ char *cp2 = memchr(cp, '>', i);
+
+ /* Reset history if audit_history_size is too small to truncate. */
+ if (!cp2++) {
+ *cp = '\0';
+ return;
+ }
+ i -= cp2 - cp;
+ memmove(cp, cp2, i + 1);
+ }
+ /* Emit the buffer. */
+ if (i) {
+ cp[i++] = '=';
+ cp[i++] = '>';
+ }
+ memcpy(cp + i, buf, required);
+}
--
2.18.4
1 year, 3 months
[PATCH v2] TaskTracker : Simplified thread information tracker.
by Tetsuo Handa
When an unexpected system event occurs, the administrator may want to
identify which application triggered the event. For example, unexpected
process termination is still a real concern enough to write articles
like https://access.redhat.com/solutions/165993 . TaskTracker is a
trivial LSM module which emits TOMOYO-like information into the audit
logs for better understanding of unexpected system events.
I suggested TaskTracker about 10 years ago [1]. Compared to that time,
security_task_alloc()/security_task_free() hooks have been revived, but
the multiple concurrent LSM patches have not completed yet.
When I proposed TaskTracker as an LSM module [2], there was a comment that
this module should not reuse the subj= field and instead add new fields to
audit logs. But that thread died for unknown reason, and there is an effort
for making it possible to enable SELinux and Smack at the same time.
Thus, retrying as an LSM module based on an assumption that the multiple
concurrent LSM patches will address how to share the subj= field. I think
that passing whole history in one string is easier for those who want to
avoid bloating audit log files to control history size and fields to
include. Also, I think that userspace tools won't try to tokenize
this history in order to perform more than fgrep matching.
But now that LSM people are about to require an LSM ID for registering an
LSM module, I can't wait till it becomes possible to enable SELinux and
Smack at the same time. I have to send TaskTracker upstream in order to
assign an LSM ID for TaskTracker.
Link: https://marc.info/?l=linux-security-module&m=138547679621695 [1]
Link: https://lkml.kernel.org/r/201405232144.JFB30480.OVMOOSFtQJHLFF@I-love.SAK... [2]
Signed-off-by: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
---
security/Kconfig | 1 +
security/Makefile | 1 +
security/tasktracker/Kconfig | 24 +++++
security/tasktracker/Makefile | 2 +
security/tasktracker/tasktracker.c | 160 +++++++++++++++++++++++++++++
5 files changed, 188 insertions(+)
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 52c9af08ad35..aea0ac2b24a1 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -194,6 +194,7 @@ source "security/yama/Kconfig"
source "security/safesetid/Kconfig"
source "security/lockdown/Kconfig"
source "security/landlock/Kconfig"
+source "security/tasktracker/Kconfig"
source "security/integrity/Kconfig"
diff --git a/security/Makefile b/security/Makefile
index 18121f8f85cd..86ae43be3207 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/
obj-$(CONFIG_CGROUPS) += device_cgroup.o
obj-$(CONFIG_BPF_LSM) += bpf/
obj-$(CONFIG_SECURITY_LANDLOCK) += landlock/
+obj-$(CONFIG_SECURITY_TASKTRACKER) += tasktracker/
# Object integrity file lists
obj-$(CONFIG_INTEGRITY) += integrity/
diff --git a/security/tasktracker/Kconfig b/security/tasktracker/Kconfig
new file mode 100644
index 000000000000..6b294bf18878
--- /dev/null
+++ b/security/tasktracker/Kconfig
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SECURITY_TASKTRACKER
+ bool "TaskTracker Support"
+ depends on SECURITY && AUDIT
+ default n
+ help
+ This selects TaskTracker, a module which provides a thread's
+ history for better understanding of audit logs.
+
+ If you enable this module, you will find history of current
+ thread in the subj= field of audit logs in the form of
+ name=$commname;pid=$pid;start=$YYYYMMDDhhmmss delimited by =>
+ like an example shown below.
+
+ [root@localhost ~]# auditctl -a exit,always -F arch=b64 -S kill
+ [root@localhost ~]# bash
+ [root@localhost ~]# kill -9 $$
+ Killed
+ [root@localhost ~]# ausearch -sc kill
+ ----
+ time->Sun Aug 6 15:36:17 2023
+ type=PROCTITLE msg=audit(1691303777.054:117): proctitle="(null)"
+ type=OBJ_PID msg=audit(1691303777.054:117): opid=3787 oauid=0 ouid=0 oses=1 ocomm="bash"
+ type=SYSCALL msg=audit(1691303777.054:117): arch=c000003e syscall=62 success=yes exit=0 a0=ecb a1=9 a2=0 a3=7ffc779be760 items=0 ppid=3766 pid=3787 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="bash" exe="/usr/bin/bash" subj="name=swapper/0;pid=0;start=20230806153345=>name=init;pid=1;start=20230806153400=>name=systemd;pid=1;start=20230806153457=>name=sshd;pid=3661;start=20230806063525=>name=sshd;pid=3764;start=20230806063543=>name=bash;pid=3766;start=20230806063549=>name=bash;pid=3787;start=20230806063612" key=(null)
diff --git a/security/tasktracker/Makefile b/security/tasktracker/Makefile
new file mode 100644
index 000000000000..1c11673c7684
--- /dev/null
+++ b/security/tasktracker/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-y = tasktracker.o
diff --git a/security/tasktracker/tasktracker.c b/security/tasktracker/tasktracker.c
new file mode 100644
index 000000000000..bd76d7e2b42b
--- /dev/null
+++ b/security/tasktracker/tasktracker.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * tt.c - Simplified thread information tracker.
+ */
+
+#include <linux/lsm_hooks.h>
+#include <linux/ctype.h>
+
+#define HISTORY_BUFFER_SIZE 1024
+
+struct lsm_blob_sizes tt_blob_sizes __ro_after_init = {
+ .lbs_task = HISTORY_BUFFER_SIZE,
+};
+
+/**
+ * tt_task - Get history of specified thread.
+ *
+ * @task - Pointer to "struct task_struct".
+ *
+ * Returns history of specified thread.
+ */
+static char *tt_task(struct task_struct *task)
+{
+ return task->security + tt_blob_sizes.lbs_task;
+}
+
+/**
+ * tt_update_history - Update history of current thread.
+ *
+ * Returns nothing.
+ */
+static void tt_update_history(void)
+{
+ int i;
+ int required;
+ struct tm tm;
+ char buf[256];
+ char *cp = buf;
+ char *history = tt_task(current);
+
+ cp += snprintf(buf, sizeof(buf) - 1, "name=");
+ for (i = 0; i < TASK_COMM_LEN; i++) {
+ const unsigned char c = current->comm[i];
+
+ if (!c)
+ break;
+ if (isalnum(c) || c == '.' || c == '_' || c == '-' || c == '/') {
+ *cp++ = c;
+ continue;
+ }
+ *cp++ = '\\';
+ *cp++ = (c >> 6) + '0';
+ *cp++ = ((c >> 3) & 7) + '0';
+ *cp++ = (c & 7) + '0';
+ }
+ /* Append PID. */
+ cp += snprintf(cp, buf - cp + sizeof(buf) - 1, ";pid=%u",
+ current->pid);
+ /* Append timestamp. */
+ time64_to_tm(ktime_get_real_seconds(), 0, &tm);
+ cp += snprintf(cp, buf - cp + sizeof(buf) - 1,
+ ";start=%04u%02u%02u%02u%02u%02u", (int) tm.tm_year + 1900,
+ tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
+ tm.tm_sec);
+ /* Terminate the buffer. */
+ if (cp >= buf + sizeof(buf))
+ cp = buf + sizeof(buf) - 1;
+ *cp = '\0';
+ required = cp - buf;
+ /* Truncate history if history is too long to append. */
+ cp = history;
+ while (i = strlen(cp), i + required >= HISTORY_BUFFER_SIZE - 10) {
+ char *cp2 = memchr(cp + 3, '>', i - 3);
+
+ if (WARN_ON_ONCE(!cp2))
+ return;
+ cp2--;
+ memmove(cp + 1, cp2, strlen(cp2) + 1);
+ }
+ /* Create or append history. */
+ if (!i)
+ sprintf(cp, "\"%s\"", buf);
+ else
+ sprintf(cp + i - 1, "=>%s\"", buf);
+}
+
+static void tt_current_getsecid_subj(u32 *secid)
+{
+ *secid = 1;
+}
+
+/**
+ * tt_secid_to_secctx - Allocate memory used for auditing.
+ *
+ * @secid: Bool flag to allocate.
+ * @secdata: Pointer to allocate memory.
+ * @seclen: Unused.
+ *
+ * Returns 0 on success, -EINVAL otherwise.
+ */
+static int tt_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+{
+ char *history = tt_task(current);
+
+ /*
+ * This module avoids returning -ENOMEM in order to avoid audit_panic(),
+ * by returning only current thread's history. Since current thread's
+ * history is updated and read by only current thread, we don't need to
+ * copy the history for reading.
+ */
+ if (secid != 1)
+ return -EINVAL;
+ if (secdata)
+ *secdata = history;
+ *seclen = strlen(history);
+ return 0;
+}
+
+static int tt_task_alloc(struct task_struct *task, unsigned long clone_flags)
+{
+ /* Copy from current thread's history upon clone(). */
+ strscpy(tt_task(task), tt_task(current), HISTORY_BUFFER_SIZE);
+ return 0;
+}
+
+static void tt_bprm_committing_creds(struct linux_binprm *bprm)
+{
+ /* Update current thread's history upon successful execve(). */
+ tt_update_history();
+}
+
+static struct security_hook_list tt_hooks[] __ro_after_init = {
+ LSM_HOOK_INIT(current_getsecid_subj, tt_current_getsecid_subj),
+ LSM_HOOK_INIT(secid_to_secctx, tt_secid_to_secctx),
+ LSM_HOOK_INIT(task_alloc, tt_task_alloc),
+ LSM_HOOK_INIT(bprm_committing_creds, tt_bprm_committing_creds),
+};
+
+/**
+ * tt_init - Register TaskTracker as a LSM module.
+ *
+ * Returns 0.
+ */
+static int __init tt_init(void)
+{
+ char *history = tt_task(current);
+
+ memset(history, 0, HISTORY_BUFFER_SIZE);
+ tt_update_history();
+ security_add_hooks(tt_hooks, ARRAY_SIZE(tt_hooks), "tt");
+ pr_info("TaskTracker initialized\n");
+ return 0;
+}
+
+DEFINE_LSM(tt) = {
+ .name = "tt",
+ .flags = LSM_FLAG_EXCLUSIVE, /* Due to use of "u32 *secid' argument. */
+ .blobs = &tt_blob_sizes,
+ .init = tt_init,
+};
--
2.18.4
1 year, 4 months
[RFC] Future audit changes
by Steve Grubb
Hello,
I am considering making some drastic changes in a future 4.0 release. This is
partly motivated by a change in my daytime job. I am no longer working in Red
Hat security. Therefore working on audit is officially a hobby. I have spent
the last weeks closing out pull requests and Issues so that whoever wants to
contribute to the audit project doesn't have a lot of history to deal with.
There's almost 500 people subscribed to this list. The community needs to
step up a little.
The proposed changes are:
1) Drop support for Python 2. Python 2 has lost upstream support over 3 years
ago. I also can't see the viability of someone saying they need the latest
audit changes for the new kernel yet they are stuck on python 2. It doesn't
compute. This is also related to proposal 5 below.
2) Drop SysVinit support. I think everyone has changed to systemd at this
point. This is to reduce potential maintenance.
3) This is probably the most controversial and would need careful testing:
Split the audit service into 2 services: auditd and rules-load. These would
be packaged in 2 different packages so that if all you want is rules-loading
and are fine with events going to journald - have at it. If you want the
tradition audit experience, then install the audit package which will depend
on the rules package. The trick is making them automatically enabled at
install. This will need testing and perhaps patches. Packagers will need to
work with their distribution to update systemd presets.
4) Change the definition of which events are simple (one record events) and
compound (multiple records per event). Over the years syscall records were
added to the simple events haphazardly. That seems to have settled down and
we can redefine which are in which group. This is important because this
determines when an event is complete and ready to process in ausearch,
aureport, and auparse. This should reduce future bug reports.
5) Drop functions from libaudit python bindings that have anything to do with
placing and removing rules in the kernel. I'd like the API to just contain
what's needed to send audit events and query kernel status. This new binding
would be hand written, thus possibly breaking compatibility with the swig
generated bindinsg. Not 100% sure on that, but it might be a side effect. The
main idea is limit the scope to reduce maintenance and future-proof kernel/
swig changes.
6) Moratorium on new arches being supported. If someone else comes along and
really shows *sustained* support for the audit project for a while and they
want a new arch to be supported, I might consider it. Since my work on this
project is now a hobby, I am not inclined to make more work for my weekends.
7) Drop the autrace & auvirt programs. Does anyone actually use these? Can
ausearch take the place of auvirt? The aim here is reduce maintenance.
Let me know what you think. I'll probably put these in a new audit-4.0 branch
until they are complete and some testing has been done.
-Steve
1 year, 4 months
audit-3.1.2 released
by Steve Grubb
Hello,
I've just released a new version of the audit daemon. It can be
downloaded from http://people.redhat.com/sgrubb/audit. It will also be
in rawhide soon. The ChangeLog is:
- When processing a run level change, make auditd exit
- In auditd, fix return code when rules added in immutable mode
- In auparse, when files are given, also consider EUID for access
- Auparse now interprets unnamed/anonymous sockets (Enzo Matsumiya)
- Disable Python bindings from setting rules due to swig bug (S. Trofimovich)
- Update all lookup tables for the 6.5 kernel
- Don't be as paranoid about auditctl -R file permissions
- In ausearch, correct subject/object search to be an and if both are given
- Adjust formats for 64 bit time_t
- Fix segfault in python bindings around the feed API
- Add feed_has_data, get_record_num, and get/goto_field_num to python bindings
There are various bugfixes, a refresh of the lookup tables for the 6.5 kernel,
and some sprucing up of the python bindings. Speaking of which, this release
removes the ability to set audit rules via the python bindings. That means no
more workaround patch is needed for the swig issue.
SHA256: c0b1792d1f0a88c6f1828710509cbb987059fc68712c97669ca90eae103d287d
Please let me know if you run across any problems with this release.
-Steve
1 year, 4 months