Commit fe0bdec6 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'audit.b61' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current:
  audit: validate comparison operations, store them in sane form
  clean up audit_rule_{add,del} a bit
  make sure that filterkey of task,always rules is reported
  audit rules ordering, part 2
  fixing audit rule ordering mess, part 1
  audit_update_lsm_rules() misses the audit_inode_hash[] ones
  sanitize audit_log_capset()
  sanitize audit_fd_pair()
  sanitize audit_mq_open()
  sanitize AUDIT_MQ_SENDRECV
  sanitize audit_mq_notify()
  sanitize audit_mq_getsetattr()
  sanitize audit_ipc_set_perm()
  sanitize audit_ipc_obj()
  sanitize audit_socketcall
  don't reallocate buffer in every audit_sockaddr()
parents 099e6576 5af75d8d
...@@ -1016,10 +1016,7 @@ int do_pipe_flags(int *fd, int flags) ...@@ -1016,10 +1016,7 @@ int do_pipe_flags(int *fd, int flags)
goto err_fdr; goto err_fdr;
fdw = error; fdw = error;
error = audit_fd_pair(fdr, fdw); audit_fd_pair(fdr, fdw);
if (error < 0)
goto err_fdw;
fd_install(fdr, fr); fd_install(fdr, fr);
fd_install(fdw, fw); fd_install(fdw, fw);
fd[0] = fdr; fd[0] = fdr;
...@@ -1027,8 +1024,6 @@ int do_pipe_flags(int *fd, int flags) ...@@ -1027,8 +1024,6 @@ int do_pipe_flags(int *fd, int flags)
return 0; return 0;
err_fdw:
put_unused_fd(fdw);
err_fdr: err_fdr:
put_unused_fd(fdr); put_unused_fd(fdr);
err_read_pipe: err_read_pipe:
......
...@@ -247,6 +247,18 @@ ...@@ -247,6 +247,18 @@
#define AUDIT_GREATER_THAN_OR_EQUAL (AUDIT_GREATER_THAN|AUDIT_EQUAL) #define AUDIT_GREATER_THAN_OR_EQUAL (AUDIT_GREATER_THAN|AUDIT_EQUAL)
#define AUDIT_OPERATORS (AUDIT_EQUAL|AUDIT_NOT_EQUAL|AUDIT_BIT_MASK) #define AUDIT_OPERATORS (AUDIT_EQUAL|AUDIT_NOT_EQUAL|AUDIT_BIT_MASK)
enum {
Audit_equal,
Audit_not_equal,
Audit_bitmask,
Audit_bittest,
Audit_lt,
Audit_gt,
Audit_le,
Audit_ge,
Audit_bad
};
/* Status symbols */ /* Status symbols */
/* Mask values */ /* Mask values */
#define AUDIT_STATUS_ENABLED 0x0001 #define AUDIT_STATUS_ENABLED 0x0001
...@@ -373,6 +385,8 @@ struct audit_krule { ...@@ -373,6 +385,8 @@ struct audit_krule {
struct audit_watch *watch; /* associated watch */ struct audit_watch *watch; /* associated watch */
struct audit_tree *tree; /* associated watched tree */ struct audit_tree *tree; /* associated watched tree */
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
struct list_head list; /* for AUDIT_LIST* purposes only */
u64 prio;
}; };
struct audit_field { struct audit_field {
...@@ -443,70 +457,56 @@ extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid); ...@@ -443,70 +457,56 @@ extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
#define audit_get_loginuid(t) ((t)->loginuid) #define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid) #define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab); extern void audit_log_task_context(struct audit_buffer *ab);
extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp); extern void __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); extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
extern int audit_bprm(struct linux_binprm *bprm); extern int audit_bprm(struct linux_binprm *bprm);
extern int audit_socketcall(int nargs, unsigned long *args); extern void 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_fd_pair(int fd1, int fd2); extern void __audit_fd_pair(int fd1, int fd2);
extern int audit_set_macxattr(const char *name); extern int audit_set_macxattr(const char *name);
extern int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr); extern void __audit_mq_open(int oflag, mode_t mode, struct mq_attr *attr);
extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout); extern void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);
extern int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout); extern void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification);
extern int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification); extern void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
const struct cred *new, const struct cred *new,
const struct cred *old); const struct cred *old);
extern int __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old); extern void __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old);
static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp) static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_ipc_obj(ipcp); __audit_ipc_obj(ipcp);
return 0;
}
static inline int audit_fd_pair(int fd1, int fd2)
{
if (unlikely(!audit_dummy_context()))
return __audit_fd_pair(fd1, fd2);
return 0;
} }
static inline int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) static inline void audit_fd_pair(int fd1, int fd2)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_ipc_set_perm(qbytes, uid, gid, mode); __audit_fd_pair(fd1, fd2);
return 0;
} }
static inline int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr) static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_mq_open(oflag, mode, u_attr); __audit_ipc_set_perm(qbytes, uid, gid, mode);
return 0;
} }
static inline int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout) static inline void audit_mq_open(int oflag, mode_t mode, struct mq_attr *attr)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout); __audit_mq_open(oflag, mode, attr);
return 0;
} }
static inline int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout) static inline void audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout); __audit_mq_sendrecv(mqdes, msg_len, msg_prio, abs_timeout);
return 0;
} }
static inline int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) static inline void audit_mq_notify(mqd_t mqdes, const struct sigevent *notification)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_mq_notify(mqdes, u_notification); __audit_mq_notify(mqdes, notification);
return 0;
} }
static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) static inline void audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_mq_getsetattr(mqdes, mqstat); __audit_mq_getsetattr(mqdes, mqstat);
return 0;
} }
static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
...@@ -518,12 +518,11 @@ static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, ...@@ -518,12 +518,11 @@ static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm,
return 0; return 0;
} }
static inline int audit_log_capset(pid_t pid, const struct cred *new, static inline void audit_log_capset(pid_t pid, const struct cred *new,
const struct cred *old) const struct cred *old)
{ {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
return __audit_log_capset(pid, new, old); __audit_log_capset(pid, new, old);
return 0;
} }
extern int audit_n_rules; extern int audit_n_rules;
...@@ -546,20 +545,19 @@ extern int audit_signals; ...@@ -546,20 +545,19 @@ extern int audit_signals;
#define audit_get_loginuid(t) (-1) #define audit_get_loginuid(t) (-1)
#define audit_get_sessionid(t) (-1) #define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0) #define audit_log_task_context(b) do { ; } while (0)
#define audit_ipc_obj(i) ({ 0; }) #define audit_ipc_obj(i) ((void)0)
#define audit_ipc_set_perm(q,u,g,m) ({ 0; }) #define audit_ipc_set_perm(q,u,g,m) ((void)0)
#define audit_bprm(p) ({ 0; }) #define audit_bprm(p) ({ 0; })
#define audit_socketcall(n,a) ({ 0; }) #define audit_socketcall(n,a) ((void)0)
#define audit_fd_pair(n,a) ({ 0; }) #define audit_fd_pair(n,a) ((void)0)
#define audit_sockaddr(len, addr) ({ 0; }) #define audit_sockaddr(len, addr) ({ 0; })
#define audit_set_macxattr(n) do { ; } while (0) #define audit_set_macxattr(n) do { ; } while (0)
#define audit_mq_open(o,m,a) ({ 0; }) #define audit_mq_open(o,m,a) ((void)0)
#define audit_mq_timedsend(d,l,p,t) ({ 0; }) #define audit_mq_sendrecv(d,l,p,t) ((void)0)
#define audit_mq_timedreceive(d,l,p,t) ({ 0; }) #define audit_mq_notify(d,n) ((void)0)
#define audit_mq_notify(d,n) ({ 0; }) #define audit_mq_getsetattr(d,s) ((void)0)
#define audit_mq_getsetattr(d,s) ({ 0; })
#define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; }) #define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; })
#define audit_log_capset(pid, ncr, ocr) ({ 0; }) #define audit_log_capset(pid, ncr, ocr) ((void)0)
#define audit_ptrace(t) ((void)0) #define audit_ptrace(t) ((void)0)
#define audit_n_rules 0 #define audit_n_rules 0
#define audit_signals 0 #define audit_signals 0
......
...@@ -524,31 +524,27 @@ static void __do_notify(struct mqueue_inode_info *info) ...@@ -524,31 +524,27 @@ static void __do_notify(struct mqueue_inode_info *info)
wake_up(&info->wait_q); wake_up(&info->wait_q);
} }
static long prepare_timeout(const struct timespec __user *u_arg) static long prepare_timeout(struct timespec *p)
{ {
struct timespec ts, nowts; struct timespec nowts;
long timeout; long timeout;
if (u_arg) { if (p) {
if (unlikely(copy_from_user(&ts, u_arg, if (unlikely(p->tv_nsec < 0 || p->tv_sec < 0
sizeof(struct timespec)))) || p->tv_nsec >= NSEC_PER_SEC))
return -EFAULT;
if (unlikely(ts.tv_nsec < 0 || ts.tv_sec < 0
|| ts.tv_nsec >= NSEC_PER_SEC))
return -EINVAL; return -EINVAL;
nowts = CURRENT_TIME; nowts = CURRENT_TIME;
/* first subtract as jiffies can't be too big */ /* first subtract as jiffies can't be too big */
ts.tv_sec -= nowts.tv_sec; p->tv_sec -= nowts.tv_sec;
if (ts.tv_nsec < nowts.tv_nsec) { if (p->tv_nsec < nowts.tv_nsec) {
ts.tv_nsec += NSEC_PER_SEC; p->tv_nsec += NSEC_PER_SEC;
ts.tv_sec--; p->tv_sec--;
} }
ts.tv_nsec -= nowts.tv_nsec; p->tv_nsec -= nowts.tv_nsec;
if (ts.tv_sec < 0) if (p->tv_sec < 0)
return 0; return 0;
timeout = timespec_to_jiffies(&ts) + 1; timeout = timespec_to_jiffies(p) + 1;
} else } else
return MAX_SCHEDULE_TIMEOUT; return MAX_SCHEDULE_TIMEOUT;
...@@ -592,22 +588,18 @@ static int mq_attr_ok(struct mq_attr *attr) ...@@ -592,22 +588,18 @@ static int mq_attr_ok(struct mq_attr *attr)
* Invoked when creating a new queue via sys_mq_open * Invoked when creating a new queue via sys_mq_open
*/ */
static struct file *do_create(struct dentry *dir, struct dentry *dentry, static struct file *do_create(struct dentry *dir, struct dentry *dentry,
int oflag, mode_t mode, struct mq_attr __user *u_attr) int oflag, mode_t mode, struct mq_attr *attr)
{ {
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct mq_attr attr;
struct file *result; struct file *result;
int ret; int ret;
if (u_attr) { if (attr) {
ret = -EFAULT;
if (copy_from_user(&attr, u_attr, sizeof(attr)))
goto out;
ret = -EINVAL; ret = -EINVAL;
if (!mq_attr_ok(&attr)) if (!mq_attr_ok(attr))
goto out; goto out;
/* store for use during create */ /* store for use during create */
dentry->d_fsdata = &attr; dentry->d_fsdata = attr;
} }
mode &= ~current->fs->umask; mode &= ~current->fs->umask;
...@@ -664,11 +656,13 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, ...@@ -664,11 +656,13 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
struct dentry *dentry; struct dentry *dentry;
struct file *filp; struct file *filp;
char *name; char *name;
struct mq_attr attr;
int fd, error; int fd, error;
error = audit_mq_open(oflag, mode, u_attr); if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
if (error != 0) return -EFAULT;
return error;
audit_mq_open(oflag, mode, u_attr ? &attr : NULL);
if (IS_ERR(name = getname(u_name))) if (IS_ERR(name = getname(u_name)))
return PTR_ERR(name); return PTR_ERR(name);
...@@ -694,7 +688,8 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode, ...@@ -694,7 +688,8 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
filp = do_open(dentry, oflag); filp = do_open(dentry, oflag);
} else { } else {
filp = do_create(mqueue_mnt->mnt_root, dentry, filp = do_create(mqueue_mnt->mnt_root, dentry,
oflag, mode, u_attr); oflag, mode,
u_attr ? &attr : NULL);
} }
} else { } else {
error = -ENOENT; error = -ENOENT;
...@@ -829,17 +824,22 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr, ...@@ -829,17 +824,22 @@ asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *u_msg_ptr,
struct ext_wait_queue *receiver; struct ext_wait_queue *receiver;
struct msg_msg *msg_ptr; struct msg_msg *msg_ptr;
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
struct timespec ts, *p = NULL;
long timeout; long timeout;
int ret; int ret;
ret = audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout); if (u_abs_timeout) {
if (ret != 0) if (copy_from_user(&ts, u_abs_timeout,
return ret; sizeof(struct timespec)))
return -EFAULT;
p = &ts;
}
if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX)) if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
return -EINVAL; return -EINVAL;
timeout = prepare_timeout(u_abs_timeout); audit_mq_sendrecv(mqdes, msg_len, msg_prio, p);
timeout = prepare_timeout(p);
ret = -EBADF; ret = -EBADF;
filp = fget(mqdes); filp = fget(mqdes);
...@@ -918,12 +918,17 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr, ...@@ -918,12 +918,17 @@ asmlinkage ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user *u_msg_ptr,
struct inode *inode; struct inode *inode;
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
struct ext_wait_queue wait; struct ext_wait_queue wait;
struct timespec ts, *p = NULL;
ret = audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout); if (u_abs_timeout) {
if (ret != 0) if (copy_from_user(&ts, u_abs_timeout,
return ret; sizeof(struct timespec)))
return -EFAULT;
p = &ts;
}
timeout = prepare_timeout(u_abs_timeout); audit_mq_sendrecv(mqdes, msg_len, 0, p);
timeout = prepare_timeout(p);
ret = -EBADF; ret = -EBADF;
filp = fget(mqdes); filp = fget(mqdes);
...@@ -1003,17 +1008,17 @@ asmlinkage long sys_mq_notify(mqd_t mqdes, ...@@ -1003,17 +1008,17 @@ asmlinkage long sys_mq_notify(mqd_t mqdes,
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
struct sk_buff *nc; struct sk_buff *nc;
ret = audit_mq_notify(mqdes, u_notification); if (u_notification) {
if (ret != 0)
return ret;
nc = NULL;
sock = NULL;
if (u_notification != NULL) {
if (copy_from_user(&notification, u_notification, if (copy_from_user(&notification, u_notification,
sizeof(struct sigevent))) sizeof(struct sigevent)))
return -EFAULT; return -EFAULT;
}
audit_mq_notify(mqdes, u_notification ? &notification : NULL);
nc = NULL;
sock = NULL;
if (u_notification != NULL) {
if (unlikely(notification.sigev_notify != SIGEV_NONE && if (unlikely(notification.sigev_notify != SIGEV_NONE &&
notification.sigev_notify != SIGEV_SIGNAL && notification.sigev_notify != SIGEV_SIGNAL &&
notification.sigev_notify != SIGEV_THREAD)) notification.sigev_notify != SIGEV_THREAD))
...@@ -1150,11 +1155,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes, ...@@ -1150,11 +1155,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t mqdes,
omqstat = info->attr; omqstat = info->attr;
omqstat.mq_flags = filp->f_flags & O_NONBLOCK; omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
if (u_mqstat) { if (u_mqstat) {
ret = audit_mq_getsetattr(mqdes, &mqstat); audit_mq_getsetattr(mqdes, &mqstat);
if (ret != 0) {
spin_unlock(&info->lock);
goto out_fput;
}
if (mqstat.mq_flags & O_NONBLOCK) if (mqstat.mq_flags & O_NONBLOCK)
filp->f_flags |= O_NONBLOCK; filp->f_flags |= O_NONBLOCK;
else else
......
...@@ -747,9 +747,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) ...@@ -747,9 +747,7 @@ asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
goto out; goto out;
} }
err = audit_ipc_obj(&(shp->shm_perm)); audit_ipc_obj(&(shp->shm_perm));
if (err)
goto out_unlock;
if (!capable(CAP_IPC_LOCK)) { if (!capable(CAP_IPC_LOCK)) {
uid_t euid = current_euid(); uid_t euid = current_euid();
......
...@@ -624,10 +624,9 @@ void ipc_rcu_putref(void *ptr) ...@@ -624,10 +624,9 @@ 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> */
uid_t euid = current_euid(); uid_t euid = current_euid();
int requested_mode, granted_mode, err; int requested_mode, granted_mode;
if (unlikely((err = audit_ipc_obj(ipcp)))) 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 (euid == ipcp->cuid || if (euid == ipcp->cuid ||
...@@ -803,16 +802,10 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, ...@@ -803,16 +802,10 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
goto out_up; goto out_up;
} }
err = audit_ipc_obj(ipcp); audit_ipc_obj(ipcp);
if (err) if (cmd == IPC_SET)
goto out_unlock; audit_ipc_set_perm(extra_perm, perm->uid,
if (cmd == IPC_SET) {
err = audit_ipc_set_perm(extra_perm, perm->uid,
perm->gid, perm->mode); perm->gid, perm->mode);
if (err)
goto out_unlock;
}
euid = current_euid(); euid = current_euid();
if (euid == ipcp->cuid || if (euid == ipcp->cuid ||
...@@ -820,7 +813,6 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, ...@@ -820,7 +813,6 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
return ipcp; return ipcp;
err = -EPERM; err = -EPERM;
out_unlock:
ipc_unlock(ipcp); ipc_unlock(ipcp);
out_up: out_up:
up_write(&ids->rw_mutex); up_write(&ids->rw_mutex);
......
...@@ -159,11 +159,8 @@ static inline int audit_signal_info(int sig, struct task_struct *t) ...@@ -159,11 +159,8 @@ static inline int audit_signal_info(int sig, struct task_struct *t)
return __audit_signal_info(sig, t); return __audit_signal_info(sig, t);
return 0; return 0;
} }
extern enum audit_state audit_filter_inodes(struct task_struct *, extern void audit_filter_inodes(struct task_struct *, struct audit_context *);
struct audit_context *);
extern void audit_set_auditable(struct audit_context *);
#else #else
#define audit_signal_info(s,t) AUDIT_DISABLED #define audit_signal_info(s,t) AUDIT_DISABLED
#define audit_filter_inodes(t,c) AUDIT_DISABLED #define audit_filter_inodes(t,c) AUDIT_DISABLED
#define audit_set_auditable(c)
#endif #endif
...@@ -450,6 +450,7 @@ static void kill_rules(struct audit_tree *tree) ...@@ -450,6 +450,7 @@ static void kill_rules(struct audit_tree *tree)
audit_log_end(ab); audit_log_end(ab);
rule->tree = NULL; rule->tree = NULL;
list_del_rcu(&entry->list); list_del_rcu(&entry->list);
list_del(&entry->rule.list);
call_rcu(&entry->rcu, audit_free_rule_rcu); call_rcu(&entry->rcu, audit_free_rule_rcu);
} }
} }
...@@ -617,7 +618,7 @@ int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) ...@@ -617,7 +618,7 @@ int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
if (pathname[0] != '/' || if (pathname[0] != '/' ||
rule->listnr != AUDIT_FILTER_EXIT || rule->listnr != AUDIT_FILTER_EXIT ||
op & ~AUDIT_EQUAL || op != Audit_equal ||
rule->inode_f || rule->watch || rule->tree) rule->inode_f || rule->watch || rule->tree)
return -EINVAL; return -EINVAL;
rule->tree = alloc_tree(pathname); rule->tree = alloc_tree(pathname);
......
...@@ -86,6 +86,14 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = { ...@@ -86,6 +86,14 @@ struct list_head audit_filter_list[AUDIT_NR_FILTERS] = {
#error Fix audit_filter_list initialiser #error Fix audit_filter_list initialiser
#endif #endif
}; };
static struct list_head audit_rules_list[AUDIT_NR_FILTERS] = {
LIST_HEAD_INIT(audit_rules_list[0]),
LIST_HEAD_INIT(audit_rules_list[1]),
LIST_HEAD_INIT(audit_rules_list[2]),
LIST_HEAD_INIT(audit_rules_list[3]),
LIST_HEAD_INIT(audit_rules_list[4]),
LIST_HEAD_INIT(audit_rules_list[5]),
};
DEFINE_MUTEX(audit_filter_mutex); DEFINE_MUTEX(audit_filter_mutex);
...@@ -244,7 +252,8 @@ static inline int audit_to_inode(struct audit_krule *krule, ...@@ -244,7 +252,8 @@ static inline int audit_to_inode(struct audit_krule *krule,
struct audit_field *f) struct audit_field *f)
{ {
if (krule->listnr != AUDIT_FILTER_EXIT || if (krule->listnr != AUDIT_FILTER_EXIT ||
krule->watch || krule->inode_f || krule->tree) krule->watch || krule->inode_f || krule->tree ||
(f->op != Audit_equal && f->op != Audit_not_equal))
return -EINVAL; return -EINVAL;
krule->inode_f = f; krule->inode_f = f;
...@@ -262,7 +271,7 @@ static int audit_to_watch(struct audit_krule *krule, char *path, int len, ...@@ -262,7 +271,7 @@ static int audit_to_watch(struct audit_krule *krule, char *path, int len,
if (path[0] != '/' || path[len-1] == '/' || if (path[0] != '/' || path[len-1] == '/' ||
krule->listnr != AUDIT_FILTER_EXIT || krule->listnr != AUDIT_FILTER_EXIT ||
op & ~AUDIT_EQUAL || op != Audit_equal ||
krule->inode_f || krule->watch || krule->tree) krule->inode_f || krule->watch || krule->tree)
return -EINVAL; return -EINVAL;
...@@ -412,12 +421,32 @@ exit_err: ...@@ -412,12 +421,32 @@ exit_err:
return ERR_PTR(err); return ERR_PTR(err);
} }
static u32 audit_ops[] =
{
[Audit_equal] = AUDIT_EQUAL,
[Audit_not_equal] = AUDIT_NOT_EQUAL,
[Audit_bitmask] = AUDIT_BIT_MASK,
[Audit_bittest] = AUDIT_BIT_TEST,
[Audit_lt] = AUDIT_LESS_THAN,
[Audit_gt] = AUDIT_GREATER_THAN,
[Audit_le] = AUDIT_LESS_THAN_OR_EQUAL,
[Audit_ge] = AUDIT_GREATER_THAN_OR_EQUAL,
};
static u32 audit_to_op(u32 op)
{
u32 n;
for (n = Audit_equal; n < Audit_bad && audit_ops[n] != op; n++)
;
return n;
}
/* Translate struct audit_rule to kernel's rule respresentation. /* Translate struct audit_rule to kernel's rule respresentation.
* Exists for backward compatibility with userspace. */ * Exists for backward compatibility with userspace. */
static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
{ {
struct audit_entry *entry; struct audit_entry *entry;
struct audit_field *ino_f;
int err = 0; int err = 0;
int i; int i;
...@@ -427,12 +456,28 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) ...@@ -427,12 +456,28 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
for (i = 0; i < rule->field_count; i++) { for (i = 0; i < rule->field_count; i++) {
struct audit_field *f = &entry->rule.fields[i]; struct audit_field *f = &entry->rule.fields[i];
u32 n;
n = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
/* Support for legacy operators where
* AUDIT_NEGATE bit signifies != and otherwise assumes == */
if (n & AUDIT_NEGATE)
f->op = Audit_not_equal;
else if (!n)
f->op = Audit_equal;
else
f->op = audit_to_op(n);
entry->rule.vers_ops = (n & AUDIT_OPERATORS) ? 2 : 1;
f->op = rule->fields[i] & (AUDIT_NEGATE|AUDIT_OPERATORS);
f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS); f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
f->val = rule->values[i]; f->val = rule->values[i];
err = -EINVAL; err = -EINVAL;
if (f->op == Audit_bad)
goto exit_free;
switch(f->type) { switch(f->type) {
default: default:
goto exit_free; goto exit_free;
...@@ -454,11 +499,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) ...@@ -454,11 +499,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
case AUDIT_EXIT: case AUDIT_EXIT:
case AUDIT_SUCCESS: case AUDIT_SUCCESS:
/* bit ops are only useful on syscall args */ /* bit ops are only useful on syscall args */
if (f->op == AUDIT_BIT_MASK || if (f->op == Audit_bitmask || f->op == Audit_bittest)
f->op == AUDIT_BIT_TEST) {
err = -EINVAL;
goto exit_free; goto exit_free;
}
break; break;
case AUDIT_ARG0: case AUDIT_ARG0:
case AUDIT_ARG1: case AUDIT_ARG1:
...@@ -467,11 +509,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) ...@@ -467,11 +509,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
break; break;
/* arch is only allowed to be = or != */ /* arch is only allowed to be = or != */
case AUDIT_ARCH: case AUDIT_ARCH:
if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL) if (f->op != Audit_not_equal && f->op != Audit_equal)
&& (f->op != AUDIT_NEGATE) && (f->op)) {
err = -EINVAL;
goto exit_free; goto exit_free;
}
entry->rule.arch_f = f; entry->rule.arch_f = f;
break; break;
case AUDIT_PERM: case AUDIT_PERM:
...@@ -488,33 +527,10 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) ...@@ -488,33 +527,10 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
goto exit_free; goto exit_free;
break; break;
} }
entry->rule.vers_ops = (f->op & AUDIT_OPERATORS) ? 2 : 1;
/* Support for legacy operators where
* AUDIT_NEGATE bit signifies != and otherwise assumes == */
if (f->op & AUDIT_NEGATE)
f->op = AUDIT_NOT_EQUAL;
else if (!f->op)
f->op = AUDIT_EQUAL;
else if (f->op == AUDIT_OPERATORS) {
err = -EINVAL;
goto exit_free;
}
} }
ino_f = entry->rule.inode_f; if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
if (ino_f) {
switch(ino_f->op) {
case AUDIT_NOT_EQUAL:
entry->rule.inode_f = NULL; entry->rule.inode_f = NULL;
case AUDIT_EQUAL:
break;
default:
err = -EINVAL;
goto exit_free;
}
}
exit_nofree: exit_nofree:
return entry; return entry;
...@@ -530,7 +546,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, ...@@ -530,7 +546,6 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
{ {
int err = 0; int err = 0;
struct audit_entry *entry; struct audit_entry *entry;
struct audit_field *ino_f;
void *bufp; void *bufp;
size_t remain = datasz - sizeof(struct audit_rule_data); size_t remain = datasz - sizeof(struct audit_rule_data);
int i; int i;
...@@ -546,11 +561,11 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, ...@@ -546,11 +561,11 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
struct audit_field *f = &entry->rule.fields[i]; struct audit_field *f = &entry->rule.fields[i];
err = -EINVAL; err = -EINVAL;
if (!(data->fieldflags[i] & AUDIT_OPERATORS) ||
data->fieldflags[i] & ~AUDIT_OPERATORS) f->op = audit_to_op(data->fieldflags[i]);
if (f->op == Audit_bad)
goto exit_free; goto exit_free;
f->op = data->fieldflags[i] & AUDIT_OPERATORS;
f->type = data->fields[i]; f->type = data->fields[i];
f->val = data->values[i]; f->val = data->values[i];
f->lsm_str = NULL; f->lsm_str = NULL;
...@@ -662,18 +677,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, ...@@ -662,18 +677,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
} }
} }
ino_f = entry->rule.inode_f; if (entry->rule.inode_f && entry->rule.inode_f->op == Audit_not_equal)
if (ino_f) {
switch(ino_f->op) {
case AUDIT_NOT_EQUAL:
entry->rule.inode_f = NULL; entry->rule.inode_f = NULL;
case AUDIT_EQUAL:
break;
default:
err = -EINVAL;
goto exit_free;
}
}
exit_nofree: exit_nofree:
return entry; return entry;
...@@ -713,10 +718,10 @@ static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule) ...@@ -713,10 +718,10 @@ static struct audit_rule *audit_krule_to_rule(struct audit_krule *krule)
rule->fields[i] = krule->fields[i].type; rule->fields[i] = krule->fields[i].type;
if (krule->vers_ops == 1) { if (krule->vers_ops == 1) {
if (krule->fields[i].op & AUDIT_NOT_EQUAL) if (krule->fields[i].op == Audit_not_equal)
rule->fields[i] |= AUDIT_NEGATE; rule->fields[i] |= AUDIT_NEGATE;
} else { } else {
rule->fields[i] |= krule->fields[i].op; rule->fields[i] |= audit_ops[krule->fields[i].op];
} }
} }
for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i]; for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = krule->mask[i];
...@@ -744,7 +749,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule) ...@@ -744,7 +749,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
struct audit_field *f = &krule->fields[i]; struct audit_field *f = &krule->fields[i];
data->fields[i] = f->type; data->fields[i] = f->type;
data->fieldflags[i] = f->op; data->fieldflags[i] = audit_ops[f->op];
switch(f->type) { switch(f->type) {
case AUDIT_SUBJ_USER: case AUDIT_SUBJ_USER:
case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_ROLE:
...@@ -919,6 +924,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old, ...@@ -919,6 +924,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
new->action = old->action; new->action = old->action;
for (i = 0; i < AUDIT_BITMASK_SIZE; i++) for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
new->mask[i] = old->mask[i]; new->mask[i] = old->mask[i];
new->prio = old->prio;
new->buflen = old->buflen; new->buflen = old->buflen;
new->inode_f = old->inode_f; new->inode_f = old->inode_f;
new->watch = NULL; new->watch = NULL;
...@@ -987,9 +993,8 @@ static void audit_update_watch(struct audit_parent *parent, ...@@ -987,9 +993,8 @@ static void audit_update_watch(struct audit_parent *parent,
/* If the update involves invalidating rules, do the inode-based /* If the update involves invalidating rules, do the inode-based
* filtering now, so we don't omit records. */ * filtering now, so we don't omit records. */
if (invalidating && current->audit_context && if (invalidating && current->audit_context)
audit_filter_inodes(current, current->audit_context) == AUDIT_RECORD_CONTEXT) audit_filter_inodes(current, current->audit_context);
audit_set_auditable(current->audit_context);
nwatch = audit_dupe_watch(owatch); nwatch = audit_dupe_watch(owatch);
if (IS_ERR(nwatch)) { if (IS_ERR(nwatch)) {
...@@ -1007,12 +1012,15 @@ static void audit_update_watch(struct audit_parent *parent, ...@@ -1007,12 +1012,15 @@ static void audit_update_watch(struct audit_parent *parent,
list_del_rcu(&oentry->list); list_del_rcu(&oentry->list);
nentry = audit_dupe_rule(&oentry->rule, nwatch); nentry = audit_dupe_rule(&oentry->rule, nwatch);
if (IS_ERR(nentry)) if (IS_ERR(nentry)) {
list_del(&oentry->rule.list);
audit_panic("error updating watch, removing"); audit_panic("error updating watch, removing");
else { } else {
int h = audit_hash_ino((u32)ino); int h = audit_hash_ino((u32)ino);
list_add(&nentry->rule.rlist, &nwatch->rules); list_add(&nentry->rule.rlist, &nwatch->rules);
list_add_rcu(&nentry->list, &audit_inode_hash[h]); list_add_rcu(&nentry->list, &audit_inode_hash[h]);
list_replace(&oentry->rule.list,
&nentry->rule.list);
} }
call_rcu(&oentry->rcu, audit_free_rule_rcu); call_rcu(&oentry->rcu, audit_free_rule_rcu);
...@@ -1077,6 +1085,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent) ...@@ -1077,6 +1085,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
audit_log_end(ab); audit_log_end(ab);
} }
list_del(&r->rlist); list_del(&r->rlist);
list_del(&r->list);
list_del_rcu(&e->list); list_del_rcu(&e->list);
call_rcu(&e->rcu, audit_free_rule_rcu); call_rcu(&e->rcu, audit_free_rule_rcu);
} }
...@@ -1102,12 +1111,16 @@ static void audit_inotify_unregister(struct list_head *in_list) ...@@ -1102,12 +1111,16 @@ static void audit_inotify_unregister(struct list_head *in_list)
/* Find an existing audit rule. /* Find an existing audit rule.
* Caller must hold audit_filter_mutex to prevent stale rule data. */ * Caller must hold audit_filter_mutex to prevent stale rule data. */
static struct audit_entry *audit_find_rule(struct audit_entry *entry, static struct audit_entry *audit_find_rule(struct audit_entry *entry,
struct list_head *list) struct list_head **p)
{ {
struct audit_entry *e, *found = NULL; struct audit_entry *e, *found = NULL;
struct list_head *list;
int h; int h;
if (entry->rule.watch) { if (entry->rule.inode_f) {
h = audit_hash_ino(entry->rule.inode_f->val);
*p = list = &audit_inode_hash[h];
} else if (entry->rule.watch) {
/* we don't know the inode number, so must walk entire hash */ /* we don't know the inode number, so must walk entire hash */
for (h = 0; h < AUDIT_INODE_BUCKETS; h++) { for (h = 0; h < AUDIT_INODE_BUCKETS; h++) {
list = &audit_inode_hash[h]; list = &audit_inode_hash[h];
...@@ -1118,6 +1131,8 @@ static struct audit_entry *audit_find_rule(struct audit_entry *entry, ...@@ -1118,6 +1131,8 @@ static struct audit_entry *audit_find_rule(struct audit_entry *entry,
} }
} }
goto out; goto out;
} else {
*p = list = &audit_filter_list[entry->rule.listnr];
} }
list_for_each_entry(e, list, list) list_for_each_entry(e, list, list)
...@@ -1258,15 +1273,17 @@ static int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp, ...@@ -1258,15 +1273,17 @@ static int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp,
return ret; return ret;
} }
static u64 prio_low = ~0ULL/2;
static u64 prio_high = ~0ULL/2 - 1;
/* Add rule to given filterlist if not a duplicate. */ /* Add rule to given filterlist if not a duplicate. */
static inline int audit_add_rule(struct audit_entry *entry, static inline int audit_add_rule(struct audit_entry *entry)
struct list_head *list)
{ {
struct audit_entry *e; struct audit_entry *e;
struct audit_field *inode_f = entry->rule.inode_f;
struct audit_watch *watch = entry->rule.watch; struct audit_watch *watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree; struct audit_tree *tree = entry->rule.tree;
struct nameidata *ndp = NULL, *ndw = NULL; struct nameidata *ndp = NULL, *ndw = NULL;
struct list_head *list;
int h, err; int h, err;
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
int dont_count = 0; int dont_count = 0;
...@@ -1277,13 +1294,8 @@ static inline int audit_add_rule(struct audit_entry *entry, ...@@ -1277,13 +1294,8 @@ static inline int audit_add_rule(struct audit_entry *entry,
dont_count = 1; dont_count = 1;
#endif #endif
if (inode_f) {
h = audit_hash_ino(inode_f->val);
list = &audit_inode_hash[h];
}
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
e = audit_find_rule(entry, list); e = audit_find_rule(entry, &list);
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
if (e) { if (e) {
err = -EEXIST; err = -EEXIST;
...@@ -1319,10 +1331,22 @@ static inline int audit_add_rule(struct audit_entry *entry, ...@@ -1319,10 +1331,22 @@ static inline int audit_add_rule(struct audit_entry *entry,
} }
} }
entry->rule.prio = ~0ULL;
if (entry->rule.listnr == AUDIT_FILTER_EXIT) {
if (entry->rule.flags & AUDIT_FILTER_PREPEND)
entry->rule.prio = ++prio_high;
else
entry->rule.prio = --prio_low;
}
if (entry->rule.flags & AUDIT_FILTER_PREPEND) { if (entry->rule.flags & AUDIT_FILTER_PREPEND) {
list_add(&entry->rule.list,
&audit_rules_list[entry->rule.listnr]);
list_add_rcu(&entry->list, list); list_add_rcu(&entry->list, list);
entry->rule.flags &= ~AUDIT_FILTER_PREPEND; entry->rule.flags &= ~AUDIT_FILTER_PREPEND;
} else { } else {
list_add_tail(&entry->rule.list,
&audit_rules_list[entry->rule.listnr]);
list_add_tail_rcu(&entry->list, list); list_add_tail_rcu(&entry->list, list);
} }
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
...@@ -1345,15 +1369,14 @@ error: ...@@ -1345,15 +1369,14 @@ error:
} }
/* Remove an existing rule from filterlist. */ /* Remove an existing rule from filterlist. */
static inline int audit_del_rule(struct audit_entry *entry, static inline int audit_del_rule(struct audit_entry *entry)
struct list_head *list)
{ {
struct audit_entry *e; struct audit_entry *e;
struct audit_field *inode_f = entry->rule.inode_f;
struct audit_watch *watch, *tmp_watch = entry->rule.watch; struct audit_watch *watch, *tmp_watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree; struct audit_tree *tree = entry->rule.tree;
struct list_head *list;
LIST_HEAD(inotify_list); LIST_HEAD(inotify_list);
int h, ret = 0; int ret = 0;
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
int dont_count = 0; int dont_count = 0;
...@@ -1363,13 +1386,8 @@ static inline int audit_del_rule(struct audit_entry *entry, ...@@ -1363,13 +1386,8 @@ static inline int audit_del_rule(struct audit_entry *entry,
dont_count = 1; dont_count = 1;
#endif #endif
if (inode_f) {
h = audit_hash_ino(inode_f->val);
list = &audit_inode_hash[h];
}
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
e = audit_find_rule(entry, list); e = audit_find_rule(entry, &list);
if (!e) { if (!e) {
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
ret = -ENOENT; ret = -ENOENT;
...@@ -1404,6 +1422,7 @@ static inline int audit_del_rule(struct audit_entry *entry, ...@@ -1404,6 +1422,7 @@ static inline int audit_del_rule(struct audit_entry *entry,
audit_remove_tree_rule(&e->rule); audit_remove_tree_rule(&e->rule);
list_del_rcu(&e->list); list_del_rcu(&e->list);
list_del(&e->rule.list);
call_rcu(&e->rcu, audit_free_rule_rcu); call_rcu(&e->rcu, audit_free_rule_rcu);
#ifdef CONFIG_AUDITSYSCALL #ifdef CONFIG_AUDITSYSCALL
...@@ -1432,30 +1451,16 @@ out: ...@@ -1432,30 +1451,16 @@ out:
static void audit_list(int pid, int seq, struct sk_buff_head *q) static void audit_list(int pid, int seq, struct sk_buff_head *q)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct audit_entry *entry; struct audit_krule *r;
int i; int i;
/* This is a blocking read, so use audit_filter_mutex instead of rcu /* This is a blocking read, so use audit_filter_mutex instead of rcu
* iterator to sync with list writers. */ * iterator to sync with list writers. */
for (i=0; i<AUDIT_NR_FILTERS; i++) { for (i=0; i<AUDIT_NR_FILTERS; i++) {
list_for_each_entry(entry, &audit_filter_list[i], list) { list_for_each_entry(r, &audit_rules_list[i], list) {
struct audit_rule *rule; struct audit_rule *rule;
rule = audit_krule_to_rule(&entry->rule); rule = audit_krule_to_rule(r);
if (unlikely(!rule))
break;
skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
rule, sizeof(*rule));
if (skb)
skb_queue_tail(q, skb);
kfree(rule);
}
}
for (i = 0; i < AUDIT_INODE_BUCKETS; i++) {
list_for_each_entry(entry, &audit_inode_hash[i], list) {
struct audit_rule *rule;
rule = audit_krule_to_rule(&entry->rule);
if (unlikely(!rule)) if (unlikely(!rule))
break; break;
skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1, skb = audit_make_reply(pid, seq, AUDIT_LIST, 0, 1,
...@@ -1474,30 +1479,16 @@ static void audit_list(int pid, int seq, struct sk_buff_head *q) ...@@ -1474,30 +1479,16 @@ static void audit_list(int pid, int seq, struct sk_buff_head *q)
static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct audit_entry *e; struct audit_krule *r;
int i; int i;
/* This is a blocking read, so use audit_filter_mutex instead of rcu /* This is a blocking read, so use audit_filter_mutex instead of rcu
* iterator to sync with list writers. */ * iterator to sync with list writers. */
for (i=0; i<AUDIT_NR_FILTERS; i++) { for (i=0; i<AUDIT_NR_FILTERS; i++) {
list_for_each_entry(e, &audit_filter_list[i], list) { list_for_each_entry(r, &audit_rules_list[i], list) {
struct audit_rule_data *data;
data = audit_krule_to_data(&e->rule);
if (unlikely(!data))
break;
skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
data, sizeof(*data) + data->buflen);
if (skb)
skb_queue_tail(q, skb);
kfree(data);
}
}
for (i=0; i< AUDIT_INODE_BUCKETS; i++) {
list_for_each_entry(e, &audit_inode_hash[i], list) {
struct audit_rule_data *data; struct audit_rule_data *data;
data = audit_krule_to_data(&e->rule); data = audit_krule_to_data(r);
if (unlikely(!data)) if (unlikely(!data))
break; break;
skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1,
...@@ -1603,8 +1594,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, ...@@ -1603,8 +1594,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
if (IS_ERR(entry)) if (IS_ERR(entry))
return PTR_ERR(entry); return PTR_ERR(entry);
err = audit_add_rule(entry, err = audit_add_rule(entry);
&audit_filter_list[entry->rule.listnr]);
audit_log_rule_change(loginuid, sessionid, sid, "add", audit_log_rule_change(loginuid, sessionid, sid, "add",
&entry->rule, !err); &entry->rule, !err);
...@@ -1620,8 +1610,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, ...@@ -1620,8 +1610,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
if (IS_ERR(entry)) if (IS_ERR(entry))
return PTR_ERR(entry); return PTR_ERR(entry);
err = audit_del_rule(entry, err = audit_del_rule(entry);
&audit_filter_list[entry->rule.listnr]);
audit_log_rule_change(loginuid, sessionid, sid, "remove", audit_log_rule_change(loginuid, sessionid, sid, "remove",
&entry->rule, !err); &entry->rule, !err);
...@@ -1634,28 +1623,29 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, ...@@ -1634,28 +1623,29 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
return err; return err;
} }
int audit_comparator(const u32 left, const u32 op, const u32 right) int audit_comparator(u32 left, u32 op, u32 right)
{ {
switch (op) { switch (op) {
case AUDIT_EQUAL: case Audit_equal:
return (left == right); return (left == right);
case AUDIT_NOT_EQUAL: case Audit_not_equal:
return (left != right); return (left != right);
case AUDIT_LESS_THAN: case Audit_lt:
return (left < right); return (left < right);
case AUDIT_LESS_THAN_OR_EQUAL: case Audit_le:
return (left <= right); return (left <= right);
case AUDIT_GREATER_THAN: case Audit_gt:
return (left > right); return (left > right);
case AUDIT_GREATER_THAN_OR_EQUAL: case Audit_ge:
return (left >= right); return (left >= right);
case AUDIT_BIT_MASK: case Audit_bitmask:
return (left & right); return (left & right);
case AUDIT_BIT_TEST: case Audit_bittest:
return ((left & right) == right); return ((left & right) == right);
} default:
BUG(); BUG();
return 0; return 0;
}
} }
/* Compare given dentry name with last component in given path, /* Compare given dentry name with last component in given path,
...@@ -1778,52 +1768,63 @@ unlock_and_return: ...@@ -1778,52 +1768,63 @@ unlock_and_return:
return result; return result;
} }
/* This function will re-initialize the lsm_rule field of all applicable rules. static int update_lsm_rule(struct audit_krule *r)
* It will traverse the filter lists serarching for rules that contain LSM
* specific filter fields. When such a rule is found, it is copied, the
* LSM field is re-initialized, and the old rule is replaced with the
* updated rule. */
int audit_update_lsm_rules(void)
{ {
struct audit_entry *entry, *n, *nentry; struct audit_entry *entry = container_of(r, struct audit_entry, rule);
struct audit_entry *nentry;
struct audit_watch *watch; struct audit_watch *watch;
struct audit_tree *tree; struct audit_tree *tree;
int i, err = 0; int err = 0;
/* audit_filter_mutex synchronizes the writers */
mutex_lock(&audit_filter_mutex);
for (i = 0; i < AUDIT_NR_FILTERS; i++) { if (!security_audit_rule_known(r))
list_for_each_entry_safe(entry, n, &audit_filter_list[i], list) { return 0;
if (!security_audit_rule_known(&entry->rule))
continue;
watch = entry->rule.watch; watch = r->watch;
tree = entry->rule.tree; tree = r->tree;
nentry = audit_dupe_rule(&entry->rule, watch); nentry = audit_dupe_rule(r, watch);
if (IS_ERR(nentry)) { if (IS_ERR(nentry)) {
/* save the first error encountered for the /* save the first error encountered for the
* return value */ * return value */
if (!err)
err = PTR_ERR(nentry); err = PTR_ERR(nentry);
audit_panic("error updating LSM filters"); audit_panic("error updating LSM filters");
if (watch) if (watch)
list_del(&entry->rule.rlist); list_del(&r->rlist);
list_del_rcu(&entry->list); list_del_rcu(&entry->list);
list_del(&r->list);
} else { } else {
if (watch) { if (watch) {
list_add(&nentry->rule.rlist, list_add(&nentry->rule.rlist, &watch->rules);
&watch->rules); list_del(&r->rlist);
list_del(&entry->rule.rlist);
} else if (tree) } else if (tree)
list_replace_init(&entry->rule.rlist, list_replace_init(&r->rlist, &nentry->rule.rlist);
&nentry->rule.rlist);
list_replace_rcu(&entry->list, &nentry->list); list_replace_rcu(&entry->list, &nentry->list);
list_replace(&r->list, &nentry->rule.list);
} }
call_rcu(&entry->rcu, audit_free_rule_rcu); call_rcu(&entry->rcu, audit_free_rule_rcu);
return err;
}
/* This function will re-initialize the lsm_rule field of all applicable rules.
* It will traverse the filter lists serarching for rules that contain LSM
* specific filter fields. When such a rule is found, it is copied, the
* LSM field is re-initialized, and the old rule is replaced with the
* updated rule. */
int audit_update_lsm_rules(void)
{
struct audit_krule *r, *n;
int i, err = 0;
/* audit_filter_mutex synchronizes the writers */
mutex_lock(&audit_filter_mutex);
for (i = 0; i < AUDIT_NR_FILTERS; i++) {
list_for_each_entry_safe(r, n, &audit_rules_list[i], list) {
int res = update_lsm_rule(r);
if (!err)
err = res;
} }
} }
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
return err; return err;
......
...@@ -124,43 +124,6 @@ struct audit_aux_data { ...@@ -124,43 +124,6 @@ struct audit_aux_data {
/* Number of target pids per aux struct. */ /* Number of target pids per aux struct. */
#define AUDIT_AUX_PIDS 16 #define AUDIT_AUX_PIDS 16
struct audit_aux_data_mq_open {
struct audit_aux_data d;
int oflag;
mode_t mode;
struct mq_attr attr;
};
struct audit_aux_data_mq_sendrecv {
struct audit_aux_data d;
mqd_t mqdes;
size_t msg_len;
unsigned int msg_prio;
struct timespec abs_timeout;
};
struct audit_aux_data_mq_notify {
struct audit_aux_data d;
mqd_t mqdes;
struct sigevent notification;
};
struct audit_aux_data_mq_getsetattr {
struct audit_aux_data d;
mqd_t mqdes;
struct mq_attr mqstat;
};
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;
u32 osid;
};
struct audit_aux_data_execve { struct audit_aux_data_execve {
struct audit_aux_data d; struct audit_aux_data d;
int argc; int argc;
...@@ -168,23 +131,6 @@ struct audit_aux_data_execve { ...@@ -168,23 +131,6 @@ struct audit_aux_data_execve {
struct mm_struct *mm; struct mm_struct *mm;
}; };
struct audit_aux_data_socketcall {
struct audit_aux_data d;
int nargs;
unsigned long args[0];
};
struct audit_aux_data_sockaddr {
struct audit_aux_data d;
int len;
char a[0];
};
struct audit_aux_data_fd_pair {
struct audit_aux_data d;
int fd[2];
};
struct audit_aux_data_pids { struct audit_aux_data_pids {
struct audit_aux_data d; struct audit_aux_data d;
pid_t target_pid[AUDIT_AUX_PIDS]; pid_t target_pid[AUDIT_AUX_PIDS];
...@@ -219,14 +165,14 @@ struct audit_tree_refs { ...@@ -219,14 +165,14 @@ struct audit_tree_refs {
struct audit_context { struct audit_context {
int dummy; /* must be the first element */ int dummy; /* must be the first element */
int in_syscall; /* 1 if task is in a syscall */ int in_syscall; /* 1 if task is in a syscall */
enum audit_state state; enum audit_state state, current_state;
unsigned int serial; /* serial number for record */ unsigned int serial; /* serial number for record */
struct timespec ctime; /* time of syscall entry */ struct timespec ctime; /* time of syscall entry */
int major; /* syscall number */ int major; /* syscall number */
unsigned long argv[4]; /* syscall arguments */ unsigned long argv[4]; /* syscall arguments */
int return_valid; /* return code is valid */ int return_valid; /* return code is valid */
long return_code;/* syscall return code */ long return_code;/* syscall return code */
int auditable; /* 1 if record should be written */ u64 prio;
int name_count; int name_count;
struct audit_names names[AUDIT_NAMES]; struct audit_names names[AUDIT_NAMES];
char * filterkey; /* key for rule that triggered record */ char * filterkey; /* key for rule that triggered record */
...@@ -234,7 +180,8 @@ struct audit_context { ...@@ -234,7 +180,8 @@ struct audit_context {
struct audit_context *previous; /* For nested syscalls */ struct audit_context *previous; /* For nested syscalls */
struct audit_aux_data *aux; struct audit_aux_data *aux;
struct audit_aux_data *aux_pids; struct audit_aux_data *aux_pids;
struct sockaddr_storage *sockaddr;
size_t sockaddr_len;
/* Save things to print about task_struct */ /* Save things to print about task_struct */
pid_t pid, ppid; pid_t pid, ppid;
uid_t uid, euid, suid, fsuid; uid_t uid, euid, suid, fsuid;
...@@ -252,6 +199,49 @@ struct audit_context { ...@@ -252,6 +199,49 @@ struct audit_context {
struct audit_tree_refs *trees, *first_trees; struct audit_tree_refs *trees, *first_trees;
int tree_count; int tree_count;
int type;
union {
struct {
int nargs;
long args[6];
} socketcall;
struct {
uid_t uid;
gid_t gid;
mode_t mode;
u32 osid;
int has_perm;
uid_t perm_uid;
gid_t perm_gid;
mode_t perm_mode;
unsigned long qbytes;
} ipc;
struct {
mqd_t mqdes;
struct mq_attr mqstat;
} mq_getsetattr;
struct {
mqd_t mqdes;
int sigev_signo;
} mq_notify;
struct {
mqd_t mqdes;
size_t msg_len;
unsigned int msg_prio;
struct timespec abs_timeout;
} mq_sendrecv;
struct {
int oflag;
mode_t mode;
struct mq_attr attr;
} mq_open;
struct {
pid_t pid;
struct audit_cap_data cap;
} capset;
};
int fds[2];
#if AUDIT_DEBUG #if AUDIT_DEBUG
int put_count; int put_count;
int ino_count; int ino_count;
...@@ -608,19 +598,12 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -608,19 +598,12 @@ static int audit_filter_rules(struct task_struct *tsk,
} }
} }
/* Find ipc objects that match */ /* Find ipc objects that match */
if (ctx) { if (!ctx || ctx->type != AUDIT_IPC)
struct audit_aux_data *aux;
for (aux = ctx->aux; aux;
aux = aux->next) {
if (aux->type == AUDIT_IPC) {
struct audit_aux_data_ipcctl *axi = (void *)aux;
if (security_audit_rule_match(axi->osid, f->type, f->op, f->lsm_rule, ctx)) {
++result;
break; break;
} if (security_audit_rule_match(ctx->ipc.osid,
} f->type, f->op,
} f->lsm_rule, ctx))
} ++result;
} }
break; break;
case AUDIT_ARG0: case AUDIT_ARG0:
...@@ -647,8 +630,16 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -647,8 +630,16 @@ static int audit_filter_rules(struct task_struct *tsk,
return 0; return 0;
} }
} }
if (rule->filterkey && ctx)
if (ctx) {
if (rule->prio <= ctx->prio)
return 0;
if (rule->filterkey) {
kfree(ctx->filterkey);
ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
}
ctx->prio = rule->prio;
}
switch (rule->action) { switch (rule->action) {
case AUDIT_NEVER: *state = AUDIT_DISABLED; break; case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
...@@ -661,7 +652,7 @@ static int audit_filter_rules(struct task_struct *tsk, ...@@ -661,7 +652,7 @@ static int audit_filter_rules(struct task_struct *tsk,
* completely disabled for this task. Since we only have the task * completely disabled for this task. Since we only have the task
* structure at this point, we can only check uid and gid. * structure at this point, we can only check uid and gid.
*/ */
static enum audit_state audit_filter_task(struct task_struct *tsk) static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
{ {
struct audit_entry *e; struct audit_entry *e;
enum audit_state state; enum audit_state state;
...@@ -669,6 +660,8 @@ static enum audit_state audit_filter_task(struct task_struct *tsk) ...@@ -669,6 +660,8 @@ static enum audit_state audit_filter_task(struct task_struct *tsk)
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) { if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) {
if (state == AUDIT_RECORD_CONTEXT)
*key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
rcu_read_unlock(); rcu_read_unlock();
return state; return state;
} }
...@@ -702,6 +695,7 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, ...@@ -702,6 +695,7 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
audit_filter_rules(tsk, &e->rule, ctx, NULL, audit_filter_rules(tsk, &e->rule, ctx, NULL,
&state)) { &state)) {
rcu_read_unlock(); rcu_read_unlock();
ctx->current_state = state;
return state; return state;
} }
} }
...@@ -715,15 +709,14 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, ...@@ -715,15 +709,14 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
* buckets applicable to the inode numbers in audit_names[]. * buckets applicable to the inode numbers in audit_names[].
* Regarding audit_state, same rules apply as for audit_filter_syscall(). * Regarding audit_state, same rules apply as for audit_filter_syscall().
*/ */
enum audit_state audit_filter_inodes(struct task_struct *tsk, void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)
struct audit_context *ctx)
{ {
int i; int i;
struct audit_entry *e; struct audit_entry *e;
enum audit_state state; enum audit_state state;
if (audit_pid && tsk->tgid == audit_pid) if (audit_pid && tsk->tgid == audit_pid)
return AUDIT_DISABLED; return;
rcu_read_lock(); rcu_read_lock();
for (i = 0; i < ctx->name_count; i++) { for (i = 0; i < ctx->name_count; i++) {
...@@ -740,17 +733,20 @@ enum audit_state audit_filter_inodes(struct task_struct *tsk, ...@@ -740,17 +733,20 @@ enum audit_state audit_filter_inodes(struct task_struct *tsk,
if ((e->rule.mask[word] & bit) == bit && if ((e->rule.mask[word] & bit) == bit &&
audit_filter_rules(tsk, &e->rule, ctx, n, &state)) { audit_filter_rules(tsk, &e->rule, ctx, n, &state)) {
rcu_read_unlock(); rcu_read_unlock();
return state; ctx->current_state = state;
return;
} }
} }
} }
rcu_read_unlock(); rcu_read_unlock();
return AUDIT_BUILD_CONTEXT;
} }
void audit_set_auditable(struct audit_context *ctx) static void audit_set_auditable(struct audit_context *ctx)
{ {
ctx->auditable = 1; if (!ctx->prio) {
ctx->prio = 1;
ctx->current_state = AUDIT_RECORD_CONTEXT;
}
} }
static inline struct audit_context *audit_get_context(struct task_struct *tsk, static inline struct audit_context *audit_get_context(struct task_struct *tsk,
...@@ -781,23 +777,11 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, ...@@ -781,23 +777,11 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
else else
context->return_code = return_code; context->return_code = return_code;
if (context->in_syscall && !context->dummy && !context->auditable) { if (context->in_syscall && !context->dummy) {
enum audit_state state; audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
audit_filter_inodes(tsk, context);
state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]);
if (state == AUDIT_RECORD_CONTEXT) {
context->auditable = 1;
goto get_context;
}
state = audit_filter_inodes(tsk, context);
if (state == AUDIT_RECORD_CONTEXT)
context->auditable = 1;
} }
get_context:
tsk->audit_context = NULL; tsk->audit_context = NULL;
return context; return context;
} }
...@@ -807,8 +791,7 @@ static inline void audit_free_names(struct audit_context *context) ...@@ -807,8 +791,7 @@ static inline void audit_free_names(struct audit_context *context)
int i; int i;
#if AUDIT_DEBUG == 2 #if AUDIT_DEBUG == 2
if (context->auditable if (context->put_count + context->ino_count != context->name_count) {
||context->put_count + context->ino_count != context->name_count) {
printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d" printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d"
" name_count=%d put_count=%d" " name_count=%d put_count=%d"
" ino_count=%d [NOT freeing]\n", " ino_count=%d [NOT freeing]\n",
...@@ -859,6 +842,7 @@ static inline void audit_zero_context(struct audit_context *context, ...@@ -859,6 +842,7 @@ static inline void audit_zero_context(struct audit_context *context,
{ {
memset(context, 0, sizeof(*context)); memset(context, 0, sizeof(*context));
context->state = state; context->state = state;
context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
} }
static inline struct audit_context *audit_alloc_context(enum audit_state state) static inline struct audit_context *audit_alloc_context(enum audit_state state)
...@@ -884,18 +868,21 @@ int audit_alloc(struct task_struct *tsk) ...@@ -884,18 +868,21 @@ int audit_alloc(struct task_struct *tsk)
{ {
struct audit_context *context; struct audit_context *context;
enum audit_state state; enum audit_state state;
char *key = NULL;
if (likely(!audit_ever_enabled)) if (likely(!audit_ever_enabled))
return 0; /* Return if not auditing. */ return 0; /* Return if not auditing. */
state = audit_filter_task(tsk); state = audit_filter_task(tsk, &key);
if (likely(state == AUDIT_DISABLED)) if (likely(state == AUDIT_DISABLED))
return 0; return 0;
if (!(context = audit_alloc_context(state))) { if (!(context = audit_alloc_context(state))) {
kfree(key);
audit_log_lost("out of memory in audit_alloc"); audit_log_lost("out of memory in audit_alloc");
return -ENOMEM; return -ENOMEM;
} }
context->filterkey = key;
tsk->audit_context = context; tsk->audit_context = context;
set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT); set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
...@@ -921,6 +908,7 @@ static inline void audit_free_context(struct audit_context *context) ...@@ -921,6 +908,7 @@ static inline void audit_free_context(struct audit_context *context)
free_tree_refs(context); free_tree_refs(context);
audit_free_aux(context); audit_free_aux(context);
kfree(context->filterkey); kfree(context->filterkey);
kfree(context->sockaddr);
kfree(context); kfree(context);
context = previous; context = previous;
} while (context); } while (context);
...@@ -1230,6 +1218,97 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) ...@@ -1230,6 +1218,97 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver); audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver);
} }
static void show_special(struct audit_context *context, int *call_panic)
{
struct audit_buffer *ab;
int i;
ab = audit_log_start(context, GFP_KERNEL, context->type);
if (!ab)
return;
switch (context->type) {
case AUDIT_SOCKETCALL: {
int nargs = context->socketcall.nargs;
audit_log_format(ab, "nargs=%d", nargs);
for (i = 0; i < nargs; i++)
audit_log_format(ab, " a%d=%lx", i,
context->socketcall.args[i]);
break; }
case AUDIT_IPC: {
u32 osid = context->ipc.osid;
audit_log_format(ab, "ouid=%u ogid=%u mode=%#o",
context->ipc.uid, context->ipc.gid, context->ipc.mode);
if (osid) {
char *ctx = NULL;
u32 len;
if (security_secid_to_secctx(osid, &ctx, &len)) {
audit_log_format(ab, " osid=%u", osid);
*call_panic = 1;
} else {
audit_log_format(ab, " obj=%s", ctx);
security_release_secctx(ctx, len);
}
}
if (context->ipc.has_perm) {
audit_log_end(ab);
ab = audit_log_start(context, GFP_KERNEL,
AUDIT_IPC_SET_PERM);
audit_log_format(ab,
"qbytes=%lx ouid=%u ogid=%u mode=%#o",
context->ipc.qbytes,
context->ipc.perm_uid,
context->ipc.perm_gid,
context->ipc.perm_mode);
if (!ab)
return;
}
break; }
case AUDIT_MQ_OPEN: {
audit_log_format(ab,
"oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld "
"mq_msgsize=%ld mq_curmsgs=%ld",
context->mq_open.oflag, context->mq_open.mode,
context->mq_open.attr.mq_flags,
context->mq_open.attr.mq_maxmsg,
context->mq_open.attr.mq_msgsize,
context->mq_open.attr.mq_curmsgs);
break; }
case AUDIT_MQ_SENDRECV: {
audit_log_format(ab,
"mqdes=%d msg_len=%zd msg_prio=%u "
"abs_timeout_sec=%ld abs_timeout_nsec=%ld",
context->mq_sendrecv.mqdes,
context->mq_sendrecv.msg_len,
context->mq_sendrecv.msg_prio,
context->mq_sendrecv.abs_timeout.tv_sec,
context->mq_sendrecv.abs_timeout.tv_nsec);
break; }
case AUDIT_MQ_NOTIFY: {
audit_log_format(ab, "mqdes=%d sigev_signo=%d",
context->mq_notify.mqdes,
context->mq_notify.sigev_signo);
break; }
case AUDIT_MQ_GETSETATTR: {
struct mq_attr *attr = &context->mq_getsetattr.mqstat;
audit_log_format(ab,
"mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld "
"mq_curmsgs=%ld ",
context->mq_getsetattr.mqdes,
attr->mq_flags, attr->mq_maxmsg,
attr->mq_msgsize, attr->mq_curmsgs);
break; }
case AUDIT_CAPSET: {
audit_log_format(ab, "pid=%d", context->capset.pid);
audit_log_cap(ab, "cap_pi", &context->capset.cap.inheritable);
audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted);
audit_log_cap(ab, "cap_pe", &context->capset.cap.effective);
break; }
}
audit_log_end(ab);
}
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{ {
const struct cred *cred; const struct cred *cred;
...@@ -1307,94 +1386,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts ...@@ -1307,94 +1386,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
continue; /* audit_panic has been called */ continue; /* audit_panic has been called */
switch (aux->type) { switch (aux->type) {
case AUDIT_MQ_OPEN: {
struct audit_aux_data_mq_open *axi = (void *)aux;
audit_log_format(ab,
"oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld "
"mq_msgsize=%ld mq_curmsgs=%ld",
axi->oflag, axi->mode, axi->attr.mq_flags,
axi->attr.mq_maxmsg, axi->attr.mq_msgsize,
axi->attr.mq_curmsgs);
break; }
case AUDIT_MQ_SENDRECV: {
struct audit_aux_data_mq_sendrecv *axi = (void *)aux;
audit_log_format(ab,
"mqdes=%d msg_len=%zd msg_prio=%u "
"abs_timeout_sec=%ld abs_timeout_nsec=%ld",
axi->mqdes, axi->msg_len, axi->msg_prio,
axi->abs_timeout.tv_sec, axi->abs_timeout.tv_nsec);
break; }
case AUDIT_MQ_NOTIFY: {
struct audit_aux_data_mq_notify *axi = (void *)aux;
audit_log_format(ab,
"mqdes=%d sigev_signo=%d",
axi->mqdes,
axi->notification.sigev_signo);
break; }
case AUDIT_MQ_GETSETATTR: {
struct audit_aux_data_mq_getsetattr *axi = (void *)aux;
audit_log_format(ab,
"mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld "
"mq_curmsgs=%ld ",
axi->mqdes,
axi->mqstat.mq_flags, axi->mqstat.mq_maxmsg,
axi->mqstat.mq_msgsize, axi->mqstat.mq_curmsgs);
break; }
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
"ouid=%u ogid=%u mode=%#o",
axi->uid, axi->gid, axi->mode);
if (axi->osid != 0) {
char *ctx = NULL;
u32 len;
if (security_secid_to_secctx(
axi->osid, &ctx, &len)) {
audit_log_format(ab, " osid=%u",
axi->osid);
call_panic = 1;
} else {
audit_log_format(ab, " obj=%s", ctx);
security_release_secctx(ctx, len);
}
}
break; }
case AUDIT_IPC_SET_PERM: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
"qbytes=%lx ouid=%u ogid=%u mode=%#o",
axi->qbytes, axi->uid, axi->gid, axi->mode);
break; }
case AUDIT_EXECVE: { case AUDIT_EXECVE: {
struct audit_aux_data_execve *axi = (void *)aux; struct audit_aux_data_execve *axi = (void *)aux;
audit_log_execve_info(context, &ab, axi); audit_log_execve_info(context, &ab, axi);
break; } break; }
case AUDIT_SOCKETCALL: {
struct audit_aux_data_socketcall *axs = (void *)aux;
audit_log_format(ab, "nargs=%d", axs->nargs);
for (i=0; i<axs->nargs; i++)
audit_log_format(ab, " a%d=%lx", i, axs->args[i]);
break; }
case AUDIT_SOCKADDR: {
struct audit_aux_data_sockaddr *axs = (void *)aux;
audit_log_format(ab, "saddr=");
audit_log_n_hex(ab, axs->a, axs->len);
break; }
case AUDIT_FD_PAIR: {
struct audit_aux_data_fd_pair *axs = (void *)aux;
audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
break; }
case AUDIT_BPRM_FCAPS: { case AUDIT_BPRM_FCAPS: {
struct audit_aux_data_bprm_fcaps *axs = (void *)aux; struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
audit_log_format(ab, "fver=%x", axs->fcap_ver); audit_log_format(ab, "fver=%x", axs->fcap_ver);
...@@ -1409,17 +1406,31 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts ...@@ -1409,17 +1406,31 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_cap(ab, "new_pe", &axs->new_pcap.effective); audit_log_cap(ab, "new_pe", &axs->new_pcap.effective);
break; } break; }
case AUDIT_CAPSET: { }
struct audit_aux_data_capset *axs = (void *)aux; audit_log_end(ab);
audit_log_format(ab, "pid=%d", axs->pid); }
audit_log_cap(ab, "cap_pi", &axs->cap.inheritable);
audit_log_cap(ab, "cap_pp", &axs->cap.permitted); if (context->type)
audit_log_cap(ab, "cap_pe", &axs->cap.effective); show_special(context, &call_panic);
break; }
if (context->fds[0] >= 0) {
ab = audit_log_start(context, GFP_KERNEL, AUDIT_FD_PAIR);
if (ab) {
audit_log_format(ab, "fd0=%d fd1=%d",
context->fds[0], context->fds[1]);
audit_log_end(ab);
}
} }
if (context->sockaddr_len) {
ab = audit_log_start(context, GFP_KERNEL, AUDIT_SOCKADDR);
if (ab) {
audit_log_format(ab, "saddr=");
audit_log_n_hex(ab, (void *)context->sockaddr,
context->sockaddr_len);
audit_log_end(ab); audit_log_end(ab);
} }
}
for (aux = context->aux_pids; aux; aux = aux->next) { for (aux = context->aux_pids; aux; aux = aux->next) {
struct audit_aux_data_pids *axs = (void *)aux; struct audit_aux_data_pids *axs = (void *)aux;
...@@ -1536,7 +1547,7 @@ void audit_free(struct task_struct *tsk) ...@@ -1536,7 +1547,7 @@ void audit_free(struct task_struct *tsk)
* We use GFP_ATOMIC here because we might be doing this * We use GFP_ATOMIC here because we might be doing this
* in the context of the idle thread */ * in the context of the idle thread */
/* that can happen only if we are called from do_exit() */ /* that can happen only if we are called from do_exit() */
if (context->in_syscall && context->auditable) if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
audit_log_exit(context, tsk); audit_log_exit(context, tsk);
audit_free_context(context); audit_free_context(context);
...@@ -1620,15 +1631,17 @@ void audit_syscall_entry(int arch, int major, ...@@ -1620,15 +1631,17 @@ void audit_syscall_entry(int arch, int major,
state = context->state; state = context->state;
context->dummy = !audit_n_rules; context->dummy = !audit_n_rules;
if (!context->dummy && (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)) if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
context->prio = 0;
state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);
}
if (likely(state == AUDIT_DISABLED)) if (likely(state == AUDIT_DISABLED))
return; return;
context->serial = 0; context->serial = 0;
context->ctime = CURRENT_TIME; context->ctime = CURRENT_TIME;
context->in_syscall = 1; context->in_syscall = 1;
context->auditable = !!(state == AUDIT_RECORD_CONTEXT); context->current_state = state;
context->ppid = 0; context->ppid = 0;
} }
...@@ -1636,17 +1649,20 @@ void audit_finish_fork(struct task_struct *child) ...@@ -1636,17 +1649,20 @@ void audit_finish_fork(struct task_struct *child)
{ {
struct audit_context *ctx = current->audit_context; struct audit_context *ctx = current->audit_context;
struct audit_context *p = child->audit_context; struct audit_context *p = child->audit_context;
if (!p || !ctx || !ctx->auditable) if (!p || !ctx)
return;
if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT)
return; return;
p->arch = ctx->arch; p->arch = ctx->arch;
p->major = ctx->major; p->major = ctx->major;
memcpy(p->argv, ctx->argv, sizeof(ctx->argv)); memcpy(p->argv, ctx->argv, sizeof(ctx->argv));
p->ctime = ctx->ctime; p->ctime = ctx->ctime;
p->dummy = ctx->dummy; p->dummy = ctx->dummy;
p->auditable = ctx->auditable;
p->in_syscall = ctx->in_syscall; p->in_syscall = ctx->in_syscall;
p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL); p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL);
p->ppid = current->pid; p->ppid = current->pid;
p->prio = ctx->prio;
p->current_state = ctx->current_state;
} }
/** /**
...@@ -1670,11 +1686,11 @@ void audit_syscall_exit(int valid, long return_code) ...@@ -1670,11 +1686,11 @@ void audit_syscall_exit(int valid, long return_code)
if (likely(!context)) if (likely(!context))
return; return;
if (context->in_syscall && context->auditable) if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
audit_log_exit(context, tsk); audit_log_exit(context, tsk);
context->in_syscall = 0; context->in_syscall = 0;
context->auditable = 0; context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
if (context->previous) { if (context->previous) {
struct audit_context *new_context = context->previous; struct audit_context *new_context = context->previous;
...@@ -1689,8 +1705,13 @@ void audit_syscall_exit(int valid, long return_code) ...@@ -1689,8 +1705,13 @@ void audit_syscall_exit(int valid, long return_code)
context->aux_pids = NULL; context->aux_pids = NULL;
context->target_pid = 0; context->target_pid = 0;
context->target_sid = 0; context->target_sid = 0;
context->sockaddr_len = 0;
context->type = 0;
context->fds[0] = -1;
if (context->state != AUDIT_RECORD_CONTEXT) {
kfree(context->filterkey); kfree(context->filterkey);
context->filterkey = NULL; context->filterkey = NULL;
}
tsk->audit_context = context; tsk->audit_context = context;
} }
} }
...@@ -2081,7 +2102,10 @@ int auditsc_get_stamp(struct audit_context *ctx, ...@@ -2081,7 +2102,10 @@ int auditsc_get_stamp(struct audit_context *ctx,
t->tv_sec = ctx->ctime.tv_sec; t->tv_sec = ctx->ctime.tv_sec;
t->tv_nsec = ctx->ctime.tv_nsec; t->tv_nsec = ctx->ctime.tv_nsec;
*serial = ctx->serial; *serial = ctx->serial;
ctx->auditable = 1; if (!ctx->prio) {
ctx->prio = 1;
ctx->current_state = AUDIT_RECORD_CONTEXT;
}
return 1; return 1;
} }
...@@ -2127,132 +2151,46 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid) ...@@ -2127,132 +2151,46 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
* @mode: mode bits * @mode: mode bits
* @u_attr: queue attributes * @u_attr: queue attributes
* *
* Returns 0 for success or NULL context or < 0 on error.
*/ */
int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr) void __audit_mq_open(int oflag, mode_t mode, struct mq_attr *attr)
{ {
struct audit_aux_data_mq_open *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
if (!audit_enabled) if (attr)
return 0; memcpy(&context->mq_open.attr, attr, sizeof(struct mq_attr));
else
if (likely(!context)) memset(&context->mq_open.attr, 0, sizeof(struct mq_attr));
return 0;
ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
if (u_attr != NULL) {
if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr))) {
kfree(ax);
return -EFAULT;
}
} else
memset(&ax->attr, 0, sizeof(ax->attr));
ax->oflag = oflag; context->mq_open.oflag = oflag;
ax->mode = mode; context->mq_open.mode = mode;
ax->d.type = AUDIT_MQ_OPEN; context->type = AUDIT_MQ_OPEN;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
} }
/** /**
* __audit_mq_timedsend - record audit data for a POSIX MQ timed send * __audit_mq_sendrecv - record audit data for a POSIX MQ timed send/receive
* @mqdes: MQ descriptor * @mqdes: MQ descriptor
* @msg_len: Message length * @msg_len: Message length
* @msg_prio: Message priority * @msg_prio: Message priority
* @u_abs_timeout: Message timeout in absolute time * @abs_timeout: Message timeout in absolute time
* *
* Returns 0 for success or NULL context or < 0 on error.
*/ */
int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
const struct timespec __user *u_abs_timeout) const struct timespec *abs_timeout)
{ {
struct audit_aux_data_mq_sendrecv *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
struct timespec *p = &context->mq_sendrecv.abs_timeout;
if (!audit_enabled) if (abs_timeout)
return 0; memcpy(p, abs_timeout, sizeof(struct timespec));
else
if (likely(!context)) memset(p, 0, sizeof(struct timespec));
return 0;
ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
if (u_abs_timeout != NULL) {
if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) {
kfree(ax);
return -EFAULT;
}
} else
memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
ax->mqdes = mqdes;
ax->msg_len = msg_len;
ax->msg_prio = msg_prio;
ax->d.type = AUDIT_MQ_SENDRECV;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
}
/**
* __audit_mq_timedreceive - record audit data for a POSIX MQ timed receive
* @mqdes: MQ descriptor
* @msg_len: Message length
* @u_msg_prio: Message priority
* @u_abs_timeout: Message timeout in absolute time
*
* Returns 0 for success or NULL context or < 0 on error.
*/
int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len,
unsigned int __user *u_msg_prio,
const struct timespec __user *u_abs_timeout)
{
struct audit_aux_data_mq_sendrecv *ax;
struct audit_context *context = current->audit_context;
if (!audit_enabled)
return 0;
if (likely(!context))
return 0;
ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
if (u_msg_prio != NULL) {
if (get_user(ax->msg_prio, u_msg_prio)) {
kfree(ax);
return -EFAULT;
}
} else
ax->msg_prio = 0;
if (u_abs_timeout != NULL) {
if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout))) {
kfree(ax);
return -EFAULT;
}
} else
memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
ax->mqdes = mqdes; context->mq_sendrecv.mqdes = mqdes;
ax->msg_len = msg_len; context->mq_sendrecv.msg_len = msg_len;
context->mq_sendrecv.msg_prio = msg_prio;
ax->d.type = AUDIT_MQ_SENDRECV; context->type = AUDIT_MQ_SENDRECV;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
} }
/** /**
...@@ -2260,38 +2198,19 @@ int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, ...@@ -2260,38 +2198,19 @@ int __audit_mq_timedreceive(mqd_t mqdes, size_t msg_len,
* @mqdes: MQ descriptor * @mqdes: MQ descriptor
* @u_notification: Notification event * @u_notification: Notification event
* *
* Returns 0 for success or NULL context or < 0 on error.
*/ */
int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification)
{ {
struct audit_aux_data_mq_notify *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
if (!audit_enabled) if (notification)
return 0; context->mq_notify.sigev_signo = notification->sigev_signo;
else
if (likely(!context)) context->mq_notify.sigev_signo = 0;
return 0;
ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
if (u_notification != NULL) {
if (copy_from_user(&ax->notification, u_notification, sizeof(ax->notification))) {
kfree(ax);
return -EFAULT;
}
} else
memset(&ax->notification, 0, sizeof(ax->notification));
ax->mqdes = mqdes;
ax->d.type = AUDIT_MQ_NOTIFY; context->mq_notify.mqdes = mqdes;
ax->d.next = context->aux; context->type = AUDIT_MQ_NOTIFY;
context->aux = (void *)ax;
return 0;
} }
/** /**
...@@ -2299,55 +2218,29 @@ int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) ...@@ -2299,55 +2218,29 @@ int __audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification)
* @mqdes: MQ descriptor * @mqdes: MQ descriptor
* @mqstat: MQ flags * @mqstat: MQ flags
* *
* Returns 0 for success or NULL context or < 0 on error.
*/ */
int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
{ {
struct audit_aux_data_mq_getsetattr *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
context->mq_getsetattr.mqdes = mqdes;
if (!audit_enabled) context->mq_getsetattr.mqstat = *mqstat;
return 0; context->type = AUDIT_MQ_GETSETATTR;
if (likely(!context))
return 0;
ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
if (!ax)
return -ENOMEM;
ax->mqdes = mqdes;
ax->mqstat = *mqstat;
ax->d.type = AUDIT_MQ_GETSETATTR;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
} }
/** /**
* audit_ipc_obj - record audit data for ipc object * audit_ipc_obj - record audit data for ipc object
* @ipcp: ipc permissions * @ipcp: ipc permissions
* *
* Returns 0 for success or NULL context or < 0 on error.
*/ */
int __audit_ipc_obj(struct kern_ipc_perm *ipcp) void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
{ {
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
context->ipc.uid = ipcp->uid;
ax = kmalloc(sizeof(*ax), GFP_ATOMIC); context->ipc.gid = ipcp->gid;
if (!ax) context->ipc.mode = ipcp->mode;
return -ENOMEM; context->ipc.has_perm = 0;
security_ipc_getsecid(ipcp, &context->ipc.osid);
ax->uid = ipcp->uid; context->type = AUDIT_IPC;
ax->gid = ipcp->gid;
ax->mode = ipcp->mode;
security_ipc_getsecid(ipcp, &ax->osid);
ax->d.type = AUDIT_IPC;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
} }
/** /**
...@@ -2357,26 +2250,17 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp) ...@@ -2357,26 +2250,17 @@ int __audit_ipc_obj(struct kern_ipc_perm *ipcp)
* @gid: msgq group id * @gid: msgq group id
* @mode: msgq mode (permissions) * @mode: msgq mode (permissions)
* *
* Returns 0 for success or NULL context or < 0 on error. * Called only after audit_ipc_obj().
*/ */
int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) void __audit_ipc_set_perm(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; struct audit_context *context = current->audit_context;
ax = kmalloc(sizeof(*ax), GFP_ATOMIC); context->ipc.qbytes = qbytes;
if (!ax) context->ipc.perm_uid = uid;
return -ENOMEM; context->ipc.perm_gid = gid;
context->ipc.perm_mode = mode;
ax->qbytes = qbytes; context->ipc.has_perm = 1;
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
ax->d.type = AUDIT_IPC_SET_PERM;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
} }
int audit_bprm(struct linux_binprm *bprm) int audit_bprm(struct linux_binprm *bprm)
...@@ -2406,27 +2290,17 @@ int audit_bprm(struct linux_binprm *bprm) ...@@ -2406,27 +2290,17 @@ int audit_bprm(struct linux_binprm *bprm)
* @nargs: number of args * @nargs: number of args
* @args: args array * @args: args array
* *
* Returns 0 for success or NULL context or < 0 on error.
*/ */
int audit_socketcall(int nargs, unsigned long *args) void audit_socketcall(int nargs, unsigned long *args)
{ {
struct audit_aux_data_socketcall *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
if (likely(!context || context->dummy)) if (likely(!context || context->dummy))
return 0; return;
ax = kmalloc(sizeof(*ax) + nargs * sizeof(unsigned long), GFP_KERNEL);
if (!ax)
return -ENOMEM;
ax->nargs = nargs;
memcpy(ax->args, args, nargs * sizeof(unsigned long));
ax->d.type = AUDIT_SOCKETCALL; context->type = AUDIT_SOCKETCALL;
ax->d.next = context->aux; context->socketcall.nargs = nargs;
context->aux = (void *)ax; memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long));
return 0;
} }
/** /**
...@@ -2434,29 +2308,12 @@ int audit_socketcall(int nargs, unsigned long *args) ...@@ -2434,29 +2308,12 @@ int audit_socketcall(int nargs, unsigned long *args)
* @fd1: the first file descriptor * @fd1: the first file descriptor
* @fd2: the second file descriptor * @fd2: the second file descriptor
* *
* Returns 0 for success or NULL context or < 0 on error.
*/ */
int __audit_fd_pair(int fd1, int fd2) void __audit_fd_pair(int fd1, int fd2)
{ {
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
struct audit_aux_data_fd_pair *ax; context->fds[0] = fd1;
context->fds[1] = fd2;
if (likely(!context)) {
return 0;
}
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
if (!ax) {
return -ENOMEM;
}
ax->fd[0] = fd1;
ax->fd[1] = fd2;
ax->d.type = AUDIT_FD_PAIR;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0;
} }
/** /**
...@@ -2468,22 +2325,20 @@ int __audit_fd_pair(int fd1, int fd2) ...@@ -2468,22 +2325,20 @@ int __audit_fd_pair(int fd1, int fd2)
*/ */
int audit_sockaddr(int len, void *a) int audit_sockaddr(int len, void *a)
{ {
struct audit_aux_data_sockaddr *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
if (likely(!context || context->dummy)) if (likely(!context || context->dummy))
return 0; return 0;
ax = kmalloc(sizeof(*ax) + len, GFP_KERNEL); if (!context->sockaddr) {
if (!ax) void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL);
if (!p)
return -ENOMEM; return -ENOMEM;
context->sockaddr = p;
}
ax->len = len; context->sockaddr_len = len;
memcpy(ax->a, a, len); memcpy(context->sockaddr, a, len);
ax->d.type = AUDIT_SOCKADDR;
ax->d.next = context->aux;
context->aux = (void *)ax;
return 0; return 0;
} }
...@@ -2617,29 +2472,15 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm, ...@@ -2617,29 +2472,15 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
* Record the aguments userspace sent to sys_capset for later printing by the * Record the aguments userspace sent to sys_capset for later printing by the
* audit system if applicable * audit system if applicable
*/ */
int __audit_log_capset(pid_t pid, void __audit_log_capset(pid_t pid,
const struct cred *new, const struct cred *old) const struct cred *new, const struct cred *old)
{ {
struct audit_aux_data_capset *ax;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
context->capset.pid = pid;
if (likely(!audit_enabled || !context || context->dummy)) context->capset.cap.effective = new->cap_effective;
return 0; context->capset.cap.inheritable = new->cap_effective;
context->capset.cap.permitted = new->cap_permitted;
ax = kmalloc(sizeof(*ax), GFP_KERNEL); context->type = AUDIT_CAPSET;
if (!ax)
return -ENOMEM;
ax->d.type = AUDIT_CAPSET;
ax->d.next = context->aux;
context->aux = (void *)ax;
ax->pid = pid;
ax->cap.effective = new->cap_effective;
ax->cap.inheritable = new->cap_effective;
ax->cap.permitted = new->cap_permitted;
return 0;
} }
/** /**
......
...@@ -280,9 +280,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) ...@@ -280,9 +280,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
if (ret < 0) if (ret < 0)
goto error; goto error;
ret = audit_log_capset(pid, new, current_cred()); audit_log_capset(pid, new, current_cred());
if (ret < 0)
return ret;
return commit_creds(new); return commit_creds(new);
......
...@@ -1313,13 +1313,7 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, ...@@ -1313,13 +1313,7 @@ asmlinkage long sys_socketpair(int family, int type, int protocol,
goto out_fd1; goto out_fd1;
} }
err = audit_fd_pair(fd1, fd2); audit_fd_pair(fd1, fd2);
if (err < 0) {
fput(newfile1);
fput(newfile2);
goto out_fd;
}
fd_install(fd1, newfile1); fd_install(fd1, newfile1);
fd_install(fd2, newfile2); fd_install(fd2, newfile2);
/* fd1 and fd2 may be already another descriptors. /* fd1 and fd2 may be already another descriptors.
...@@ -1349,7 +1343,6 @@ out_fd2: ...@@ -1349,7 +1343,6 @@ out_fd2:
out_fd1: out_fd1:
put_filp(newfile2); put_filp(newfile2);
sock_release(sock2); sock_release(sock2);
out_fd:
put_unused_fd(fd1); put_unused_fd(fd1);
put_unused_fd(fd2); put_unused_fd(fd2);
goto out; goto out;
...@@ -2065,9 +2058,7 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args) ...@@ -2065,9 +2058,7 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
if (copy_from_user(a, args, nargs[call])) if (copy_from_user(a, args, nargs[call]))
return -EFAULT; return -EFAULT;
err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); audit_socketcall(nargs[call] / sizeof(unsigned long), a);
if (err)
return err;
a0 = a[0]; a0 = a[0];
a1 = a[1]; a1 = a[1];
......
...@@ -2602,7 +2602,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -2602,7 +2602,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
case AUDIT_OBJ_ROLE: case AUDIT_OBJ_ROLE:
case AUDIT_OBJ_TYPE: case AUDIT_OBJ_TYPE:
/* only 'equals' and 'not equals' fit user, role, and type */ /* only 'equals' and 'not equals' fit user, role, and type */
if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL) if (op != Audit_equal && op != Audit_not_equal)
return -EINVAL; return -EINVAL;
break; break;
case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_SEN:
...@@ -2736,10 +2736,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, ...@@ -2736,10 +2736,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
case AUDIT_SUBJ_USER: case AUDIT_SUBJ_USER:
case AUDIT_OBJ_USER: case AUDIT_OBJ_USER:
switch (op) { switch (op) {
case AUDIT_EQUAL: case Audit_equal:
match = (ctxt->user == rule->au_ctxt.user); match = (ctxt->user == rule->au_ctxt.user);
break; break;
case AUDIT_NOT_EQUAL: case Audit_not_equal:
match = (ctxt->user != rule->au_ctxt.user); match = (ctxt->user != rule->au_ctxt.user);
break; break;
} }
...@@ -2747,10 +2747,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, ...@@ -2747,10 +2747,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_ROLE:
case AUDIT_OBJ_ROLE: case AUDIT_OBJ_ROLE:
switch (op) { switch (op) {
case AUDIT_EQUAL: case Audit_equal:
match = (ctxt->role == rule->au_ctxt.role); match = (ctxt->role == rule->au_ctxt.role);
break; break;
case AUDIT_NOT_EQUAL: case Audit_not_equal:
match = (ctxt->role != rule->au_ctxt.role); match = (ctxt->role != rule->au_ctxt.role);
break; break;
} }
...@@ -2758,10 +2758,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, ...@@ -2758,10 +2758,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_TYPE:
case AUDIT_OBJ_TYPE: case AUDIT_OBJ_TYPE:
switch (op) { switch (op) {
case AUDIT_EQUAL: case Audit_equal:
match = (ctxt->type == rule->au_ctxt.type); match = (ctxt->type == rule->au_ctxt.type);
break; break;
case AUDIT_NOT_EQUAL: case Audit_not_equal:
match = (ctxt->type != rule->au_ctxt.type); match = (ctxt->type != rule->au_ctxt.type);
break; break;
} }
...@@ -2774,31 +2774,31 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, ...@@ -2774,31 +2774,31 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
field == AUDIT_OBJ_LEV_LOW) ? field == AUDIT_OBJ_LEV_LOW) ?
&ctxt->range.level[0] : &ctxt->range.level[1]); &ctxt->range.level[0] : &ctxt->range.level[1]);
switch (op) { switch (op) {
case AUDIT_EQUAL: case Audit_equal:
match = mls_level_eq(&rule->au_ctxt.range.level[0], match = mls_level_eq(&rule->au_ctxt.range.level[0],
level); level);
break; break;
case AUDIT_NOT_EQUAL: case Audit_not_equal:
match = !mls_level_eq(&rule->au_ctxt.range.level[0], match = !mls_level_eq(&rule->au_ctxt.range.level[0],
level); level);
break; break;
case AUDIT_LESS_THAN: case Audit_lt:
match = (mls_level_dom(&rule->au_ctxt.range.level[0], match = (mls_level_dom(&rule->au_ctxt.range.level[0],
level) && level) &&
!mls_level_eq(&rule->au_ctxt.range.level[0], !mls_level_eq(&rule->au_ctxt.range.level[0],
level)); level));
break; break;
case AUDIT_LESS_THAN_OR_EQUAL: case Audit_le:
match = mls_level_dom(&rule->au_ctxt.range.level[0], match = mls_level_dom(&rule->au_ctxt.range.level[0],
level); level);
break; break;
case AUDIT_GREATER_THAN: case Audit_gt:
match = (mls_level_dom(level, match = (mls_level_dom(level,
&rule->au_ctxt.range.level[0]) && &rule->au_ctxt.range.level[0]) &&
!mls_level_eq(level, !mls_level_eq(level,
&rule->au_ctxt.range.level[0])); &rule->au_ctxt.range.level[0]));
break; break;
case AUDIT_GREATER_THAN_OR_EQUAL: case Audit_ge:
match = mls_level_dom(level, match = mls_level_dom(level,
&rule->au_ctxt.range.level[0]); &rule->au_ctxt.range.level[0]);
break; break;
......
...@@ -2492,7 +2492,7 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -2492,7 +2492,7 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
return -EINVAL; return -EINVAL;
if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL) if (op != Audit_equal && op != Audit_not_equal)
return -EINVAL; return -EINVAL;
*rule = smk_import(rulestr, 0); *rule = smk_import(rulestr, 0);
...@@ -2556,9 +2556,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, ...@@ -2556,9 +2556,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
* both pointers will point to the same smack_known * both pointers will point to the same smack_known
* label. * label.
*/ */
if (op == AUDIT_EQUAL) if (op == Audit_equal)
return (rule == smack); return (rule == smack);
if (op == AUDIT_NOT_EQUAL) if (op == Audit_not_equal)
return (rule != smack); return (rule != smack);
return 0; 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