Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / kernel / auditsc.c
index 6593a52..d1eab1d 100644 (file)
@@ -631,9 +631,8 @@ static int audit_filter_rules(struct task_struct *tsk,
                                        need_sid = 0;
                                }
                                result = security_audit_rule_match(sid, f->type,
-                                                                 f->op,
-                                                                 f->lsm_rule,
-                                                                 ctx);
+                                                                  f->op,
+                                                                  f->lsm_rule);
                        }
                        break;
                case AUDIT_OBJ_USER:
@@ -647,13 +646,17 @@ static int audit_filter_rules(struct task_struct *tsk,
                                /* Find files that match */
                                if (name) {
                                        result = security_audit_rule_match(
-                                                  name->osid, f->type, f->op,
-                                                  f->lsm_rule, ctx);
+                                                               name->osid,
+                                                               f->type,
+                                                               f->op,
+                                                               f->lsm_rule);
                                } else if (ctx) {
                                        list_for_each_entry(n, &ctx->names_list, list) {
-                                               if (security_audit_rule_match(n->osid, f->type,
-                                                                             f->op, f->lsm_rule,
-                                                                             ctx)) {
+                                               if (security_audit_rule_match(
+                                                               n->osid,
+                                                               f->type,
+                                                               f->op,
+                                                               f->lsm_rule)) {
                                                        ++result;
                                                        break;
                                                }
@@ -664,7 +667,7 @@ static int audit_filter_rules(struct task_struct *tsk,
                                        break;
                                if (security_audit_rule_match(ctx->ipc.osid,
                                                              f->type, f->op,
-                                                             f->lsm_rule, ctx))
+                                                             f->lsm_rule))
                                        ++result;
                        }
                        break;
@@ -1136,6 +1139,32 @@ out:
        kfree(buf_head);
 }
 
+void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap)
+{
+       int i;
+
+       if (cap_isclear(*cap)) {
+               audit_log_format(ab, " %s=0", prefix);
+               return;
+       }
+       audit_log_format(ab, " %s=", prefix);
+       CAP_FOR_EACH_U32(i)
+               audit_log_format(ab, "%08x", cap->cap[CAP_LAST_U32 - i]);
+}
+
+static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
+{
+       if (name->fcap_ver == -1) {
+               audit_log_format(ab, " cap_fe=? cap_fver=? cap_fp=? cap_fi=?");
+               return;
+       }
+       audit_log_cap(ab, "cap_fp", &name->fcap.permitted);
+       audit_log_cap(ab, "cap_fi", &name->fcap.inheritable);
+       audit_log_format(ab, " cap_fe=%d cap_fver=%x cap_frootid=%d",
+                        name->fcap.fE, name->fcap_ver,
+                        from_kuid(&init_user_ns, name->fcap.rootid));
+}
+
 static void show_special(struct audit_context *context, int *call_panic)
 {
        struct audit_buffer *ab;
@@ -1258,6 +1287,97 @@ static inline int audit_proctitle_rtrim(char *proctitle, int len)
        return len;
 }
 
+/*
+ * audit_log_name - produce AUDIT_PATH record from struct audit_names
+ * @context: audit_context for the task
+ * @n: audit_names structure with reportable details
+ * @path: optional path to report instead of audit_names->name
+ * @record_num: record number to report when handling a list of names
+ * @call_panic: optional pointer to int that will be updated if secid fails
+ */
+static void audit_log_name(struct audit_context *context, struct audit_names *n,
+                   const struct path *path, int record_num, int *call_panic)
+{
+       struct audit_buffer *ab;
+
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
+       if (!ab)
+               return;
+
+       audit_log_format(ab, "item=%d", record_num);
+
+       if (path)
+               audit_log_d_path(ab, " name=", path);
+       else if (n->name) {
+               switch (n->name_len) {
+               case AUDIT_NAME_FULL:
+                       /* log the full path */
+                       audit_log_format(ab, " name=");
+                       audit_log_untrustedstring(ab, n->name->name);
+                       break;
+               case 0:
+                       /* name was specified as a relative path and the
+                        * directory component is the cwd
+                        */
+                       audit_log_d_path(ab, " name=", &context->pwd);
+                       break;
+               default:
+                       /* log the name's directory component */
+                       audit_log_format(ab, " name=");
+                       audit_log_n_untrustedstring(ab, n->name->name,
+                                                   n->name_len);
+               }
+       } else
+               audit_log_format(ab, " name=(null)");
+
+       if (n->ino != AUDIT_INO_UNSET)
+               audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#ho ouid=%u ogid=%u rdev=%02x:%02x",
+                                n->ino,
+                                MAJOR(n->dev),
+                                MINOR(n->dev),
+                                n->mode,
+                                from_kuid(&init_user_ns, n->uid),
+                                from_kgid(&init_user_ns, n->gid),
+                                MAJOR(n->rdev),
+                                MINOR(n->rdev));
+       if (n->osid != 0) {
+               char *ctx = NULL;
+               u32 len;
+
+               if (security_secid_to_secctx(
+                       n->osid, &ctx, &len)) {
+                       audit_log_format(ab, " osid=%u", n->osid);
+                       if (call_panic)
+                               *call_panic = 2;
+               } else {
+                       audit_log_format(ab, " obj=%s", ctx);
+                       security_release_secctx(ctx, len);
+               }
+       }
+
+       /* log the audit_names record type */
+       switch (n->type) {
+       case AUDIT_TYPE_NORMAL:
+               audit_log_format(ab, " nametype=NORMAL");
+               break;
+       case AUDIT_TYPE_PARENT:
+               audit_log_format(ab, " nametype=PARENT");
+               break;
+       case AUDIT_TYPE_CHILD_DELETE:
+               audit_log_format(ab, " nametype=DELETE");
+               break;
+       case AUDIT_TYPE_CHILD_CREATE:
+               audit_log_format(ab, " nametype=CREATE");
+               break;
+       default:
+               audit_log_format(ab, " nametype=UNKNOWN");
+               break;
+       }
+
+       audit_log_fcaps(ab, n);
+       audit_log_end(ab);
+}
+
 static void audit_log_proctitle(void)
 {
        int res;
@@ -1358,6 +1478,9 @@ static void audit_log_exit(void)
                        audit_log_cap(ab, "pi", &axs->new_pcap.inheritable);
                        audit_log_cap(ab, "pe", &axs->new_pcap.effective);
                        audit_log_cap(ab, "pa", &axs->new_pcap.ambient);
+                       audit_log_format(ab, " frootid=%d",
+                                        from_kuid(&init_user_ns,
+                                                  axs->fcap.rootid));
                        break; }
 
                }
@@ -1444,6 +1567,9 @@ void __audit_free(struct task_struct *tsk)
        if (!context)
                return;
 
+       if (!list_empty(&context->killed_trees))
+               audit_kill_trees(context);
+
        /* We are called either by do_exit() or the fork() error handling code;
         * in the former case tsk == current and in the latter tsk is a
         * random task_struct that doesn't doesn't have any meaningful data we
@@ -1460,9 +1586,6 @@ void __audit_free(struct task_struct *tsk)
                        audit_log_exit();
        }
 
-       if (!list_empty(&context->killed_trees))
-               audit_kill_trees(&context->killed_trees);
-
        audit_set_context(tsk, NULL);
        audit_free_context(context);
 }
@@ -1537,6 +1660,9 @@ void __audit_syscall_exit(int success, long return_code)
        if (!context)
                return;
 
+       if (!list_empty(&context->killed_trees))
+               audit_kill_trees(context);
+
        if (!context->dummy && context->in_syscall) {
                if (success)
                        context->return_valid = AUDITSC_SUCCESS;
@@ -1571,9 +1697,6 @@ void __audit_syscall_exit(int success, long return_code)
        context->in_syscall = 0;
        context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
 
-       if (!list_empty(&context->killed_trees))
-               audit_kill_trees(&context->killed_trees);
-
        audit_free_names(context);
        unroll_tree_refs(context, NULL, 0);
        audit_free_aux(context);
@@ -1750,6 +1873,47 @@ void __audit_getname(struct filename *name)
                get_fs_pwd(current->fs, &context->pwd);
 }
 
+static inline int audit_copy_fcaps(struct audit_names *name,
+                                  const struct dentry *dentry)
+{
+       struct cpu_vfs_cap_data caps;
+       int rc;
+
+       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.rootid = caps.rootid;
+       name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >>
+                               VFS_CAP_REVISION_SHIFT;
+
+       return 0;
+}
+
+/* Copy inode data into an audit_names. */
+void audit_copy_inode(struct audit_names *name, const struct dentry *dentry,
+                     struct inode *inode, unsigned int flags)
+{
+       name->ino   = inode->i_ino;
+       name->dev   = inode->i_sb->s_dev;
+       name->mode  = inode->i_mode;
+       name->uid   = inode->i_uid;
+       name->gid   = inode->i_gid;
+       name->rdev  = inode->i_rdev;
+       security_inode_getsecid(inode, &name->osid);
+       if (flags & AUDIT_INODE_NOEVAL) {
+               name->fcap_ver = -1;
+               return;
+       }
+       audit_copy_fcaps(name, dentry);
+}
+
 /**
  * __audit_inode - store the inode and device from a lookup
  * @name: name being audited
@@ -1763,10 +1927,31 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
        struct inode *inode = d_backing_inode(dentry);
        struct audit_names *n;
        bool parent = flags & AUDIT_INODE_PARENT;
+       struct audit_entry *e;
+       struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
+       int i;
 
        if (!context->in_syscall)
                return;
 
+       rcu_read_lock();
+       if (!list_empty(list)) {
+               list_for_each_entry_rcu(e, list, list) {
+                       for (i = 0; i < e->rule.field_count; i++) {
+                               struct audit_field *f = &e->rule.fields[i];
+
+                               if (f->type == AUDIT_FSTYPE
+                                   && audit_comparator(inode->i_sb->s_magic,
+                                                       f->op, f->val)
+                                   && e->rule.action == AUDIT_NEVER) {
+                                       rcu_read_unlock();
+                                       return;
+                               }
+                       }
+               }
+       }
+       rcu_read_unlock();
+
        if (!name)
                goto out_alloc;
 
@@ -1832,7 +2017,7 @@ out:
                n->type = AUDIT_TYPE_NORMAL;
        }
        handle_path(dentry);
-       audit_copy_inode(n, dentry, inode);
+       audit_copy_inode(n, dentry, inode, flags & AUDIT_INODE_NOEVAL);
 }
 
 void __audit_file(const struct file *file)
@@ -1875,14 +2060,12 @@ void __audit_inode_child(struct inode *parent,
                        for (i = 0; i < e->rule.field_count; i++) {
                                struct audit_field *f = &e->rule.fields[i];
 
-                               if (f->type == AUDIT_FSTYPE) {
-                                       if (audit_comparator(parent->i_sb->s_magic,
-                                           f->op, f->val)) {
-                                               if (e->rule.action == AUDIT_NEVER) {
-                                                       rcu_read_unlock();
-                                                       return;
-                                               }
-                                       }
+                               if (f->type == AUDIT_FSTYPE
+                                   && audit_comparator(parent->i_sb->s_magic,
+                                                       f->op, f->val)
+                                   && e->rule.action == AUDIT_NEVER) {
+                                       rcu_read_unlock();
+                                       return;
                                }
                        }
                }
@@ -1933,7 +2116,7 @@ void __audit_inode_child(struct inode *parent,
                n = audit_alloc_name(context, AUDIT_TYPE_PARENT);
                if (!n)
                        return;
-               audit_copy_inode(n, NULL, parent);
+               audit_copy_inode(n, NULL, parent, 0);
        }
 
        if (!found_child) {
@@ -1952,7 +2135,7 @@ void __audit_inode_child(struct inode *parent,
        }
 
        if (inode)
-               audit_copy_inode(found_child, dentry, inode);
+               audit_copy_inode(found_child, dentry, inode, 0);
        else
                found_child->ino = AUDIT_INO_UNSET;
 }
@@ -1983,90 +2166,6 @@ int auditsc_get_stamp(struct audit_context *ctx,
        return 1;
 }
 
-/* global counter which is incremented every time something logs in */
-static atomic_t session_id = ATOMIC_INIT(0);
-
-static int audit_set_loginuid_perm(kuid_t loginuid)
-{
-       /* if we are unset, we don't need privs */
-       if (!audit_loginuid_set(current))
-               return 0;
-       /* if AUDIT_FEATURE_LOGINUID_IMMUTABLE means never ever allow a change*/
-       if (is_audit_feature_set(AUDIT_FEATURE_LOGINUID_IMMUTABLE))
-               return -EPERM;
-       /* it is set, you need permission */
-       if (!capable(CAP_AUDIT_CONTROL))
-               return -EPERM;
-       /* reject if this is not an unset and we don't allow that */
-       if (is_audit_feature_set(AUDIT_FEATURE_ONLY_UNSET_LOGINUID) && uid_valid(loginuid))
-               return -EPERM;
-       return 0;
-}
-
-static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid,
-                                  unsigned int oldsessionid, unsigned int sessionid,
-                                  int rc)
-{
-       struct audit_buffer *ab;
-       uid_t uid, oldloginuid, loginuid;
-       struct tty_struct *tty;
-
-       if (!audit_enabled)
-               return;
-
-       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
-       if (!ab)
-               return;
-
-       uid = from_kuid(&init_user_ns, task_uid(current));
-       oldloginuid = from_kuid(&init_user_ns, koldloginuid);
-       loginuid = from_kuid(&init_user_ns, kloginuid),
-       tty = audit_get_tty();
-
-       audit_log_format(ab, "pid=%d uid=%u", task_tgid_nr(current), uid);
-       audit_log_task_context(ab);
-       audit_log_format(ab, " old-auid=%u auid=%u tty=%s old-ses=%u ses=%u res=%d",
-                        oldloginuid, loginuid, tty ? tty_name(tty) : "(none)",
-                        oldsessionid, sessionid, !rc);
-       audit_put_tty(tty);
-       audit_log_end(ab);
-}
-
-/**
- * audit_set_loginuid - set current task's audit_context loginuid
- * @loginuid: loginuid value
- *
- * Returns 0.
- *
- * Called (set) from fs/proc/base.c::proc_loginuid_write().
- */
-int audit_set_loginuid(kuid_t loginuid)
-{
-       unsigned int oldsessionid, sessionid = AUDIT_SID_UNSET;
-       kuid_t oldloginuid;
-       int rc;
-
-       oldloginuid = audit_get_loginuid(current);
-       oldsessionid = audit_get_sessionid(current);
-
-       rc = audit_set_loginuid_perm(loginuid);
-       if (rc)
-               goto out;
-
-       /* are we setting or clearing? */
-       if (uid_valid(loginuid)) {
-               sessionid = (unsigned int)atomic_inc_return(&session_id);
-               if (unlikely(sessionid == AUDIT_SID_UNSET))
-                       sessionid = (unsigned int)atomic_inc_return(&session_id);
-       }
-
-       current->sessionid = sessionid;
-       current->loginuid = loginuid;
-out:
-       audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc);
-       return rc;
-}
-
 /**
  * __audit_mq_open - record audit data for a POSIX MQ open
  * @oflag: open flag
@@ -2355,6 +2454,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
        ax->fcap.permitted = vcaps.permitted;
        ax->fcap.inheritable = vcaps.inheritable;
        ax->fcap.fE = !!(vcaps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE);
+       ax->fcap.rootid = vcaps.rootid;
        ax->fcap_ver = (vcaps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT;
 
        ax->old_pcap.permitted   = old->cap_permitted;