Skip to content

Commit

Permalink
Merge branch 'upstream' of git://git.infradead.org/users/pcmoore/audit
Browse files Browse the repository at this point in the history
Pull audit fixes from Paul Moore:
 "Seven audit patches for v4.1, all bug fixes.

  The largest, and perhaps most significant commit helps resolve some
  memory pressure issues related to the inode cache and audit, there are
  also a few small commits which help resolve some timing issues with
  the audit log queue, and the rest fall into the always popular "code
  clean-up" category.

  In general, nothing really substantial, just a nice set of maintenance
  patches"

* 'upstream' of git://git.infradead.org/users/pcmoore/audit:
  audit: Remove condition which always evaluates to false
  audit: reduce mmap_sem hold for mm->exe_file
  audit: consolidate handling of mm->exe_file
  audit: code clean up
  audit: don't reset working wait time accidentally with auditd
  audit: don't lose set wait time on first successful call to audit_log_start()
  audit: move the tree pruning to a dedicated thread
  • Loading branch information
torvalds committed Apr 22, 2015
2 parents a62d016 + 724e7bf commit 27cf3a1
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 53 deletions.
47 changes: 30 additions & 17 deletions kernel/audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/file.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/atomic.h>
Expand Down Expand Up @@ -107,6 +108,7 @@ static u32 audit_rate_limit;
* When set to zero, this means unlimited. */
static u32 audit_backlog_limit = 64;
#define AUDIT_BACKLOG_WAIT_TIME (60 * HZ)
static u32 audit_backlog_wait_time_master = AUDIT_BACKLOG_WAIT_TIME;
static u32 audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
static u32 audit_backlog_wait_overflow = 0;

Expand Down Expand Up @@ -338,13 +340,13 @@ static int audit_set_backlog_limit(u32 limit)
static int audit_set_backlog_wait_time(u32 timeout)
{
return audit_do_config_change("audit_backlog_wait_time",
&audit_backlog_wait_time, timeout);
&audit_backlog_wait_time_master, timeout);
}

static int audit_set_enabled(u32 state)
{
int rc;
if (state < AUDIT_OFF || state > AUDIT_LOCKED)
if (state > AUDIT_LOCKED)
return -EINVAL;

rc = audit_do_config_change("audit_enabled", &audit_enabled, state);
Expand Down Expand Up @@ -663,7 +665,7 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
case AUDIT_MAKE_EQUIV:
/* Only support auditd and auditctl in initial pid namespace
* for now. */
if ((task_active_pid_ns(current) != &init_pid_ns))
if (task_active_pid_ns(current) != &init_pid_ns)
return -EPERM;

if (!netlink_capable(skb, CAP_AUDIT_CONTROL))
Expand Down Expand Up @@ -834,7 +836,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
s.lost = atomic_read(&audit_lost);
s.backlog = skb_queue_len(&audit_skb_queue);
s.feature_bitmap = AUDIT_FEATURE_BITMAP_ALL;
s.backlog_wait_time = audit_backlog_wait_time;
s.backlog_wait_time = audit_backlog_wait_time_master;
audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
break;
}
Expand Down Expand Up @@ -877,8 +879,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (s.mask & AUDIT_STATUS_BACKLOG_WAIT_TIME) {
if (sizeof(s) > (size_t)nlh->nlmsg_len)
return -EINVAL;
if (s.backlog_wait_time < 0 ||
s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME)
if (s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME)
return -EINVAL;
err = audit_set_backlog_wait_time(s.backlog_wait_time);
if (err < 0)
Expand Down Expand Up @@ -1385,7 +1386,8 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
return NULL;
}

audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME;
if (!reserve)
audit_backlog_wait_time = audit_backlog_wait_time_master;

ab = audit_buffer_alloc(ctx, gfp_mask, type);
if (!ab) {
Expand Down Expand Up @@ -1759,7 +1761,7 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
} else
audit_log_format(ab, " name=(null)");

if (n->ino != (unsigned long)-1) {
if (n->ino != (unsigned long)-1)
audit_log_format(ab, " inode=%lu"
" dev=%02x:%02x mode=%#ho"
" ouid=%u ogid=%u rdev=%02x:%02x",
Expand All @@ -1771,7 +1773,6 @@ void audit_log_name(struct audit_context *context, struct audit_names *n,
from_kgid(&init_user_ns, n->gid),
MAJOR(n->rdev),
MINOR(n->rdev));
}
if (n->osid != 0) {
char *ctx = NULL;
u32 len;
Expand Down Expand Up @@ -1838,11 +1839,29 @@ int audit_log_task_context(struct audit_buffer *ab)
}
EXPORT_SYMBOL(audit_log_task_context);

void audit_log_d_path_exe(struct audit_buffer *ab,
struct mm_struct *mm)
{
struct file *exe_file;

if (!mm)
goto out_null;

exe_file = get_mm_exe_file(mm);
if (!exe_file)
goto out_null;

audit_log_d_path(ab, " exe=", &exe_file->f_path);
fput(exe_file);
return;
out_null:
audit_log_format(ab, " exe=(null)");
}

void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
{
const struct cred *cred;
char comm[sizeof(tsk->comm)];
struct mm_struct *mm = tsk->mm;
char *tty;

if (!ab)
Expand Down Expand Up @@ -1878,13 +1897,7 @@ void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
audit_log_format(ab, " comm=");
audit_log_untrustedstring(ab, get_task_comm(comm, tsk));

if (mm) {
down_read(&mm->mmap_sem);
if (mm->exe_file)
audit_log_d_path(ab, " exe=", &mm->exe_file->f_path);
up_read(&mm->mmap_sem);
} else
audit_log_format(ab, " exe=(null)");
audit_log_d_path_exe(ab, tsk->mm);
audit_log_task_context(ab);
}
EXPORT_SYMBOL(audit_log_task_info);
Expand Down
3 changes: 3 additions & 0 deletions kernel/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ extern struct list_head audit_filter_list[];

extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);

extern void audit_log_d_path_exe(struct audit_buffer *ab,
struct mm_struct *mm);

/* audit watch functions */
#ifdef CONFIG_AUDIT_WATCH
extern void audit_put_watch(struct audit_watch *watch);
Expand Down
88 changes: 60 additions & 28 deletions kernel/audit_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct audit_chunk {

static LIST_HEAD(tree_list);
static LIST_HEAD(prune_list);
static struct task_struct *prune_thread;

/*
* One struct chunk is attached to each inode of interest.
Expand Down Expand Up @@ -651,6 +652,57 @@ static int tag_mount(struct vfsmount *mnt, void *arg)
return tag_chunk(mnt->mnt_root->d_inode, arg);
}

/*
* That gets run when evict_chunk() ends up needing to kill audit_tree.
* Runs from a separate thread.
*/
static int prune_tree_thread(void *unused)
{
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (list_empty(&prune_list))
schedule();
__set_current_state(TASK_RUNNING);

mutex_lock(&audit_cmd_mutex);
mutex_lock(&audit_filter_mutex);

while (!list_empty(&prune_list)) {
struct audit_tree *victim;

victim = list_entry(prune_list.next,
struct audit_tree, list);
list_del_init(&victim->list);

mutex_unlock(&audit_filter_mutex);

prune_one(victim);

mutex_lock(&audit_filter_mutex);
}

mutex_unlock(&audit_filter_mutex);
mutex_unlock(&audit_cmd_mutex);
}
return 0;
}

static int audit_launch_prune(void)
{
if (prune_thread)
return 0;
prune_thread = kthread_create(prune_tree_thread, NULL,
"audit_prune_tree");
if (IS_ERR(prune_thread)) {
pr_err("cannot start thread audit_prune_tree");
prune_thread = NULL;
return -ENOMEM;
} else {
wake_up_process(prune_thread);
return 0;
}
}

/* called with audit_filter_mutex */
int audit_add_tree_rule(struct audit_krule *rule)
{
Expand All @@ -674,6 +726,12 @@ int audit_add_tree_rule(struct audit_krule *rule)
/* do not set rule->tree yet */
mutex_unlock(&audit_filter_mutex);

if (unlikely(!prune_thread)) {
err = audit_launch_prune();
if (err)
goto Err;
}

err = kern_path(tree->pathname, 0, &path);
if (err)
goto Err;
Expand Down Expand Up @@ -811,36 +869,10 @@ int audit_tag_tree(char *old, char *new)
return failed;
}

/*
* That gets run when evict_chunk() ends up needing to kill audit_tree.
* Runs from a separate thread.
*/
static int prune_tree_thread(void *unused)
{
mutex_lock(&audit_cmd_mutex);
mutex_lock(&audit_filter_mutex);

while (!list_empty(&prune_list)) {
struct audit_tree *victim;

victim = list_entry(prune_list.next, struct audit_tree, list);
list_del_init(&victim->list);

mutex_unlock(&audit_filter_mutex);

prune_one(victim);

mutex_lock(&audit_filter_mutex);
}

mutex_unlock(&audit_filter_mutex);
mutex_unlock(&audit_cmd_mutex);
return 0;
}

static void audit_schedule_prune(void)
{
kthread_run(prune_tree_thread, NULL, "audit_prune_tree");
wake_up_process(prune_thread);
}

/*
Expand Down Expand Up @@ -907,9 +939,9 @@ static void evict_chunk(struct audit_chunk *chunk)
for (n = 0; n < chunk->count; n++)
list_del_init(&chunk->owners[n].list);
spin_unlock(&hash_lock);
mutex_unlock(&audit_filter_mutex);
if (need_prune)
audit_schedule_prune();
mutex_unlock(&audit_filter_mutex);
}

static int audit_tree_handle_event(struct fsnotify_group *group,
Expand Down
9 changes: 1 addition & 8 deletions kernel/auditsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2361,7 +2361,6 @@ static void audit_log_task(struct audit_buffer *ab)
kuid_t auid, uid;
kgid_t gid;
unsigned int sessionid;
struct mm_struct *mm = current->mm;
char comm[sizeof(current->comm)];

auid = audit_get_loginuid(current);
Expand All @@ -2376,13 +2375,7 @@ static void audit_log_task(struct audit_buffer *ab)
audit_log_task_context(ab);
audit_log_format(ab, " pid=%d comm=", task_pid_nr(current));
audit_log_untrustedstring(ab, get_task_comm(comm, current));
if (mm) {
down_read(&mm->mmap_sem);
if (mm->exe_file)
audit_log_d_path(ab, " exe=", &mm->exe_file->f_path);
up_read(&mm->mmap_sem);
} else
audit_log_format(ab, " exe=(null)");
audit_log_d_path_exe(ab, current->mm);
}

/**
Expand Down

0 comments on commit 27cf3a1

Please sign in to comment.