Commit 847f8776 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'audit.b64' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current:
  audit mmap
  audit: make link()/linkat() match "attribute change" predicate
  audit: Use rcu for task lookup protection
  audit: Do not send uninitialized data for AUDIT_TTY_GET
  audit: Call tty_audit_push_task() outside preempt disabled
  in untag_chunk() we need to do alloc_chunk() a bit earlier
  audit: make functions static
  Audit: add support to match lsm labels on user audit messages
parents 79346507 120a795d
...@@ -189,24 +189,42 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch) ...@@ -189,24 +189,42 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
/** /**
* tty_audit_push_task - Flush task's pending audit data * tty_audit_push_task - Flush task's pending audit data
* @tsk: task pointer
* @loginuid: sender login uid
* @sessionid: sender session id
*
* Called with a ref on @tsk held. Try to lock sighand and get a
* reference to the tty audit buffer if available.
* Flush the buffer or return an appropriate error code.
*/ */
void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
{ {
struct tty_audit_buf *buf; struct tty_audit_buf *buf = ERR_PTR(-EPERM);
unsigned long flags;
spin_lock_irq(&tsk->sighand->siglock); if (!lock_task_sighand(tsk, &flags))
return -ESRCH;
if (tsk->signal->audit_tty) {
buf = tsk->signal->tty_audit_buf; buf = tsk->signal->tty_audit_buf;
if (buf) if (buf)
atomic_inc(&buf->count); atomic_inc(&buf->count);
spin_unlock_irq(&tsk->sighand->siglock); }
if (!buf) unlock_task_sighand(tsk, &flags);
return;
/*
* Return 0 when signal->audit_tty set
* but tsk->signal->tty_audit_buf == NULL.
*/
if (!buf || IS_ERR(buf))
return PTR_ERR(buf);
mutex_lock(&buf->mutex); mutex_lock(&buf->mutex);
tty_audit_buf_push(tsk, loginuid, sessionid, buf); tty_audit_buf_push(tsk, loginuid, sessionid, buf);
mutex_unlock(&buf->mutex); mutex_unlock(&buf->mutex);
tty_audit_buf_put(buf); tty_audit_buf_put(buf);
return 0;
} }
/** /**
......
...@@ -20,3 +20,7 @@ __NR_chown32, ...@@ -20,3 +20,7 @@ __NR_chown32,
__NR_fchown32, __NR_fchown32,
__NR_lchown32, __NR_lchown32,
#endif #endif
__NR_link,
#ifdef __NR_linkat
__NR_linkat,
#endif
...@@ -102,6 +102,7 @@ ...@@ -102,6 +102,7 @@
#define AUDIT_EOE 1320 /* End of multi-record event */ #define AUDIT_EOE 1320 /* End of multi-record event */
#define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ #define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */
#define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */ #define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */
#define AUDIT_MMAP 1323 /* Record showing descriptor and flags in mmap */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ #define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ #define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
...@@ -478,6 +479,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, ...@@ -478,6 +479,7 @@ 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 void __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);
extern void __audit_mmap_fd(int fd, int flags);
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{ {
...@@ -531,6 +533,12 @@ static inline void audit_log_capset(pid_t pid, const struct cred *new, ...@@ -531,6 +533,12 @@ static inline void audit_log_capset(pid_t pid, const struct cred *new,
__audit_log_capset(pid, new, old); __audit_log_capset(pid, new, old);
} }
static inline void audit_mmap_fd(int fd, int flags)
{
if (unlikely(!audit_dummy_context()))
__audit_mmap_fd(fd, flags);
}
extern int audit_n_rules; extern int audit_n_rules;
extern int audit_signals; extern int audit_signals;
#else #else
...@@ -564,6 +572,7 @@ extern int audit_signals; ...@@ -564,6 +572,7 @@ extern int audit_signals;
#define audit_mq_getsetattr(d,s) ((void)0) #define audit_mq_getsetattr(d,s) ((void)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) ((void)0) #define audit_log_capset(pid, ncr, ocr) ((void)0)
#define audit_mmap_fd(fd, flags) ((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
......
...@@ -541,7 +541,7 @@ extern void tty_audit_exit(void); ...@@ -541,7 +541,7 @@ extern void tty_audit_exit(void);
extern void tty_audit_fork(struct signal_struct *sig); extern void tty_audit_fork(struct signal_struct *sig);
extern void tty_audit_tiocsti(struct tty_struct *tty, char ch); extern void tty_audit_tiocsti(struct tty_struct *tty, char ch);
extern void tty_audit_push(struct tty_struct *tty); extern void tty_audit_push(struct tty_struct *tty);
extern void tty_audit_push_task(struct task_struct *tsk, extern int tty_audit_push_task(struct task_struct *tsk,
uid_t loginuid, u32 sessionid); uid_t loginuid, u32 sessionid);
#else #else
static inline void tty_audit_add_data(struct tty_struct *tty, static inline void tty_audit_add_data(struct tty_struct *tty,
...@@ -560,9 +560,10 @@ static inline void tty_audit_fork(struct signal_struct *sig) ...@@ -560,9 +560,10 @@ static inline void tty_audit_fork(struct signal_struct *sig)
static inline void tty_audit_push(struct tty_struct *tty) static inline void tty_audit_push(struct tty_struct *tty)
{ {
} }
static inline void tty_audit_push_task(struct task_struct *tsk, static inline int tty_audit_push_task(struct task_struct *tsk,
uid_t loginuid, u32 sessionid) uid_t loginuid, u32 sessionid)
{ {
return 0;
} }
#endif #endif
......
...@@ -467,23 +467,16 @@ static int audit_prepare_user_tty(pid_t pid, uid_t loginuid, u32 sessionid) ...@@ -467,23 +467,16 @@ static int audit_prepare_user_tty(pid_t pid, uid_t loginuid, u32 sessionid)
struct task_struct *tsk; struct task_struct *tsk;
int err; int err;
read_lock(&tasklist_lock); rcu_read_lock();
tsk = find_task_by_vpid(pid); tsk = find_task_by_vpid(pid);
err = -ESRCH; if (!tsk) {
if (!tsk) rcu_read_unlock();
goto out; return -ESRCH;
err = 0; }
get_task_struct(tsk);
spin_lock_irq(&tsk->sighand->siglock); rcu_read_unlock();
if (!tsk->signal->audit_tty) err = tty_audit_push_task(tsk, loginuid, sessionid);
err = -EPERM; put_task_struct(tsk);
spin_unlock_irq(&tsk->sighand->siglock);
if (err)
goto out;
tty_audit_push_task(tsk, loginuid, sessionid);
out:
read_unlock(&tasklist_lock);
return err; return err;
} }
...@@ -506,7 +499,7 @@ int audit_send_list(void *_dest) ...@@ -506,7 +499,7 @@ int audit_send_list(void *_dest)
} }
struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, struct sk_buff *audit_make_reply(int pid, int seq, int type, int done,
int multi, void *payload, int size) int multi, const void *payload, int size)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
...@@ -555,8 +548,8 @@ static int audit_send_reply_thread(void *arg) ...@@ -555,8 +548,8 @@ static int audit_send_reply_thread(void *arg)
* Allocates an skb, builds the netlink message, and sends it to the pid. * Allocates an skb, builds the netlink message, and sends it to the pid.
* No failure notifications. * No failure notifications.
*/ */
void audit_send_reply(int pid, int seq, int type, int done, int multi, static void audit_send_reply(int pid, int seq, int type, int done, int multi,
void *payload, int size) const void *payload, int size)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct task_struct *tsk; struct task_struct *tsk;
...@@ -880,40 +873,40 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -880,40 +873,40 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case AUDIT_TTY_GET: { case AUDIT_TTY_GET: {
struct audit_tty_status s; struct audit_tty_status s;
struct task_struct *tsk; struct task_struct *tsk;
unsigned long flags;
read_lock(&tasklist_lock); rcu_read_lock();
tsk = find_task_by_vpid(pid); tsk = find_task_by_vpid(pid);
if (!tsk) if (tsk && lock_task_sighand(tsk, &flags)) {
err = -ESRCH;
else {
spin_lock_irq(&tsk->sighand->siglock);
s.enabled = tsk->signal->audit_tty != 0; s.enabled = tsk->signal->audit_tty != 0;
spin_unlock_irq(&tsk->sighand->siglock); unlock_task_sighand(tsk, &flags);
} } else
read_unlock(&tasklist_lock); err = -ESRCH;
audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_TTY_GET, 0, 0, rcu_read_unlock();
&s, sizeof(s));
if (!err)
audit_send_reply(NETLINK_CB(skb).pid, seq,
AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
break; break;
} }
case AUDIT_TTY_SET: { case AUDIT_TTY_SET: {
struct audit_tty_status *s; struct audit_tty_status *s;
struct task_struct *tsk; struct task_struct *tsk;
unsigned long flags;
if (nlh->nlmsg_len < sizeof(struct audit_tty_status)) if (nlh->nlmsg_len < sizeof(struct audit_tty_status))
return -EINVAL; return -EINVAL;
s = data; s = data;
if (s->enabled != 0 && s->enabled != 1) if (s->enabled != 0 && s->enabled != 1)
return -EINVAL; return -EINVAL;
read_lock(&tasklist_lock); rcu_read_lock();
tsk = find_task_by_vpid(pid); tsk = find_task_by_vpid(pid);
if (!tsk) if (tsk && lock_task_sighand(tsk, &flags)) {
err = -ESRCH;
else {
spin_lock_irq(&tsk->sighand->siglock);
tsk->signal->audit_tty = s->enabled != 0; tsk->signal->audit_tty = s->enabled != 0;
spin_unlock_irq(&tsk->sighand->siglock); unlock_task_sighand(tsk, &flags);
} } else
read_unlock(&tasklist_lock); err = -ESRCH;
rcu_read_unlock();
break; break;
} }
default: default:
......
...@@ -84,10 +84,7 @@ extern int audit_compare_dname_path(const char *dname, const char *path, ...@@ -84,10 +84,7 @@ extern int audit_compare_dname_path(const char *dname, const char *path,
int *dirlen); int *dirlen);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type, extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
int done, int multi, int done, int multi,
void *payload, int size); const void *payload, int size);
extern void audit_send_reply(int pid, int seq, int type,
int done, int multi,
void *payload, int size);
extern void audit_panic(const char *message); extern void audit_panic(const char *message);
struct audit_netlink_list { struct audit_netlink_list {
......
...@@ -223,7 +223,7 @@ static void untag_chunk(struct node *p) ...@@ -223,7 +223,7 @@ static void untag_chunk(struct node *p)
{ {
struct audit_chunk *chunk = find_chunk(p); struct audit_chunk *chunk = find_chunk(p);
struct fsnotify_mark *entry = &chunk->mark; struct fsnotify_mark *entry = &chunk->mark;
struct audit_chunk *new; struct audit_chunk *new = NULL;
struct audit_tree *owner; struct audit_tree *owner;
int size = chunk->count - 1; int size = chunk->count - 1;
int i, j; int i, j;
...@@ -232,9 +232,14 @@ static void untag_chunk(struct node *p) ...@@ -232,9 +232,14 @@ static void untag_chunk(struct node *p)
spin_unlock(&hash_lock); spin_unlock(&hash_lock);
if (size)
new = alloc_chunk(size);
spin_lock(&entry->lock); spin_lock(&entry->lock);
if (chunk->dead || !entry->i.inode) { if (chunk->dead || !entry->i.inode) {
spin_unlock(&entry->lock); spin_unlock(&entry->lock);
if (new)
free_chunk(new);
goto out; goto out;
} }
...@@ -255,9 +260,9 @@ static void untag_chunk(struct node *p) ...@@ -255,9 +260,9 @@ static void untag_chunk(struct node *p)
goto out; goto out;
} }
new = alloc_chunk(size);
if (!new) if (!new)
goto Fallback; goto Fallback;
fsnotify_duplicate_mark(&new->mark, entry); fsnotify_duplicate_mark(&new->mark, entry);
if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) { if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) {
free_chunk(new); free_chunk(new);
......
...@@ -60,7 +60,7 @@ struct audit_parent { ...@@ -60,7 +60,7 @@ struct audit_parent {
}; };
/* fsnotify handle. */ /* fsnotify handle. */
struct fsnotify_group *audit_watch_group; static struct fsnotify_group *audit_watch_group;
/* fsnotify events we care about. */ /* fsnotify events we care about. */
#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\ #define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
...@@ -123,7 +123,7 @@ void audit_put_watch(struct audit_watch *watch) ...@@ -123,7 +123,7 @@ void audit_put_watch(struct audit_watch *watch)
} }
} }
void audit_remove_watch(struct audit_watch *watch) static void audit_remove_watch(struct audit_watch *watch)
{ {
list_del(&watch->wlist); list_del(&watch->wlist);
audit_put_parent(watch->parent); audit_put_parent(watch->parent);
......
...@@ -1252,6 +1252,18 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb, ...@@ -1252,6 +1252,18 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb,
case AUDIT_LOGINUID: case AUDIT_LOGINUID:
result = audit_comparator(cb->loginuid, f->op, f->val); result = audit_comparator(cb->loginuid, f->op, f->val);
break; break;
case AUDIT_SUBJ_USER:
case AUDIT_SUBJ_ROLE:
case AUDIT_SUBJ_TYPE:
case AUDIT_SUBJ_SEN:
case AUDIT_SUBJ_CLR:
if (f->lsm_rule)
result = security_audit_rule_match(cb->sid,
f->type,
f->op,
f->lsm_rule,
NULL);
break;
} }
if (!result) if (!result)
......
...@@ -241,6 +241,10 @@ struct audit_context { ...@@ -241,6 +241,10 @@ struct audit_context {
pid_t pid; pid_t pid;
struct audit_cap_data cap; struct audit_cap_data cap;
} capset; } capset;
struct {
int fd;
int flags;
} mmap;
}; };
int fds[2]; int fds[2];
...@@ -1305,6 +1309,10 @@ static void show_special(struct audit_context *context, int *call_panic) ...@@ -1305,6 +1309,10 @@ static void show_special(struct audit_context *context, int *call_panic)
audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted); audit_log_cap(ab, "cap_pp", &context->capset.cap.permitted);
audit_log_cap(ab, "cap_pe", &context->capset.cap.effective); audit_log_cap(ab, "cap_pe", &context->capset.cap.effective);
break; } break; }
case AUDIT_MMAP: {
audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
context->mmap.flags);
break; }
} }
audit_log_end(ab); audit_log_end(ab);
} }
...@@ -2476,6 +2484,14 @@ void __audit_log_capset(pid_t pid, ...@@ -2476,6 +2484,14 @@ void __audit_log_capset(pid_t pid,
context->type = AUDIT_CAPSET; context->type = AUDIT_CAPSET;
} }
void __audit_mmap_fd(int fd, int flags)
{
struct audit_context *context = current->audit_context;
context->mmap.fd = fd;
context->mmap.flags = flags;
context->type = AUDIT_MMAP;
}
/** /**
* audit_core_dumps - record information about processes that end abnormally * audit_core_dumps - record information about processes that end abnormally
* @signr: signal value * @signr: signal value
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/rmap.h> #include <linux/rmap.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/audit.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -1108,6 +1109,7 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, ...@@ -1108,6 +1109,7 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
unsigned long retval = -EBADF; unsigned long retval = -EBADF;
if (!(flags & MAP_ANONYMOUS)) { if (!(flags & MAP_ANONYMOUS)) {
audit_mmap_fd(fd, flags);
if (unlikely(flags & MAP_HUGETLB)) if (unlikely(flags & MAP_HUGETLB))
return -EINVAL; return -EINVAL;
file = fget(fd); file = fget(fd);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/personality.h> #include <linux/personality.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 <asm/tlb.h> #include <asm/tlb.h>
...@@ -1458,6 +1459,7 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, ...@@ -1458,6 +1459,7 @@ SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
struct file *file = NULL; struct file *file = NULL;
unsigned long retval = -EBADF; unsigned long retval = -EBADF;
audit_mmap_fd(fd, flags);
if (!(flags & MAP_ANONYMOUS)) { if (!(flags & MAP_ANONYMOUS)) {
file = fget(fd); file = fget(fd);
if (!file) if (!file)
......
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