Index: arch/ppc/Kconfig =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/arch/ppc/Kconfig (mode:100644 sha1:600f23d7fd33aae9e5115875ada43a289e075b5d) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/arch/ppc/Kconfig (mode:100644 sha1:cd752a3cf3bd288e96c852bd6af0e4aa6ea5da8e) @@ -1083,6 +1083,23 @@ source kernel/power/Kconfig +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + depends on PROC_FS + default y + help + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via /proc//seccomp, it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + + If unsure, say Y. Only embedded should say N here. + endmenu config ISA_DMA_API Index: arch/ppc/kernel/entry.S =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/arch/ppc/kernel/entry.S (mode:100644 sha1:5f075dbc4ee72546e710a546db046ca58a1ad5a2) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/arch/ppc/kernel/entry.S (mode:100644 sha1:661523707e8c4c92790450e2256d8496163bf324) @@ -202,7 +202,7 @@ rlwinm r11,r11,0,~_TIFL_FORCE_NOERROR stw r11,TI_LOCAL_FLAGS(r10) lwz r11,TI_FLAGS(r10) - andi. r11,r11,_TIF_SYSCALL_TRACE + andi. r11,r11,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace syscall_dotrace_cont: cmplwi 0,r0,NR_syscalls @@ -237,7 +237,7 @@ SYNC MTMSRD(r10) lwz r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_TRACE|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) bne- syscall_exit_work syscall_exit_cont: #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) @@ -277,7 +277,8 @@ SAVE_NVGPRS(r1) li r0,0xc00 stw r0,TRAP(r1) - bl do_syscall_trace + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_syscall_trace_enter lwz r0,GPR0(r1) /* Restore original registers */ lwz r3,GPR3(r1) lwz r4,GPR4(r1) @@ -291,7 +292,7 @@ syscall_exit_work: stw r6,RESULT(r1) /* Save result */ stw r3,GPR3(r1) /* Update return value */ - andi. r0,r9,_TIF_SYSCALL_TRACE + andi. r0,r9,_TIF_SYSCALL_T_OR_A beq 5f ori r10,r10,MSR_EE SYNC @@ -303,7 +304,8 @@ li r4,0xc00 stw r4,TRAP(r1) 4: - bl do_syscall_trace + addi r3,r1,STACK_FRAME_OVERHEAD + bl do_syscall_trace_leave REST_NVGPRS(r1) 2: lwz r3,GPR3(r1) @@ -627,8 +629,8 @@ subi r1,r3,STACK_FRAME_OVERHEAD rlwinm r12,r1,0,0,18 /* current_thread_info() */ lwz r9,TI_FLAGS(r12) - andi. r0,r9,_TIF_SYSCALL_TRACE - bnel- do_syscall_trace + andi. r0,r9,_TIF_SYSCALL_T_OR_A + bnel- do_syscall_trace_leave /* fall through */ .globl ret_from_except_full Index: arch/ppc/kernel/ppc_ksyms.c =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/arch/ppc/kernel/ppc_ksyms.c (mode:100644 sha1:2ccb58fe4fc3caf391fc914cb496fb6a82f9d741) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/arch/ppc/kernel/ppc_ksyms.c (mode:100644 sha1:d59ad07de8e7d83b3931b90e3777aef95d7df532) @@ -55,7 +55,6 @@ #define EXPORT_SYMTAB_STROPS extern void transfer_to_handler(void); -extern void do_syscall_trace(void); extern void do_IRQ(struct pt_regs *regs); extern void MachineCheckException(struct pt_regs *regs); extern void AlignmentException(struct pt_regs *regs); @@ -74,7 +73,6 @@ EXPORT_SYMBOL(clear_pages); EXPORT_SYMBOL(clear_user_page); EXPORT_SYMBOL(do_signal); -EXPORT_SYMBOL(do_syscall_trace); EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(do_IRQ); EXPORT_SYMBOL(MachineCheckException); Index: arch/ppc/kernel/ptrace.c =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/arch/ppc/kernel/ptrace.c (mode:100644 sha1:59d59a8dc249675b1f2e5186568dfbeae344c8a1) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/arch/ppc/kernel/ptrace.c (mode:100644 sha1:e7aee4108dea69985ba02507a78a46f227ba47da) @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include #include #include @@ -455,11 +458,10 @@ return ret; } -void do_syscall_trace(void) +static void do_syscall_trace(void) { - if (!test_thread_flag(TIF_SYSCALL_TRACE) - || !(current->ptrace & PT_PTRACED)) - return; + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); @@ -473,3 +475,33 @@ current->exit_code = 0; } } + +void do_syscall_trace_enter(struct pt_regs *regs) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); + + if (unlikely(current->audit_context)) + audit_syscall_entry(current, AUDIT_ARCH_PPC, + regs->gpr[0], + regs->gpr[3], regs->gpr[4], + regs->gpr[5], regs->gpr[6]); +} + +void do_syscall_trace_leave(struct pt_regs *regs) +{ + secure_computing(regs->gpr[0]); + + if (unlikely(current->audit_context)) + audit_syscall_exit(current, + (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, + regs->result); + + if ((test_thread_flag(TIF_SYSCALL_TRACE)) + && (current->ptrace & PT_PTRACED)) + do_syscall_trace(); +} + +EXPORT_SYMBOL(do_syscall_trace_enter); +EXPORT_SYMBOL(do_syscall_trace_leave); Index: include/asm-ppc/seccomp.h =================================================================== --- /dev/null (tree:eed337ef5e9ae7d62caa84b7974a11fddc7f06e0) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/include/asm-ppc/seccomp.h (mode:100644 sha1:666c4da96d87114cf79e94912df165aedf47ca21) @@ -0,0 +1,10 @@ +#ifndef _ASM_SECCOMP_H + +#include + +#define __NR_seccomp_read __NR_read +#define __NR_seccomp_write __NR_write +#define __NR_seccomp_exit __NR_exit +#define __NR_seccomp_sigreturn __NR_rt_sigreturn + +#endif /* _ASM_SECCOMP_H */ Index: include/asm-ppc/thread_info.h =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/include/asm-ppc/thread_info.h (mode:100644 sha1:f7f01524e8a8936424b0602ec1754b71f8411d0c) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/include/asm-ppc/thread_info.h (mode:100644 sha1:e3b5284a6f91c0be27f766d4aaf0fe2671c8d2f1) @@ -77,12 +77,19 @@ #define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 5 +#define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ +#define TIF_SECCOMP 7 /* secure computing */ + /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1< /* Request and reply types */ -#define AUDIT_GET 1000 /* Get status */ -#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ -#define AUDIT_LIST 1002 /* List filtering rules */ -#define AUDIT_ADD 1003 /* Add filtering rule */ -#define AUDIT_DEL 1004 /* Delete filtering rule */ -#define AUDIT_USER 1005 /* Send a message from user-space */ -#define AUDIT_LOGIN 1006 /* Define the login id and informaiton */ -#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ +#define AUDIT_GET 1000 /* Get status */ +#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ +#define AUDIT_LIST 1002 /* List filtering rules */ +#define AUDIT_ADD 1003 /* Add filtering rule */ +#define AUDIT_DEL 1004 /* Delete filtering rule */ +#define AUDIT_USER 1005 /* Send a message from user-space */ +#define AUDIT_LOGIN 1006 /* Define the login id and information */ +#define AUDIT_SIGNAL_INFO 1010 /* Get information about sender of signal*/ + +#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ /* Rule flags */ #define AUDIT_PER_TASK 0x01 /* Apply rule at task creation (not syscall) */ @@ -161,6 +163,11 @@ #ifdef __KERNEL__ +struct audit_sig_info { + uid_t uid; + pid_t pid; +}; + struct audit_buffer; struct audit_context; struct inode; @@ -185,11 +192,12 @@ /* Private API (for audit.c only) */ extern int audit_receive_filter(int type, int pid, int uid, int seq, void *data, uid_t loginuid); -extern void audit_get_stamp(struct audit_context *ctx, +extern int audit_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); +extern void audit_signal_info(int sig, struct task_struct *t); #else #define audit_alloc(t) ({ 0; }) #define audit_free(t) do { ; } while (0) @@ -198,18 +206,24 @@ #define audit_getname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0) #define audit_inode(n,i) do { ; } while (0) +#define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) +#define audit_get_stamp(c,t,s) ({ 0; }) #define audit_get_loginuid(c) ({ -1; }) #define audit_ipc_perms(q,u,g,m) ({ 0; }) +#define audit_signal_info(s,t) do { ; } while (0) #endif #ifdef CONFIG_AUDIT /* These are defined in audit.c */ /* Public API */ -extern void audit_log(struct audit_context *ctx, - const char *fmt, ...) - __attribute__((format(printf,2,3))); +#define audit_log(ctx, fmt, args...) \ + audit_log_type(ctx, AUDIT_KERNEL, 0, fmt, ##args) +extern void audit_log_type(struct audit_context *ctx, int type, + int pid, const char *fmt, ...) + __attribute__((format(printf,4,5))); -extern struct audit_buffer *audit_log_start(struct audit_context *ctx); +extern struct audit_buffer *audit_log_start(struct audit_context *ctx, int type, + int pid); extern void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) __attribute__((format(printf,2,3))); @@ -229,8 +243,9 @@ void *payload, int size); extern void audit_log_lost(const char *message); #else -#define audit_log(t,f,...) do { ; } while (0) -#define audit_log_start(t) ({ NULL; }) +#define audit_log(c,f,...) do { ; } while (0) +#define audit_log_type(c,t,p,f,...) do { ; } while (0) +#define audit_log_start(c,t,p) ({ NULL; }) #define audit_log_vformat(b,f,a) do { ; } while (0) #define audit_log_format(b,f,...) do { ; } while (0) #define audit_log_end(b) do { ; } while (0) Index: init/Kconfig =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/init/Kconfig (mode:100644 sha1:d920baed109a4c0bfb91d85e436626ccac886fbb) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/init/Kconfig (mode:100644 sha1:448939d183dd1f8aed00f20c2b397d3ca6b00e6b) @@ -164,6 +164,7 @@ config AUDIT bool "Auditing support" + depends on NET default y if SECURITY_SELINUX help Enable auditing infrastructure that can be used with another @@ -173,7 +174,7 @@ config AUDITSYSCALL bool "Enable system-call auditing support" - depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64 || UML) + depends on AUDIT && (X86 || PPC || PPC64 || ARCH_S390 || IA64 || UML) default y if SECURITY_SELINUX help Enable low-overhead system-call auditing infrastructure that Index: kernel/audit.c =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/kernel/audit.c (mode:100644 sha1:9c4f1af0c794674404810d7caff0131218cbc950) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/kernel/audit.c (mode:100644 sha1:060b554f481e430fd2154be52dc5a6181a5e9f33) @@ -68,7 +68,7 @@ /* If audit records are to be written to the netlink socket, audit_pid * contains the (non-zero) pid. */ -static int audit_pid; +int audit_pid; /* If audit_limit is non-zero, limit the rate of sending audit records * to that number per second. This prevents DoS attacks, but results in @@ -79,6 +79,10 @@ static int audit_backlog_limit = 64; static atomic_t audit_backlog = ATOMIC_INIT(0); +/* The identity of the user shutting down the audit system. */ +uid_t audit_sig_uid = -1; +pid_t audit_sig_pid = -1; + /* Records can be lost in several ways: 0) [suppressed in audit_alloc] 1) out of memory in audit_log_start [kmalloc of struct audit_buffer] @@ -132,23 +136,10 @@ * use simultaneously. */ struct audit_buffer { struct list_head list; - struct sk_buff_head sklist; /* formatted skbs ready to send */ + struct sk_buff *skb; /* formatted skb ready to send */ struct audit_context *ctx; /* NULL or associated context */ - int len; /* used area of tmp */ - char tmp[AUDIT_BUFSIZ]; - - /* Pointer to header and contents */ - struct nlmsghdr *nlh; - int total; - int type; - int pid; }; -void audit_set_type(struct audit_buffer *ab, int type) -{ - ab->type = type; -} - struct audit_entry { struct list_head list; struct audit_rule rule; @@ -280,7 +271,6 @@ return old; } -#ifdef CONFIG_NET void audit_send_reply(int pid, int seq, int type, int done, int multi, void *payload, int size) { @@ -321,6 +311,7 @@ case AUDIT_SET: case AUDIT_ADD: case AUDIT_DEL: + case AUDIT_SIGNAL_INFO: if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL)) err = -EPERM; break; @@ -341,9 +332,9 @@ void *data; struct audit_status *status_get, status_set; int err; - struct audit_buffer *ab; u16 msg_type = nlh->nlmsg_type; uid_t loginuid; /* loginuid of sender */ + struct audit_sig_info sig_data; err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); if (err) @@ -392,19 +383,13 @@ loginuid); break; case AUDIT_USER: - ab = audit_log_start(NULL); - if (!ab) - break; /* audit_panic has been called */ - audit_log_format(ab, + audit_log_type(NULL, AUDIT_USER, pid, "user pid=%d uid=%d length=%d loginuid=%u" " msg='%.1024s'", pid, uid, (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh)), loginuid, (char *)data); - ab->type = AUDIT_USER; - ab->pid = pid; - audit_log_end(ab); break; case AUDIT_ADD: case AUDIT_DEL: @@ -412,12 +397,14 @@ return -EINVAL; /* fallthrough */ case AUDIT_LIST: -#ifdef CONFIG_AUDITSYSCALL err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid, uid, seq, data, loginuid); -#else - err = -EOPNOTSUPP; -#endif + break; + case AUDIT_SIGNAL_INFO: + sig_data.uid = audit_sig_uid; + sig_data.pid = audit_sig_pid; + audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO, + 0, 0, &sig_data, sizeof(sig_data)); break; default: err = -EINVAL; @@ -467,64 +454,23 @@ up(&audit_netlink_sem); } -/* Move data from tmp buffer into an skb. This is an extra copy, and - * that is unfortunate. However, the copy will only occur when a record - * is being written to user space, which is already a high-overhead - * operation. (Elimination of the copy is possible, for example, by - * writing directly into a pre-allocated skb, at the cost of wasting - * memory. */ -static void audit_log_move(struct audit_buffer *ab) -{ - struct sk_buff *skb; - char *start; - int extra = ab->nlh ? 0 : NLMSG_SPACE(0); - - /* possible resubmission */ - if (ab->len == 0) - return; - - skb = skb_peek_tail(&ab->sklist); - if (!skb || skb_tailroom(skb) <= ab->len + extra) { - skb = alloc_skb(2 * ab->len + extra, GFP_ATOMIC); - if (!skb) { - ab->len = 0; /* Lose information in ab->tmp */ - audit_log_lost("out of memory in audit_log_move"); - return; - } - __skb_queue_tail(&ab->sklist, skb); - if (!ab->nlh) - ab->nlh = (struct nlmsghdr *)skb_put(skb, - NLMSG_SPACE(0)); - } - start = skb_put(skb, ab->len); - memcpy(start, ab->tmp, ab->len); - ab->len = 0; -} - -/* Iterate over the skbuff in the audit_buffer, sending their contents - * to user space. */ +/* Grab skbuff from the audit_buffer and send to user space. */ static inline int audit_log_drain(struct audit_buffer *ab) { - struct sk_buff *skb; + struct sk_buff *skb = ab->skb; - while ((skb = skb_dequeue(&ab->sklist))) { + if (skb) { int retval = 0; if (audit_pid) { - if (ab->nlh) { - ab->nlh->nlmsg_len = ab->total; - ab->nlh->nlmsg_type = ab->type; - ab->nlh->nlmsg_flags = 0; - ab->nlh->nlmsg_seq = 0; - ab->nlh->nlmsg_pid = ab->pid; - } + struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_len = skb->len - NLMSG_SPACE(0); skb_get(skb); /* because netlink_* frees */ retval = netlink_unicast(audit_sock, skb, audit_pid, MSG_DONTWAIT); } if (retval == -EAGAIN && (atomic_read(&audit_backlog)) < audit_backlog_limit) { - skb_queue_head(&ab->sklist, skb); audit_log_end_irq(ab); return 1; } @@ -538,13 +484,11 @@ audit_log_lost("netlink socket too busy"); } if (!audit_pid) { /* No daemon */ - int offset = ab->nlh ? NLMSG_SPACE(0) : 0; + int offset = NLMSG_SPACE(0); int len = skb->len - offset; skb->data[offset + len] = '\0'; printk(KERN_ERR "%s\n", skb->data + offset); } - kfree_skb(skb); - ab->nlh = NULL; } return 0; } @@ -563,35 +507,6 @@ audit_log(NULL, "initialized"); return 0; } - -#else -/* Without CONFIG_NET, we have no skbuffs. For now, print what we have - * in the buffer. */ -static void audit_log_move(struct audit_buffer *ab) -{ - printk(KERN_ERR "%*.*s\n", ab->len, ab->len, ab->tmp); - ab->len = 0; -} - -static inline int audit_log_drain(struct audit_buffer *ab) -{ - return 0; -} - -/* Initialize audit support at boot time. */ -int __init audit_init(void) -{ - printk(KERN_INFO "audit: initializing WITHOUT netlink support\n"); - audit_sock = NULL; - audit_pid = 0; - - audit_initialized = 1; - audit_enabled = audit_default; - audit_log(NULL, "initialized"); - return 0; -} -#endif - __initcall(audit_init); /* Process kernel command-line parameter at boot time. audit=0 or audit=1. */ @@ -608,6 +523,54 @@ __setup("audit=", audit_enable); +static void audit_buffer_free(struct audit_buffer *ab) +{ + unsigned long flags; + + if (!ab) + return; + + if (ab->skb) + kfree_skb(ab->skb); + atomic_dec(&audit_backlog); + spin_lock_irqsave(&audit_freelist_lock, flags); + if (++audit_freelist_count > AUDIT_MAXFREE) + kfree(ab); + else + list_add(&ab->list, &audit_freelist); + spin_unlock_irqrestore(&audit_freelist_lock, flags); +} + +static struct audit_buffer * audit_buffer_alloc(int gfp_mask) +{ + unsigned long flags; + struct audit_buffer *ab = NULL; + + spin_lock_irqsave(&audit_freelist_lock, flags); + if (!list_empty(&audit_freelist)) { + ab = list_entry(audit_freelist.next, + struct audit_buffer, list); + list_del(&ab->list); + --audit_freelist_count; + } + spin_unlock_irqrestore(&audit_freelist_lock, flags); + + if (!ab) { + ab = kmalloc(sizeof(*ab), gfp_mask); + if (!ab) + goto err; + } + atomic_inc(&audit_backlog); + + ab->skb = alloc_skb(AUDIT_BUFSIZ, gfp_mask); + if (!ab->skb) + goto err; + + return ab; +err: + audit_buffer_free(ab); + return NULL; +} /* Obtain an audit buffer. This routine does locking to obtain the * audit buffer, but then no locking is required for calls to @@ -615,12 +578,12 @@ * syscall, then the syscall is marked as auditable and an audit record * will be written at syscall exit. If there is no associated task, tsk * should be NULL. */ -struct audit_buffer *audit_log_start(struct audit_context *ctx) +struct audit_buffer *audit_log_start(struct audit_context *ctx, int type, int pid) { struct audit_buffer *ab = NULL; - unsigned long flags; struct timespec t; unsigned int serial; + struct nlmsghdr *nlh; if (!audit_initialized) return NULL; @@ -637,46 +600,47 @@ return NULL; } - spin_lock_irqsave(&audit_freelist_lock, flags); - if (!list_empty(&audit_freelist)) { - ab = list_entry(audit_freelist.next, - struct audit_buffer, list); - list_del(&ab->list); - --audit_freelist_count; - } - spin_unlock_irqrestore(&audit_freelist_lock, flags); - - if (!ab) - ab = kmalloc(sizeof(*ab), GFP_ATOMIC); + ab = audit_buffer_alloc(GFP_ATOMIC); if (!ab) { audit_log_lost("out of memory in audit_log_start"); return NULL; } - atomic_inc(&audit_backlog); - skb_queue_head_init(&ab->sklist); - ab->ctx = ctx; - ab->len = 0; - ab->nlh = NULL; - ab->total = 0; - ab->type = AUDIT_KERNEL; - ab->pid = 0; - -#ifdef CONFIG_AUDITSYSCALL - if (ab->ctx) - audit_get_stamp(ab->ctx, &t, &serial); - else -#endif - { + nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0)); + nlh->nlmsg_type = type; + nlh->nlmsg_flags = 0; + nlh->nlmsg_pid = pid; + nlh->nlmsg_seq = 0; + + if (!audit_get_stamp(ab->ctx, &t, &serial)) { t = CURRENT_TIME; serial = 0; } + audit_log_format(ab, "audit(%lu.%03lu:%u): ", t.tv_sec, t.tv_nsec/1000000, serial); return ab; } +/** + * audit_expand - expand skb in the audit buffer + * @ab: audit_buffer + * + * Returns 0 (no space) on failed expansion, or available space if + * successful. + */ +static inline int audit_expand(struct audit_buffer *ab, int extra) +{ + struct sk_buff *skb = ab->skb; + int ret = pskb_expand_head(skb, skb_headroom(skb), extra, + GFP_ATOMIC); + if (ret < 0) { + audit_log_lost("out of memory in audit_expand"); + return 0; + } + return skb_tailroom(skb); +} /* Format an audit message into the audit buffer. If there isn't enough * room in the audit buffer, more room will be allocated and vsnprint @@ -686,26 +650,34 @@ va_list args) { int len, avail; + struct sk_buff *skb; + va_list args2; if (!ab) return; - avail = sizeof(ab->tmp) - ab->len; - if (avail <= 0) { - audit_log_move(ab); - avail = sizeof(ab->tmp) - ab->len; + BUG_ON(!ab->skb); + skb = ab->skb; + avail = skb_tailroom(skb); + if (avail == 0) { + avail = audit_expand(ab, AUDIT_BUFSIZ); + if (!avail) + goto out; } - len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); + va_copy(args2, args); + len = vsnprintf(skb->tail, avail, fmt, args); if (len >= avail) { /* The printk buffer is 1024 bytes long, so if we get * here and AUDIT_BUFSIZ is at least 1024, then we can * log everything that printk could have logged. */ - audit_log_move(ab); - avail = sizeof(ab->tmp) - ab->len; - len = vsnprintf(ab->tmp + ab->len, avail, fmt, args); + avail = audit_expand(ab, 1+len-avail); + if (!avail) + goto out; + len = vsnprintf(skb->tail, avail, fmt, args2); } - ab->len += (len < avail) ? len : avail; - ab->total += (len < avail) ? len : avail; + skb_put(skb, (len < avail) ? len : avail); +out: + return; } /* Format a message into the audit buffer. All the work is done in @@ -751,23 +723,22 @@ struct dentry *dentry, struct vfsmount *vfsmnt) { char *p; + struct sk_buff *skb = ab->skb; int len, avail; - if (prefix) audit_log_format(ab, " %s", prefix); + if (prefix) + audit_log_format(ab, " %s", prefix); - if (ab->len > 128) - audit_log_move(ab); - avail = sizeof(ab->tmp) - ab->len; - p = d_path(dentry, vfsmnt, ab->tmp + ab->len, avail); + avail = skb_tailroom(skb); + p = d_path(dentry, vfsmnt, skb->tail, avail); if (IS_ERR(p)) { /* FIXME: can we save some information here? */ audit_log_format(ab, ""); } else { - /* path isn't at start of buffer */ - len = (ab->tmp + sizeof(ab->tmp) - 1) - p; - memmove(ab->tmp + ab->len, p, len); - ab->len += len; - ab->total += len; + /* path isn't at start of buffer */ + len = ((char *)skb->tail + avail - 1) - p; + memmove(skb->tail, p, len); + skb_put(skb, len); } } @@ -812,26 +783,16 @@ * be called in an irq context. */ static void audit_log_end_fast(struct audit_buffer *ab) { - unsigned long flags; - BUG_ON(in_irq()); if (!ab) return; if (!audit_rate_check()) { audit_log_lost("rate limit exceeded"); } else { - audit_log_move(ab); if (audit_log_drain(ab)) return; } - - atomic_dec(&audit_backlog); - spin_lock_irqsave(&audit_freelist_lock, flags); - if (++audit_freelist_count > AUDIT_MAXFREE) - kfree(ab); - else - list_add(&ab->list, &audit_freelist); - spin_unlock_irqrestore(&audit_freelist_lock, flags); + audit_buffer_free(ab); } /* Send or queue the message in the audit buffer, depending on the @@ -848,12 +809,13 @@ /* Log an audit record. This is a convenience function that calls * audit_log_start, audit_log_vformat, and audit_log_end. It may be * called in any context. */ -void audit_log(struct audit_context *ctx, const char *fmt, ...) +void audit_log_type(struct audit_context *ctx, int type, int pid, + const char *fmt, ...) { struct audit_buffer *ab; va_list args; - ab = audit_log_start(ctx); + ab = audit_log_start(ctx, type, pid); if (ab) { va_start(args, fmt); audit_log_vformat(ab, fmt, args); Index: kernel/auditsc.c =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/kernel/auditsc.c (mode:100644 sha1:37b3ac94bc47492d026ae697cc92b1d4ddd70bd5) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/kernel/auditsc.c (mode:100644 sha1:d089263253a77c646690e7b3c4d8d2c5d4fc3b3c) @@ -226,7 +226,6 @@ return -EFAULT; /* No matching rule */ } -#ifdef CONFIG_NET /* Copy rule from user-space to kernel-space. Called during * AUDIT_ADD. */ static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) @@ -305,7 +304,6 @@ return err; } -#endif /* Compare a task_struct with an audit_rule. Return 1 on match, 0 * otherwise. */ @@ -650,7 +648,7 @@ int i; struct audit_buffer *ab; - ab = audit_log_start(context); + ab = audit_log_start(context, AUDIT_KERNEL, 0); if (!ab) return; /* audit_panic has been called */ audit_log_format(ab, "syscall=%d", context->major); @@ -682,7 +680,7 @@ while (context->aux) { struct audit_aux_data *aux; - ab = audit_log_start(context); + ab = audit_log_start(context, AUDIT_KERNEL, 0); if (!ab) continue; /* audit_panic has been called */ @@ -703,7 +701,7 @@ } for (i = 0; i < context->name_count; i++) { - ab = audit_log_start(context); + ab = audit_log_start(context, AUDIT_KERNEL, 0); if (!ab) continue; /* audit_panic has been called */ audit_log_format(ab, "item=%d", i); @@ -994,7 +992,7 @@ context->names[idx].rdev = inode->i_rdev; } -void audit_get_stamp(struct audit_context *ctx, +int audit_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial) { if (ctx) { @@ -1002,28 +1000,18 @@ t->tv_nsec = ctx->ctime.tv_nsec; *serial = ctx->serial; ctx->auditable = 1; - } else { - *t = CURRENT_TIME; - *serial = 0; + return 1; } + return 0; } -extern int audit_set_type(struct audit_buffer *ab, int type); - int audit_set_loginuid(struct task_struct *task, uid_t loginuid) { if (task->audit_context) { - struct audit_buffer *ab; - - ab = audit_log_start(NULL); - if (ab) { - audit_log_format(ab, "login pid=%d uid=%u " - "old loginuid=%u new loginuid=%u", - task->pid, task->uid, - task->audit_context->loginuid, loginuid); - audit_set_type(ab, AUDIT_LOGIN); - audit_log_end(ab); - } + audit_log_type(NULL, AUDIT_LOGIN, 0, + "login pid=%d uid=%u old loginuid=%u new loginuid=%u", + task->pid, task->uid, task->audit_context->loginuid, + loginuid); task->audit_context->loginuid = loginuid; } return 0; @@ -1056,3 +1044,22 @@ context->aux = (void *)ax; return 0; } + +void audit_signal_info(int sig, struct task_struct *t) +{ + extern pid_t audit_sig_pid; + extern uid_t audit_sig_uid; + extern int audit_pid; + + if (unlikely(audit_pid && t->pid == audit_pid)) { + if (sig == SIGTERM || sig == SIGHUP) { + struct audit_context *ctx = current->audit_context; + audit_sig_pid = current->pid; + if (ctx) + audit_sig_uid = ctx->loginuid; + else + audit_sig_uid = current->uid; + } + } +} + Index: kernel/signal.c =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/kernel/signal.c (mode:100644 sha1:8f3debc77c5b2c6db5c7e360d18f9d2e2502a068) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/kernel/signal.c (mode:100644 sha1:293e189d8bc3ccfadb6eb7e445c9f4822fffa999) @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -658,7 +659,11 @@ && (current->uid ^ t->suid) && (current->uid ^ t->uid) && !capable(CAP_KILL)) return error; - return security_task_kill(t, info, sig); + + error = security_task_kill(t, info, sig); + if (!error) + audit_signal_info(sig, t); /* Let audit system see the signal */ + return error; } /* forward decl */ Index: security/selinux/avc.c =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/security/selinux/avc.c (mode:100644 sha1:85a6f66a873f5194bc2f32908fb18a9ada1df2de) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/security/selinux/avc.c (mode:100644 sha1:9e71a1bbe011b94d0f4d5c6f178a59c9078833b6) @@ -549,7 +549,7 @@ return; } - ab = audit_log_start(current->audit_context); + ab = audit_log_start(current->audit_context, AUDIT_KERNEL, 0); if (!ab) return; /* audit_panic has been called */ audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); Index: security/selinux/nlmsgtab.c =================================================================== --- eed337ef5e9ae7d62caa84b7974a11fddc7f06e0/security/selinux/nlmsgtab.c (mode:100644 sha1:b3adb481bc250bf49c5a82aad706c6bf8c7b16db) +++ 28463bc2721725fadcfb62a9657c39c91cc2fb05/security/selinux/nlmsgtab.c (mode:100644 sha1:deac14367d438c2d7eddb7b056a2a6d06b4c3090) @@ -97,6 +97,7 @@ { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, + { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, };