Commit cae3cf8f authored by Linus Torvalds's avatar Linus Torvalds

Merge

parents 94dad77b 76ae6d56
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/user.h> #include <linux/user.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/audit.h>
#include <asm/cpu.h> #include <asm/cpu.h>
#include <asm/fpu.h> #include <asm/fpu.h>
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/user.h> #include <linux/user.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/audit.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/page.h> #include <asm/page.h>
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "linux/smp_lock.h" #include "linux/smp_lock.h"
#include "linux/security.h" #include "linux/security.h"
#include "linux/ptrace.h" #include "linux/ptrace.h"
#include "linux/audit.h"
#ifdef CONFIG_PROC_MM #ifdef CONFIG_PROC_MM
#include "linux/proc_mm.h" #include "linux/proc_mm.h"
#endif #endif
...@@ -336,11 +337,15 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) ...@@ -336,11 +337,15 @@ 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, regs->orig_eax, audit_syscall_entry(current,
regs->ebx, regs->ecx, UPT_SYSCALL_NR(&regs->regs),
regs->edx, regs->esi); UPT_SYSCALL_ARG1(&regs->regs),
UPT_SYSCALL_ARG2(&regs->regs),
UPT_SYSCALL_ARG3(&regs->regs),
UPT_SYSCALL_ARG4(&regs->regs));
else else
audit_syscall_exit(current, regs->eax); audit_syscall_exit(current,
UPT_SYSCALL_RET(&regs->regs));
} }
/* Fake a debug trap */ /* Fake a debug trap */
......
...@@ -148,11 +148,22 @@ char * getname(const char __user * filename) ...@@ -148,11 +148,22 @@ char * getname(const char __user * filename)
result = ERR_PTR(retval); result = ERR_PTR(retval);
} }
} }
if (unlikely(current->audit_context) && !IS_ERR(result) && result) audit_getname(result);
audit_getname(result);
return result; return result;
} }
#ifdef CONFIG_AUDITSYSCALL
void putname(const char *name)
{
if (unlikely(current->audit_context))
audit_putname(name);
else
__putname(name);
}
EXPORT_SYMBOL(putname);
#endif
/** /**
* generic_permission - check for access rights on a Posix-like filesystem * generic_permission - check for access rights on a Posix-like filesystem
* @inode: inode to check access rights for * @inode: inode to check access rights for
...@@ -1012,9 +1023,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata ...@@ -1012,9 +1023,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata
retval = link_path_walk(name, nd); retval = link_path_walk(name, nd);
if (unlikely(current->audit_context if (unlikely(current->audit_context
&& nd && nd->dentry && nd->dentry->d_inode)) && nd && nd->dentry && nd->dentry->d_inode))
audit_inode(name, audit_inode(name, nd->dentry->d_inode);
nd->dentry->d_inode->i_ino,
nd->dentry->d_inode->i_rdev);
return retval; return retval;
} }
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/seccomp.h> #include <linux/seccomp.h>
#include <linux/cpuset.h> #include <linux/cpuset.h>
#include <linux/audit.h>
#include "internal.h" #include "internal.h"
/* /*
......
...@@ -125,10 +125,9 @@ struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */ ...@@ -125,10 +125,9 @@ struct audit_rule { /* for AUDIT_LIST, AUDIT_ADD, and AUDIT_DEL */
#ifdef __KERNEL__ #ifdef __KERNEL__
#ifdef CONFIG_AUDIT
struct audit_buffer; struct audit_buffer;
struct audit_context; struct audit_context;
#endif struct inode;
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */ /* These are defined in auditsc.c */
...@@ -141,7 +140,7 @@ extern void audit_syscall_entry(struct task_struct *task, ...@@ -141,7 +140,7 @@ extern void audit_syscall_entry(struct task_struct *task,
extern void audit_syscall_exit(struct task_struct *task, int return_code); extern void audit_syscall_exit(struct task_struct *task, int 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, unsigned long ino, dev_t rdev); extern void audit_inode(const char *name, const struct inode *inode);
/* Private API (for audit.c only) */ /* Private API (for audit.c only) */
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,
...@@ -150,6 +149,7 @@ extern void audit_get_stamp(struct audit_context *ctx, ...@@ -150,6 +149,7 @@ extern void audit_get_stamp(struct audit_context *ctx,
struct timespec *t, int *serial); struct timespec *t, int *serial);
extern int audit_set_loginuid(struct audit_context *ctx, uid_t loginuid); extern int audit_set_loginuid(struct audit_context *ctx, 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);
#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)
...@@ -157,8 +157,9 @@ extern uid_t audit_get_loginuid(struct audit_context *ctx); ...@@ -157,8 +157,9 @@ extern uid_t audit_get_loginuid(struct audit_context *ctx);
#define audit_syscall_exit(t,r) do { ; } while (0) #define audit_syscall_exit(t,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,d) do { ; } while (0) #define audit_inode(n,i) do { ; } while (0)
#define audit_get_loginuid(c) ({ -1; }) #define audit_get_loginuid(c) ({ -1; })
#define audit_ipc_perms(q,u,g,m) ({ 0; })
#endif #endif
#ifdef CONFIG_AUDIT #ifdef CONFIG_AUDIT
......
...@@ -212,7 +212,6 @@ extern int dir_notify_enable; ...@@ -212,7 +212,6 @@ extern int dir_notify_enable;
#include <linux/list.h> #include <linux/list.h>
#include <linux/radix-tree.h> #include <linux/radix-tree.h>
#include <linux/prio_tree.h> #include <linux/prio_tree.h>
#include <linux/audit.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/atomic.h> #include <asm/atomic.h>
...@@ -1272,13 +1271,7 @@ extern void __init vfs_caches_init(unsigned long); ...@@ -1272,13 +1271,7 @@ extern void __init vfs_caches_init(unsigned long);
#ifndef CONFIG_AUDITSYSCALL #ifndef CONFIG_AUDITSYSCALL
#define putname(name) __putname(name) #define putname(name) __putname(name)
#else #else
#define putname(name) \ extern void putname(const char *name);
do { \
if (unlikely(current->audit_context)) \
audit_putname(name); \
else \
__putname(name); \
} while (0)
#endif #endif
extern int register_blkdev(unsigned int, const char *); extern int register_blkdev(unsigned int, const char *);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/security.h> #include <linux/security.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/audit.h>
#include <asm/current.h> #include <asm/current.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "util.h" #include "util.h"
...@@ -425,6 +426,8 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf) ...@@ -425,6 +426,8 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf)
return -EFAULT; return -EFAULT;
if (copy_msqid_from_user (&setbuf, buf, version)) if (copy_msqid_from_user (&setbuf, buf, version))
return -EFAULT; return -EFAULT;
if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
return err;
break; break;
case IPC_RMID: case IPC_RMID:
break; break;
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/audit.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "util.h" #include "util.h"
...@@ -803,6 +804,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun ...@@ -803,6 +804,8 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
if(cmd == IPC_SET) { if(cmd == IPC_SET) {
if(copy_semid_from_user (&setbuf, arg.buf, version)) if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT; return -EFAULT;
if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
return err;
} }
sma = sem_lock(semid); sma = sem_lock(semid);
if(sma==NULL) if(sma==NULL)
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/audit.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "util.h" #include "util.h"
...@@ -600,6 +601,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) ...@@ -600,6 +601,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
err = -EFAULT; err = -EFAULT;
goto out; goto out;
} }
if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
return err;
down(&shm_ids.sem); down(&shm_ids.sem);
shp = shm_lock(shmid); shp = shm_lock(shmid);
err=-EINVAL; err=-EINVAL;
......
...@@ -89,9 +89,30 @@ enum audit_state { ...@@ -89,9 +89,30 @@ enum audit_state {
struct audit_names { struct audit_names {
const char *name; const char *name;
unsigned long ino; unsigned long ino;
dev_t dev;
umode_t mode;
uid_t uid;
gid_t gid;
dev_t rdev; dev_t rdev;
}; };
struct audit_aux_data {
struct audit_aux_data *next;
int type;
};
#define AUDIT_AUX_IPCPERM 0
struct audit_aux_data_ipcctl {
struct audit_aux_data d;
struct ipc_perm p;
unsigned long qbytes;
uid_t uid;
gid_t gid;
mode_t mode;
};
/* The per-task audit context. */ /* The per-task audit context. */
struct audit_context { struct audit_context {
int in_syscall; /* 1 if task is in a syscall */ int in_syscall; /* 1 if task is in a syscall */
...@@ -107,6 +128,7 @@ struct audit_context { ...@@ -107,6 +128,7 @@ struct audit_context {
int name_count; int name_count;
struct audit_names names[AUDIT_NAMES]; struct audit_names names[AUDIT_NAMES];
struct audit_context *previous; /* For nested syscalls */ struct audit_context *previous; /* For nested syscalls */
struct audit_aux_data *aux;
/* Save things to print about task_struct */ /* Save things to print about task_struct */
pid_t pid; pid_t pid;
...@@ -338,7 +360,7 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -338,7 +360,7 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_DEVMAJOR: case AUDIT_DEVMAJOR:
if (ctx) { if (ctx) {
for (j = 0; j < ctx->name_count; j++) { for (j = 0; j < ctx->name_count; j++) {
if (MAJOR(ctx->names[j].rdev)==value) { if (MAJOR(ctx->names[j].dev)==value) {
++result; ++result;
break; break;
} }
...@@ -348,7 +370,7 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -348,7 +370,7 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_DEVMINOR: case AUDIT_DEVMINOR:
if (ctx) { if (ctx) {
for (j = 0; j < ctx->name_count; j++) { for (j = 0; j < ctx->name_count; j++) {
if (MINOR(ctx->names[j].rdev)==value) { if (MINOR(ctx->names[j].dev)==value) {
++result; ++result;
break; break;
} }
...@@ -504,6 +526,16 @@ static inline void audit_free_names(struct audit_context *context) ...@@ -504,6 +526,16 @@ static inline void audit_free_names(struct audit_context *context)
context->name_count = 0; context->name_count = 0;
} }
static inline void audit_free_aux(struct audit_context *context)
{
struct audit_aux_data *aux;
while ((aux = context->aux)) {
context->aux = aux->next;
kfree(aux);
}
}
static inline void audit_zero_context(struct audit_context *context, static inline void audit_zero_context(struct audit_context *context,
enum audit_state state) enum audit_state state)
{ {
...@@ -570,6 +602,7 @@ static inline void audit_free_context(struct audit_context *context) ...@@ -570,6 +602,7 @@ static inline void audit_free_context(struct audit_context *context)
context->name_count, count); context->name_count, count);
} }
audit_free_names(context); audit_free_names(context);
audit_free_aux(context);
kfree(context); kfree(context);
context = previous; context = previous;
} while (context); } while (context);
...@@ -607,6 +640,29 @@ static void audit_log_exit(struct audit_context *context) ...@@ -607,6 +640,29 @@ static void audit_log_exit(struct audit_context *context)
context->euid, context->suid, context->fsuid, context->euid, context->suid, context->fsuid,
context->egid, context->sgid, context->fsgid); context->egid, context->sgid, context->fsgid);
audit_log_end(ab); audit_log_end(ab);
while (context->aux) {
struct audit_aux_data *aux;
ab = audit_log_start(context);
if (!ab)
continue; /* audit_panic has been called */
aux = context->aux;
context->aux = aux->next;
audit_log_format(ab, "auxitem=%d", aux->type);
switch (aux->type) {
case AUDIT_AUX_IPCPERM: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
" qbytes=%lx uid=%d gid=%d mode=%x",
axi->qbytes, axi->uid, axi->gid, axi->mode);
}
}
audit_log_end(ab);
kfree(aux);
}
for (i = 0; i < context->name_count; i++) { for (i = 0; i < context->name_count; i++) {
ab = audit_log_start(context); ab = audit_log_start(context);
if (!ab) if (!ab)
...@@ -616,12 +672,14 @@ static void audit_log_exit(struct audit_context *context) ...@@ -616,12 +672,14 @@ static void audit_log_exit(struct audit_context *context)
audit_log_format(ab, " name=%s", audit_log_format(ab, " name=%s",
context->names[i].name); context->names[i].name);
if (context->names[i].ino != (unsigned long)-1) if (context->names[i].ino != (unsigned long)-1)
audit_log_format(ab, " inode=%lu", audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
context->names[i].ino); " uid=%d gid=%d rdev=%02x:%02x",
/* FIXME: should use format_dev_t, but ab structure is context->names[i].ino,
* opaque. */ MAJOR(context->names[i].dev),
if (context->names[i].rdev != -1) MINOR(context->names[i].dev),
audit_log_format(ab, " dev=%02x:%02x", context->names[i].mode,
context->names[i].uid,
context->names[i].gid,
MAJOR(context->names[i].rdev), MAJOR(context->names[i].rdev),
MINOR(context->names[i].rdev)); MINOR(context->names[i].rdev));
audit_log_end(ab); audit_log_end(ab);
...@@ -789,6 +847,7 @@ void audit_syscall_exit(struct task_struct *tsk, int return_code) ...@@ -789,6 +847,7 @@ void audit_syscall_exit(struct task_struct *tsk, int return_code)
tsk->audit_context = new_context; tsk->audit_context = new_context;
} else { } else {
audit_free_names(context); audit_free_names(context);
audit_free_aux(context);
audit_zero_context(context, context->state); audit_zero_context(context, context->state);
tsk->audit_context = context; tsk->audit_context = context;
} }
...@@ -800,7 +859,9 @@ void audit_getname(const char *name) ...@@ -800,7 +859,9 @@ void audit_getname(const char *name)
{ {
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
BUG_ON(!context); if (!context || IS_ERR(name) || !name)
return;
if (!context->in_syscall) { if (!context->in_syscall) {
#if AUDIT_DEBUG == 2 #if AUDIT_DEBUG == 2
printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n", printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n",
...@@ -812,7 +873,6 @@ void audit_getname(const char *name) ...@@ -812,7 +873,6 @@ void audit_getname(const char *name)
BUG_ON(context->name_count >= AUDIT_NAMES); BUG_ON(context->name_count >= AUDIT_NAMES);
context->names[context->name_count].name = name; context->names[context->name_count].name = name;
context->names[context->name_count].ino = (unsigned long)-1; context->names[context->name_count].ino = (unsigned long)-1;
context->names[context->name_count].rdev = -1;
++context->name_count; ++context->name_count;
} }
...@@ -855,11 +915,10 @@ void audit_putname(const char *name) ...@@ -855,11 +915,10 @@ void audit_putname(const char *name)
} }
#endif #endif
} }
EXPORT_SYMBOL(audit_putname);
/* Store the inode and device from a lookup. Called from /* Store the inode and device from a lookup. Called from
* fs/namei.c:path_lookup(). */ * fs/namei.c:path_lookup(). */
void audit_inode(const char *name, unsigned long ino, dev_t rdev) void audit_inode(const char *name, const struct inode *inode)
{ {
int idx; int idx;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
...@@ -885,8 +944,12 @@ void audit_inode(const char *name, unsigned long ino, dev_t rdev) ...@@ -885,8 +944,12 @@ void audit_inode(const char *name, unsigned long ino, dev_t rdev)
++context->ino_count; ++context->ino_count;
#endif #endif
} }
context->names[idx].ino = ino; context->names[idx].ino = inode->i_ino;
context->names[idx].rdev = rdev; context->names[idx].dev = inode->i_sb->s_dev;
context->names[idx].mode = inode->i_mode;
context->names[idx].uid = inode->i_uid;
context->names[idx].gid = inode->i_gid;
context->names[idx].rdev = inode->i_rdev;
} }
void audit_get_stamp(struct audit_context *ctx, void audit_get_stamp(struct audit_context *ctx,
...@@ -927,3 +990,26 @@ uid_t audit_get_loginuid(struct audit_context *ctx) ...@@ -927,3 +990,26 @@ uid_t audit_get_loginuid(struct audit_context *ctx)
{ {
return ctx ? ctx->loginuid : -1; return ctx ? ctx->loginuid : -1;
} }
int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
{
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context;
if (likely(!context))
return 0;
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
if (!ax)
return -ENOMEM;
ax->qbytes = qbytes;
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
ax->d.type = AUDIT_AUX_IPCPERM;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
}
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