[PATCH 1/2] auditsc: audit_krule mask accesses need bounds checking
by Eric Paris
From: Andy Lutomirski <luto(a)amacapital.net>
Fixes an easy DoS and possible information disclosure.
This does nothing about the broken state of x32 auditing.
eparis: If the admin has enabled auditd and has specifically loaded audit
rules. This bug has been around since before git. Wow...
Cc: stable(a)vger.kernel.org
Signed-off-by: Andy Lutomirski <luto(a)amacapital.net>
Signed-off-by: Eric Paris <eparis(a)redhat.com>
---
kernel/auditsc.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 254ce20..842f58a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -728,6 +728,22 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
return AUDIT_BUILD_CONTEXT;
}
+static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
+{
+ int word, bit;
+
+ if (val > 0xffffffff)
+ return false;
+
+ word = AUDIT_WORD(val);
+ if (word >= AUDIT_BITMASK_SIZE)
+ return false;
+
+ bit = AUDIT_BIT(val);
+
+ return rule->mask[word] & bit;
+}
+
/* At syscall entry and exit time, this filter is called if the
* audit_state is not low enough that auditing cannot take place, but is
* also not high enough that we already know we have to write an audit
@@ -745,11 +761,8 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
rcu_read_lock();
if (!list_empty(list)) {
- int word = AUDIT_WORD(ctx->major);
- int bit = AUDIT_BIT(ctx->major);
-
list_for_each_entry_rcu(e, list, list) {
- if ((e->rule.mask[word] & bit) == bit &&
+ if (audit_in_mask(&e->rule, ctx->major) &&
audit_filter_rules(tsk, &e->rule, ctx, NULL,
&state, false)) {
rcu_read_unlock();
@@ -769,20 +782,16 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
static int audit_filter_inode_name(struct task_struct *tsk,
struct audit_names *n,
struct audit_context *ctx) {
- int word, bit;
int h = audit_hash_ino((u32)n->ino);
struct list_head *list = &audit_inode_hash[h];
struct audit_entry *e;
enum audit_state state;
- word = AUDIT_WORD(ctx->major);
- bit = AUDIT_BIT(ctx->major);
-
if (list_empty(list))
return 0;
list_for_each_entry_rcu(e, list, list) {
- if ((e->rule.mask[word] & bit) == bit &&
+ if (audit_in_mask(&e->rule, ctx->major) &&
audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
ctx->current_state = state;
return 1;
--
1.9.0
10 years, 6 months
[PATCH 0/2] Syscall auditing lite
by Andy Lutomirski
I've made no secret of the fact that I dislike syscall auditing. As far
as I can tell, the main technical (i.e. not compliance-related) use of
syscall auditing is to supply some useful context information to go
along with events like AVC denials.
CONFIG_AUDITSYSCALL is serious overkill to do this. kernel/auditsc.c is
~2500 lines of terror.
This patchset accomplishes the same goal, more usefully, with no
overhead at all, in under 70 lines of code. It tries to coexist cleanly
with CONFIG_AUDITSYSCALL.
This is only implemented for x86. Other architectures can add support
fairly easily, I think.
Andy Lutomirski (2):
x86,syscall: Add syscall_in_syscall to test whether we're in a syscall
audit: Syscall auditing lite
arch/x86/Kconfig | 1 +
arch/x86/include/asm/syscall.h | 21 ++++++++++++++++++++
init/Kconfig | 3 +++
kernel/audit.c | 44 +++++++++++++++++++++++++++++++++++++++++-
4 files changed, 68 insertions(+), 1 deletion(-)
--
1.9.3
10 years, 6 months
Diskless workstation audit advice
by Burn Alting
Hi All,
I have some disk less workstations upon which I wish to collect audit.
Once a workstation is running, I periodically transmit audit in
compressed batches of enriched audit (i.e. "ausearch -i" output is
sent).
My question is:
To collect AND transmit audit until the last possible moment, is the
logical place to perform the last collection and transmission operation
within the 'stop' function of /etc/init.d/auditd ?
The enrichment (calling ausearch -i) rules out syslog.
Thanks in advance
Burn
10 years, 7 months
auditd 2.0.5 and 2.2 log format changes
by Ismail Yenigul
Hello,
I have a scipt to correlate(for user friendly report) auditd 2.2 version
logs. It works on RedHat.
We have suse 11.4 server running audit 2.0.5 version .
I could not see any major log format difference between two version.
I see that there is nametype=NORMAL field difference at the end of each
line for version 2.2.
Is there any other log format changes between two versions?
PS: I execute /sbin/ausearch -i -if /var/log/audit/audit.log command before
to start log processing.
Thanks in advance.
10 years, 7 months
saddr value in connect()
by lists_todd@mac.com
I have a question about the SOCKADDR token in a SYSCALL record (syscall 42 -- connect())
Most of my records begin with one of the two values:
saddr=0200
saddr=0100
Followed by the port & IPv4 address or the file path.
QUESTION 1: The file path appears to be NULL terminated. Is this correct?
QUESTION 2: There is often additional characters after the 00 termination (and IP address). Is this just garbage that should be ignored?
QUESTION 3: Sometimes the first byte in a file path is 00 termination (e.g., saddr=0100002F…). Does this mean the string is empty and the content following it is garbage? Or is there a bug that accidentally prepends the 00 to the front of the saddr sequence?
Here is an example:
————————
type=SYSCALL msg=audit(1397089029.264:7407): arch=c000003e syscall=42 success=yes exit=0 a0=3 a1=7fff3a7fdf70 a2=16 a3=7fff3a7fdd20 items=0 ppid=805 pid=1064 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 ses=4294967295 tty=(none) comm="initctl" exe="/sbin/initctl" key=(null)
type=SOCKADDR msg=audit(1397089029.264:7407): saddr=0100002F636F6D2F7562756E74752F75707374617274
————————
If I assume the first 00 is a bug, the string decodes to
/com/ubuntu/upstart
Thanks,
Todd
PS. uname -r gives 3.13.0-24-generic (though, I think I collected these logs before the last software update)
10 years, 7 months
[PATCH 1/3] audit: implement audit by executable
by Eric Paris
This patch implements the ability to filter on the executable. It is
clearly incomplete! This patch adds the inode/dev of the executable at
the moment the rule is loaded. It does not update if the executable is
updated/moved/whatever. That should be added. But at this moment, this
patch works.
Based-on-user-interface-by: Richard Guy Briggs <rgb(a)redhat.com>
Cc: rgb(a)redhat.com
Based-on-idea-by: Peter Moody <pmoody(a)google.com>
Cc: pmoody(a)google.com
Signed-off-by: Eric Paris <eparis(a)redhat.com>
---
include/linux/audit.h | 1 +
include/uapi/linux/audit.h | 2 +
kernel/Makefile | 2 +-
kernel/audit.h | 27 +++++++++++
kernel/audit_exe.c | 113 +++++++++++++++++++++++++++++++++++++++++++++
kernel/auditfilter.c | 43 +++++++++++++++++
kernel/auditsc.c | 16 +++++++
7 files changed, 203 insertions(+), 1 deletion(-)
create mode 100644 kernel/audit_exe.c
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 1ae0089..84e7bc4 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -59,6 +59,7 @@ struct audit_krule {
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct audit_tree *tree; /* associated watched tree */
+ struct audit_exe *exe;
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
struct list_head list; /* for AUDIT_LIST* purposes only */
u64 prio;
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index d95eba0..e916088 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -266,6 +266,8 @@
#define AUDIT_OBJ_UID 109
#define AUDIT_OBJ_GID 110
#define AUDIT_FIELD_COMPARE 111
+#define AUDIT_EXE 112
+#define AUDIT_EXE_CHILDREN 113
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
diff --git a/kernel/Makefile b/kernel/Makefile
index bc010ee..a1d5715 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -61,7 +61,7 @@ obj-$(CONFIG_SMP) += stop_machine.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
-obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o
+obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_exe.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/kernel/audit.h b/kernel/audit.h
index 7bb6573..58ed955 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -56,6 +56,7 @@ enum audit_state {
/* Rule lists */
struct audit_watch;
+struct audit_exe;
struct audit_tree;
struct audit_chunk;
@@ -280,6 +281,13 @@ extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
extern void audit_remove_watch_rule(struct audit_krule *krule);
extern char *audit_watch_path(struct audit_watch *watch);
extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
+
+int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op);
+void audit_remove_exe_rule(struct audit_krule *krule);
+char *audit_exe_path(struct audit_exe *exe);
+int audit_dup_exe(struct audit_krule *new, struct audit_krule *old);
+int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe);
+
#else
#define audit_put_watch(w) {}
#define audit_get_watch(w) {}
@@ -289,6 +297,25 @@ extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev
#define audit_watch_path(w) ""
#define audit_watch_compare(w, i, d) 0
+static inline int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op) {
+ return -EINVAL;
+}
+static inline void audit_remove_exe_rule(struct audit_krule *krule) {
+ BUG();
+ return 0;
+}
+static inline char *audit_exe_path(struct audit_exe *exe) {
+ BUG();
+ return "";
+}
+static inline int audit_dup_exe(struct audit_krule *new, struct audit_krule *old) {
+ BUG();
+ return -EINVAL
+}
+static inline int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe) {
+ BUG();
+ return 0;
+}
#endif /* CONFIG_AUDIT_WATCH */
#ifdef CONFIG_AUDIT_TREE
diff --git a/kernel/audit_exe.c b/kernel/audit_exe.c
new file mode 100644
index 0000000..09c436c
--- /dev/null
+++ b/kernel/audit_exe.c
@@ -0,0 +1,113 @@
+/* audit_exe.c -- filtering of audit events
+ *
+ * Copyright 2014 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/audit.h>
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include "audit.h"
+
+struct audit_exe {
+ char *pathname;
+ unsigned long ino;
+ dev_t dev;
+};
+
+/* Translate a watch string to kernel respresentation. */
+int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op)
+{
+ struct audit_exe *exe;
+ struct path path;
+ struct dentry *dentry;
+ unsigned long ino;
+ dev_t dev;
+
+ if (pathname[0] != '/' || pathname[len-1] == '/')
+ return -EINVAL;
+
+ dentry = kern_path_locked(pathname, &path);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+ mutex_unlock(&path.dentry->d_inode->i_mutex);
+
+ if (!dentry->d_inode)
+ return -ENOENT;
+ dev = dentry->d_inode->i_sb->s_dev;
+ ino = dentry->d_inode->i_ino;
+ dput(dentry);
+
+ exe = kmalloc(sizeof(*exe), GFP_KERNEL);
+ if (!exe)
+ return -ENOMEM;
+ exe->ino = ino;
+ exe->dev = dev;
+ exe->pathname = pathname;
+ krule->exe = exe;
+
+ return 0;
+}
+
+void audit_remove_exe_rule(struct audit_krule *krule)
+{
+ struct audit_exe *exe;
+
+ exe = krule->exe;
+ krule->exe = NULL;
+ kfree(exe->pathname);
+ kfree(exe);
+}
+
+char *audit_exe_path(struct audit_exe *exe)
+{
+ return exe->pathname;
+}
+
+int audit_dup_exe(struct audit_krule *new, struct audit_krule *old)
+{
+ struct audit_exe *exe;
+
+ exe = kmalloc(sizeof(*exe), GFP_KERNEL);
+ if (!exe)
+ return -ENOMEM;
+
+ exe->pathname = kstrdup(old->exe->pathname, GFP_KERNEL);
+ if (!exe->pathname) {
+ kfree(exe);
+ return -ENOMEM;
+ }
+
+ exe->ino = old->exe->ino;
+ exe->dev = old->exe->dev;
+ new->exe = exe;
+
+ return 0;
+}
+
+int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe)
+{
+ if (tsk->mm->exe_file->f_inode->i_ino != exe->ino)
+ return 0;
+ if (tsk->mm->exe_file->f_inode->i_sb->s_dev != exe->dev)
+ return 0;
+ return 1;
+}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 8e9bc9c..9caeaf5 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -390,6 +390,13 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
if (f->val > AUDIT_MAX_FIELD_COMPARE)
return -EINVAL;
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ if (f->op != Audit_equal)
+ return -EINVAL;
+ if (entry->rule.listnr != AUDIT_FILTER_EXIT)
+ return -EINVAL;
+ break;
};
return 0;
}
@@ -541,6 +548,23 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
entry->rule.buflen += f->val;
entry->rule.filterkey = str;
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ if (entry->rule.exe || f->val > PATH_MAX)
+ goto exit_free;
+ str = audit_unpack_string(&bufp, &remain, f->val);
+ if (IS_ERR(str)) {
+ err = PTR_ERR(str);
+ goto exit_free;
+ }
+ entry->rule.buflen += f->val;
+
+ err = audit_make_exe_rule(&entry->rule, str, f->val, f->op);
+ if (err) {
+ kfree(str);
+ goto exit_free;
+ }
+ break;
}
}
@@ -619,6 +643,11 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
data->buflen += data->values[i] =
audit_pack_string(&bufp, krule->filterkey);
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ data->buflen += data->values[i] =
+ audit_pack_string(&bufp, audit_exe_path(krule->exe));
+ break;
default:
data->values[i] = f->val;
}
@@ -674,6 +703,13 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
if (strcmp(a->filterkey, b->filterkey))
return 1;
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ /* both paths exist based on above type compare */
+ if (strcmp(audit_exe_path(a->exe),
+ audit_exe_path(b->exe)))
+ return 1;
+ break;
case AUDIT_UID:
case AUDIT_EUID:
case AUDIT_SUID:
@@ -795,6 +831,11 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
err = -ENOMEM;
else
new->filterkey = fk;
+ break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ err = audit_dup_exe(new, old);
+ break;
}
if (err) {
audit_free_rule(entry);
@@ -966,6 +1007,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
if (e->rule.tree)
audit_remove_tree_rule(&e->rule);
+ if (e->rule.exe)
+ audit_remove_exe_rule(&e->rule);
list_del_rcu(&e->list);
list_del(&e->rule.list);
call_rcu(&e->rcu, audit_free_rule_rcu);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b12a712..fa11362 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -48,6 +48,7 @@
#include <asm/types.h>
#include <linux/atomic.h>
#include <linux/fs.h>
+#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/mm.h>
#include <linux/export.h>
@@ -71,6 +72,7 @@
#include <linux/capability.h>
#include <linux/fs_struct.h>
#include <linux/compat.h>
+#include <linux/sched.h>
#include <linux/ctype.h>
#include "audit.h"
@@ -472,6 +474,20 @@ static int audit_filter_rules(struct task_struct *tsk,
result = audit_comparator(ctx->ppid, f->op, f->val);
}
break;
+ case AUDIT_EXE:
+ result = audit_exe_compare(tsk, rule->exe);
+ break;
+ case AUDIT_EXE_CHILDREN:
+ {
+ struct task_struct *ptsk;
+ for (ptsk = tsk; ptsk->parent->pid > 0; ptsk = find_task_by_vpid(ptsk->parent->pid)) {
+ if (audit_exe_compare(ptsk, rule->exe)) {
+ ++result;
+ break;
+ }
+ }
+ }
+ break;
case AUDIT_UID:
result = audit_uid_comparator(cred->uid, f->op, f->uid);
break;
--
1.9.0
10 years, 7 months
[PATCH V2 0/6] namespaces: log namespaces per task
by Richard Guy Briggs
The purpose is to track namespaces in use by logged processes from the
perspective of init_*_ns. The first patch defines a function to generate them
and assigns them. The second patch provides an example of usage for
audit_log_task_info() which is used by syscall audits, among others.
audit_log_task() and audit_common_recv_message() would be other potential use
cases.
Use a serial number per namespace (unique across one boot of one kernel)
instead of the inode number (which is claimed to have had the right to change
reserved and is not necessarily unique if there is more than one proc fs). It
could be argued that the inode numbers have now become a defacto interface and
can't change now, but I'm proposing this approach to see if this helps address
some of the objections to the earlier patchset.
There could also have messages added to track the creation and the destruction
of namespaces, listing the parent for hierarchical namespaces such as pidns,
userns, and listing other ids for non-hierarchical namespaces, as well as other
information to help identify a namespace.
There has been some progress made for audit in net namespaces and pid
namespaces since this previous thread. net namespaces are now served as peers
by one auditd in the init_net namespace with processes in a non-init_net
namespace being able to write records if they are in the init_user_ns and have
CAP_AUDIT_WRITE. Processes in a non-init_pid_ns can now similarly write
records. As for CAP_AUDIT_READ, I just posted a patchset to check capabilities
of userspace processes that try to join netlink broadcast groups.
Questions:
Is there a way to link serial numbers of namespaces involved in migration of a
container to another kernel? It sounds like what is needed is a part of a
mangement application that is able to pull the audit rcords from constituent
hosts to build an audit trail of a container.
What additional events should list this information?
Does this present any problematic information leaks? Only CAP_AUDIT_CONTROL
(and proposed CAP_AUDIT_READ) in init_user_ns can get to this information in
the init namespace at the moment from audit. *However*, the addition of the
proc/<pid>/ns/*_snum does make it available to other processes now.
Proposed output format:
This differs slightly from Aristeu's patch because of the label conflict with
"pid=" due to including it in existing records rather than it being a seperate
record. The serial numbers are printed in hex.
type=SYSCALL msg=audit(1399651071.433:72): arch=c000003e syscall=272 success=yes exit=0 a0=40000000 a1=ffffffffffffffff a2=0 a3=22 items=0 ppid=1 pid=483 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="(t-daemon)" exe="/usr/lib/systemd/systemd" netns=97 utsns=2 ipcns=1 pidns=4 userns=3 mntns=5 subj=system_u:system_r:init_t:s0 key=(null)
The third patch adds access functions to get to the serial numbers in a similar
way to inode access for namespace proc operations.
The fourth patch implements, as suggested by Serge Hallyn, making these serial
numbers available in /proc/self/ns/{ipc,mnt,net,pid,user,uts}_snum. I chose
"snum" instead of "seq" for consistency with inum and there are a number of
other uses of "seq" in the namespace code.
**Although it works as expected, I'm not that happy with that patch because it
duplicates a lot of code, including minor changes to proc_ns_follow_link(),
proc_ns_readlink(), ns_dname(). The only way I could see to get that
information into those functions would be through dentry. Maybe the
information I need is already in there in d_name or d_iname? Or I could add a
flag to d_flags (there are 9 bits unused?) but that flag isn't useful for any
other types of entries, so I'm not so keen to pollute it.
The fifth patch exposes proc's ns entries structure which lists a number of
useful operations per namespace type for other subsystems to use.
The sixth patch converts the audit namespace serial number logging over to use
the ns_entries access methods.
The two audit patches should really be squashed down to one if the exposure of
ns_entries is ok.
Note: This set does not try to solve the non-init namespace audit messages and
auditd problem yet. That will come later, likely with additional auditd
instances running in another namespace with a limited ability to influence the
master auditd. I echo Eric B's idea that messages destined for different
namespaces would have to be tailored for that namespace with references that
make sense (such as the right pid number reported to that pid namespace, and
not leaking info about parents or peers).
v1 -> v2:
Avoid rollover by switching from an int to a long long.
Change rollover behaviour from simply avoiding zero to raising a BUG.
Expose serial numbers in /proc/<pid>/ns/*_snum.
Expose ns_entries and use it in audit.
Richard Guy Briggs (6):
namespaces: assign each namespace instance a serial number
audit: log namespace serial numbers
namespaces: expose namespace instance serial number in
proc_ns_operations
namespaces: expose ns instance serial numbers in proc
namespaces: expose ns_entries
audit: convert namespace serial number logging to use proc ns_entries
fs/mount.h | 1 +
fs/namespace.c | 8 ++
fs/proc/namespaces.c | 152 ++++++++++++++++++++++++++++++++++++----
include/linux/audit.h | 7 ++
include/linux/ipc_namespace.h | 1 +
include/linux/nsproxy.h | 8 ++
include/linux/pid_namespace.h | 1 +
include/linux/proc_ns.h | 2 +
include/linux/user_namespace.h | 1 +
include/linux/utsname.h | 1 +
include/net/net_namespace.h | 1 +
init/version.c | 1 +
ipc/msgutil.c | 1 +
ipc/namespace.c | 10 +++
kernel/audit.c | 21 +++++-
kernel/nsproxy.c | 20 +++++
kernel/pid.c | 1 +
kernel/pid_namespace.c | 9 +++
kernel/user.c | 1 +
kernel/user_namespace.c | 9 +++
kernel/utsname.c | 10 +++
net/core/net_namespace.c | 11 +++-
22 files changed, 262 insertions(+), 15 deletions(-)
10 years, 7 months
[PATCH 0/4] arm64: Add audit support
by AKASHI Takahiro
This patchset adds audit support on arm64.
The implementation is just like in other architectures,
and so I think little explanation is needed.
I verified this patch with some commands on both 64-bit rootfs
and 32-bit rootfs(, but only in little-endian):
# auditctl -a exit,always -S openat -F path=/etc/inittab
# auditctl -a exit,always -F dir=/tmp -F perm=rw
# auditctl -a task,always
# autrace /bin/ls
What else?
(Thanks to Clayton for his cross-compiling patch)
I'd like to discuss about the following issues:
(issues)
* AUDIT_ARCH_*
Why do we need to distiguish big-endian and little-endian? [2/4]
* AArch32
We need to add a check for identifying the endian in 32-bit tasks. [3/4]
* syscall no in AArch32
Currently all the definitions are added in unistd32.h with
"ifdef __AARCH32_AUDITSYSCALL" to use asm-generic/audit_*.h. [3/4]
"ifdef" is necessary to avoid a conflict with 64-bit definitions.
Do we need a more sophisticated way?
* TIF_AUDITSYSCALL
Most architectures, except x86, do not check TIF_AUDITSYSCALL. Why not? [4/4]
* Userspace audit package
There are some missing syscall definitions in lib/aarch64_table.h.
There is no support for AUDIT_ARCH_ARM (I mean LE. armeb is BE).
AKASHI Takahiro (4):
audit: Enable arm64 support
arm64: Add audit support
arm64: audit: Add AArch32 support
arm64: audit: Add audit hook in ptrace/syscall_trace
arch/arm64/Kconfig | 3 +
arch/arm64/include/asm/audit32.h | 12 ++
arch/arm64/include/asm/ptrace.h | 5 +
arch/arm64/include/asm/syscall.h | 18 ++
arch/arm64/include/asm/thread_info.h | 1 +
arch/arm64/include/asm/unistd32.h | 387 ++++++++++++++++++++++++++++++++++
arch/arm64/kernel/Makefile | 4 +
arch/arm64/kernel/audit.c | 77 +++++++
arch/arm64/kernel/audit32.c | 46 ++++
arch/arm64/kernel/entry.S | 3 +
arch/arm64/kernel/ptrace.c | 12 ++
include/uapi/linux/audit.h | 2 +
init/Kconfig | 2 +-
13 files changed, 571 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/audit32.h
create mode 100644 arch/arm64/kernel/audit.c
create mode 100644 arch/arm64/kernel/audit32.c
--
1.7.9.5
10 years, 7 months
USER_END vs USER_LOGOUT
by Florin Andrei
For a group of cloud instances, I am looking to implement a policy
whereby any instance will self-destroy if no users were logged into it
via ssh for the last X hours. This requires me to track logout events.
It seems like the audit log might provide this information.
However, looking at that log while a user logs out of an ssh session, I
noticed two lines:
type=USER_END msg=audit(1399507220.412:179): pid=1327 uid=0 auid=0 ses=2
msg='op=login id=0 exe="/usr/sbin/sshd" hostname=? addr=?
terminal=/dev/pts/0 res=success'
type=USER_LOGOUT msg=audit(1399507220.412:180): pid=1327 uid=0 auid=0
ses=2 msg='op=login id=0 exe="/usr/sbin/sshd" hostname=? addr=?
terminal=/dev/pts/0 res=success'
They appear to correspond to two other events recorded during the same
user's login:
type=USER_LOGIN msg=audit(1399507218.420:173): pid=22523 uid=0 auid=0
ses=2 msg='op=login id=0 exe="/usr/sbin/sshd" hostname=XXX.XXX.XXX.XXX
addr=XXX.XXX.XXX.XXX terminal=/dev/pts/0 res=success'
type=USER_START msg=audit(1399507218.420:174): pid=22523 uid=0 auid=0
ses=2 msg='op=login id=0 exe="/usr/sbin/sshd" hostname=XXX.XXX.XXX.XXX
addr=XXX.XXX.XXX.XXX terminal=/dev/pts/0 res=success'
What is the difference between USER_END and USER_LOGOUT? Which one
should I track, in order to capture all session-end events, including
the ssh connection being terminated without the user actually typing in
"logout"?
--
Florin Andrei
http://florin.myip.org/
10 years, 7 months
[PATCH] audit: implement audit by executable
by Eric Paris
This patch implements the ability to filter on the executable. It is
clearly incomplete! This patch adds the inode/dev of the executable at
the moment the rule is loaded. It does not update if the executable is
updated/moved/whatever. That should be added. But at this moment, this
patch works.
Based-on-user-interface-by: Richard Guy Briggs <rgb(a)redhat.com>
Cc: rgb(a)redhat.com
Based-on-idea-by: Peter Moody <pmoody(a)google.com>
Cc: pmoody(a)google.com
Signed-off-by: Eric Paris <eparis(a)redhat.com>
---
include/linux/audit.h | 1 +
include/uapi/linux/audit.h | 2 +
kernel/Makefile | 2 +-
kernel/audit.h | 27 +++++++++++
kernel/audit_exe.c | 113 +++++++++++++++++++++++++++++++++++++++++++++
kernel/auditfilter.c | 42 +++++++++++++++++
kernel/auditsc.c | 16 +++++++
7 files changed, 202 insertions(+), 1 deletion(-)
create mode 100644 kernel/audit_exe.c
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 1ae0089..84e7bc4 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -59,6 +59,7 @@ struct audit_krule {
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct audit_tree *tree; /* associated watched tree */
+ struct audit_exe *exe;
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
struct list_head list; /* for AUDIT_LIST* purposes only */
u64 prio;
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index d95eba0..e916088 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -266,6 +266,8 @@
#define AUDIT_OBJ_UID 109
#define AUDIT_OBJ_GID 110
#define AUDIT_FIELD_COMPARE 111
+#define AUDIT_EXE 112
+#define AUDIT_EXE_CHILDREN 113
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
diff --git a/kernel/Makefile b/kernel/Makefile
index bc010ee..a1d5715 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -61,7 +61,7 @@ obj-$(CONFIG_SMP) += stop_machine.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
-obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o
+obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_exe.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/kernel/audit.h b/kernel/audit.h
index 7bb6573..58ed955 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -56,6 +56,7 @@ enum audit_state {
/* Rule lists */
struct audit_watch;
+struct audit_exe;
struct audit_tree;
struct audit_chunk;
@@ -280,6 +281,13 @@ extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
extern void audit_remove_watch_rule(struct audit_krule *krule);
extern char *audit_watch_path(struct audit_watch *watch);
extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
+
+int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op);
+void audit_remove_exe_rule(struct audit_krule *krule);
+char *audit_exe_path(struct audit_exe *exe);
+int audit_dup_exe(struct audit_krule *new, struct audit_krule *old);
+int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe);
+
#else
#define audit_put_watch(w) {}
#define audit_get_watch(w) {}
@@ -289,6 +297,25 @@ extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev
#define audit_watch_path(w) ""
#define audit_watch_compare(w, i, d) 0
+static inline int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op) {
+ return -EINVAL;
+}
+static inline void audit_remove_exe_rule(struct audit_krule *krule) {
+ BUG();
+ return 0;
+}
+static inline char *audit_exe_path(struct audit_exe *exe) {
+ BUG();
+ return "";
+}
+static inline int audit_dup_exe(struct audit_krule *new, struct audit_krule *old) {
+ BUG();
+ return -EINVAL
+}
+static inline int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe) {
+ BUG();
+ return 0;
+}
#endif /* CONFIG_AUDIT_WATCH */
#ifdef CONFIG_AUDIT_TREE
diff --git a/kernel/audit_exe.c b/kernel/audit_exe.c
new file mode 100644
index 0000000..baf2d82
--- /dev/null
+++ b/kernel/audit_exe.c
@@ -0,0 +1,113 @@
+/* audit_exe.c -- filtering of audit events
+ *
+ * Copyright 2003-2014 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/audit.h>
+#include <linux/mutex.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include "audit.h"
+
+struct audit_exe {
+ char *pathname;
+ unsigned long ino;
+ dev_t dev;
+};
+
+/* Translate a watch string to kernel respresentation. */
+int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op)
+{
+ struct audit_exe *exe;
+ struct path path;
+ struct dentry *dentry;
+ unsigned long ino;
+ dev_t dev;
+
+ if (pathname[0] != '/' || pathname[len-1] == '/')
+ return -EINVAL;
+
+ dentry = kern_path_locked(pathname, &path);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+ mutex_unlock(&path.dentry->d_inode->i_mutex);
+
+ if (!dentry->d_inode)
+ return -ENOENT;
+ dev = dentry->d_inode->i_sb->s_dev;
+ ino = dentry->d_inode->i_ino;
+ dput(dentry);
+
+ exe = kmalloc(sizeof(*exe), GFP_KERNEL);
+ if (!exe)
+ return -ENOMEM;
+ exe->ino = ino;
+ exe->dev = dev;
+ exe->pathname = pathname;
+ krule->exe = exe;
+
+ return 0;
+}
+
+void audit_remove_exe_rule(struct audit_krule *krule)
+{
+ struct audit_exe *exe;
+
+ exe = krule->exe;
+ krule->exe = NULL;
+ kfree(exe->pathname);
+ kfree(exe);
+}
+
+char *audit_exe_path(struct audit_exe *exe)
+{
+ return exe->pathname;
+}
+
+int audit_dup_exe(struct audit_krule *new, struct audit_krule *old)
+{
+ struct audit_exe *exe;
+
+ exe = kmalloc(sizeof(*exe), GFP_KERNEL);
+ if (!exe)
+ return -ENOMEM;
+
+ exe->pathname = kstrdup(old->exe->pathname, GFP_KERNEL);
+ if (!exe->pathname) {
+ kfree(exe);
+ return -ENOMEM;
+ }
+
+ exe->ino = old->exe->ino;
+ exe->dev = old->exe->dev;
+ new->exe = exe;
+
+ return 0;
+}
+
+int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe)
+{
+ if (tsk->mm->exe_file->f_inode->i_ino != exe->ino)
+ return 0;
+ if (tsk->mm->exe_file->f_inode->i_sb->s_dev != exe->dev)
+ return 0;
+ return 1;
+}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 8e9bc9c..ad9512c 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -390,6 +390,13 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
if (f->val > AUDIT_MAX_FIELD_COMPARE)
return -EINVAL;
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ if (f->op != Audit_equal)
+ return -EINVAL;
+ if (entry->rule.listnr != AUDIT_FILTER_EXIT)
+ return -EINVAL;
+ break;
};
return 0;
}
@@ -541,6 +548,21 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
entry->rule.buflen += f->val;
entry->rule.filterkey = str;
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ if (entry->rule.exe || f->val > PATH_MAX)
+ goto exit_free;
+ str = audit_unpack_string(&bufp, &remain, f->val);
+ if (IS_ERR(str))
+ goto exit_free;
+ entry->rule.buflen += f->val;
+
+ err = audit_make_exe_rule(&entry->rule, str, f->val, f->op);
+ if (err) {
+ kfree(str);
+ goto exit_free;
+ }
+ break;
}
}
@@ -619,6 +641,12 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
data->buflen += data->values[i] =
audit_pack_string(&bufp, krule->filterkey);
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ data->buflen += data->values[i] =
+ audit_pack_string(&bufp,
+ audit_exe_path(krule->exe));
+ break;
default:
data->values[i] = f->val;
}
@@ -674,6 +702,13 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
if (strcmp(a->filterkey, b->filterkey))
return 1;
break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ /* both paths exist based on above type compare */
+ if (strcmp(audit_exe_path(a->exe),
+ audit_exe_path(b->exe)))
+ return 1;
+ break;
case AUDIT_UID:
case AUDIT_EUID:
case AUDIT_SUID:
@@ -795,6 +830,11 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
err = -ENOMEM;
else
new->filterkey = fk;
+ break;
+ case AUDIT_EXE:
+ case AUDIT_EXE_CHILDREN:
+ err = audit_dup_exe(new, old);
+ break;
}
if (err) {
audit_free_rule(entry);
@@ -966,6 +1006,8 @@ static inline int audit_del_rule(struct audit_entry *entry)
if (e->rule.tree)
audit_remove_tree_rule(&e->rule);
+ if (e->rule.exe)
+ audit_remove_exe_rule(&e->rule);
list_del_rcu(&e->list);
list_del(&e->rule.list);
call_rcu(&e->rcu, audit_free_rule_rcu);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b12a712..fa11362 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -48,6 +48,7 @@
#include <asm/types.h>
#include <linux/atomic.h>
#include <linux/fs.h>
+#include <linux/dcache.h>
#include <linux/namei.h>
#include <linux/mm.h>
#include <linux/export.h>
@@ -71,6 +72,7 @@
#include <linux/capability.h>
#include <linux/fs_struct.h>
#include <linux/compat.h>
+#include <linux/sched.h>
#include <linux/ctype.h>
#include "audit.h"
@@ -472,6 +474,20 @@ static int audit_filter_rules(struct task_struct *tsk,
result = audit_comparator(ctx->ppid, f->op, f->val);
}
break;
+ case AUDIT_EXE:
+ result = audit_exe_compare(tsk, rule->exe);
+ break;
+ case AUDIT_EXE_CHILDREN:
+ {
+ struct task_struct *ptsk;
+ for (ptsk = tsk; ptsk->parent->pid > 0; ptsk = find_task_by_vpid(ptsk->parent->pid)) {
+ if (audit_exe_compare(ptsk, rule->exe)) {
+ ++result;
+ break;
+ }
+ }
+ }
+ break;
case AUDIT_UID:
result = audit_uid_comparator(cred->uid, f->op, f->uid);
break;
--
1.9.0
10 years, 7 months