This patch add a generic cpu endian caps structure and externally available
functions which retrieve fcaps information from disk. This information is
necessary so fcaps information can be collected and recorded by the audit
system.
Signed-off-by: Eric Paris <[email protected]>
---
include/linux/capability.h | 7 ++
security/commoncap.c | 129 ++++++++++++++++++++++++--------------------
2 files changed, 78 insertions(+), 58 deletions(-)
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 9d1fe30..9d64a9c 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -96,6 +96,13 @@ typedef struct kernel_cap_struct {
__u32 cap[_KERNEL_CAPABILITY_U32S];
} kernel_cap_t;
+/* exact same as vfs_cap_data but in cpu endian and always filled completely */
+struct cpu_vfs_cap_data {
+ __u32 magic_etc;
+ kernel_cap_t permitted;
+ kernel_cap_t inheritable;
+};
+
#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
diff --git a/security/commoncap.c b/security/commoncap.c
index 3976613..8bb95ed 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -202,17 +202,70 @@ int cap_inode_killpriv(struct dentry *dentry)
return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
}
-static inline int cap_from_disk(struct vfs_cap_data *caps,
- struct linux_binprm *bprm, unsigned size)
+static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
+ struct linux_binprm *bprm)
{
+ unsigned i;
+ int ret = 0;
+
+ if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
+ bprm->cap_effective = true;
+ else
+ bprm->cap_effective = false;
+
+ CAP_FOR_EACH_U32(i) {
+ __u32 permitted = caps->permitted.cap[i];
+ __u32 inheritable = caps->inheritable.cap[i];
+
+ /*
+ * pP' = (X & fP) | (pI & fI)
+ */
+ bprm->cap_post_exec_permitted.cap[i] =
+ (current->cap_bset.cap[i] & permitted) |
+ (current->cap_inheritable.cap[i] & inheritable);
+
+ if (permitted & ~bprm->cap_post_exec_permitted.cap[i]) {
+ /*
+ * insufficient to execute correctly
+ */
+ ret = -EPERM;
+ }
+ }
+
+ /*
+ * For legacy apps, with no internal support for recognizing they
+ * do not have enough capabilities, we return an error if they are
+ * missing some "forced" (aka file-permitted) capabilities.
+ */
+ return bprm->cap_effective ? ret : 0;
+}
+
+int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
+{
+ struct inode *inode = dentry->d_inode;
__u32 magic_etc;
unsigned tocopy, i;
- int ret;
+ int size;
+ struct vfs_cap_data caps;
+
+ memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
+
+ if (!inode || !inode->i_op || !inode->i_op->getxattr)
+ return -ENODATA;
+
+ size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
+ XATTR_CAPS_SZ);
+ if (size == -ENODATA || size == -EOPNOTSUPP) {
+ /* no data, that's ok */
+ return -ENODATA;
+ }
+ if (size < 0)
+ return size;
if (size < sizeof(magic_etc))
return -EINVAL;
- magic_etc = le32_to_cpu(caps->magic_etc);
+ cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc);
switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
case VFS_CAP_REVISION_1:
@@ -229,46 +282,13 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
return -EINVAL;
}
- if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
- bprm->cap_effective = true;
- } else {
- bprm->cap_effective = false;
- }
-
- ret = 0;
-
CAP_FOR_EACH_U32(i) {
- __u32 value_cpu;
-
- if (i >= tocopy) {
- /*
- * Legacy capability sets have no upper bits
- */
- bprm->cap_post_exec_permitted.cap[i] = 0;
- continue;
- }
- /*
- * pP' = (X & fP) | (pI & fI)
- */
- value_cpu = le32_to_cpu(caps->data[i].permitted);
- bprm->cap_post_exec_permitted.cap[i] =
- (current->cap_bset.cap[i] & value_cpu) |
- (current->cap_inheritable.cap[i] &
- le32_to_cpu(caps->data[i].inheritable));
- if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
- /*
- * insufficient to execute correctly
- */
- ret = -EPERM;
- }
+ if (i >= tocopy)
+ break;
+ cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
+ cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
}
-
- /*
- * For legacy apps, with no internal support for recognizing they
- * do not have enough capabilities, we return an error if they are
- * missing some "forced" (aka file-permitted) capabilities.
- */
- return bprm->cap_effective ? ret : 0;
+ return 0;
}
/* Locate any VFS capabilities: */
@@ -276,8 +296,7 @@ static int get_file_caps(struct linux_binprm *bprm)
{
struct dentry *dentry;
int rc = 0;
- struct vfs_cap_data vcaps;
- struct inode *inode;
+ struct cpu_vfs_cap_data vcaps;
bprm_clear_caps(bprm);
@@ -285,24 +304,18 @@ static int get_file_caps(struct linux_binprm *bprm)
return 0;
dentry = dget(bprm->file->f_dentry);
- inode = dentry->d_inode;
- if (!inode->i_op || !inode->i_op->getxattr)
- goto out;
- rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
- XATTR_CAPS_SZ);
- if (rc == -ENODATA || rc == -EOPNOTSUPP) {
- /* no data, that's ok */
- rc = 0;
+ rc = get_vfs_caps_from_disk(dentry, &vcaps);
+ if (rc < 0) {
+ if (rc == -EINVAL)
+ printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n",
+ __func__, rc, bprm->filename);
+ else if (rc == -ENODATA)
+ rc = 0;
goto out;
}
- if (rc < 0)
- goto out;
- rc = cap_from_disk(&vcaps, bprm, rc);
- if (rc == -EINVAL)
- printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
- __func__, rc, bprm->filename);
+ rc = bprm_caps_from_vfs_caps(&vcaps, bprm);
out:
dput(dentry);
This patch will print cap_permitted and cap_inheritable data in the PATH
records of any file that has file capabilities set. Files which do not
have fcaps set will not have different PATH records.
An example audit record if you run:
setcap "cap_net_admin+pie" /bin/bash
/bin/bash
type=SYSCALL msg=audit(1225741937.363:230): arch=c000003e syscall=59 success=yes exit=0 a0=2119230 a1=210da30 a2=20ee290 a3=8 items=2 ppid=2149 pid=2923 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=3 comm="ping" exe="/bin/ping" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=EXECVE msg=audit(1225741937.363:230): argc=2 a0="ping" a1="http://www.google.com"
type=CWD msg=audit(1225741937.363:230): cwd="/root"
type=PATH msg=audit(1225741937.363:230): item=0 name="/bin/ping" inode=49256 dev=fd:00 mode=0104755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ping_exec_t:s0 cap_fp=0000000000002000 cap_fi=0000000000002000 cap_fe=1 cap_fver=2
type=PATH msg=audit(1225741937.363:230): item=1 name=(null) inode=507915 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0
Signed-off-by: Eric Paris <[email protected]>
---
include/linux/capability.h | 5 +++
kernel/auditsc.c | 82 +++++++++++++++++++++++++++++++++++++++++---
2 files changed, 82 insertions(+), 5 deletions(-)
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 9d64a9c..3f7920b 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -53,6 +53,7 @@ typedef struct __user_cap_data_struct {
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
#define VFS_CAP_REVISION_MASK 0xFF000000
+#define VFS_CAP_REVISION_SHIFT 24
#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
@@ -524,6 +525,10 @@ kernel_cap_t cap_set_effective(const kernel_cap_t pE_new);
extern int capable(int cap);
+/* audit system wants to get cap info from files as well */
+struct dentry;
+extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
+
#endif /* __KERNEL__ */
#endif /* !_LINUX_CAPABILITY_H */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index cf5bc2f..f87f31a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -65,6 +65,7 @@
#include <linux/highmem.h>
#include <linux/syscalls.h>
#include <linux/inotify.h>
+#include <linux/capability.h>
#include "audit.h"
@@ -84,6 +85,15 @@ int audit_n_rules;
/* determines whether we collect data for signals sent */
int audit_signals;
+struct audit_cap_data {
+ kernel_cap_t permitted;
+ kernel_cap_t inheritable;
+ union {
+ unsigned int fE;
+ kernel_cap_t effective;
+ };
+};
+
/* When fs/namei.c:getname() is called, we store the pointer in name and
* we don't let putname() free it (instead we free all of the saved
* pointers at syscall exit time).
@@ -100,6 +110,8 @@ struct audit_names {
gid_t gid;
dev_t rdev;
u32 osid;
+ struct audit_cap_data fcap;
+ unsigned int fcap_ver;
};
struct audit_aux_data {
@@ -1171,6 +1183,35 @@ static void audit_log_execve_info(struct audit_context *context,
kfree(buf);
}
+static void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
+{
+ int i;
+
+ audit_log_format(ab, " %s=", prefix);
+ CAP_FOR_EACH_U32(i) {
+ audit_log_format(ab, "%08x", cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
+ }
+}
+
+static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
+{
+ kernel_cap_t *perm = &name->fcap.permitted;
+ kernel_cap_t *inh = &name->fcap.inheritable;
+ int log = 0;
+
+ if (!cap_isclear(*perm)) {
+ audit_log_cap(ab, "cap_fp", perm);
+ log = 1;
+ }
+ if (!cap_isclear(*inh)) {
+ audit_log_cap(ab, "cap_fi", inh);
+ log = 1;
+ }
+
+ if (log)
+ audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver);
+}
+
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
int i, call_panic = 0;
@@ -1421,6 +1462,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
}
}
+ audit_log_fcaps(ab, n);
+
audit_log_end(ab);
}
@@ -1787,8 +1830,36 @@ static int audit_inc_name_count(struct audit_context *context,
return 0;
}
+
+static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry)
+{
+ struct cpu_vfs_cap_data caps;
+ int rc;
+
+ memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t));
+ memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t));
+ name->fcap.fE = 0;
+ name->fcap_ver = 0;
+
+ if (!dentry)
+ return 0;
+
+ rc = get_vfs_caps_from_disk(dentry, &caps);
+ if (rc)
+ return rc;
+
+ name->fcap.permitted = caps.permitted;
+ name->fcap.inheritable = caps.inheritable;
+ name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+ name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
+
+ return 0;
+}
+
+
/* Copy inode data into an audit_names. */
-static void audit_copy_inode(struct audit_names *name, const struct inode *inode)
+static void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
+ const struct inode *inode)
{
name->ino = inode->i_ino;
name->dev = inode->i_sb->s_dev;
@@ -1797,6 +1868,7 @@ static void audit_copy_inode(struct audit_names *name, const struct inode *inode
name->gid = inode->i_gid;
name->rdev = inode->i_rdev;
security_inode_getsecid(inode, &name->osid);
+ audit_copy_fcaps(name, dentry);
}
/**
@@ -1831,7 +1903,7 @@ void __audit_inode(const char *name, const struct dentry *dentry)
context->names[idx].name = NULL;
}
handle_path(dentry);
- audit_copy_inode(&context->names[idx], inode);
+ audit_copy_inode(&context->names[idx], dentry, inode);
}
/**
@@ -1892,7 +1964,7 @@ void __audit_inode_child(const char *dname, const struct dentry *dentry,
if (!strcmp(dname, n->name) ||
!audit_compare_dname_path(dname, n->name, &dirlen)) {
if (inode)
- audit_copy_inode(n, inode);
+ audit_copy_inode(n, NULL, inode);
else
n->ino = (unsigned long)-1;
found_child = n->name;
@@ -1906,7 +1978,7 @@ add_names:
return;
idx = context->name_count - 1;
context->names[idx].name = NULL;
- audit_copy_inode(&context->names[idx], parent);
+ audit_copy_inode(&context->names[idx], NULL, parent);
}
if (!found_child) {
@@ -1927,7 +1999,7 @@ add_names:
}
if (inode)
- audit_copy_inode(&context->names[idx], inode);
+ audit_copy_inode(&context->names[idx], NULL, inode);
else
context->names[idx].ino = (unsigned long)-1;
}
Any time fcaps or a setuid app under SECURE_NOROOT is used to result in a
non-zero pE we will crate a new audit record which contains the entire set
of known information about the executable in question, fP, fI, fE, fversion
and includes the process's pE, pI, pP. Before and after the bprm capability
are applied. This record type will only be emitted from execve syscalls.
an example of making ping use fcaps instead of setuid:
setcap "cat_net_raw+pe" /bin/ping
type=SYSCALL msg=audit(1225742021.015:236): arch=c000003e syscall=59 success=yes exit=0 a0=1457f30 a1=14606b0 a2=1463940 a3=321b770a70 items=2 ppid=2929 pid=2963 auid=0 uid=500 gid=500 euid=500 suid=500 fsuid=500 egid=500 sgid=500 fsgid=500 tty=pts0 ses=3 comm="ping" exe="/bin/ping" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=UNKNOWN[1321] msg=audit(1225742021.015:236): fver=2 fp=0000000000002000 fi=0000000000000000 fe=1 old_pp=0000000000000000 old_pi=0000000000000000 old_pe=0000000000000000 new_pp=0000000000002000 new_pi=0000000000000000 new_pe=0000000000002000
type=EXECVE msg=audit(1225742021.015:236): argc=2 a0="ping" a1="127.0.0.1"
type=CWD msg=audit(1225742021.015:236): cwd="/home/test"
type=PATH msg=audit(1225742021.015:236): item=0 name="/bin/ping" inode=49256 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ping_exec_t:s0 cap_fp=0000000000002000 cap_fe=1 cap_fver=2
type=PATH msg=audit(1225742021.015:236): item=1 name=(null) inode=507915 dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0
Signed-off-by: Eric Paris <[email protected]>
---
include/linux/audit.h | 11 ++++++++
kernel/auditsc.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++
security/commoncap.c | 10 ++++++++
3 files changed, 86 insertions(+), 0 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 6272a39..5ecca2b 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -99,6 +99,7 @@
#define AUDIT_OBJ_PID 1318 /* ptrace target */
#define AUDIT_TTY 1319 /* Input on an administrative TTY */
#define AUDIT_EOE 1320 /* End of multi-record event */
+#define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -452,6 +453,7 @@ extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_pr
extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
+extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE);
static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
@@ -501,6 +503,14 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
return __audit_mq_getsetattr(mqdes, mqstat);
return 0;
}
+
+static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE)
+{
+ if (unlikely(!audit_dummy_context()))
+ return __audit_log_bprm_fcaps(bprm, pP, pE);
+ return 0;
+}
+
extern int audit_n_rules;
extern int audit_signals;
#else
@@ -532,6 +542,7 @@ extern int audit_signals;
#define audit_mq_timedreceive(d,l,p,t) ({ 0; })
#define audit_mq_notify(d,n) ({ 0; })
#define audit_mq_getsetattr(d,s) ({ 0; })
+#define audit_log_bprm_fcaps(b, p, e) 0
#define audit_ptrace(t) ((void)0)
#define audit_n_rules 0
#define audit_signals 0
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f87f31a..8fe907a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -196,6 +196,14 @@ struct audit_aux_data_pids {
int pid_count;
};
+struct audit_aux_data_bprm_fcaps {
+ struct audit_aux_data d;
+ struct audit_cap_data fcap;
+ unsigned int fcap_ver;
+ struct audit_cap_data old_pcap;
+ struct audit_cap_data new_pcap;
+};
+
struct audit_tree_refs {
struct audit_tree_refs *next;
struct audit_chunk *c[31];
@@ -1375,6 +1383,20 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
break; }
+ case AUDIT_BPRM_FCAPS: {
+ struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
+ audit_log_format(ab, "fver=%x", axs->fcap_ver);
+ audit_log_cap(ab, "fp", &axs->fcap.permitted);
+ audit_log_cap(ab, "fi", &axs->fcap.inheritable);
+ audit_log_format(ab, " fe=%d", axs->fcap.fE);
+ audit_log_cap(ab, "old_pp", &axs->old_pcap.permitted);
+ audit_log_cap(ab, "old_pi", &axs->old_pcap.inheritable);
+ audit_log_cap(ab, "old_pe", &axs->old_pcap.effective);
+ audit_log_cap(ab, "new_pp", &axs->new_pcap.permitted);
+ audit_log_cap(ab, "new_pi", &axs->new_pcap.inheritable);
+ audit_log_cap(ab, "new_pe", &axs->new_pcap.effective);
+ break; }
+
}
audit_log_end(ab);
}
@@ -2502,6 +2524,49 @@ int __audit_signal_info(int sig, struct task_struct *t)
}
/**
+ * __audit_log_bprm_fcaps - store information about a loading bprm and relevant fcaps
+ * @bprm pointer to the bprm being processed
+ * @caps the caps read from the disk
+ *
+ * Simply check if the proc already has the caps given by the file and if not
+ * store the priv escalation info for later auditing at the end of the syscall
+ */
+int __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE)
+{
+ struct audit_aux_data_bprm_fcaps *ax;
+ struct audit_context *context = current->audit_context;
+ struct cpu_vfs_cap_data vcaps;
+ struct dentry *dentry;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ return -ENOMEM;
+
+ ax->d.type = AUDIT_BPRM_FCAPS;
+ ax->d.next = context->aux;
+ context->aux = (void *)ax;
+
+ dentry = dget(bprm->file->f_dentry);
+ get_vfs_caps_from_disk(dentry, &vcaps);
+ dput(dentry);
+
+ ax->fcap.permitted = vcaps.permitted;
+ ax->fcap.inheritable = vcaps.inheritable;
+ ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+ ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
+
+ ax->old_pcap.permitted = *pP;
+ ax->old_pcap.inheritable = current->cap_inheritable;
+ ax->old_pcap.effective = *pE;
+
+ ax->new_pcap.permitted = current->cap_permitted;
+ ax->new_pcap.inheritable = current->cap_inheritable;
+ ax->new_pcap.effective = current->cap_effective;
+
+ return 0;
+}
+
+/**
* audit_core_dumps - record information about processes that end abnormally
* @signr: signal value
*
diff --git a/security/commoncap.c b/security/commoncap.c
index 8bb95ed..534abb5 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -8,6 +8,7 @@
*/
#include <linux/capability.h>
+#include <linux/audit.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -373,6 +374,9 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
+ kernel_cap_t pP = current->cap_permitted;
+ kernel_cap_t pE = current->cap_effective;
+
if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
!cap_issubset(bprm->cap_post_exec_permitted,
current->cap_permitted)) {
@@ -407,6 +411,12 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
}
/* AUD: Audit candidate if current->cap_effective is set */
+ if (!cap_isclear(current->cap_effective)) {
+ if (!cap_issubset(current->cap_effective, CAP_FULL_SET) ||
+ (bprm->e_uid != 0) || (current->uid != 0) ||
+ issecure(SECURE_NOROOT))
+ audit_log_bprm_fcaps(bprm, &pP, &pE);
+ }
current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
}
When the capset syscall is used it is not possible for audit to record the
actual capbilities being added/removed. This patch adds a new record type
which emits the target pid and the eff, inh, and perm cap sets.
example output if you audit capset syscalls would be:
type=SYSCALL msg=audit(1225743140.465:76): arch=c000003e syscall=126 success=yes exit=0 a0=17f2014 a1=17f201c a2=80000000 a3=7fff2ab7f060 items=0 ppid=2160 pid=2223 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="setcap" exe="/usr/sbin/setcap" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=UNKNOWN[1322] msg=audit(1225743140.465:76): pid=0 cap_pi=ffffffffffffffff cap_pp=ffffffffffffffff cap_pe=ffffffffffffffff
Signed-off-by: Eric Paris <[email protected]>
---
include/linux/audit.h | 10 ++++++++++
kernel/auditsc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
kernel/capability.c | 3 +++
3 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 5ecca2b..d6176f1 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -100,6 +100,7 @@
#define AUDIT_TTY 1319 /* Input on an administrative TTY */
#define AUDIT_EOE 1320 /* End of multi-record event */
#define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */
+#define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -454,6 +455,7 @@ extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __u
extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_cap_t *pE);
+extern int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm);
static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp)
{
@@ -511,6 +513,13 @@ static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *
return 0;
}
+static inline int audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm)
+{
+ if (unlikely(!audit_dummy_context()))
+ return __audit_log_capset(pid, eff, inh, perm);
+ return 0;
+}
+
extern int audit_n_rules;
extern int audit_signals;
#else
@@ -543,6 +552,7 @@ extern int audit_signals;
#define audit_mq_notify(d,n) ({ 0; })
#define audit_mq_getsetattr(d,s) ({ 0; })
#define audit_log_bprm_fcaps(b, p, e) 0
+#define audit_log_capset(pid, e, i, p) do { ; } while (0)
#define audit_ptrace(t) ((void)0)
#define audit_n_rules 0
#define audit_signals 0
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 8fe907a..a4ff5fa 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -204,6 +204,12 @@ struct audit_aux_data_bprm_fcaps {
struct audit_cap_data new_pcap;
};
+struct audit_aux_data_capset {
+ struct audit_aux_data d;
+ pid_t pid;
+ struct audit_cap_data cap;
+};
+
struct audit_tree_refs {
struct audit_tree_refs *next;
struct audit_chunk *c[31];
@@ -1397,6 +1403,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_cap(ab, "new_pe", &axs->new_pcap.effective);
break; }
+ case AUDIT_CAPSET: {
+ struct audit_aux_data_capset *axs = (void *)aux;
+ audit_log_format(ab, "pid=%d", axs->pid);
+ audit_log_cap(ab, "cap_pi", &axs->cap.inheritable);
+ audit_log_cap(ab, "cap_pp", &axs->cap.permitted);
+ audit_log_cap(ab, "cap_pe", &axs->cap.effective);
+ break; }
+
}
audit_log_end(ab);
}
@@ -2567,6 +2581,40 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm, kernel_cap_t *pP, kernel_c
}
/**
+ * __audit_log_capset - store information about the arguments to the capset syscall
+ * @pid target pid of the capset call
+ * @eff effective cap set
+ * @inh inheritible cap set
+ * @perm permited cap set
+ *
+ * Record the aguments userspace sent to sys_capset for later printing by the
+ * audit system if applicable
+ */
+int __audit_log_capset(pid_t pid, kernel_cap_t *eff, kernel_cap_t *inh, kernel_cap_t *perm)
+{
+ struct audit_aux_data_capset *ax;
+ struct audit_context *context = current->audit_context;
+
+ if (likely(!audit_enabled || !context || context->dummy))
+ return 0;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+ if (!ax)
+ return -ENOMEM;
+
+ ax->d.type = AUDIT_CAPSET;
+ ax->d.next = context->aux;
+ context->aux = (void *)ax;
+
+ ax->pid = pid;
+ ax->cap.effective = *eff;
+ ax->cap.inheritable = *eff;
+ ax->cap.permitted = *perm;
+
+ return 0;
+}
+
+/**
* audit_core_dumps - record information about processes that end abnormally
* @signr: signal value
*
diff --git a/kernel/capability.c b/kernel/capability.c
index 33e51e7..3d7fc70 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -7,6 +7,7 @@
* 30 May 2002: Cleanup, Robert M. Love <[email protected]>
*/
+#include <linux/audit.h>
#include <linux/capability.h>
#include <linux/mm.h>
#include <linux/module.h>
@@ -457,6 +458,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
i++;
}
+ audit_log_capset(pid, &effective, &inheritable, &permitted);
+
if (pid && (pid != task_pid_vnr(current)))
ret = do_sys_capset_other_tasks(pid, &effective, &inheritable,
&permitted);
Quoting Eric Paris ([email protected]):
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 8bb95ed..534abb5 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -8,6 +8,7 @@
> */
>
> #include <linux/capability.h>
> +#include <linux/audit.h>
> #include <linux/module.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> @@ -373,6 +374,9 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
>
> void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> {
> + kernel_cap_t pP = current->cap_permitted;
> + kernel_cap_t pE = current->cap_effective;
> +
> if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
> !cap_issubset(bprm->cap_post_exec_permitted,
> current->cap_permitted)) {
> @@ -407,6 +411,12 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> }
>
> /* AUD: Audit candidate if current->cap_effective is set */
> + if (!cap_isclear(current->cap_effective)) {
> + if (!cap_issubset(current->cap_effective, CAP_FULL_SET) ||
Hi Eric,
can you explain what the cap_issubset() check is for here?
thanks,
-serge
> + (bprm->e_uid != 0) || (current->uid != 0) ||
> + issecure(SECURE_NOROOT))
> + audit_log_bprm_fcaps(bprm, &pP, &pE);
> + }
>
> current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
> }
Quoting Eric Paris ([email protected]):
> diff --git a/kernel/capability.c b/kernel/capability.c
> index 33e51e7..3d7fc70 100644
> --- a/kernel/capability.c
> +++ b/kernel/capability.c
> @@ -7,6 +7,7 @@
> * 30 May 2002: Cleanup, Robert M. Love <[email protected]>
> */
>
> +#include <linux/audit.h>
> #include <linux/capability.h>
> #include <linux/mm.h>
> #include <linux/module.h>
> @@ -457,6 +458,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
> i++;
> }
>
> + audit_log_capset(pid, &effective, &inheritable, &permitted);
Shouldn't sys_capset() fail if audit_log_capset() returns -ENOMEM?
> +
> if (pid && (pid != task_pid_vnr(current)))
> ret = do_sys_capset_other_tasks(pid, &effective, &inheritable,
> &permitted);
Quoting Eric Paris ([email protected]):
> This patch add a generic cpu endian caps structure and externally available
> functions which retrieve fcaps information from disk. This information is
> necessary so fcaps information can be collected and recorded by the audit
> system.
>
> Signed-off-by: Eric Paris <[email protected]>
Looks good, and seems to make the code a bit easier to read as well.
Acked-by: Serge Hallyn <[email protected]>
thanks,
-serge
> ---
>
> include/linux/capability.h | 7 ++
> security/commoncap.c | 129 ++++++++++++++++++++++++--------------------
> 2 files changed, 78 insertions(+), 58 deletions(-)
>
> diff --git a/include/linux/capability.h b/include/linux/capability.h
> index 9d1fe30..9d64a9c 100644
> --- a/include/linux/capability.h
> +++ b/include/linux/capability.h
> @@ -96,6 +96,13 @@ typedef struct kernel_cap_struct {
> __u32 cap[_KERNEL_CAPABILITY_U32S];
> } kernel_cap_t;
>
> +/* exact same as vfs_cap_data but in cpu endian and always filled completely */
> +struct cpu_vfs_cap_data {
> + __u32 magic_etc;
> + kernel_cap_t permitted;
> + kernel_cap_t inheritable;
> +};
> +
> #define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
> #define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
>
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 3976613..8bb95ed 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -202,17 +202,70 @@ int cap_inode_killpriv(struct dentry *dentry)
> return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
> }
>
> -static inline int cap_from_disk(struct vfs_cap_data *caps,
> - struct linux_binprm *bprm, unsigned size)
> +static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
> + struct linux_binprm *bprm)
> {
> + unsigned i;
> + int ret = 0;
> +
> + if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
> + bprm->cap_effective = true;
> + else
> + bprm->cap_effective = false;
> +
> + CAP_FOR_EACH_U32(i) {
> + __u32 permitted = caps->permitted.cap[i];
> + __u32 inheritable = caps->inheritable.cap[i];
> +
> + /*
> + * pP' = (X & fP) | (pI & fI)
> + */
> + bprm->cap_post_exec_permitted.cap[i] =
> + (current->cap_bset.cap[i] & permitted) |
> + (current->cap_inheritable.cap[i] & inheritable);
> +
> + if (permitted & ~bprm->cap_post_exec_permitted.cap[i]) {
> + /*
> + * insufficient to execute correctly
> + */
> + ret = -EPERM;
> + }
> + }
> +
> + /*
> + * For legacy apps, with no internal support for recognizing they
> + * do not have enough capabilities, we return an error if they are
> + * missing some "forced" (aka file-permitted) capabilities.
> + */
> + return bprm->cap_effective ? ret : 0;
> +}
> +
> +int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
> +{
> + struct inode *inode = dentry->d_inode;
> __u32 magic_etc;
> unsigned tocopy, i;
> - int ret;
> + int size;
> + struct vfs_cap_data caps;
> +
> + memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
> +
> + if (!inode || !inode->i_op || !inode->i_op->getxattr)
> + return -ENODATA;
> +
> + size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
> + XATTR_CAPS_SZ);
> + if (size == -ENODATA || size == -EOPNOTSUPP) {
> + /* no data, that's ok */
> + return -ENODATA;
> + }
> + if (size < 0)
> + return size;
>
> if (size < sizeof(magic_etc))
> return -EINVAL;
>
> - magic_etc = le32_to_cpu(caps->magic_etc);
> + cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc);
>
> switch ((magic_etc & VFS_CAP_REVISION_MASK)) {
> case VFS_CAP_REVISION_1:
> @@ -229,46 +282,13 @@ static inline int cap_from_disk(struct vfs_cap_data *caps,
> return -EINVAL;
> }
>
> - if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) {
> - bprm->cap_effective = true;
> - } else {
> - bprm->cap_effective = false;
> - }
> -
> - ret = 0;
> -
> CAP_FOR_EACH_U32(i) {
> - __u32 value_cpu;
> -
> - if (i >= tocopy) {
> - /*
> - * Legacy capability sets have no upper bits
> - */
> - bprm->cap_post_exec_permitted.cap[i] = 0;
> - continue;
> - }
> - /*
> - * pP' = (X & fP) | (pI & fI)
> - */
> - value_cpu = le32_to_cpu(caps->data[i].permitted);
> - bprm->cap_post_exec_permitted.cap[i] =
> - (current->cap_bset.cap[i] & value_cpu) |
> - (current->cap_inheritable.cap[i] &
> - le32_to_cpu(caps->data[i].inheritable));
> - if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
> - /*
> - * insufficient to execute correctly
> - */
> - ret = -EPERM;
> - }
> + if (i >= tocopy)
> + break;
> + cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted);
> + cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable);
> }
> -
> - /*
> - * For legacy apps, with no internal support for recognizing they
> - * do not have enough capabilities, we return an error if they are
> - * missing some "forced" (aka file-permitted) capabilities.
> - */
> - return bprm->cap_effective ? ret : 0;
> + return 0;
> }
>
> /* Locate any VFS capabilities: */
> @@ -276,8 +296,7 @@ static int get_file_caps(struct linux_binprm *bprm)
> {
> struct dentry *dentry;
> int rc = 0;
> - struct vfs_cap_data vcaps;
> - struct inode *inode;
> + struct cpu_vfs_cap_data vcaps;
>
> bprm_clear_caps(bprm);
>
> @@ -285,24 +304,18 @@ static int get_file_caps(struct linux_binprm *bprm)
> return 0;
>
> dentry = dget(bprm->file->f_dentry);
> - inode = dentry->d_inode;
> - if (!inode->i_op || !inode->i_op->getxattr)
> - goto out;
>
> - rc = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, &vcaps,
> - XATTR_CAPS_SZ);
> - if (rc == -ENODATA || rc == -EOPNOTSUPP) {
> - /* no data, that's ok */
> - rc = 0;
> + rc = get_vfs_caps_from_disk(dentry, &vcaps);
> + if (rc < 0) {
> + if (rc == -EINVAL)
> + printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n",
> + __func__, rc, bprm->filename);
> + else if (rc == -ENODATA)
> + rc = 0;
> goto out;
> }
> - if (rc < 0)
> - goto out;
>
> - rc = cap_from_disk(&vcaps, bprm, rc);
> - if (rc == -EINVAL)
> - printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
> - __func__, rc, bprm->filename);
> + rc = bprm_caps_from_vfs_caps(&vcaps, bprm);
>
> out:
> dput(dentry);
On Tue, 2008-11-04 at 10:35 -0600, Serge E. Hallyn wrote:
> Quoting Eric Paris ([email protected]):
> > diff --git a/security/commoncap.c b/security/commoncap.c
> > index 8bb95ed..534abb5 100644
> > --- a/security/commoncap.c
> > +++ b/security/commoncap.c
> > @@ -8,6 +8,7 @@
> > */
> >
> > #include <linux/capability.h>
> > +#include <linux/audit.h>
> > #include <linux/module.h>
> > #include <linux/init.h>
> > #include <linux/kernel.h>
> > @@ -373,6 +374,9 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
> >
> > void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> > {
> > + kernel_cap_t pP = current->cap_permitted;
> > + kernel_cap_t pE = current->cap_effective;
> > +
> > if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
> > !cap_issubset(bprm->cap_post_exec_permitted,
> > current->cap_permitted)) {
> > @@ -407,6 +411,12 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> > }
> >
> > /* AUD: Audit candidate if current->cap_effective is set */
> > + if (!cap_isclear(current->cap_effective)) {
> > + if (!cap_issubset(current->cap_effective, CAP_FULL_SET) ||
>
> Hi Eric,
>
> can you explain what the cap_issubset() check is for here?
I'm glad you noticed it, because it is backwards!
should be
if (!cap_issubset(CAP_FULL_SET, current->cap_effective) ||
The idea is that I don't care to audit
1) full set &&
2) this is root &&
3) root should have a full set
This would still consider a root without a full set because the bset had
been changed to be an interesting event. I'm fine with that.
I'll send -v3 once I hear comments on everything else....
-Eric
Quoting Eric Paris ([email protected]):
> On Tue, 2008-11-04 at 10:35 -0600, Serge E. Hallyn wrote:
> > Quoting Eric Paris ([email protected]):
> > > diff --git a/security/commoncap.c b/security/commoncap.c
> > > index 8bb95ed..534abb5 100644
> > > --- a/security/commoncap.c
> > > +++ b/security/commoncap.c
> > > @@ -8,6 +8,7 @@
> > > */
> > >
> > > #include <linux/capability.h>
> > > +#include <linux/audit.h>
> > > #include <linux/module.h>
> > > #include <linux/init.h>
> > > #include <linux/kernel.h>
> > > @@ -373,6 +374,9 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
> > >
> > > void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> > > {
> > > + kernel_cap_t pP = current->cap_permitted;
> > > + kernel_cap_t pE = current->cap_effective;
> > > +
> > > if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
> > > !cap_issubset(bprm->cap_post_exec_permitted,
> > > current->cap_permitted)) {
> > > @@ -407,6 +411,12 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> > > }
> > >
> > > /* AUD: Audit candidate if current->cap_effective is set */
> > > + if (!cap_isclear(current->cap_effective)) {
> > > + if (!cap_issubset(current->cap_effective, CAP_FULL_SET) ||
> >
> > Hi Eric,
> >
> > can you explain what the cap_issubset() check is for here?
>
> I'm glad you noticed it, because it is backwards!
>
> should be
>
> if (!cap_issubset(CAP_FULL_SET, current->cap_effective) ||
>
> The idea is that I don't care to audit
> 1) full set &&
> 2) this is root &&
> 3) root should have a full set
Cool, that makes sense.
Would you mind adding a trivial patch to your set commenting
cap_issubset() in capability.h? If you feel it's too outside the scope
of this set I'll send such separately. Every time I see code using
it, it takes me 5 mins to remember which order they're supposed to be
in...
> This would still consider a root without a full set because the bset had
> been changed to be an interesting event. I'm fine with that.
>
> I'll send -v3 once I hear comments on everything else....
>
> -Eric
thanks,
-serge
On Tue, 2008-11-04 at 10:55 -0600, Serge E. Hallyn wrote:
> Quoting Eric Paris ([email protected]):
> > diff --git a/kernel/capability.c b/kernel/capability.c
> > index 33e51e7..3d7fc70 100644
> > --- a/kernel/capability.c
> > +++ b/kernel/capability.c
> > @@ -7,6 +7,7 @@
> > * 30 May 2002: Cleanup, Robert M. Love <[email protected]>
> > */
> >
> > +#include <linux/audit.h>
> > #include <linux/capability.h>
> > #include <linux/mm.h>
> > #include <linux/module.h>
> > @@ -457,6 +458,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
> > i++;
> > }
> >
> > + audit_log_capset(pid, &effective, &inheritable, &permitted);
>
> Shouldn't sys_capset() fail if audit_log_capset() returns -ENOMEM?
yes, I think it should, but look for the next e-mail.....
On Tue, 2008-11-04 at 10:35 -0600, Serge E. Hallyn wrote:
> Quoting Eric Paris ([email protected]):
> > diff --git a/security/commoncap.c b/security/commoncap.c
> > index 8bb95ed..534abb5 100644
> > --- a/security/commoncap.c
> > +++ b/security/commoncap.c
> > @@ -8,6 +8,7 @@
> > */
> >
> > #include <linux/capability.h>
> > +#include <linux/audit.h>
> > #include <linux/module.h>
> > #include <linux/init.h>
> > #include <linux/kernel.h>
> > @@ -373,6 +374,9 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
> >
> > void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> > {
> > + kernel_cap_t pP = current->cap_permitted;
> > + kernel_cap_t pE = current->cap_effective;
> > +
> > if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
> > !cap_issubset(bprm->cap_post_exec_permitted,
> > current->cap_permitted)) {
> > @@ -407,6 +411,12 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
> > }
> >
> > /* AUD: Audit candidate if current->cap_effective is set */
> > + if (!cap_isclear(current->cap_effective)) {
> > + if (!cap_issubset(current->cap_effective, CAP_FULL_SET) ||
>
> Hi Eric,
>
> can you explain what the cap_issubset() check is for here?
>
> thanks,
> -serge
>
> > + (bprm->e_uid != 0) || (current->uid != 0) ||
> > + issecure(SECURE_NOROOT))
> > + audit_log_bprm_fcaps(bprm, &pP, &pE);
So here's the problem.... I can't fail this syscall, it's too late. I
can do a couple of things.
1) waste lots of space in the execve record so we know memory has
already been allocated
2) just ignore the memory failure and don't worry about it. We are
still going to get the fcaps info from the patch record and should be
able to piece together the starting and finishing caps by looking at
past audit records if you really need it.
3) I can call audit_log_lost(). I don't think we know are this time
that we really needed this record, but this is the 'safest' approach.
If people have their machines set to panic on lost records we would
panic. Honestly though, if we don't have enough memory to satisfy this
request (we're talking about 72 bytes or something?) we are going to
fail the next audit message, so doing it now would be just fine.
I vote #2 since I don't think we are really going to have any lose of
info. But if people want it I'll go #3 since I don't think it will hurt
anything.
-Eric
Quoting Eric Paris ([email protected]):
> So here's the problem.... I can't fail this syscall, it's too late. I
Oh, right...
> can do a couple of things.
>
> 1) waste lots of space in the execve record so we know memory has
> already been allocated
> 2) just ignore the memory failure and don't worry about it. We are
> still going to get the fcaps info from the patch record and should be
> able to piece together the starting and finishing caps by looking at
> past audit records if you really need it.
> 3) I can call audit_log_lost(). I don't think we know are this time
> that we really needed this record, but this is the 'safest' approach.
> If people have their machines set to panic on lost records we would
> panic. Honestly though, if we don't have enough memory to satisfy this
> request (we're talking about 72 bytes or something?) we are going to
> fail the next audit message, so doing it now would be just fine.
>
> I vote #2 since I don't think we are really going to have any lose of
> info. But if people want it I'll go #3 since I don't think it will hurt
> anything.
2 sounds reasonable to me. Reckon sgrubb will speak up if it violates
some audit requirement.
thanks,
-serge