]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
Merge branch 'audit.b10' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit...
authorLinus Torvalds <torvalds@g5.osdl.org>
Tue, 2 May 2006 04:43:05 +0000 (21:43 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 2 May 2006 04:43:05 +0000 (21:43 -0700)
* 'audit.b10' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current:
  [PATCH] Audit Filter Performance
  [PATCH] Rework of IPC auditing
  [PATCH] More user space subject labels
  [PATCH] Reworked patch for labels on user space messages
  [PATCH] change lspp ipc auditing
  [PATCH] audit inode patch
  [PATCH] support for context based audit filtering, part 2
  [PATCH] support for context based audit filtering
  [PATCH] no need to wank with task_lock() and pinning task down in audit_syscall_exit()
  [PATCH] drop task argument of audit_syscall_{entry,exit}
  [PATCH] drop gfp_mask in audit_log_exit()
  [PATCH] move call of audit_free() into do_exit()
  [PATCH] sockaddr patch
  [PATCH] deal with deadlocks in audit_free()

33 files changed:
arch/i386/kernel/ptrace.c
arch/i386/kernel/vm86.c
arch/ia64/kernel/ptrace.c
arch/mips/kernel/ptrace.c
arch/powerpc/kernel/ptrace.c
arch/s390/kernel/ptrace.c
arch/sparc64/kernel/ptrace.c
arch/um/kernel/ptrace.c
arch/x86_64/kernel/ptrace.c
include/linux/audit.h
include/linux/netlink.h
include/linux/security.h
include/linux/selinux.h [new file with mode: 0644]
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
kernel/audit.c
kernel/audit.h
kernel/auditfilter.c
kernel/auditsc.c
kernel/exit.c
kernel/fork.c
net/netlink/af_netlink.c
net/socket.c
security/dummy.c
security/selinux/Makefile
security/selinux/avc.c
security/selinux/exports.c [new file with mode: 0644]
security/selinux/hooks.c
security/selinux/ss/mls.c
security/selinux/ss/mls.h
security/selinux/ss/services.c

index 506462ef36a089845f1f20047c008465a5d6c847..fd7eaf7866e0e118cd6852ade5122e4f6ef14051 100644 (file)
@@ -671,7 +671,7 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit)
 
        if (unlikely(current->audit_context)) {
                if (entryexit)
-                       audit_syscall_exit(current, AUDITSC_RESULT(regs->eax),
+                       audit_syscall_exit(AUDITSC_RESULT(regs->eax),
                                                regs->eax);
                /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
                 * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
@@ -720,14 +720,13 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit)
        ret = is_sysemu;
 out:
        if (unlikely(current->audit_context) && !entryexit)
-               audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
+               audit_syscall_entry(AUDIT_ARCH_I386, regs->orig_eax,
                                    regs->ebx, regs->ecx, regs->edx, regs->esi);
        if (ret == 0)
                return 0;
 
        regs->orig_eax = -1; /* force skip of syscall restarting */
        if (unlikely(current->audit_context))
-               audit_syscall_exit(current, AUDITSC_RESULT(regs->eax),
-                               regs->eax);
+               audit_syscall_exit(AUDITSC_RESULT(regs->eax), regs->eax);
        return 1;
 }
index aee14fafd13dfc0f9aa302d9f8d642208f6f4b98..00e0118e717c3568a960021be276e9c4f7e37835 100644 (file)
@@ -312,7 +312,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk
 
        /*call audit_syscall_exit since we do not exit via the normal paths */
        if (unlikely(current->audit_context))
-               audit_syscall_exit(current, AUDITSC_RESULT(eax), eax);
+               audit_syscall_exit(AUDITSC_RESULT(eax), eax);
 
        __asm__ __volatile__(
                "movl %0,%%esp\n\t"
index 9887c8787e7ad38490b425cdf77663a4a4e69106..e61e15e28d8b61cebff7eb2facfcf0692c6cf35f 100644 (file)
@@ -1644,7 +1644,7 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3,
                        arch = AUDIT_ARCH_IA64;
                }
 
-               audit_syscall_entry(current, arch, syscall, arg0, arg1, arg2, arg3);
+               audit_syscall_entry(arch, syscall, arg0, arg1, arg2, arg3);
        }
 
 }
@@ -1662,7 +1662,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
 
                if (success != AUDITSC_SUCCESS)
                        result = -result;
-               audit_syscall_exit(current, success, result);
+               audit_syscall_exit(success, result);
        }
 
        if (test_thread_flag(TIF_SYSCALL_TRACE)
index f3106d0771b0707ba21a767c32ed852530bc78d9..9b4733c12395ba59012408249cace1386f30bc84 100644 (file)
@@ -483,7 +483,7 @@ static inline int audit_arch(void)
 asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
        if (unlikely(current->audit_context) && entryexit)
-               audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]),
+               audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]),
                                   regs->regs[2]);
 
        if (!(current->ptrace & PT_PTRACED))
@@ -507,7 +507,7 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
        }
  out:
        if (unlikely(current->audit_context) && !entryexit)
-               audit_syscall_entry(current, audit_arch(), regs->regs[2],
+               audit_syscall_entry(audit_arch(), regs->regs[2],
                                    regs->regs[4], regs->regs[5],
                                    regs->regs[6], regs->regs[7]);
 }
index bcb83574335b0e80821bae2e6f78349f90ed7da4..4a677d1bd4ef717baa0d748b4652f757ed12a321 100644 (file)
@@ -538,7 +538,7 @@ void do_syscall_trace_enter(struct pt_regs *regs)
                do_syscall_trace();
 
        if (unlikely(current->audit_context))
-               audit_syscall_entry(current,
+               audit_syscall_entry(
 #ifdef CONFIG_PPC32
                                    AUDIT_ARCH_PPC,
 #else
@@ -556,8 +556,7 @@ void do_syscall_trace_leave(struct pt_regs *regs)
 #endif
 
        if (unlikely(current->audit_context))
-               audit_syscall_exit(current,
-                                  (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
+               audit_syscall_exit((regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
                                   regs->result);
 
        if ((test_thread_flag(TIF_SYSCALL_TRACE)
index 37dfe33dab735986e3eb781028884ac1e5c65816..8f36504075ed0bf1239a605b56c293bb779f03cd 100644 (file)
@@ -734,7 +734,7 @@ asmlinkage void
 syscall_trace(struct pt_regs *regs, int entryexit)
 {
        if (unlikely(current->audit_context) && entryexit)
-               audit_syscall_exit(current, AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
+               audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
 
        if (!test_thread_flag(TIF_SYSCALL_TRACE))
                goto out;
@@ -761,8 +761,7 @@ syscall_trace(struct pt_regs *regs, int entryexit)
        }
  out:
        if (unlikely(current->audit_context) && !entryexit)
-               audit_syscall_entry(current, 
-                                   test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
+               audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
                                    regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
                                    regs->gprs[4], regs->gprs[5]);
 }
index 49e6dedd027d603b9b1788af35f38fb27a452515..d31975e6d6f6bd80aa4b8adee52c5d6a36181239 100644 (file)
@@ -653,7 +653,7 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
                if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
                        result = AUDITSC_FAILURE;
 
-               audit_syscall_exit(current, result, regs->u_regs[UREG_I0]);
+               audit_syscall_exit(result, regs->u_regs[UREG_I0]);
        }
 
        if (!(current->ptrace & PT_PTRACED))
@@ -677,8 +677,7 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
 
 out:
        if (unlikely(current->audit_context) && !syscall_exit_p)
-               audit_syscall_entry(current,
-                                   (test_thread_flag(TIF_32BIT) ?
+               audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
                                     AUDIT_ARCH_SPARC :
                                     AUDIT_ARCH_SPARC64),
                                    regs->u_regs[UREG_G1],
index 60d2eda995c175060615b041abe931e6805faad1..9a77fb3c269d667d122c628fec3dd90d8fc4222a 100644 (file)
@@ -275,15 +275,13 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit)
 
        if (unlikely(current->audit_context)) {
                if (!entryexit)
-                       audit_syscall_entry(current,
-                                            HOST_AUDIT_ARCH,
+                       audit_syscall_entry(HOST_AUDIT_ARCH,
                                            UPT_SYSCALL_NR(regs),
                                            UPT_SYSCALL_ARG1(regs),
                                            UPT_SYSCALL_ARG2(regs),
                                            UPT_SYSCALL_ARG3(regs),
                                            UPT_SYSCALL_ARG4(regs));
-               else audit_syscall_exit(current,
-                                        AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
+               else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
                                         UPT_SYSCALL_RET(regs));
        }
 
index da8e7903d8174a59ff1caf84202fa943e5372c7e..2d50024c9f308b8fb5f390fb46e88d33bc843d3d 100644 (file)
@@ -600,12 +600,12 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 
        if (unlikely(current->audit_context)) {
                if (test_thread_flag(TIF_IA32)) {
-                       audit_syscall_entry(current, AUDIT_ARCH_I386,
+                       audit_syscall_entry(AUDIT_ARCH_I386,
                                            regs->orig_rax,
                                            regs->rbx, regs->rcx,
                                            regs->rdx, regs->rsi);
                } else {
-                       audit_syscall_entry(current, AUDIT_ARCH_X86_64,
+                       audit_syscall_entry(AUDIT_ARCH_X86_64,
                                            regs->orig_rax,
                                            regs->rdi, regs->rsi,
                                            regs->rdx, regs->r10);
@@ -616,7 +616,7 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
        if (unlikely(current->audit_context))
-               audit_syscall_exit(current, AUDITSC_RESULT(regs->rax), regs->rax);
+               audit_syscall_exit(AUDITSC_RESULT(regs->rax), regs->rax);
 
        if ((test_thread_flag(TIF_SYSCALL_TRACE)
             || test_thread_flag(TIF_SINGLESTEP))
index 1c47c59058c1ad2573d4c77a9f4dc5912750d687..b74c148f14e30ad26b1b1a63cbe22765bb4a2651 100644 (file)
@@ -83,6 +83,7 @@
 #define AUDIT_CONFIG_CHANGE    1305    /* Audit system configuration change */
 #define AUDIT_SOCKADDR         1306    /* sockaddr copied as syscall arg */
 #define AUDIT_CWD              1307    /* Current working directory */
+#define AUDIT_IPC_SET_PERM     1311    /* IPC new permissions record type */
 
 #define AUDIT_AVC              1400    /* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR      1401    /* Internal SE Linux Errors */
 #define AUDIT_PERS     10
 #define AUDIT_ARCH     11
 #define AUDIT_MSGTYPE  12
+#define AUDIT_SE_USER  13      /* security label user */
+#define AUDIT_SE_ROLE  14      /* security label role */
+#define AUDIT_SE_TYPE  15      /* security label type */
+#define AUDIT_SE_SEN   16      /* security label sensitivity label */
+#define AUDIT_SE_CLR   17      /* security label clearance label */
 
                                /* These are ONLY useful when checking
                                 * at syscall exit time (AUDIT_AT_EXIT). */
@@ -287,10 +293,10 @@ struct netlink_skb_parms;
                                /* Public API */
 extern int  audit_alloc(struct task_struct *task);
 extern void audit_free(struct task_struct *task);
-extern void audit_syscall_entry(struct task_struct *task, int arch,
+extern void audit_syscall_entry(int arch,
                                int major, unsigned long a0, unsigned long a1,
                                unsigned long a2, unsigned long a3);
-extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
+extern void audit_syscall_exit(int failed, long return_code);
 extern void audit_getname(const char *name);
 extern void audit_putname(const char *name);
 extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags);
@@ -314,7 +320,8 @@ extern void auditsc_get_stamp(struct audit_context *ctx,
                              struct timespec *t, unsigned int *serial);
 extern int  audit_set_loginuid(struct task_struct *task, uid_t loginuid);
 extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
+extern int audit_ipc_obj(struct kern_ipc_perm *ipcp);
+extern int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
 extern int audit_socketcall(int nargs, unsigned long *args);
 extern int audit_sockaddr(int len, void *addr);
 extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
@@ -323,8 +330,8 @@ extern int audit_set_macxattr(const char *name);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
-#define audit_syscall_entry(t,ta,a,b,c,d,e) do { ; } while (0)
-#define audit_syscall_exit(t,f,r) do { ; } while (0)
+#define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0)
+#define audit_syscall_exit(f,r) do { ; } while (0)
 #define audit_getname(n) do { ; } while (0)
 #define audit_putname(n) do { ; } while (0)
 #define __audit_inode(n,i,f) do { ; } while (0)
@@ -333,7 +340,8 @@ extern int audit_set_macxattr(const char *name);
 #define audit_inode_child(d,i,p) do { ; } while (0)
 #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
 #define audit_get_loginuid(c) ({ -1; })
-#define audit_ipc_perms(q,u,g,m,i) ({ 0; })
+#define audit_ipc_obj(i) ({ 0; })
+#define audit_ipc_set_perm(q,u,g,m,i) ({ 0; })
 #define audit_socketcall(n,a) ({ 0; })
 #define audit_sockaddr(len, addr) ({ 0; })
 #define audit_avc_path(dentry, mnt) ({ 0; })
@@ -366,7 +374,7 @@ extern void             audit_log_d_path(struct audit_buffer *ab,
 extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
 extern int audit_filter_type(int type);
 extern int  audit_receive_filter(int type, int pid, int uid, int seq,
-                                void *data, size_t datasz, uid_t loginuid);
+                        void *data, size_t datasz, uid_t loginuid, u32 sid);
 #else
 #define audit_log(c,g,t,f,...) do { ; } while (0)
 #define audit_log_start(c,g,t) ({ NULL; })
index f8f3d1c927f8b1ebd8de989ae5cf752f503356d8..87b8a5703ebc09618140c2a72d5e7e1927299b61 100644 (file)
@@ -143,6 +143,7 @@ struct netlink_skb_parms
        __u32                   dst_group;
        kernel_cap_t            eff_cap;
        __u32                   loginuid;       /* Login (audit) uid */
+       __u32                   sid;            /* SELinux security id */
 };
 
 #define NETLINK_CB(skb)                (*(struct netlink_skb_parms*)&((skb)->cb))
index aaa0a5cdbf751c857f5a5adcfbe880da478c1acf..1bab48f6aeac1e16df3d6edb62cafdfc1db71f41 100644 (file)
@@ -869,11 +869,6 @@ struct swap_info_struct;
  *     @ipcp contains the kernel IPC permission structure
  *     @flag contains the desired (requested) permission set
  *     Return 0 if permission is granted.
- * @ipc_getsecurity:
- *      Copy the security label associated with the ipc object into
- *      @buffer.  @buffer may be NULL to request the size of the buffer 
- *      required.  @size indicates the size of @buffer in bytes. Return 
- *      number of bytes used/required on success.
  *
  * Security hooks for individual messages held in System V IPC message queues
  * @msg_msg_alloc_security:
@@ -1223,7 +1218,6 @@ struct security_operations {
        void (*task_to_inode)(struct task_struct *p, struct inode *inode);
 
        int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
-       int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size);
 
        int (*msg_msg_alloc_security) (struct msg_msg * msg);
        void (*msg_msg_free_security) (struct msg_msg * msg);
@@ -1887,11 +1881,6 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
        return security_ops->ipc_permission (ipcp, flag);
 }
 
-static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
-{
-       return security_ops->ipc_getsecurity(ipcp, buffer, size);
-}
-
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
        return security_ops->msg_msg_alloc_security (msg);
@@ -2532,11 +2521,6 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
        return 0;
 }
 
-static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
-{
-       return -EOPNOTSUPP;
-}
-
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
        return 0;
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
new file mode 100644 (file)
index 0000000..4047bcd
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris@redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#ifndef _LINUX_SELINUX_H
+#define _LINUX_SELINUX_H
+
+struct selinux_audit_rule;
+struct audit_context;
+struct inode;
+struct kern_ipc_perm;
+
+#ifdef CONFIG_SECURITY_SELINUX
+
+/**
+ *     selinux_audit_rule_init - alloc/init an selinux audit rule structure.
+ *     @field: the field this rule refers to
+ *     @op: the operater the rule uses
+ *     @rulestr: the text "target" of the rule
+ *     @rule: pointer to the new rule structure returned via this
+ *
+ *     Returns 0 if successful, -errno if not.  On success, the rule structure
+ *     will be allocated internally.  The caller must free this structure with
+ *     selinux_audit_rule_free() after use.
+ */
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
+                            struct selinux_audit_rule **rule);
+
+/**
+ *     selinux_audit_rule_free - free an selinux audit rule structure.
+ *     @rule: pointer to the audit rule to be freed
+ *
+ *     This will free all memory associated with the given rule.
+ *     If @rule is NULL, no operation is performed.
+ */
+void selinux_audit_rule_free(struct selinux_audit_rule *rule);
+
+/**
+ *     selinux_audit_rule_match - determine if a context ID matches a rule.
+ *     @ctxid: the context ID to check
+ *     @field: the field this rule refers to
+ *     @op: the operater the rule uses
+ *     @rule: pointer to the audit rule to check against
+ *     @actx: the audit context (can be NULL) associated with the check
+ *
+ *     Returns 1 if the context id matches the rule, 0 if it does not, and
+ *     -errno on failure.
+ */
+int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
+                             struct selinux_audit_rule *rule,
+                             struct audit_context *actx);
+
+/**
+ *     selinux_audit_set_callback - set the callback for policy reloads.
+ *     @callback: the function to call when the policy is reloaded
+ *
+ *     This sets the function callback function that will update the rules
+ *     upon policy reloads.  This callback should rebuild all existing rules
+ *     using selinux_audit_rule_init().
+ */
+void selinux_audit_set_callback(int (*callback)(void));
+
+/**
+ *     selinux_task_ctxid - determine a context ID for a process.
+ *     @tsk: the task object
+ *     @ctxid: ID value returned via this
+ *
+ *     On return, ctxid will contain an ID for the context.  This value
+ *     should only be used opaquely.
+ */
+void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid);
+
+/**
+ *     selinux_ctxid_to_string - map a security context ID to a string
+ *     @ctxid: security context ID to be converted.
+ *     @ctx: address of context string to be returned
+ *     @ctxlen: length of returned context string.
+ *
+ *     Returns 0 if successful, -errno if not.  On success, the context
+ *     string will be allocated internally, and the caller must call
+ *     kfree() on it after use.
+ */
+int selinux_ctxid_to_string(u32 ctxid, char **ctx, u32 *ctxlen);
+
+/**
+ *     selinux_get_inode_sid - get the inode's security context ID
+ *     @inode: inode structure to get the sid from.
+ *     @sid: pointer to security context ID to be filled in.
+ *
+ *     Returns nothing
+ */
+void selinux_get_inode_sid(const struct inode *inode, u32 *sid);
+
+/**
+ *     selinux_get_ipc_sid - get the ipc security context ID
+ *     @ipcp: ipc structure to get the sid from.
+ *     @sid: pointer to security context ID to be filled in.
+ *
+ *     Returns nothing
+ */
+void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid);
+
+/**
+ *     selinux_get_task_sid - return the SID of task
+ *     @tsk: the task whose SID will be returned
+ *     @sid: pointer to security context ID to be filled in.
+ *
+ *     Returns nothing
+ */
+void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
+
+
+#else
+
+static inline int selinux_audit_rule_init(u32 field, u32 op,
+                                          char *rulestr,
+                                          struct selinux_audit_rule **rule)
+{
+       return -ENOTSUPP;
+}
+
+static inline void selinux_audit_rule_free(struct selinux_audit_rule *rule)
+{
+       return;
+}
+
+static inline int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
+                                           struct selinux_audit_rule *rule,
+                                           struct audit_context *actx)
+{
+       return 0;
+}
+
+static inline void selinux_audit_set_callback(int (*callback)(void))
+{
+       return;
+}
+
+static inline void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+{
+       *ctxid = 0;
+}
+
+static inline int selinux_ctxid_to_string(u32 ctxid, char **ctx, u32 *ctxlen)
+{
+       *ctx = NULL;
+       *ctxlen = 0;
+       return 0;
+}
+
+static inline void selinux_get_inode_sid(const struct inode *inode, u32 *sid)
+{
+       *sid = 0;
+}
+
+static inline void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid)
+{
+       *sid = 0;
+}
+
+static inline void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
+{
+       *sid = 0;
+}
+
+#endif /* CONFIG_SECURITY_SELINUX */
+
+#endif /* _LINUX_SELINUX_H */
index 48a7f17a7236397c219e03799117718fa4b2d3ec..7d1340ccb16b7d333cbbc9d1b2177943d3d63737 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -13,6 +13,9 @@
  * mostly rewritten, threaded and wake-one semantics added
  * MSGMAX limit removed, sysctl's added
  * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
+ *
+ * support for audit of ipc object properties and permission changes
+ * Dustin Kirkland <dustin.kirkland@us.ibm.com>
  */
 
 #include <linux/capability.h>
@@ -447,6 +450,11 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
        if (msg_checkid(msq,msqid))
                goto out_unlock_up;
        ipcp = &msq->q_perm;
+
+       err = audit_ipc_obj(ipcp);
+       if (err)
+               goto out_unlock_up;
+
        err = -EPERM;
        if (current->euid != ipcp->cuid && 
            current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
@@ -460,7 +468,8 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
        switch (cmd) {
        case IPC_SET:
        {
-               if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+               err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
+               if (err)
                        goto out_unlock_up;
 
                err = -EPERM;
index 642659cd596b82f5aa3974e61925708cdc62f9dd..7919f8ece6bac8c89cd255b367fa8dfcb722fca5 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -61,6 +61,9 @@
  * (c) 2001 Red Hat Inc <alan@redhat.com>
  * Lockless wakeup
  * (c) 2003 Manfred Spraul <manfred@colorfullife.com>
+ *
+ * support for audit of ipc object properties and permission changes
+ * Dustin Kirkland <dustin.kirkland@us.ibm.com>
  */
 
 #include <linux/config.h>
@@ -820,6 +823,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
                goto out_unlock;
        }       
        ipcp = &sma->sem_perm;
+
+       err = audit_ipc_obj(ipcp);
+       if (err)
+               goto out_unlock;
+
        if (current->euid != ipcp->cuid && 
            current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
                err=-EPERM;
@@ -836,7 +844,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
                err = 0;
                break;
        case IPC_SET:
-               if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+               err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp);
+               if (err)
                        goto out_unlock;
                ipcp->uid = setbuf.uid;
                ipcp->gid = setbuf.gid;
index 1c2faf62bc7301a823b26cee9ae738069e93aaa6..8098968519026406191014b4cb64ee870e2a721c 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -13,6 +13,8 @@
  * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
  * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
  *
+ * support for audit of ipc object properties and permission changes
+ * Dustin Kirkland <dustin.kirkland@us.ibm.com>
  */
 
 #include <linux/config.h>
@@ -542,6 +544,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
                if(err)
                        goto out_unlock;
 
+               err = audit_ipc_obj(&(shp->shm_perm));
+               if (err)
+                       goto out_unlock;
+
                if (!capable(CAP_IPC_LOCK)) {
                        err = -EPERM;
                        if (current->euid != shp->shm_perm.uid &&
@@ -594,6 +600,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
                if(err)
                        goto out_unlock_up;
 
+               err = audit_ipc_obj(&(shp->shm_perm));
+               if (err)
+                       goto out_unlock_up;
+
                if (current->euid != shp->shm_perm.uid &&
                    current->euid != shp->shm_perm.cuid && 
                    !capable(CAP_SYS_ADMIN)) {
@@ -627,12 +637,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
                err=-EINVAL;
                if(shp==NULL)
                        goto out_up;
-               if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid,
-                                       setbuf.mode, &(shp->shm_perm))))
-                       goto out_unlock_up;
                err = shm_checkid(shp,shmid);
                if(err)
                        goto out_unlock_up;
+               err = audit_ipc_obj(&(shp->shm_perm));
+               if (err)
+                       goto out_unlock_up;
+               err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm));
+               if (err)
+                       goto out_unlock_up;
                err=-EPERM;
                if (current->euid != shp->shm_perm.uid &&
                    current->euid != shp->shm_perm.cuid && 
index b3dcfad3b4f72075b7c338dc182eeb0c2403d482..8193299f45f664e5b01e74960c804e9421bc4cf1 100644 (file)
@@ -10,6 +10,8 @@
  *           Manfred Spraul <manfred@colorfullife.com>
  * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().
  *            Mingming Cao <cmm@us.ibm.com>
+ * Mar 2006 - support for audit of ipc object properties
+ *            Dustin Kirkland <dustin.kirkland@us.ibm.com>
  */
 
 #include <linux/config.h>
@@ -27,6 +29,7 @@
 #include <linux/workqueue.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
+#include <linux/audit.h>
 
 #include <asm/unistd.h>
 
@@ -464,8 +467,10 @@ void ipc_rcu_putref(void *ptr)
  
 int ipcperms (struct kern_ipc_perm *ipcp, short flag)
 {      /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
-       int requested_mode, granted_mode;
+       int requested_mode, granted_mode, err;
 
+       if (unlikely((err = audit_ipc_obj(ipcp))))
+               return err;
        requested_mode = (flag >> 6) | (flag >> 3) | flag;
        granted_mode = ipcp->mode;
        if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
index c8ccbd09048f44aa3eebbcda06a091183ac1278f..df57b493e1cb2c35a8d6fd7f4602751f2ac7fd6d 100644 (file)
@@ -55,6 +55,9 @@
 #include <net/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
+#include <linux/selinux.h>
+
+#include "audit.h"
 
 /* No auditing will take place until audit_initialized != 0.
  * (Initialization happens after skb_init is called.) */
@@ -227,49 +230,103 @@ void audit_log_lost(const char *message)
        }
 }
 
-static int audit_set_rate_limit(int limit, uid_t loginuid)
+static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
 {
-       int old          = audit_rate_limit;
-       audit_rate_limit = limit;
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, 
+       int old = audit_rate_limit;
+
+       if (sid) {
+               char *ctx = NULL;
+               u32 len;
+               int rc;
+               if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
+                       return rc;
+               else
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                               "audit_rate_limit=%d old=%d by auid=%u subj=%s",
+                               limit, old, loginuid, ctx);
+               kfree(ctx);
+       } else
+               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                        "audit_rate_limit=%d old=%d by auid=%u",
-                       audit_rate_limit, old, loginuid);
+                       limit, old, loginuid);
+       audit_rate_limit = limit;
        return old;
 }
 
-static int audit_set_backlog_limit(int limit, uid_t loginuid)
+static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
 {
-       int old          = audit_backlog_limit;
-       audit_backlog_limit = limit;
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+       int old = audit_backlog_limit;
+
+       if (sid) {
+               char *ctx = NULL;
+               u32 len;
+               int rc;
+               if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
+                       return rc;
+               else
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                           "audit_backlog_limit=%d old=%d by auid=%u subj=%s",
+                               limit, old, loginuid, ctx);
+               kfree(ctx);
+       } else
+               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                        "audit_backlog_limit=%d old=%d by auid=%u",
-                       audit_backlog_limit, old, loginuid);
+                       limit, old, loginuid);
+       audit_backlog_limit = limit;
        return old;
 }
 
-static int audit_set_enabled(int state, uid_t loginuid)
+static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
 {
-       int old          = audit_enabled;
+       int old = audit_enabled;
+
        if (state != 0 && state != 1)
                return -EINVAL;
-       audit_enabled = state;
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+
+       if (sid) {
+               char *ctx = NULL;
+               u32 len;
+               int rc;
+               if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
+                       return rc;
+               else
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                               "audit_enabled=%d old=%d by auid=%u subj=%s",
+                               state, old, loginuid, ctx);
+               kfree(ctx);
+       } else
+               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                        "audit_enabled=%d old=%d by auid=%u",
-                       audit_enabled, old, loginuid);
+                       state, old, loginuid);
+       audit_enabled = state;
        return old;
 }
 
-static int audit_set_failure(int state, uid_t loginuid)
+static int audit_set_failure(int state, uid_t loginuid, u32 sid)
 {
-       int old          = audit_failure;
+       int old = audit_failure;
+
        if (state != AUDIT_FAIL_SILENT
            && state != AUDIT_FAIL_PRINTK
            && state != AUDIT_FAIL_PANIC)
                return -EINVAL;
-       audit_failure = state;
-       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+
+       if (sid) {
+               char *ctx = NULL;
+               u32 len;
+               int rc;
+               if ((rc = selinux_ctxid_to_string(sid, &ctx, &len)))
+                       return rc;
+               else
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                               "audit_failure=%d old=%d by auid=%u subj=%s",
+                               state, old, loginuid, ctx);
+               kfree(ctx);
+       } else
+               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
                        "audit_failure=%d old=%d by auid=%u",
-                       audit_failure, old, loginuid);
+                       state, old, loginuid);
+       audit_failure = state;
        return old;
 }
 
@@ -387,7 +444,7 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
 
 static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-       u32                     uid, pid, seq;
+       u32                     uid, pid, seq, sid;
        void                    *data;
        struct audit_status     *status_get, status_set;
        int                     err;
@@ -413,6 +470,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        pid  = NETLINK_CREDS(skb)->pid;
        uid  = NETLINK_CREDS(skb)->uid;
        loginuid = NETLINK_CB(skb).loginuid;
+       sid  = NETLINK_CB(skb).sid;
        seq  = nlh->nlmsg_seq;
        data = NLMSG_DATA(nlh);
 
@@ -433,25 +491,43 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        return -EINVAL;
                status_get   = (struct audit_status *)data;
                if (status_get->mask & AUDIT_STATUS_ENABLED) {
-                       err = audit_set_enabled(status_get->enabled, loginuid);
+                       err = audit_set_enabled(status_get->enabled,
+                                                       loginuid, sid);
                        if (err < 0) return err;
                }
                if (status_get->mask & AUDIT_STATUS_FAILURE) {
-                       err = audit_set_failure(status_get->failure, loginuid);
+                       err = audit_set_failure(status_get->failure,
+                                                        loginuid, sid);
                        if (err < 0) return err;
                }
                if (status_get->mask & AUDIT_STATUS_PID) {
                        int old   = audit_pid;
+                       if (sid) {
+                               char *ctx = NULL;
+                               u32 len;
+                               int rc;
+                               if ((rc = selinux_ctxid_to_string(
+                                               sid, &ctx, &len)))
+                                       return rc;
+                               else
+                                       audit_log(NULL, GFP_KERNEL,
+                                               AUDIT_CONFIG_CHANGE,
+                                               "audit_pid=%d old=%d by auid=%u subj=%s",
+                                               status_get->pid, old,
+                                               loginuid, ctx);
+                               kfree(ctx);
+                       } else
+                               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                                       "audit_pid=%d old=%d by auid=%u",
+                                         status_get->pid, old, loginuid);
                        audit_pid = status_get->pid;
-                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                               "audit_pid=%d old=%d by auid=%u",
-                                 audit_pid, old, loginuid);
                }
                if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
-                       audit_set_rate_limit(status_get->rate_limit, loginuid);
+                       audit_set_rate_limit(status_get->rate_limit,
+                                                        loginuid, sid);
                if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
                        audit_set_backlog_limit(status_get->backlog_limit,
-                                                       loginuid);
+                                                       loginuid, sid);
                break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
@@ -465,8 +541,23 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
                        if (ab) {
                                audit_log_format(ab,
-                                                "user pid=%d uid=%u auid=%u msg='%.1024s'",
-                                                pid, uid, loginuid, (char *)data);
+                                                "user pid=%d uid=%u auid=%u",
+                                                pid, uid, loginuid);
+                               if (sid) {
+                                       char *ctx = NULL;
+                                       u32 len;
+                                       if (selinux_ctxid_to_string(
+                                                       sid, &ctx, &len)) {
+                                               audit_log_format(ab, 
+                                                       " ssid=%u", sid);
+                                               /* Maybe call audit_panic? */
+                                       } else
+                                               audit_log_format(ab, 
+                                                       " subj=%s", ctx);
+                                       kfree(ctx);
+                               }
+                               audit_log_format(ab, " msg='%.1024s'",
+                                        (char *)data);
                                audit_set_pid(ab, pid);
                                audit_log_end(ab);
                        }
@@ -480,7 +571,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        case AUDIT_LIST:
                err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
                                           uid, seq, data, nlmsg_len(nlh),
-                                          loginuid);
+                                          loginuid, sid);
                break;
        case AUDIT_ADD_RULE:
        case AUDIT_DEL_RULE:
@@ -490,7 +581,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        case AUDIT_LIST_RULES:
                err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
                                           uid, seq, data, nlmsg_len(nlh),
-                                          loginuid);
+                                          loginuid, sid);
                break;
        case AUDIT_SIGNAL_INFO:
                sig_data.uid = audit_sig_uid;
@@ -564,6 +655,11 @@ static int __init audit_init(void)
        skb_queue_head_init(&audit_skb_queue);
        audit_initialized = 1;
        audit_enabled = audit_default;
+
+       /* Register the callback with selinux.  This callback will be invoked
+        * when a new policy is loaded. */
+       selinux_audit_set_callback(&selinux_audit_rule_update);
+
        audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
        return 0;
 }
index bc5392076e2be43349caa39ad5c42b2ea1520fd6..6f733920fd32e1cc88fe6840620720ec8cb62978 100644 (file)
@@ -54,9 +54,11 @@ enum audit_state {
 
 /* Rule lists */
 struct audit_field {
-       u32                     type;
-       u32                     val;
-       u32                     op;
+       u32                             type;
+       u32                             val;
+       u32                             op;
+       char                            *se_str;
+       struct selinux_audit_rule       *se_rule;
 };
 
 struct audit_krule {
@@ -86,3 +88,5 @@ extern void               audit_send_reply(int pid, int seq, int type,
 extern void                audit_log_lost(const char *message);
 extern void                audit_panic(const char *message);
 extern struct mutex audit_netlink_mutex;
+
+extern int selinux_audit_rule_update(void);
index d3a8539f3a8333e6ce3fc69a8423af2fd1746d65..7c134906d689c8af18397351089dc01fbbf00461 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/audit.h>
 #include <linux/kthread.h>
 #include <linux/netlink.h>
+#include <linux/selinux.h>
 #include "audit.h"
 
 /* There are three lists of rules -- one to search at task creation
@@ -42,6 +43,13 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
 
 static inline void audit_free_rule(struct audit_entry *e)
 {
+       int i;
+       if (e->rule.fields)
+               for (i = 0; i < e->rule.field_count; i++) {
+                       struct audit_field *f = &e->rule.fields[i];
+                       kfree(f->se_str);
+                       selinux_audit_rule_free(f->se_rule);
+               }
        kfree(e->rule.fields);
        kfree(e);
 }
@@ -52,9 +60,29 @@ static inline void audit_free_rule_rcu(struct rcu_head *head)
        audit_free_rule(e);
 }
 
+/* Initialize an audit filterlist entry. */
+static inline struct audit_entry *audit_init_entry(u32 field_count)
+{
+       struct audit_entry *entry;
+       struct audit_field *fields;
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (unlikely(!entry))
+               return NULL;
+
+       fields = kzalloc(sizeof(*fields) * field_count, GFP_KERNEL);
+       if (unlikely(!fields)) {
+               kfree(entry);
+               return NULL;
+       }
+       entry->rule.fields = fields;
+
+       return entry;
+}
+
 /* Unpack a filter field's string representation from user-space
  * buffer. */
-static __attribute__((unused)) char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
+static char *audit_unpack_string(void **bufp, size_t *remain, size_t len)
 {
        char *str;
 
@@ -84,7 +112,6 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
 {
        unsigned listnr;
        struct audit_entry *entry;
-       struct audit_field *fields;
        int i, err;
 
        err = -EINVAL;
@@ -108,23 +135,14 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
                goto exit_err;
 
        err = -ENOMEM;
-       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-       if (unlikely(!entry))
-               goto exit_err;
-       fields = kmalloc(sizeof(*fields) * rule->field_count, GFP_KERNEL);
-       if (unlikely(!fields)) {
-               kfree(entry);
+       entry = audit_init_entry(rule->field_count);
+       if (!entry)
                goto exit_err;
-       }
-
-       memset(&entry->rule, 0, sizeof(struct audit_krule));
-       memset(fields, 0, sizeof(struct audit_field));
 
        entry->rule.flags = rule->flags & AUDIT_FILTER_PREPEND;
        entry->rule.listnr = listnr;
        entry->rule.action = rule->action;
        entry->rule.field_count = rule->field_count;
-       entry->rule.fields = fields;
 
        for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
                entry->rule.mask[i] = rule->mask[i];
@@ -150,15 +168,20 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
        for (i = 0; i < rule->field_count; i++) {
                struct audit_field *f = &entry->rule.fields[i];
 
-               if (rule->fields[i] & AUDIT_UNUSED_BITS) {
-                       err = -EINVAL;
-                       goto exit_free;
-               }
-
                f->op = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
                f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
                f->val = rule->values[i];
 
+               if (f->type & AUDIT_UNUSED_BITS ||
+                   f->type == AUDIT_SE_USER ||
+                   f->type == AUDIT_SE_ROLE ||
+                   f->type == AUDIT_SE_TYPE ||
+                   f->type == AUDIT_SE_SEN ||
+                   f->type == AUDIT_SE_CLR) {
+                       err = -EINVAL;
+                       goto exit_free;
+               }
+
                entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1;
 
                /* Support for legacy operators where
@@ -188,8 +211,9 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
        int err = 0;
        struct audit_entry *entry;
        void *bufp;
-       /* size_t remain = datasz - sizeof(struct audit_rule_data); */
+       size_t remain = datasz - sizeof(struct audit_rule_data);
        int i;
+       char *str;
 
        entry = audit_to_entry_common((struct audit_rule *)data);
        if (IS_ERR(entry))
@@ -207,10 +231,35 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 
                f->op = data->fieldflags[i] & AUDIT_OPERATORS;
                f->type = data->fields[i];
+               f->val = data->values[i];
+               f->se_str = NULL;
+               f->se_rule = NULL;
                switch(f->type) {
-               /* call type-specific conversion routines here */
-               default:
-                       f->val = data->values[i];
+               case AUDIT_SE_USER:
+               case AUDIT_SE_ROLE:
+               case AUDIT_SE_TYPE:
+               case AUDIT_SE_SEN:
+               case AUDIT_SE_CLR:
+                       str = audit_unpack_string(&bufp, &remain, f->val);
+                       if (IS_ERR(str))
+                               goto exit_free;
+                       entry->rule.buflen += f->val;
+
+                       err = selinux_audit_rule_init(f->type, f->op, str,
+                                                     &f->se_rule);
+                       /* Keep currently invalid fields around in case they
+                        * become valid after a policy reload. */
+                       if (err == -EINVAL) {
+                               printk(KERN_WARNING "audit rule for selinux "
+                                      "\'%s\' is invalid\n",  str);
+                               err = 0;
+                       }
+                       if (err) {
+                               kfree(str);
+                               goto exit_free;
+                       } else
+                               f->se_str = str;
+                       break;
                }
        }
 
@@ -286,7 +335,14 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
                data->fields[i] = f->type;
                data->fieldflags[i] = f->op;
                switch(f->type) {
-               /* call type-specific conversion routines here */
+               case AUDIT_SE_USER:
+               case AUDIT_SE_ROLE:
+               case AUDIT_SE_TYPE:
+               case AUDIT_SE_SEN:
+               case AUDIT_SE_CLR:
+                       data->buflen += data->values[i] =
+                               audit_pack_string(&bufp, f->se_str);
+                       break;
                default:
                        data->values[i] = f->val;
                }
@@ -314,7 +370,14 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
                        return 1;
 
                switch(a->fields[i].type) {
-               /* call type-specific comparison routines here */
+               case AUDIT_SE_USER:
+               case AUDIT_SE_ROLE:
+               case AUDIT_SE_TYPE:
+               case AUDIT_SE_SEN:
+               case AUDIT_SE_CLR:
+                       if (strcmp(a->fields[i].se_str, b->fields[i].se_str))
+                               return 1;
+                       break;
                default:
                        if (a->fields[i].val != b->fields[i].val)
                                return 1;
@@ -328,6 +391,81 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
        return 0;
 }
 
+/* Duplicate selinux field information.  The se_rule is opaque, so must be
+ * re-initialized. */
+static inline int audit_dupe_selinux_field(struct audit_field *df,
+                                          struct audit_field *sf)
+{
+       int ret = 0;
+       char *se_str;
+
+       /* our own copy of se_str */
+       se_str = kstrdup(sf->se_str, GFP_KERNEL);
+       if (unlikely(IS_ERR(se_str)))
+           return -ENOMEM;
+       df->se_str = se_str;
+
+       /* our own (refreshed) copy of se_rule */
+       ret = selinux_audit_rule_init(df->type, df->op, df->se_str,
+                                     &df->se_rule);
+       /* Keep currently invalid fields around in case they
+        * become valid after a policy reload. */
+       if (ret == -EINVAL) {
+               printk(KERN_WARNING "audit rule for selinux \'%s\' is "
+                      "invalid\n", df->se_str);
+               ret = 0;
+       }
+
+       return ret;
+}
+
+/* Duplicate an audit rule.  This will be a deep copy with the exception
+ * of the watch - that pointer is carried over.  The selinux specific fields
+ * will be updated in the copy.  The point is to be able to replace the old
+ * rule with the new rule in the filterlist, then free the old rule. */
+static struct audit_entry *audit_dupe_rule(struct audit_krule *old)
+{
+       u32 fcount = old->field_count;
+       struct audit_entry *entry;
+       struct audit_krule *new;
+       int i, err = 0;
+
+       entry = audit_init_entry(fcount);
+       if (unlikely(!entry))
+               return ERR_PTR(-ENOMEM);
+
+       new = &entry->rule;
+       new->vers_ops = old->vers_ops;
+       new->flags = old->flags;
+       new->listnr = old->listnr;
+       new->action = old->action;
+       for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+               new->mask[i] = old->mask[i];
+       new->buflen = old->buflen;
+       new->field_count = old->field_count;
+       memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
+
+       /* deep copy this information, updating the se_rule fields, because
+        * the originals will all be freed when the old rule is freed. */
+       for (i = 0; i < fcount; i++) {
+               switch (new->fields[i].type) {
+               case AUDIT_SE_USER:
+               case AUDIT_SE_ROLE:
+               case AUDIT_SE_TYPE:
+               case AUDIT_SE_SEN:
+               case AUDIT_SE_CLR:
+                       err = audit_dupe_selinux_field(&new->fields[i],
+                                                      &old->fields[i]);
+               }
+               if (err) {
+                       audit_free_rule(entry);
+                       return ERR_PTR(err);
+               }
+       }
+
+       return entry;
+}
+
 /* Add rule to given filterlist if not a duplicate.  Protected by
  * audit_netlink_mutex. */
 static inline int audit_add_rule(struct audit_entry *entry,
@@ -448,9 +586,10 @@ static int audit_list_rules(void *_dest)
  * @data: payload data
  * @datasz: size of payload data
  * @loginuid: loginuid of sender
+ * @sid: SE Linux Security ID of sender
  */
 int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
-                        size_t datasz, uid_t loginuid)
+                        size_t datasz, uid_t loginuid, u32 sid)
 {
        struct task_struct *tsk;
        int *dest;
@@ -493,9 +632,23 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
 
                err = audit_add_rule(entry,
                                     &audit_filter_list[entry->rule.listnr]);
-               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                       "auid=%u add rule to list=%d res=%d\n",
-                       loginuid, entry->rule.listnr, !err);
+               if (sid) {
+                       char *ctx = NULL;
+                       u32 len;
+                       if (selinux_ctxid_to_string(sid, &ctx, &len)) {
+                               /* Maybe call audit_panic? */
+                               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                                "auid=%u ssid=%u add rule to list=%d res=%d",
+                                loginuid, sid, entry->rule.listnr, !err);
+                       } else
+                               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                                "auid=%u subj=%s add rule to list=%d res=%d",
+                                loginuid, ctx, entry->rule.listnr, !err);
+                       kfree(ctx);
+               } else
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                               "auid=%u add rule to list=%d res=%d",
+                               loginuid, entry->rule.listnr, !err);
 
                if (err)
                        audit_free_rule(entry);
@@ -511,9 +664,24 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
 
                err = audit_del_rule(entry,
                                     &audit_filter_list[entry->rule.listnr]);
-               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
-                       "auid=%u remove rule from list=%d res=%d\n",
-                       loginuid, entry->rule.listnr, !err);
+
+               if (sid) {
+                       char *ctx = NULL;
+                       u32 len;
+                       if (selinux_ctxid_to_string(sid, &ctx, &len)) {
+                               /* Maybe call audit_panic? */
+                               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                                       "auid=%u ssid=%u remove rule from list=%d res=%d",
+                                        loginuid, sid, entry->rule.listnr, !err);
+                       } else
+                               audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                                       "auid=%u subj=%s remove rule from list=%d res=%d",
+                                        loginuid, ctx, entry->rule.listnr, !err);
+                       kfree(ctx);
+               } else
+                       audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
+                               "auid=%u remove rule from list=%d res=%d",
+                               loginuid, entry->rule.listnr, !err);
 
                audit_free_rule(entry);
                break;
@@ -628,3 +796,62 @@ unlock_and_return:
        rcu_read_unlock();
        return result;
 }
+
+/* Check to see if the rule contains any selinux fields.  Returns 1 if there
+   are selinux fields specified in the rule, 0 otherwise. */
+static inline int audit_rule_has_selinux(struct audit_krule *rule)
+{
+       int i;
+
+       for (i = 0; i < rule->field_count; i++) {
+               struct audit_field *f = &rule->fields[i];
+               switch (f->type) {
+               case AUDIT_SE_USER:
+               case AUDIT_SE_ROLE:
+               case AUDIT_SE_TYPE:
+               case AUDIT_SE_SEN:
+               case AUDIT_SE_CLR:
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+/* This function will re-initialize the se_rule field of all applicable rules.
+ * It will traverse the filter lists serarching for rules that contain selinux
+ * specific filter fields.  When such a rule is found, it is copied, the
+ * selinux field is re-initialized, and the old rule is replaced with the
+ * updated rule. */
+int selinux_audit_rule_update(void)
+{
+       struct audit_entry *entry, *n, *nentry;
+       int i, err = 0;
+
+       /* audit_netlink_mutex synchronizes the writers */
+       mutex_lock(&audit_netlink_mutex);
+
+       for (i = 0; i < AUDIT_NR_FILTERS; i++) {
+               list_for_each_entry_safe(entry, n, &audit_filter_list[i], list) {
+                       if (!audit_rule_has_selinux(&entry->rule))
+                               continue;
+
+                       nentry = audit_dupe_rule(&entry->rule);
+                       if (unlikely(IS_ERR(nentry))) {
+                               /* save the first error encountered for the
+                                * return value */
+                               if (!err)
+                                       err = PTR_ERR(nentry);
+                               audit_panic("error updating selinux filters");
+                               list_del_rcu(&entry->list);
+                       } else {
+                               list_replace_rcu(&entry->list, &nentry->list);
+                       }
+                       call_rcu(&entry->rcu, audit_free_rule_rcu);
+               }
+       }
+
+       mutex_unlock(&audit_netlink_mutex);
+
+       return err;
+}
index 7f160df21a23e22a3d8e0e36b29712bcc9758692..1c03a4ed1b27fb8b6f4276b3305ed10907f8f4c3 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/security.h>
 #include <linux/list.h>
 #include <linux/tty.h>
+#include <linux/selinux.h>
 
 #include "audit.h"
 
@@ -89,7 +90,7 @@ struct audit_names {
        uid_t           uid;
        gid_t           gid;
        dev_t           rdev;
-       char            *ctx;
+       u32             osid;
 };
 
 struct audit_aux_data {
@@ -106,7 +107,7 @@ struct audit_aux_data_ipcctl {
        uid_t                   uid;
        gid_t                   gid;
        mode_t                  mode;
-       char                    *ctx;
+       u32                     osid;
 };
 
 struct audit_aux_data_socketcall {
@@ -167,7 +168,8 @@ static int audit_filter_rules(struct task_struct *tsk,
                              struct audit_context *ctx,
                              enum audit_state *state)
 {
-       int i, j;
+       int i, j, need_sid = 1;
+       u32 sid;
 
        for (i = 0; i < rule->field_count; i++) {
                struct audit_field *f = &rule->fields[i];
@@ -257,6 +259,27 @@ static int audit_filter_rules(struct task_struct *tsk,
                        if (ctx)
                                result = audit_comparator(ctx->loginuid, f->op, f->val);
                        break;
+               case AUDIT_SE_USER:
+               case AUDIT_SE_ROLE:
+               case AUDIT_SE_TYPE:
+               case AUDIT_SE_SEN:
+               case AUDIT_SE_CLR:
+                       /* NOTE: this may return negative values indicating
+                          a temporary error.  We simply treat this as a
+                          match for now to avoid losing information that
+                          may be wanted.   An error message will also be
+                          logged upon error */
+                       if (f->se_rule) {
+                               if (need_sid) {
+                                       selinux_task_ctxid(tsk, &sid);
+                                       need_sid = 0;
+                               }
+                               result = selinux_audit_rule_match(sid, f->type,
+                                                                 f->op,
+                                                                 f->se_rule,
+                                                                 ctx);
+                       }
+                       break;
                case AUDIT_ARG0:
                case AUDIT_ARG1:
                case AUDIT_ARG2:
@@ -329,7 +352,6 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
        return AUDIT_BUILD_CONTEXT;
 }
 
-/* This should be called with task_lock() held. */
 static inline struct audit_context *audit_get_context(struct task_struct *tsk,
                                                      int return_valid,
                                                      int return_code)
@@ -391,9 +413,6 @@ static inline void audit_free_names(struct audit_context *context)
 #endif
 
        for (i = 0; i < context->name_count; i++) {
-               char *p = context->names[i].ctx;
-               context->names[i].ctx = NULL;
-               kfree(p);
                if (context->names[i].name)
                        __putname(context->names[i].name);
        }
@@ -416,11 +435,6 @@ static inline void audit_free_aux(struct audit_context *context)
                        dput(axi->dentry);
                        mntput(axi->mnt);
                }
-               if ( aux->type == AUDIT_IPC ) {
-                       struct audit_aux_data_ipcctl *axi = (void *)aux;
-                       if (axi->ctx)
-                               kfree(axi->ctx);
-               }
 
                context->aux = aux->next;
                kfree(aux);
@@ -506,7 +520,7 @@ 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, gfp_t gfp_mask)
+static void audit_log_task_context(struct audit_buffer *ab)
 {
        char *ctx = NULL;
        ssize_t len = 0;
@@ -518,7 +532,7 @@ static void audit_log_task_context(struct audit_buffer *ab, gfp_t gfp_mask)
                return;
        }
 
-       ctx = kmalloc(len, gfp_mask);
+       ctx = kmalloc(len, GFP_KERNEL);
        if (!ctx)
                goto error_path;
 
@@ -536,47 +550,46 @@ error_path:
        return;
 }
 
-static void audit_log_task_info(struct audit_buffer *ab, gfp_t gfp_mask)
+static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
 {
-       char name[sizeof(current->comm)];
-       struct mm_struct *mm = current->mm;
+       char name[sizeof(tsk->comm)];
+       struct mm_struct *mm = tsk->mm;
        struct vm_area_struct *vma;
 
-       get_task_comm(name, current);
+       /* tsk == current */
+
+       get_task_comm(name, tsk);
        audit_log_format(ab, " comm=");
        audit_log_untrustedstring(ab, name);
 
-       if (!mm)
-               return;
-
-       /*
-        * this is brittle; all callers that pass GFP_ATOMIC will have
-        * NULL current->mm and we won't get here.
-        */
-       down_read(&mm->mmap_sem);
-       vma = mm->mmap;
-       while (vma) {
-               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);
-                       break;
+       if (mm) {
+               down_read(&mm->mmap_sem);
+               vma = mm->mmap;
+               while (vma) {
+                       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);
+                               break;
+                       }
+                       vma = vma->vm_next;
                }
-               vma = vma->vm_next;
+               up_read(&mm->mmap_sem);
        }
-       up_read(&mm->mmap_sem);
-       audit_log_task_context(ab, gfp_mask);
+       audit_log_task_context(ab);
 }
 
-static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
+static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
 {
-       int i;
+       int i, call_panic = 0;
        struct audit_buffer *ab;
        struct audit_aux_data *aux;
        const char *tty;
 
-       ab = audit_log_start(context, gfp_mask, AUDIT_SYSCALL);
+       /* tsk == current */
+
+       ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
        if (!ab)
                return;         /* audit_panic has been called */
        audit_log_format(ab, "arch=%x syscall=%d",
@@ -587,8 +600,8 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
                audit_log_format(ab, " success=%s exit=%ld", 
                                 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
                                 context->return_code);
-       if (current->signal->tty && current->signal->tty->name)
-               tty = current->signal->tty->name;
+       if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
+               tty = tsk->signal->tty->name;
        else
                tty = "(none)";
        audit_log_format(ab,
@@ -607,12 +620,12 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
                  context->gid,
                  context->euid, context->suid, context->fsuid,
                  context->egid, context->sgid, context->fsgid, tty);
-       audit_log_task_info(ab, gfp_mask);
+       audit_log_task_info(ab, tsk);
        audit_log_end(ab);
 
        for (aux = context->aux; aux; aux = aux->next) {
 
-               ab = audit_log_start(context, gfp_mask, aux->type);
+               ab = audit_log_start(context, GFP_KERNEL, aux->type);
                if (!ab)
                        continue; /* audit_panic has been called */
 
@@ -620,8 +633,39 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
                case AUDIT_IPC: {
                        struct audit_aux_data_ipcctl *axi = (void *)aux;
                        audit_log_format(ab, 
-                                        " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
-                                        axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
+                                " qbytes=%lx iuid=%u igid=%u mode=%x",
+                                axi->qbytes, axi->uid, axi->gid, axi->mode);
+                       if (axi->osid != 0) {
+                               char *ctx = NULL;
+                               u32 len;
+                               if (selinux_ctxid_to_string(
+                                               axi->osid, &ctx, &len)) {
+                                       audit_log_format(ab, " osid=%u",
+                                                       axi->osid);
+                                       call_panic = 1;
+                               } else
+                                       audit_log_format(ab, " obj=%s", ctx);
+                               kfree(ctx);
+                       }
+                       break; }
+
+               case AUDIT_IPC_SET_PERM: {
+                       struct audit_aux_data_ipcctl *axi = (void *)aux;
+                       audit_log_format(ab,
+                               " new qbytes=%lx new iuid=%u new igid=%u new mode=%x",
+                               axi->qbytes, axi->uid, axi->gid, axi->mode);
+                       if (axi->osid != 0) {
+                               char *ctx = NULL;
+                               u32 len;
+                               if (selinux_ctxid_to_string(
+                                               axi->osid, &ctx, &len)) {
+                                       audit_log_format(ab, " osid=%u",
+                                                       axi->osid);
+                                       call_panic = 1;
+                               } else
+                                       audit_log_format(ab, " obj=%s", ctx);
+                               kfree(ctx);
+                       }
                        break; }
 
                case AUDIT_SOCKETCALL: {
@@ -649,7 +693,7 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
        }
 
        if (context->pwd && context->pwdmnt) {
-               ab = audit_log_start(context, gfp_mask, AUDIT_CWD);
+               ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
                if (ab) {
                        audit_log_d_path(ab, "cwd=", context->pwd, context->pwdmnt);
                        audit_log_end(ab);
@@ -659,7 +703,7 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
                unsigned long ino  = context->names[i].ino;
                unsigned long pino = context->names[i].pino;
 
-               ab = audit_log_start(context, gfp_mask, AUDIT_PATH);
+               ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH);
                if (!ab)
                        continue; /* audit_panic has been called */
 
@@ -685,32 +729,35 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
                                         context->names[i].gid, 
                                         MAJOR(context->names[i].rdev), 
                                         MINOR(context->names[i].rdev));
-               if (context->names[i].ctx) {
-                       audit_log_format(ab, " obj=%s",
-                                       context->names[i].ctx);
+               if (context->names[i].osid != 0) {
+                       char *ctx = NULL;
+                       u32 len;
+                       if (selinux_ctxid_to_string(
+                               context->names[i].osid, &ctx, &len)) {
+                               audit_log_format(ab, " osid=%u",
+                                               context->names[i].osid);
+                               call_panic = 2;
+                       } else
+                               audit_log_format(ab, " obj=%s", ctx);
+                       kfree(ctx);
                }
 
                audit_log_end(ab);
        }
+       if (call_panic)
+               audit_panic("error converting sid to string");
 }
 
 /**
  * audit_free - free a per-task audit context
  * @tsk: task whose audit context block to free
  *
- * Called from copy_process and __put_task_struct.
+ * Called from copy_process and do_exit
  */
 void audit_free(struct task_struct *tsk)
 {
        struct audit_context *context;
 
-       /*
-        * No need to lock the task - when we execute audit_free()
-        * then the task has no external references anymore, and
-        * we are tearing it down. (The locking also confuses
-        * DEBUG_LOCKDEP - this freeing may occur in softirq
-        * contexts as well, via RCU.)
-        */
        context = audit_get_context(tsk, 0, 0);
        if (likely(!context))
                return;
@@ -719,8 +766,9 @@ void audit_free(struct task_struct *tsk)
         * function (e.g., exit_group), then free context block. 
         * We use GFP_ATOMIC here because we might be doing this 
         * in the context of the idle thread */
+       /* that can happen only if we are called from do_exit() */
        if (context->in_syscall && context->auditable)
-               audit_log_exit(context, GFP_ATOMIC);
+               audit_log_exit(context, tsk);
 
        audit_free_context(context);
 }
@@ -743,10 +791,11 @@ void audit_free(struct task_struct *tsk)
  * will only be written if another part of the kernel requests that it
  * be written).
  */
-void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
+void audit_syscall_entry(int arch, int major,
                         unsigned long a1, unsigned long a2,
                         unsigned long a3, unsigned long a4)
 {
+       struct task_struct *tsk = current;
        struct audit_context *context = tsk->audit_context;
        enum audit_state     state;
 
@@ -824,22 +873,18 @@ void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
  * message), then write out the syscall information.  In call cases,
  * free the names stored from getname().
  */
-void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
+void audit_syscall_exit(int valid, long return_code)
 {
+       struct task_struct *tsk = current;
        struct audit_context *context;
 
-       get_task_struct(tsk);
-       task_lock(tsk);
        context = audit_get_context(tsk, valid, return_code);
-       task_unlock(tsk);
 
-       /* Not having a context here is ok, since the parent may have
-        * called __put_task_struct. */
        if (likely(!context))
-               goto out;
+               return;
 
        if (context->in_syscall && context->auditable)
-               audit_log_exit(context, GFP_KERNEL);
+               audit_log_exit(context, tsk);
 
        context->in_syscall = 0;
        context->auditable  = 0;
@@ -854,8 +899,6 @@ void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
                audit_free_aux(context);
                tsk->audit_context = context;
        }
- out:
-       put_task_struct(tsk);
 }
 
 /**
@@ -936,40 +979,11 @@ void audit_putname(const char *name)
 #endif
 }
 
-void audit_inode_context(int idx, const struct inode *inode)
+static void audit_inode_context(int idx, const struct inode *inode)
 {
        struct audit_context *context = current->audit_context;
-       const char *suffix = security_inode_xattr_getsuffix();
-       char *ctx = NULL;
-       int len = 0;
-
-       if (!suffix)
-               goto ret;
-
-       len = security_inode_getsecurity(inode, suffix, NULL, 0, 0);
-       if (len == -EOPNOTSUPP)
-               goto ret;
-       if (len < 0) 
-               goto error_path;
-
-       ctx = kmalloc(len, GFP_KERNEL);
-       if (!ctx) 
-               goto error_path;
 
-       len = security_inode_getsecurity(inode, suffix, ctx, len, 0);
-       if (len < 0)
-               goto error_path;
-
-       kfree(context->names[idx].ctx);
-       context->names[idx].ctx = ctx;
-       goto ret;
-
-error_path:
-       if (ctx)
-               kfree(ctx);
-       audit_panic("error in audit_inode_context");
-ret:
-       return;
+       selinux_get_inode_sid(inode, &context->names[idx].osid);
 }
 
 
@@ -1155,40 +1169,37 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
        return ctx ? ctx->loginuid : -1;
 }
 
-static char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+/**
+ * audit_ipc_obj - record audit data for ipc object
+ * @ipcp: ipc permissions
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_ipc_obj(struct kern_ipc_perm *ipcp)
 {
+       struct audit_aux_data_ipcctl *ax;
        struct audit_context *context = current->audit_context;
-       char *ctx = NULL;
-       int len = 0;
 
        if (likely(!context))
-               return NULL;
-
-       len = security_ipc_getsecurity(ipcp, NULL, 0);
-       if (len == -EOPNOTSUPP)
-               goto ret;
-       if (len < 0)
-               goto error_path;
-
-       ctx = kmalloc(len, GFP_ATOMIC);
-       if (!ctx)
-               goto error_path;
+               return 0;
 
-       len = security_ipc_getsecurity(ipcp, ctx, len);
-       if (len < 0)
-               goto error_path;
+       ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+       if (!ax)
+               return -ENOMEM;
 
-       return ctx;
+       ax->uid = ipcp->uid;
+       ax->gid = ipcp->gid;
+       ax->mode = ipcp->mode;
+       selinux_get_ipc_sid(ipcp, &ax->osid);
 
-error_path:
-       kfree(ctx);
-       audit_panic("error in audit_ipc_context");
-ret:
-       return NULL;
+       ax->d.type = AUDIT_IPC;
+       ax->d.next = context->aux;
+       context->aux = (void *)ax;
+       return 0;
 }
 
 /**
- * audit_ipc_perms - record audit data for ipc
+ * audit_ipc_set_perm - record audit data for new ipc permissions
  * @qbytes: msgq bytes
  * @uid: msgq user id
  * @gid: msgq group id
@@ -1196,7 +1207,7 @@ ret:
  *
  * Returns 0 for success or NULL context or < 0 on error.
  */
-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
+int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
 {
        struct audit_aux_data_ipcctl *ax;
        struct audit_context *context = current->audit_context;
@@ -1212,9 +1223,9 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, str
        ax->uid = uid;
        ax->gid = gid;
        ax->mode = mode;
-       ax->ctx = audit_ipc_context(ipcp);
+       selinux_get_ipc_sid(ipcp, &ax->osid);
 
-       ax->d.type = AUDIT_IPC;
+       ax->d.type = AUDIT_IPC_SET_PERM;
        ax->d.next = context->aux;
        context->aux = (void *)ax;
        return 0;
index f86434d7b3d1811b689bfedcfc1bc40079950a34..e95b932822109e6bd517eee9a67876fedc91b426 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/futex.h>
 #include <linux/compat.h>
 #include <linux/pipe_fs_i.h>
+#include <linux/audit.h> /* for audit_free() */
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -910,6 +911,8 @@ fastcall NORET_TYPE void do_exit(long code)
        if (unlikely(tsk->compat_robust_list))
                compat_exit_robust_list(tsk);
 #endif
+       if (unlikely(tsk->audit_context))
+               audit_free(tsk);
        exit_mm(tsk);
 
        exit_sem(tsk);
index d2fa57d480d4af9c868c2e7a5602f50b6e164795..ac8100e3088a1f6d99d8ad640a70a3de5ec96e5e 100644 (file)
@@ -114,8 +114,6 @@ void __put_task_struct(struct task_struct *tsk)
        WARN_ON(atomic_read(&tsk->usage));
        WARN_ON(tsk == current);
 
-       if (unlikely(tsk->audit_context))
-               audit_free(tsk);
        security_task_free(tsk);
        free_uid(tsk->user);
        put_group_info(tsk->group_info);
index b8ea61f357e68aa46f1b4bc38bd29df5a3b580ad..3862e73d14d731b1c3674d811412fe1b29eab6dc 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/audit.h>
+#include <linux/selinux.h>
 
 #include <net/sock.h>
 #include <net/scm.h>
@@ -1156,6 +1157,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
        NETLINK_CB(skb).dst_pid = dst_pid;
        NETLINK_CB(skb).dst_group = dst_group;
        NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
+       selinux_get_task_sid(current, &(NETLINK_CB(skb).sid));
        memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
 
        /* What can I do? Netlink is asynchronous, so that
index 0ce12dfc7a71651cd1d3c49f8d7881da14a02020..02948b622bd2e938bfc6d02e44f2d13ae2b9f874 100644 (file)
@@ -267,6 +267,8 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ule
                return -EINVAL;
        if(len)
        {
+               if (audit_sockaddr(klen, kaddr))
+                       return -ENOMEM;
                if(copy_to_user(uaddr,kaddr,len))
                        return -EFAULT;
        }
index fd99429278e905e4ec33558d8e31895928359bb6..8ccccccc12acd78f72395dabd4f1c4aade37e784 100644 (file)
@@ -563,11 +563,6 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
        return 0;
 }
 
-static int dummy_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
-{
-       return -EOPNOTSUPP;
-}
-
 static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
 {
        return 0;
@@ -976,7 +971,6 @@ void security_fixup_ops (struct security_operations *ops)
        set_to_dummy_if_null(ops, task_reparent_to_init);
        set_to_dummy_if_null(ops, task_to_inode);
        set_to_dummy_if_null(ops, ipc_permission);
-       set_to_dummy_if_null(ops, ipc_getsecurity);
        set_to_dummy_if_null(ops, msg_msg_alloc_security);
        set_to_dummy_if_null(ops, msg_msg_free_security);
        set_to_dummy_if_null(ops, msg_queue_alloc_security);
index 688c0a267b62060de2f0b4172b8fe09fe5ff7361..faf2e02e4410d14fb62ae2d754df24a6d05071ab 100644 (file)
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
 
-selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o
+selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o exports.o
 
 selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
 
index ac5d69bb3377edb3c8bec35f7a1c1570425980d8..a300702da5276a41a5c86a68e389f5ebcacdc058 100644 (file)
@@ -800,7 +800,7 @@ out:
 int avc_ss_reset(u32 seqno)
 {
        struct avc_callback_node *c;
-       int i, rc = 0;
+       int i, rc = 0, tmprc;
        unsigned long flag;
        struct avc_node *node;
 
@@ -813,15 +813,16 @@ int avc_ss_reset(u32 seqno)
 
        for (c = avc_callbacks; c; c = c->next) {
                if (c->events & AVC_CALLBACK_RESET) {
-                       rc = c->callback(AVC_CALLBACK_RESET,
-                                        0, 0, 0, 0, NULL);
-                       if (rc)
-                               goto out;
+                       tmprc = c->callback(AVC_CALLBACK_RESET,
+                                           0, 0, 0, 0, NULL);
+                       /* save the first error encountered for the return
+                          value and continue processing the callbacks */
+                       if (!rc)
+                               rc = tmprc;
                }
        }
 
        avc_latest_notif_update(seqno, 0);
-out:
        return rc;
 }
 
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
new file mode 100644 (file)
index 0000000..ae4c73e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * SELinux services exported to the rest of the kernel.
+ *
+ * Author: James Morris <jmorris@redhat.com>
+ *
+ * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/selinux.h>
+#include <linux/fs.h>
+#include <linux/ipc.h>
+
+#include "security.h"
+#include "objsec.h"
+
+void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+{
+       struct task_security_struct *tsec = tsk->security;
+       if (selinux_enabled)
+               *ctxid = tsec->sid;
+       else
+               *ctxid = 0;
+}
+
+int selinux_ctxid_to_string(u32 ctxid, char **ctx, u32 *ctxlen)
+{
+       if (selinux_enabled)
+               return security_sid_to_context(ctxid, ctx, ctxlen);
+       else {
+               *ctx = NULL;
+               *ctxlen = 0;
+       }
+
+       return 0;
+}
+
+void selinux_get_inode_sid(const struct inode *inode, u32 *sid)
+{
+       if (selinux_enabled) {
+               struct inode_security_struct *isec = inode->i_security;
+               *sid = isec->sid;
+               return;
+       }
+       *sid = 0;
+}
+
+void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid)
+{
+       if (selinux_enabled) {
+               struct ipc_security_struct *isec = ipcp->security;
+               *sid = isec->sid;
+               return;
+       }
+       *sid = 0;
+}
+
+void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
+{
+       if (selinux_enabled) {
+               struct task_security_struct *tsec = tsk->security;
+               *sid = tsec->sid;
+               return;
+       }
+       *sid = 0;
+}
+
index b61b9554bc27c1d9eec70e3bce7e6a4f020d2345..3cf368a16448c54a4fccd4686765fd8569cee50a 100644 (file)
@@ -4052,13 +4052,6 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
        return ipc_has_perm(ipcp, av);
 }
 
-static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
-{
-       struct ipc_security_struct *isec = ipcp->security;
-
-       return selinux_getsecurity(isec->sid, buffer, size);
-}
-
 /* module stacking operations */
 static int selinux_register_security (const char *name, struct security_operations *ops)
 {
@@ -4321,7 +4314,6 @@ static struct security_operations selinux_ops = {
        .task_to_inode =                selinux_task_to_inode,
 
        .ipc_permission =               selinux_ipc_permission,
-       .ipc_getsecurity =              selinux_ipc_getsecurity,
 
        .msg_msg_alloc_security =       selinux_msg_msg_alloc_security,
        .msg_msg_free_security =        selinux_msg_msg_free_security,
index 84047f69f9c1b4d0bdfbbfe511457d6a62c18dad..7bc5b6440f70ba1ab45a66d0a7b3152d394096af 100644 (file)
@@ -8,7 +8,7 @@
  *
  *     Support for enhanced MLS infrastructure.
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
 
 #include <linux/kernel.h>
@@ -384,6 +384,34 @@ out:
        return rc;
 }
 
+/*
+ * Set the MLS fields in the security context structure
+ * `context' based on the string representation in
+ * the string `str'.  This function will allocate temporary memory with the
+ * given constraints of gfp_mask.
+ */
+int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
+{
+       char *tmpstr, *freestr;
+       int rc;
+
+       if (!selinux_mls_enabled)
+               return -EINVAL;
+
+       /* we need freestr because mls_context_to_sid will change
+          the value of tmpstr */
+       tmpstr = freestr = kstrdup(str, gfp_mask);
+       if (!tmpstr) {
+               rc = -ENOMEM;
+       } else {
+               rc = mls_context_to_sid(':', &tmpstr, context,
+                                       NULL, SECSID_NULL);
+               kfree(freestr);
+       }
+
+       return rc;
+}
+
 /*
  * Copies the effective MLS range from `src' into `dst'.
  */
index 03de697c8058c98ef222100504db6186c592c7fd..fbb42f07dd7c04f390ecb7c07d5872514ed8a4df 100644 (file)
@@ -8,7 +8,7 @@
  *
  *     Support for enhanced MLS infrastructure.
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  */
 
 #ifndef _SS_MLS_H_
@@ -27,6 +27,8 @@ int mls_context_to_sid(char oldc,
                       struct sidtab *s,
                       u32 def_sid);
 
+int mls_from_string(char *str, struct context *context, gfp_t gfp_mask);
+
 int mls_convert_context(struct policydb *oldp,
                        struct policydb *newp,
                        struct context *context);
index 61492485de84503f4ba87fff57326a3efde187a9..7177e98df7f33a4e06b521fbb2bb987150838246 100644 (file)
@@ -7,12 +7,13 @@
  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
  *
  *     Support for enhanced MLS infrastructure.
+ *     Support for context based audit filters.
  *
  * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
  *
  *     Added conditional policy language extensions
  *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004 Tresys Technology, LLC
  * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *     This program is free software; you can redistribute it and/or modify
@@ -1811,3 +1812,235 @@ out:
        POLICY_RDUNLOCK;
        return rc;
 }
+
+struct selinux_audit_rule {
+       u32 au_seqno;
+       struct context au_ctxt;
+};
+
+void selinux_audit_rule_free(struct selinux_audit_rule *rule)
+{
+       if (rule) {
+               context_destroy(&rule->au_ctxt);
+               kfree(rule);
+       }
+}
+
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
+                            struct selinux_audit_rule **rule)
+{
+       struct selinux_audit_rule *tmprule;
+       struct role_datum *roledatum;
+       struct type_datum *typedatum;
+       struct user_datum *userdatum;
+       int rc = 0;
+
+       *rule = NULL;
+
+       if (!ss_initialized)
+               return -ENOTSUPP;
+
+       switch (field) {
+       case AUDIT_SE_USER:
+       case AUDIT_SE_ROLE:
+       case AUDIT_SE_TYPE:
+               /* only 'equals' and 'not equals' fit user, role, and type */
+               if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+                       return -EINVAL;
+               break;
+       case AUDIT_SE_SEN:
+       case AUDIT_SE_CLR:
+               /* we do not allow a range, indicated by the presense of '-' */
+               if (strchr(rulestr, '-'))
+                       return -EINVAL;
+               break;
+       default:
+               /* only the above fields are valid */
+               return -EINVAL;
+       }
+
+       tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
+       if (!tmprule)
+               return -ENOMEM;
+
+       context_init(&tmprule->au_ctxt);
+
+       POLICY_RDLOCK;
+
+       tmprule->au_seqno = latest_granting;
+
+       switch (field) {
+       case AUDIT_SE_USER:
+               userdatum = hashtab_search(policydb.p_users.table, rulestr);
+               if (!userdatum)
+                       rc = -EINVAL;
+               else
+                       tmprule->au_ctxt.user = userdatum->value;
+               break;
+       case AUDIT_SE_ROLE:
+               roledatum = hashtab_search(policydb.p_roles.table, rulestr);
+               if (!roledatum)
+                       rc = -EINVAL;
+               else
+                       tmprule->au_ctxt.role = roledatum->value;
+               break;
+       case AUDIT_SE_TYPE:
+               typedatum = hashtab_search(policydb.p_types.table, rulestr);
+               if (!typedatum)
+                       rc = -EINVAL;
+               else
+                       tmprule->au_ctxt.type = typedatum->value;
+               break;
+       case AUDIT_SE_SEN:
+       case AUDIT_SE_CLR:
+               rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
+               break;
+       }
+
+       POLICY_RDUNLOCK;
+
+       if (rc) {
+               selinux_audit_rule_free(tmprule);
+               tmprule = NULL;
+       }
+
+       *rule = tmprule;
+
+       return rc;
+}
+
+int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
+                             struct selinux_audit_rule *rule,
+                             struct audit_context *actx)
+{
+       struct context *ctxt;
+       struct mls_level *level;
+       int match = 0;
+
+       if (!rule) {
+               audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                         "selinux_audit_rule_match: missing rule\n");
+               return -ENOENT;
+       }
+
+       POLICY_RDLOCK;
+
+       if (rule->au_seqno < latest_granting) {
+               audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                         "selinux_audit_rule_match: stale rule\n");
+               match = -ESTALE;
+               goto out;
+       }
+
+       ctxt = sidtab_search(&sidtab, ctxid);
+       if (!ctxt) {
+               audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                         "selinux_audit_rule_match: unrecognized SID %d\n",
+                         ctxid);
+               match = -ENOENT;
+               goto out;
+       }
+
+       /* a field/op pair that is not caught here will simply fall through
+          without a match */
+       switch (field) {
+       case AUDIT_SE_USER:
+               switch (op) {
+               case AUDIT_EQUAL:
+                       match = (ctxt->user == rule->au_ctxt.user);
+                       break;
+               case AUDIT_NOT_EQUAL:
+                       match = (ctxt->user != rule->au_ctxt.user);
+                       break;
+               }
+               break;
+       case AUDIT_SE_ROLE:
+               switch (op) {
+               case AUDIT_EQUAL:
+                       match = (ctxt->role == rule->au_ctxt.role);
+                       break;
+               case AUDIT_NOT_EQUAL:
+                       match = (ctxt->role != rule->au_ctxt.role);
+                       break;
+               }
+               break;
+       case AUDIT_SE_TYPE:
+               switch (op) {
+               case AUDIT_EQUAL:
+                       match = (ctxt->type == rule->au_ctxt.type);
+                       break;
+               case AUDIT_NOT_EQUAL:
+                       match = (ctxt->type != rule->au_ctxt.type);
+                       break;
+               }
+               break;
+       case AUDIT_SE_SEN:
+       case AUDIT_SE_CLR:
+               level = (op == AUDIT_SE_SEN ?
+                        &ctxt->range.level[0] : &ctxt->range.level[1]);
+               switch (op) {
+               case AUDIT_EQUAL:
+                       match = mls_level_eq(&rule->au_ctxt.range.level[0],
+                                            level);
+                       break;
+               case AUDIT_NOT_EQUAL:
+                       match = !mls_level_eq(&rule->au_ctxt.range.level[0],
+                                             level);
+                       break;
+               case AUDIT_LESS_THAN:
+                       match = (mls_level_dom(&rule->au_ctxt.range.level[0],
+                                              level) &&
+                                !mls_level_eq(&rule->au_ctxt.range.level[0],
+                                              level));
+                       break;
+               case AUDIT_LESS_THAN_OR_EQUAL:
+                       match = mls_level_dom(&rule->au_ctxt.range.level[0],
+                                             level);
+                       break;
+               case AUDIT_GREATER_THAN:
+                       match = (mls_level_dom(level,
+                                             &rule->au_ctxt.range.level[0]) &&
+                                !mls_level_eq(level,
+                                              &rule->au_ctxt.range.level[0]));
+                       break;
+               case AUDIT_GREATER_THAN_OR_EQUAL:
+                       match = mls_level_dom(level,
+                                             &rule->au_ctxt.range.level[0]);
+                       break;
+               }
+       }
+
+out:
+       POLICY_RDUNLOCK;
+       return match;
+}
+
+static int (*aurule_callback)(void) = NULL;
+
+static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
+                               u16 class, u32 perms, u32 *retained)
+{
+       int err = 0;
+
+       if (event == AVC_CALLBACK_RESET && aurule_callback)
+               err = aurule_callback();
+       return err;
+}
+
+static int __init aurule_init(void)
+{
+       int err;
+
+       err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET,
+                              SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
+       if (err)
+               panic("avc_add_callback() failed, error %d\n", err);
+
+       return err;
+}
+__initcall(aurule_init);
+
+void selinux_audit_set_callback(int (*callback)(void))
+{
+       aurule_callback = callback;
+}