type=SYSCALL msg=audit(1224342849.465:43): arch=c000003e syscall=59 success=yes 
exit=0 a0=25b6a00 a1=2580410 a2=2580140 a3=8 items=2 ppid=2219 pid=2266 auid=0 
uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 
comm="ping" exe="/bin/ping" 
subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=EXECVE msg=audit(1224342849.465:43): argc=2 a0="ping" a1="127.0.0.1" 
type=CWD msg=audit(1224342849.465:43):  cwd="/root"
type=PATH msg=audit(1224342849.465:43): item=0 name="/bin/ping" inode=49227 
dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 
obj=system_u:object_r:ping_exec_t:s0 cap_permitted=0000000000002000 
cap_inheritable=0000000000000000
type=PATH msg=audit(1224342849.465:43): item=1 name=(null) inode=507963 
dev=fd:00 mode=0100755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:ld_so_t:s0

This good?  If either cap_permitted or cap_inheritable have anything set
I show them both.  In the above example would you rather I only showed
cap_permitted and dropped cap_inheritable?  Did I see correctly that
it's possible to set a cap_effective on a file?  Does it do anything?  I
didn't see that getting used or read in the kernel, so I didn't put any
way to display it in kernel....

-Eric

---

 include/linux/capability.h |   11 ++++
 kernel/auditsc.c           |   68 ++++++++++++++++++++++++--
 security/commoncap.c       |  115 +++++++++++++++++++++++++-------------------
 3 files changed, 140 insertions(+), 54 deletions(-)

diff --git a/include/linux/capability.h b/include/linux/capability.h
index 9d1fe30..a3785e7 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))
 
@@ -517,6 +524,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..800fc55 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"
 
@@ -100,6 +101,8 @@ struct audit_names {
        gid_t           gid;
        dev_t           rdev;
        u32             osid;
+       kernel_cap_t    cap_permitted;
+       kernel_cap_t    cap_inheritable;
 };
 
 struct audit_aux_data {
@@ -1171,6 +1174,33 @@ static void audit_log_execve_info(struct audit_context 
*context,
        kfree(buf);
 }
 
+static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
+{
+       int i;
+       int print = 0;
+       kernel_cap_t *perm = &name->cap_permitted;
+       kernel_cap_t *inh = &name->cap_inheritable;
+
+       CAP_FOR_EACH_U32(i) {
+               if (perm->cap[i] || inh->cap[i]) {
+                       print = 1;
+                       break;
+               }
+       }
+
+       if (likely(!print))
+               return;
+
+       audit_log_format(ab, " %s", "cap_permitted=");
+        CAP_FOR_EACH_U32(i) {
+                audit_log_format(ab, "%08x", 
perm->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
+        }
+       audit_log_format(ab, " %s", "cap_inheritable=");
+        CAP_FOR_EACH_U32(i) {
+                audit_log_format(ab, "%08x", 
inh->cap[(_KERNEL_CAPABILITY_U32S-1) - i]);
+        }
+}
+
 static void audit_log_exit(struct audit_context *context, struct task_struct 
*tsk)
 {
        int i, call_panic = 0;
@@ -1421,6 +1451,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 +1819,33 @@ 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, i;
+
+       memset(&name->cap_permitted, 0, sizeof(kernel_cap_t));
+       memset(&name->cap_inheritable, 0, sizeof(kernel_cap_t));
+
+       if (!dentry)
+               return 0;
+
+       rc = get_vfs_caps_from_disk(dentry, &caps);
+       if (rc)
+               return rc;
+
+       CAP_FOR_EACH_U32(i) {
+               name->cap_permitted.cap[i] = caps.permitted.cap[i];
+               name->cap_inheritable.cap[i] = caps.inheritable.cap[i];
+       }
+       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 +1854,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 +1889,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 +1950,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 +1964,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 +1985,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;
        }
diff --git a/security/commoncap.c b/security/commoncap.c
index 399bfdb..9f109b9 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 0;
+
+       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 0;
+       }
+       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,16 @@ 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;
+               if (i > tocopy) {
+                       cpu_caps->permitted.cap[i] = 0;
+                       cpu_caps->inheritable.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;
-               }
+               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,7 +299,7 @@ static int get_file_caps(struct linux_binprm *bprm)
 {
        struct dentry *dentry;
        int rc = 0;
-       struct vfs_cap_data vcaps;
+       struct cpu_vfs_cap_data vcaps;
        struct inode *inode;
 
        if (bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID) {
@@ -289,17 +312,11 @@ static int get_file_caps(struct linux_binprm *bprm)
        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;
-               goto out;
-       }
+       rc = get_vfs_caps_from_disk(dentry, &vcaps);
        if (rc < 0)
                goto out;
 
-       rc = cap_from_disk(&vcaps, bprm, rc);
+       rc = bprm_caps_from_vfs_caps(&vcaps, bprm);
        if (rc == -EINVAL)
                printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
                       __func__, rc, bprm->filename);


--
Linux-audit mailing list
Linux-audit@redhat.com
https://www.redhat.com/mailman/listinfo/linux-audit

Reply via email to