hecubafb: use fb_sys_read()
[safe/jmp/linux-2.6] / kernel / auditsc.c
index f571c7e..628c7ac 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/tty.h>
 #include <linux/selinux.h>
 #include <linux/binfmts.h>
+#include <linux/highmem.h>
 #include <linux/syscalls.h>
 
 #include "audit.h"
@@ -169,6 +170,11 @@ struct audit_aux_data_sockaddr {
        char                    a[0];
 };
 
+struct audit_aux_data_fd_pair {
+       struct  audit_aux_data d;
+       int     fd[2];
+};
+
 struct audit_aux_data_path {
        struct audit_aux_data   d;
        struct dentry           *dentry;
@@ -209,6 +215,54 @@ struct audit_context {
 #endif
 };
 
+#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
+static inline int open_arg(int flags, int mask)
+{
+       int n = ACC_MODE(flags);
+       if (flags & (O_TRUNC | O_CREAT))
+               n |= AUDIT_PERM_WRITE;
+       return n & mask;
+}
+
+static int audit_match_perm(struct audit_context *ctx, int mask)
+{
+       unsigned n = ctx->major;
+       switch (audit_classify_syscall(ctx->arch, n)) {
+       case 0: /* native */
+               if ((mask & AUDIT_PERM_WRITE) &&
+                    audit_match_class(AUDIT_CLASS_WRITE, n))
+                       return 1;
+               if ((mask & AUDIT_PERM_READ) &&
+                    audit_match_class(AUDIT_CLASS_READ, n))
+                       return 1;
+               if ((mask & AUDIT_PERM_ATTR) &&
+                    audit_match_class(AUDIT_CLASS_CHATTR, n))
+                       return 1;
+               return 0;
+       case 1: /* 32bit on biarch */
+               if ((mask & AUDIT_PERM_WRITE) &&
+                    audit_match_class(AUDIT_CLASS_WRITE_32, n))
+                       return 1;
+               if ((mask & AUDIT_PERM_READ) &&
+                    audit_match_class(AUDIT_CLASS_READ_32, n))
+                       return 1;
+               if ((mask & AUDIT_PERM_ATTR) &&
+                    audit_match_class(AUDIT_CLASS_CHATTR_32, n))
+                       return 1;
+               return 0;
+       case 2: /* open */
+               return mask & ACC_MODE(ctx->argv[1]);
+       case 3: /* openat */
+               return mask & ACC_MODE(ctx->argv[2]);
+       case 4: /* socketcall */
+               return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND);
+       case 5: /* execve */
+               return mask & AUDIT_PERM_EXEC;
+       default:
+               return 0;
+       }
+}
+
 /* Determine if any context name data matches a rule's watch data */
 /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
  * otherwise. */
@@ -230,8 +284,11 @@ static int audit_filter_rules(struct task_struct *tsk,
                        result = audit_comparator(tsk->pid, f->op, f->val);
                        break;
                case AUDIT_PPID:
-                       if (ctx)
+                       if (ctx) {
+                               if (!ctx->ppid)
+                                       ctx->ppid = sys_getppid();
                                result = audit_comparator(ctx->ppid, f->op, f->val);
+                       }
                        break;
                case AUDIT_UID:
                        result = audit_comparator(tsk->uid, f->op, f->val);
@@ -337,7 +394,7 @@ static int audit_filter_rules(struct task_struct *tsk,
                           logged upon error */
                        if (f->se_rule) {
                                if (need_sid) {
-                                       selinux_task_ctxid(tsk, &sid);
+                                       selinux_get_task_sid(tsk, &sid);
                                        need_sid = 0;
                                }
                                result = selinux_audit_rule_match(sid, f->type,
@@ -397,6 +454,9 @@ static int audit_filter_rules(struct task_struct *tsk,
                        /* ignore this field for filtering */
                        result = 1;
                        break;
+               case AUDIT_PERM:
+                       result = audit_match_perm(ctx, f->val);
+                       break;
                }
 
                if (!result)
@@ -534,17 +594,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
        }
 
 get_context:
-       context->pid = tsk->pid;
-       context->ppid = sys_getppid();  /* sic.  tsk == current in all cases */
-       context->uid = tsk->uid;
-       context->gid = tsk->gid;
-       context->euid = tsk->euid;
-       context->suid = tsk->suid;
-       context->fsuid = tsk->fsuid;
-       context->egid = tsk->egid;
-       context->sgid = tsk->sgid;
-       context->fsgid = tsk->fsgid;
-       context->personality = tsk->personality;
+
        tsk->audit_context = NULL;
        return context;
 }
@@ -686,35 +736,35 @@ static inline void audit_free_context(struct audit_context *context)
                printk(KERN_ERR "audit: freed %d contexts\n", count);
 }
 
-static void audit_log_task_context(struct audit_buffer *ab)
+void audit_log_task_context(struct audit_buffer *ab)
 {
        char *ctx = NULL;
-       ssize_t len = 0;
+       unsigned len;
+       int error;
+       u32 sid;
+
+       selinux_get_task_sid(current, &sid);
+       if (!sid)
+               return;
 
-       len = security_getprocattr(current, "current", NULL, 0);
-       if (len < 0) {
-               if (len != -EINVAL)
+       error = selinux_sid_to_string(sid, &ctx, &len);
+       if (error) {
+               if (error != -EINVAL)
                        goto error_path;
                return;
        }
 
-       ctx = kmalloc(len, GFP_KERNEL);
-       if (!ctx)
-               goto error_path;
-
-       len = security_getprocattr(current, "current", ctx, len);
-       if (len < 0 )
-               goto error_path;
-
        audit_log_format(ab, " subj=%s", ctx);
+       kfree(ctx);
        return;
 
 error_path:
-       kfree(ctx);
        audit_panic("error in audit_log_task_context");
        return;
 }
 
+EXPORT_SYMBOL(audit_log_task_context);
+
 static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
 {
        char name[sizeof(tsk->comm)];
@@ -734,8 +784,8 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
                        if ((vma->vm_flags & VM_EXECUTABLE) &&
                            vma->vm_file) {
                                audit_log_d_path(ab, "exe=",
-                                                vma->vm_file->f_dentry,
-                                                vma->vm_file->f_vfsmnt);
+                                                vma->vm_file->f_path.dentry,
+                                                vma->vm_file->f_path.mnt);
                                break;
                        }
                        vma = vma->vm_next;
@@ -753,6 +803,18 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
        const char *tty;
 
        /* tsk == current */
+       context->pid = tsk->pid;
+       if (!context->ppid)
+               context->ppid = sys_getppid();
+       context->uid = tsk->uid;
+       context->gid = tsk->gid;
+       context->euid = tsk->euid;
+       context->suid = tsk->suid;
+       context->fsuid = tsk->fsuid;
+       context->egid = tsk->egid;
+       context->sgid = tsk->sgid;
+       context->fsgid = tsk->fsgid;
+       context->personality = tsk->personality;
 
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
        if (!ab)
@@ -765,10 +827,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                audit_log_format(ab, " success=%s exit=%ld", 
                                 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
                                 context->return_code);
+
+       mutex_lock(&tty_mutex);
+       read_lock(&tasklist_lock);
        if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
                tty = tsk->signal->tty->name;
        else
                tty = "(none)";
+       read_unlock(&tasklist_lock);
        audit_log_format(ab,
                  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
                  " ppid=%d pid=%d auid=%u uid=%u gid=%u"
@@ -786,6 +852,9 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                  context->gid,
                  context->euid, context->suid, context->fsuid,
                  context->egid, context->sgid, context->fsgid, tty);
+
+       mutex_unlock(&tty_mutex);
+
        audit_log_task_info(ab, tsk);
        if (context->filterkey) {
                audit_log_format(ab, " key=");
@@ -846,7 +915,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        if (axi->osid != 0) {
                                char *ctx = NULL;
                                u32 len;
-                               if (selinux_ctxid_to_string(
+                               if (selinux_sid_to_string(
                                                axi->osid, &ctx, &len)) {
                                        audit_log_format(ab, " osid=%u",
                                                        axi->osid);
@@ -895,6 +964,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                        audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
                        break; }
 
+               case AUDIT_FD_PAIR: {
+                       struct audit_aux_data_fd_pair *axs = (void *)aux;
+                       audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
+                       break; }
+
                }
                audit_log_end(ab);
        }
@@ -953,7 +1027,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
                if (n->osid != 0) {
                        char *ctx = NULL;
                        u32 len;
-                       if (selinux_ctxid_to_string(
+                       if (selinux_sid_to_string(
                                n->osid, &ctx, &len)) {
                                audit_log_format(ab, " osid=%u", n->osid);
                                call_panic = 2;
@@ -1080,6 +1154,7 @@ void audit_syscall_entry(int arch, int major,
        context->ctime      = CURRENT_TIME;
        context->in_syscall = 1;
        context->auditable  = !!(state == AUDIT_RECORD_CONTEXT);
+       context->ppid       = 0;
 }
 
 /**
@@ -1295,7 +1370,13 @@ void __audit_inode_child(const char *dname, const struct inode *inode,
                }
 
 update_context:
-       idx = context->name_count++;
+       idx = context->name_count;
+       if (context->name_count == AUDIT_NAMES) {
+               printk(KERN_DEBUG "name_count maxed and losing %s\n",
+                       found_name ?: "(null)");
+               return;
+       }
+       context->name_count++;
 #if AUDIT_DEBUG
        context->ino_count++;
 #endif
@@ -1313,7 +1394,16 @@ update_context:
        /* A parent was not found in audit_names, so copy the inode data for the
         * provided parent. */
        if (!found_name) {
-               idx = context->name_count++;
+               idx = context->name_count;
+               if (context->name_count == AUDIT_NAMES) {
+                       printk(KERN_DEBUG
+                               "name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu",
+                               MAJOR(parent->i_sb->s_dev),
+                               MINOR(parent->i_sb->s_dev),
+                               parent->i_ino);
+                       return;
+               }
+               context->name_count++;
 #if AUDIT_DEBUG
                context->ino_count++;
 #endif
@@ -1410,6 +1500,8 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
        return ctx ? ctx->loginuid : -1;
 }
 
+EXPORT_SYMBOL(audit_get_loginuid);
+
 /**
  * __audit_mq_open - record audit data for a POSIX MQ open
  * @oflag: open flag
@@ -1731,6 +1823,36 @@ int audit_socketcall(int nargs, unsigned long *args)
 }
 
 /**
+ * __audit_fd_pair - record audit data for pipe and socketpair
+ * @fd1: the first file descriptor
+ * @fd2: the second file descriptor
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int __audit_fd_pair(int fd1, int fd2)
+{
+       struct audit_context *context = current->audit_context;
+       struct audit_aux_data_fd_pair *ax;
+
+       if (likely(!context)) {
+               return 0;
+       }
+
+       ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+       if (!ax) {
+               return -ENOMEM;
+       }
+
+       ax->fd[0] = fd1;
+       ax->fd[1] = fd2;
+
+       ax->d.type = AUDIT_FD_PAIR;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+       return 0;
+}
+
+/**
  * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto
  * @len: data length in user space
  * @a: data address in kernel space