Commit 532f57da authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'audit.b10' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current

* '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()
parents 46c5ea3c 2ad312d2
...@@ -671,7 +671,7 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit) ...@@ -671,7 +671,7 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit)
if (unlikely(current->audit_context)) { if (unlikely(current->audit_context)) {
if (entryexit) if (entryexit)
audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), audit_syscall_exit(AUDITSC_RESULT(regs->eax),
regs->eax); regs->eax);
/* Debug traps, when using PTRACE_SINGLESTEP, must be sent only /* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
* on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is * 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) ...@@ -720,14 +720,13 @@ int do_syscall_trace(struct pt_regs *regs, int entryexit)
ret = is_sysemu; ret = is_sysemu;
out: out:
if (unlikely(current->audit_context) && !entryexit) 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); regs->ebx, regs->ecx, regs->edx, regs->esi);
if (ret == 0) if (ret == 0)
return 0; return 0;
regs->orig_eax = -1; /* force skip of syscall restarting */ regs->orig_eax = -1; /* force skip of syscall restarting */
if (unlikely(current->audit_context)) if (unlikely(current->audit_context))
audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), audit_syscall_exit(AUDITSC_RESULT(regs->eax), regs->eax);
regs->eax);
return 1; return 1;
} }
...@@ -312,7 +312,7 @@ static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk ...@@ -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 */ /*call audit_syscall_exit since we do not exit via the normal paths */
if (unlikely(current->audit_context)) if (unlikely(current->audit_context))
audit_syscall_exit(current, AUDITSC_RESULT(eax), eax); audit_syscall_exit(AUDITSC_RESULT(eax), eax);
__asm__ __volatile__( __asm__ __volatile__(
"movl %0,%%esp\n\t" "movl %0,%%esp\n\t"
......
...@@ -1644,7 +1644,7 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3, ...@@ -1644,7 +1644,7 @@ syscall_trace_enter (long arg0, long arg1, long arg2, long arg3,
arch = AUDIT_ARCH_IA64; 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, ...@@ -1662,7 +1662,7 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
if (success != AUDITSC_SUCCESS) if (success != AUDITSC_SUCCESS)
result = -result; result = -result;
audit_syscall_exit(current, success, result); audit_syscall_exit(success, result);
} }
if (test_thread_flag(TIF_SYSCALL_TRACE) if (test_thread_flag(TIF_SYSCALL_TRACE)
......
...@@ -483,7 +483,7 @@ static inline int audit_arch(void) ...@@ -483,7 +483,7 @@ static inline int audit_arch(void)
asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
{ {
if (unlikely(current->audit_context) && 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]); regs->regs[2]);
if (!(current->ptrace & PT_PTRACED)) if (!(current->ptrace & PT_PTRACED))
...@@ -507,7 +507,7 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) ...@@ -507,7 +507,7 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
} }
out: out:
if (unlikely(current->audit_context) && !entryexit) 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[4], regs->regs[5],
regs->regs[6], regs->regs[7]); regs->regs[6], regs->regs[7]);
} }
...@@ -538,7 +538,7 @@ void do_syscall_trace_enter(struct pt_regs *regs) ...@@ -538,7 +538,7 @@ void do_syscall_trace_enter(struct pt_regs *regs)
do_syscall_trace(); do_syscall_trace();
if (unlikely(current->audit_context)) if (unlikely(current->audit_context))
audit_syscall_entry(current, audit_syscall_entry(
#ifdef CONFIG_PPC32 #ifdef CONFIG_PPC32
AUDIT_ARCH_PPC, AUDIT_ARCH_PPC,
#else #else
...@@ -556,8 +556,7 @@ void do_syscall_trace_leave(struct pt_regs *regs) ...@@ -556,8 +556,7 @@ void do_syscall_trace_leave(struct pt_regs *regs)
#endif #endif
if (unlikely(current->audit_context)) if (unlikely(current->audit_context))
audit_syscall_exit(current, audit_syscall_exit((regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
(regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
regs->result); regs->result);
if ((test_thread_flag(TIF_SYSCALL_TRACE) if ((test_thread_flag(TIF_SYSCALL_TRACE)
......
...@@ -734,7 +734,7 @@ asmlinkage void ...@@ -734,7 +734,7 @@ asmlinkage void
syscall_trace(struct pt_regs *regs, int entryexit) syscall_trace(struct pt_regs *regs, int entryexit)
{ {
if (unlikely(current->audit_context) && 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)) if (!test_thread_flag(TIF_SYSCALL_TRACE))
goto out; goto out;
...@@ -761,8 +761,7 @@ syscall_trace(struct pt_regs *regs, int entryexit) ...@@ -761,8 +761,7 @@ syscall_trace(struct pt_regs *regs, int entryexit)
} }
out: out:
if (unlikely(current->audit_context) && !entryexit) if (unlikely(current->audit_context) && !entryexit)
audit_syscall_entry(current, audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
regs->gprs[2], regs->orig_gpr2, regs->gprs[3], regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
regs->gprs[4], regs->gprs[5]); regs->gprs[4], regs->gprs[5]);
} }
...@@ -653,7 +653,7 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) ...@@ -653,7 +653,7 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
result = AUDITSC_FAILURE; 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)) if (!(current->ptrace & PT_PTRACED))
...@@ -677,8 +677,7 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) ...@@ -677,8 +677,7 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
out: out:
if (unlikely(current->audit_context) && !syscall_exit_p) if (unlikely(current->audit_context) && !syscall_exit_p)
audit_syscall_entry(current, audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
(test_thread_flag(TIF_32BIT) ?
AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC :
AUDIT_ARCH_SPARC64), AUDIT_ARCH_SPARC64),
regs->u_regs[UREG_G1], regs->u_regs[UREG_G1],
......
...@@ -275,15 +275,13 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) ...@@ -275,15 +275,13 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit)
if (unlikely(current->audit_context)) { if (unlikely(current->audit_context)) {
if (!entryexit) if (!entryexit)
audit_syscall_entry(current, audit_syscall_entry(HOST_AUDIT_ARCH,
HOST_AUDIT_ARCH,
UPT_SYSCALL_NR(regs), UPT_SYSCALL_NR(regs),
UPT_SYSCALL_ARG1(regs), UPT_SYSCALL_ARG1(regs),
UPT_SYSCALL_ARG2(regs), UPT_SYSCALL_ARG2(regs),
UPT_SYSCALL_ARG3(regs), UPT_SYSCALL_ARG3(regs),
UPT_SYSCALL_ARG4(regs)); UPT_SYSCALL_ARG4(regs));
else audit_syscall_exit(current, else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
UPT_SYSCALL_RET(regs)); UPT_SYSCALL_RET(regs));
} }
......
...@@ -600,12 +600,12 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs) ...@@ -600,12 +600,12 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
if (unlikely(current->audit_context)) { if (unlikely(current->audit_context)) {
if (test_thread_flag(TIF_IA32)) { if (test_thread_flag(TIF_IA32)) {
audit_syscall_entry(current, AUDIT_ARCH_I386, audit_syscall_entry(AUDIT_ARCH_I386,
regs->orig_rax, regs->orig_rax,
regs->rbx, regs->rcx, regs->rbx, regs->rcx,
regs->rdx, regs->rsi); regs->rdx, regs->rsi);
} else { } else {
audit_syscall_entry(current, AUDIT_ARCH_X86_64, audit_syscall_entry(AUDIT_ARCH_X86_64,
regs->orig_rax, regs->orig_rax,
regs->rdi, regs->rsi, regs->rdi, regs->rsi,
regs->rdx, regs->r10); regs->rdx, regs->r10);
...@@ -616,7 +616,7 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs) ...@@ -616,7 +616,7 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
asmlinkage void syscall_trace_leave(struct pt_regs *regs) asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{ {
if (unlikely(current->audit_context)) 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) if ((test_thread_flag(TIF_SYSCALL_TRACE)
|| test_thread_flag(TIF_SINGLESTEP)) || test_thread_flag(TIF_SINGLESTEP))
......
...@@ -83,6 +83,7 @@ ...@@ -83,6 +83,7 @@
#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */ #define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */ #define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
#define AUDIT_CWD 1307 /* Current working directory */ #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_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
...@@ -145,6 +146,11 @@ ...@@ -145,6 +146,11 @@
#define AUDIT_PERS 10 #define AUDIT_PERS 10
#define AUDIT_ARCH 11 #define AUDIT_ARCH 11
#define AUDIT_MSGTYPE 12 #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 /* These are ONLY useful when checking
* at syscall exit time (AUDIT_AT_EXIT). */ * at syscall exit time (AUDIT_AT_EXIT). */
...@@ -287,10 +293,10 @@ struct netlink_skb_parms; ...@@ -287,10 +293,10 @@ struct netlink_skb_parms;
/* Public API */ /* Public API */
extern int audit_alloc(struct task_struct *task); extern int audit_alloc(struct task_struct *task);
extern void audit_free(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, int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3); 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_getname(const char *name);
extern void audit_putname(const char *name); extern void audit_putname(const char *name);
extern void __audit_inode(const char *name, const struct inode *inode, unsigned flags); 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, ...@@ -314,7 +320,8 @@ extern void auditsc_get_stamp(struct audit_context *ctx,
struct timespec *t, unsigned int *serial); struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx); 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_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr); extern int audit_sockaddr(int len, void *addr);
extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
...@@ -323,8 +330,8 @@ extern int audit_set_macxattr(const char *name); ...@@ -323,8 +330,8 @@ extern int audit_set_macxattr(const char *name);
#else #else
#define audit_alloc(t) ({ 0; }) #define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (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_entry(ta,a,b,c,d,e) do { ; } while (0)
#define audit_syscall_exit(t,f,r) do { ; } while (0) #define audit_syscall_exit(f,r) do { ; } while (0)
#define audit_getname(n) do { ; } while (0) #define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0)
#define __audit_inode(n,i,f) do { ; } while (0) #define __audit_inode(n,i,f) do { ; } while (0)
...@@ -333,7 +340,8 @@ extern int audit_set_macxattr(const char *name); ...@@ -333,7 +340,8 @@ extern int audit_set_macxattr(const char *name);
#define audit_inode_child(d,i,p) do { ; } while (0) #define audit_inode_child(d,i,p) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
#define audit_get_loginuid(c) ({ -1; }) #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_socketcall(n,a) ({ 0; })
#define audit_sockaddr(len, addr) ({ 0; }) #define audit_sockaddr(len, addr) ({ 0; })
#define audit_avc_path(dentry, mnt) ({ 0; }) #define audit_avc_path(dentry, mnt) ({ 0; })
...@@ -366,7 +374,7 @@ extern void audit_log_d_path(struct audit_buffer *ab, ...@@ -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_user(struct netlink_skb_parms *cb, int type);
extern int audit_filter_type(int type); extern int audit_filter_type(int type);
extern int audit_receive_filter(int type, int pid, int uid, int seq, 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 #else
#define audit_log(c,g,t,f,...) do { ; } while (0) #define audit_log(c,g,t,f,...) do { ; } while (0)
#define audit_log_start(c,g,t) ({ NULL; }) #define audit_log_start(c,g,t) ({ NULL; })
......
...@@ -143,6 +143,7 @@ struct netlink_skb_parms ...@@ -143,6 +143,7 @@ struct netlink_skb_parms
__u32 dst_group; __u32 dst_group;
kernel_cap_t eff_cap; kernel_cap_t eff_cap;
__u32 loginuid; /* Login (audit) uid */ __u32 loginuid; /* Login (audit) uid */
__u32 sid; /* SELinux security id */
}; };
#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))
......
...@@ -869,11 +869,6 @@ struct swap_info_struct; ...@@ -869,11 +869,6 @@ struct swap_info_struct;
* @ipcp contains the kernel IPC permission structure * @ipcp contains the kernel IPC permission structure
* @flag contains the desired (requested) permission set * @flag contains the desired (requested) permission set
* Return 0 if permission is granted. * 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 * Security hooks for individual messages held in System V IPC message queues
* @msg_msg_alloc_security: * @msg_msg_alloc_security:
...@@ -1223,7 +1218,6 @@ struct security_operations { ...@@ -1223,7 +1218,6 @@ struct security_operations {
void (*task_to_inode)(struct task_struct *p, struct inode *inode); void (*task_to_inode)(struct task_struct *p, struct inode *inode);
int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag); 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); int (*msg_msg_alloc_security) (struct msg_msg * msg);
void (*msg_msg_free_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, ...@@ -1887,11 +1881,6 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
return security_ops->ipc_permission (ipcp, flag); 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) static inline int security_msg_msg_alloc (struct msg_msg * msg)
{ {
return security_ops->msg_msg_alloc_security (msg); return security_ops->msg_msg_alloc_security (msg);
...@@ -2532,11 +2521,6 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp, ...@@ -2532,11 +2521,6 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
return 0; 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) static inline int security_msg_msg_alloc (struct msg_msg * msg)
{ {
return 0; return 0;
......
/*
* 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 */
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
* mostly rewritten, threaded and wake-one semantics added * mostly rewritten, threaded and wake-one semantics added
* MSGMAX limit removed, sysctl's added * MSGMAX limit removed, sysctl's added
* (c) 1999 Manfred Spraul <manfred@colorfullife.com> * (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> #include <linux/capability.h>
...@@ -447,6 +450,11 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) ...@@ -447,6 +450,11 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
if (msg_checkid(msq,msqid)) if (msg_checkid(msq,msqid))
goto out_unlock_up; goto out_unlock_up;
ipcp = &msq->q_perm; ipcp = &msq->q_perm;
err = audit_ipc_obj(ipcp);
if (err)
goto out_unlock_up;
err = -EPERM; err = -EPERM;
if (current->euid != ipcp->cuid && if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) 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) ...@@ -460,7 +468,8 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
switch (cmd) { switch (cmd) {
case IPC_SET: 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; goto out_unlock_up;
err = -EPERM; err = -EPERM;
......
...@@ -61,6 +61,9 @@ ...@@ -61,6 +61,9 @@
* (c) 2001 Red Hat Inc <alan@redhat.com> * (c) 2001 Red Hat Inc <alan@redhat.com>
* Lockless wakeup * Lockless wakeup
* (c) 2003 Manfred Spraul <manfred@colorfullife.com> * (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> #include <linux/config.h>
...@@ -820,6 +823,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun ...@@ -820,6 +823,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
goto out_unlock; goto out_unlock;
} }
ipcp = &sma->sem_perm; ipcp = &sma->sem_perm;
err = audit_ipc_obj(ipcp);
if (err)
goto out_unlock;
if (current->euid != ipcp->cuid && if (current->euid != ipcp->cuid &&
current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
err=-EPERM; err=-EPERM;
...@@ -836,7 +844,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun ...@@ -836,7 +844,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
err = 0; err = 0;
break; break;
case IPC_SET: 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; goto out_unlock;
ipcp->uid = setbuf.uid; ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid; ipcp->gid = setbuf.gid;
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
* Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com> * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
* Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.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> #include <linux/config.h>
...@@ -542,6 +544,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) ...@@ -542,6 +544,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
if(err) if(err)
goto out_unlock; goto out_unlock;
err = audit_ipc_obj(&(shp->shm_perm));
if (err)
goto out_unlock;
if (!capable(CAP_IPC_LOCK)) { if (!capable(CAP_IPC_LOCK)) {
err = -EPERM; err = -EPERM;
if (current->euid != shp->shm_perm.uid && if (current->euid != shp->shm_perm.uid &&
...@@ -594,6 +600,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) ...@@ -594,6 +600,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
if(err) if(err)
goto out_unlock_up; goto out_unlock_up;
err = audit_ipc_obj(&(shp->shm_perm));
if (err)
goto out_unlock_up;
if (current->euid != shp->shm_perm.uid && if (current->euid != shp->shm_perm.uid &&
current->euid != shp->shm_perm.cuid && current->euid != shp->shm_perm.cuid &&
!capable(CAP_SYS_ADMIN)) { !capable(CAP_SYS_ADMIN)) {
...@@ -627,12 +637,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) ...@@ -627,12 +637,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
err=-EINVAL; err=-EINVAL;
if(shp==NULL) if(shp==NULL)
goto out_up; 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); err = shm_checkid(shp,shmid);
if(err) if(err)
goto out_unlock_up; 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; err=-EPERM;
if (current->euid != shp->shm_perm.uid && if (current->euid != shp->shm_perm.uid &&
current->euid != shp->shm_perm.cuid && current->euid != shp->shm_perm.cuid &&
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
* Manfred Spraul <manfred@colorfullife.com> * Manfred Spraul <manfred@colorfullife.com>
* Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary(). * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().
* Mingming Cao <cmm@us.ibm.com> * 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> #include <linux/config.h>
...@@ -27,6 +29,7 @@ ...@@ -27,6 +29,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/audit.h>
#include <asm/unistd.h> #include <asm/unistd.h>
...@@ -464,8 +467,10 @@ void ipc_rcu_putref(void *ptr) ...@@ -464,8 +467,10 @@ void ipc_rcu_putref(void *ptr)
int ipcperms (struct kern_ipc_perm *ipcp, short flag) int ipcperms (struct kern_ipc_perm *ipcp, short flag)
{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */ { /* 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; requested_mode = (flag >> 6) | (flag >> 3) | flag;
granted_mode = ipcp->mode; granted_mode = ipcp->mode;
if (current->euid == ipcp->cuid || current->euid == ipcp->uid) if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
......
...@@ -55,6 +55,9 @@ ...@@ -55,6 +55,9 @@
#include <net/netlink.h> #include <net/netlink.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/selinux.h>
#include "audit.h"
/* No auditing will take place until audit_initialized != 0. /* No auditing will take place until audit_initialized != 0.
* (Initialization happens after skb_init is called.) */ * (Initialization happens after skb_init is called.) */
...@@ -227,49 +230,103 @@ void audit_log_lost(const char *message) ...@@ -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; int old = audit_rate_limit;
audit_rate_limit = limit;
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_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=%d old=%d by auid=%u",
audit_rate_limit, old, loginuid); limit, old, loginuid);
audit_rate_limit = limit;
return old; 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; int old = audit_backlog_limit;
audit_backlog_limit = limit;
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_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=%d old=%d by auid=%u",
audit_backlog_limit, old, loginuid); limit, old, loginuid);
audit_backlog_limit = limit;
return old; 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) if (state != 0 && state != 1)
return -EINVAL; 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=%d old=%d by auid=%u",
audit_enabled, old, loginuid); state, old, loginuid);
audit_enabled = state;
return old; 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 if (state != AUDIT_FAIL_SILENT
&& state != AUDIT_FAIL_PRINTK && state != AUDIT_FAIL_PRINTK
&& state != AUDIT_FAIL_PANIC) && state != AUDIT_FAIL_PANIC)
return -EINVAL; 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=%d old=%d by auid=%u",
audit_failure, old, loginuid); state, old, loginuid);
audit_failure = state;
return old; return old;
} }
...@@ -387,7 +444,7 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type) ...@@ -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) static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{ {
u32 uid, pid, seq; u32 uid, pid, seq, sid;
void *data; void *data;
struct audit_status *status_get, status_set; struct audit_status *status_get, status_set;
int err; int err;
...@@ -413,6 +470,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -413,6 +470,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
pid = NETLINK_CREDS(skb)->pid; pid = NETLINK_CREDS(skb)->pid;
uid = NETLINK_CREDS(skb)->uid; uid = NETLINK_CREDS(skb)->uid;
loginuid = NETLINK_CB(skb).loginuid; loginuid = NETLINK_CB(skb).loginuid;
sid = NETLINK_CB(skb).sid;
seq = nlh->nlmsg_seq; seq = nlh->nlmsg_seq;
data = NLMSG_DATA(nlh); data = NLMSG_DATA(nlh);
...@@ -433,25 +491,43 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -433,25 +491,43 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return -EINVAL; return -EINVAL;
status_get = (struct audit_status *)data; status_get = (struct audit_status *)data;
if (status_get->mask & AUDIT_STATUS_ENABLED) { 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 (err < 0) return err;
} }
if (status_get->mask & AUDIT_STATUS_FAILURE) { 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 (err < 0) return err;
} }
if (status_get->mask & AUDIT_STATUS_PID) { if (status_get->mask & AUDIT_STATUS_PID) {
int old = audit_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_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) 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) if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
audit_set_backlog_limit(status_get->backlog_limit, audit_set_backlog_limit(status_get->backlog_limit,
loginuid); loginuid, sid);
break; break;
case AUDIT_USER: case AUDIT_USER:
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: 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) ...@@ -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); ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
if (ab) { if (ab) {
audit_log_format(ab, audit_log_format(ab,
"user pid=%d uid=%u auid=%u msg='%.1024s'", "user pid=%d uid=%u auid=%u",
pid, uid, loginuid, (char *)data); 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_set_pid(ab, pid);
audit_log_end(ab); audit_log_end(ab);
} }
...@@ -480,7 +571,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -480,7 +571,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case AUDIT_LIST: case AUDIT_LIST:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
uid, seq, data, nlmsg_len(nlh), uid, seq, data, nlmsg_len(nlh),
loginuid); loginuid, sid);
break; break;
case AUDIT_ADD_RULE: case AUDIT_ADD_RULE:
case AUDIT_DEL_RULE: case AUDIT_DEL_RULE:
...@@ -490,7 +581,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -490,7 +581,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case AUDIT_LIST_RULES: case AUDIT_LIST_RULES:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
uid, seq, data, nlmsg_len(nlh), uid, seq, data, nlmsg_len(nlh),
loginuid); loginuid, sid);
break; break;
case AUDIT_SIGNAL_INFO: case AUDIT_SIGNAL_INFO:
sig_data.uid = audit_sig_uid; sig_data.uid = audit_sig_uid;
...@@ -564,6 +655,11 @@ static int __init audit_init(void) ...@@ -564,6 +655,11 @@ static int __init audit_init(void)
skb_queue_head_init(&audit_skb_queue); skb_queue_head_init(&audit_skb_queue);
audit_initialized = 1; audit_initialized = 1;
audit_enabled = audit_default; 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"); audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
return 0; return 0;
} }
......
...@@ -54,9 +54,11 @@ enum audit_state { ...@@ -54,9 +54,11 @@ enum audit_state {
/* Rule lists */ /* Rule lists */
struct audit_field { struct audit_field {
u32 type; u32 type;
u32 val; u32 val;
u32 op; u32 op;
char *se_str;
struct selinux_audit_rule *se_rule;
}; };
struct audit_krule { struct audit_krule {
...@@ -86,3 +88,5 @@ extern void audit_send_reply(int pid, int seq, int type, ...@@ -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_log_lost(const char *message);
extern void audit_panic(const char *message); extern void audit_panic(const char *message);
extern struct mutex audit_netlink_mutex; extern struct mutex audit_netlink_mutex;
extern int selinux_audit_rule_update(void);
This diff is collapsed.
This diff is collapsed.
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/futex.h> #include <linux/futex.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/pipe_fs_i.h> #include <linux/pipe_fs_i.h>
#include <linux/audit.h> /* for audit_free() */
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
...@@ -910,6 +911,8 @@ fastcall NORET_TYPE void do_exit(long code) ...@@ -910,6 +911,8 @@ fastcall NORET_TYPE void do_exit(long code)
if (unlikely(tsk->compat_robust_list)) if (unlikely(tsk->compat_robust_list))
compat_exit_robust_list(tsk); compat_exit_robust_list(tsk);
#endif #endif
if (unlikely(tsk->audit_context))
audit_free(tsk);
exit_mm(tsk); exit_mm(tsk);
exit_sem(tsk); exit_sem(tsk);
......
...@@ -114,8 +114,6 @@ void __put_task_struct(struct task_struct *tsk) ...@@ -114,8 +114,6 @@ void __put_task_struct(struct task_struct *tsk)
WARN_ON(atomic_read(&tsk->usage)); WARN_ON(atomic_read(&tsk->usage));
WARN_ON(tsk == current); WARN_ON(tsk == current);
if (unlikely(tsk->audit_context))
audit_free(tsk);
security_task_free(tsk); security_task_free(tsk);
free_uid(tsk->user); free_uid(tsk->user);
put_group_info(tsk->group_info); put_group_info(tsk->group_info);
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/selinux.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/scm.h> #include <net/scm.h>
...@@ -1156,6 +1157,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, ...@@ -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_pid = dst_pid;
NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).dst_group = dst_group;
NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); 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)); memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
/* What can I do? Netlink is asynchronous, so that /* What can I do? Netlink is asynchronous, so that
......
...@@ -267,6 +267,8 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ule ...@@ -267,6 +267,8 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ule
return -EINVAL; return -EINVAL;
if(len) if(len)
{ {
if (audit_sockaddr(klen, kaddr))
return -ENOMEM;
if(copy_to_user(uaddr,kaddr,len)) if(copy_to_user(uaddr,kaddr,len))
return -EFAULT; return -EFAULT;
} }
......
...@@ -563,11 +563,6 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag) ...@@ -563,11 +563,6 @@ static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
return 0; 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) static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
{ {
return 0; return 0;
...@@ -976,7 +971,6 @@ void security_fixup_ops (struct security_operations *ops) ...@@ -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_reparent_to_init);
set_to_dummy_if_null(ops, task_to_inode); set_to_dummy_if_null(ops, task_to_inode);
set_to_dummy_if_null(ops, ipc_permission); 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_alloc_security);
set_to_dummy_if_null(ops, msg_msg_free_security); set_to_dummy_if_null(ops, msg_msg_free_security);
set_to_dummy_if_null(ops, msg_queue_alloc_security); set_to_dummy_if_null(ops, msg_queue_alloc_security);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/ 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 selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
......
...@@ -800,7 +800,7 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass) ...@@ -800,7 +800,7 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
int avc_ss_reset(u32 seqno) int avc_ss_reset(u32 seqno)
{ {
struct avc_callback_node *c; struct avc_callback_node *c;
int i, rc = 0; int i, rc = 0, tmprc;
unsigned long flag; unsigned long flag;
struct avc_node *node; struct avc_node *node;
...@@ -813,15 +813,16 @@ int avc_ss_reset(u32 seqno) ...@@ -813,15 +813,16 @@ int avc_ss_reset(u32 seqno)
for (c = avc_callbacks; c; c = c->next) { for (c = avc_callbacks; c; c = c->next) {
if (c->events & AVC_CALLBACK_RESET) { if (c->events & AVC_CALLBACK_RESET) {
rc = c->callback(AVC_CALLBACK_RESET, tmprc = c->callback(AVC_CALLBACK_RESET,
0, 0, 0, 0, NULL); 0, 0, 0, 0, NULL);
if (rc) /* save the first error encountered for the return
goto out; value and continue processing the callbacks */
if (!rc)
rc = tmprc;
} }
} }
avc_latest_notif_update(seqno, 0); avc_latest_notif_update(seqno, 0);
out:
return rc; return rc;
} }
......
/*
* 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;
}
...@@ -4052,13 +4052,6 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) ...@@ -4052,13 +4052,6 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
return ipc_has_perm(ipcp, av); 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 */ /* module stacking operations */
static int selinux_register_security (const char *name, struct security_operations *ops) static int selinux_register_security (const char *name, struct security_operations *ops)
{ {
...@@ -4321,7 +4314,6 @@ static struct security_operations selinux_ops = { ...@@ -4321,7 +4314,6 @@ static struct security_operations selinux_ops = {
.task_to_inode = selinux_task_to_inode, .task_to_inode = selinux_task_to_inode,
.ipc_permission = selinux_ipc_permission, .ipc_permission = selinux_ipc_permission,
.ipc_getsecurity = selinux_ipc_getsecurity,
.msg_msg_alloc_security = selinux_msg_msg_alloc_security, .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
.msg_msg_free_security = selinux_msg_msg_free_security, .msg_msg_free_security = selinux_msg_msg_free_security,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* Support for enhanced MLS infrastructure. * 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> #include <linux/kernel.h>
...@@ -384,6 +384,34 @@ int mls_context_to_sid(char oldc, ...@@ -384,6 +384,34 @@ int mls_context_to_sid(char oldc,
return rc; 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'. * Copies the effective MLS range from `src' into `dst'.
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* Support for enhanced MLS infrastructure. * 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_ #ifndef _SS_MLS_H_
...@@ -27,6 +27,8 @@ int mls_context_to_sid(char oldc, ...@@ -27,6 +27,8 @@ int mls_context_to_sid(char oldc,
struct sidtab *s, struct sidtab *s,
u32 def_sid); u32 def_sid);
int mls_from_string(char *str, struct context *context, gfp_t gfp_mask);
int mls_convert_context(struct policydb *oldp, int mls_convert_context(struct policydb *oldp,
struct policydb *newp, struct policydb *newp,
struct context *context); struct context *context);
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
* *
* Support for enhanced MLS infrastructure. * Support for enhanced MLS infrastructure.
* Support for context based audit filters.
* *
* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
* *
* Added conditional policy language extensions * 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 - 2004 Tresys Technology, LLC
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -1811,3 +1812,235 @@ int security_get_bool_value(int bool) ...@@ -1811,3 +1812,235 @@ int security_get_bool_value(int bool)
POLICY_RDUNLOCK; POLICY_RDUNLOCK;
return rc; 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment