https://github.com/torvalds/linux
Revision ca10b9e9a8ca7342ee07065289cbe74ac128c169 authored by Eric Dumazet on 08 April 2013, 17:58:11 UTC, committed by David S. Miller on 09 April 2013, 17:23:11 UTC
Commit 90ba9b1986b5ac (tcp: tcp_make_synack() can use alloc_skb())
broke certain SELinux/NetLabel configurations by no longer correctly
assigning the sock to the outgoing SYNACK packet.

Cost of atomic operations on the LISTEN socket is quite big,
and we would like it to happen only if really needed.

This patch introduces a new security_ops->skb_owned_by() method,
that is a void operation unless selinux is active.

Reported-by: Miroslav Vadkerti <mvadkert@redhat.com>
Diagnosed-by: Paul Moore <pmoore@redhat.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-security-module@vger.kernel.org
Acked-by: James Morris <james.l.morris@oracle.com>
Tested-by: Paul Moore <pmoore@redhat.com>
Acked-by: Paul Moore <pmoore@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent c802d75
Raw File
Tip revision: ca10b9e9a8ca7342ee07065289cbe74ac128c169 authored by Eric Dumazet on 08 April 2013, 17:58:11 UTC
selinux: add a skb_owned_by() hook
Tip revision: ca10b9e
syscall.c
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/export.h>
#include <asm/syscall.h>

static int collect_syscall(struct task_struct *target, long *callno,
			   unsigned long args[6], unsigned int maxargs,
			   unsigned long *sp, unsigned long *pc)
{
	struct pt_regs *regs = task_pt_regs(target);
	if (unlikely(!regs))
		return -EAGAIN;

	*sp = user_stack_pointer(regs);
	*pc = instruction_pointer(regs);

	*callno = syscall_get_nr(target, regs);
	if (*callno != -1L && maxargs > 0)
		syscall_get_arguments(target, regs, 0, maxargs, args);

	return 0;
}

/**
 * task_current_syscall - Discover what a blocked task is doing.
 * @target:		thread to examine
 * @callno:		filled with system call number or -1
 * @args:		filled with @maxargs system call arguments
 * @maxargs:		number of elements in @args to fill
 * @sp:			filled with user stack pointer
 * @pc:			filled with user PC
 *
 * If @target is blocked in a system call, returns zero with *@callno
 * set to the the call's number and @args filled in with its arguments.
 * Registers not used for system call arguments may not be available and
 * it is not kosher to use &struct user_regset calls while the system
 * call is still in progress.  Note we may get this result if @target
 * has finished its system call but not yet returned to user mode, such
 * as when it's stopped for signal handling or syscall exit tracing.
 *
 * If @target is blocked in the kernel during a fault or exception,
 * returns zero with *@callno set to -1 and does not fill in @args.
 * If so, it's now safe to examine @target using &struct user_regset
 * get() calls as long as we're sure @target won't return to user mode.
 *
 * Returns -%EAGAIN if @target does not remain blocked.
 *
 * Returns -%EINVAL if @maxargs is too large (maximum is six).
 */
int task_current_syscall(struct task_struct *target, long *callno,
			 unsigned long args[6], unsigned int maxargs,
			 unsigned long *sp, unsigned long *pc)
{
	long state;
	unsigned long ncsw;

	if (unlikely(maxargs > 6))
		return -EINVAL;

	if (target == current)
		return collect_syscall(target, callno, args, maxargs, sp, pc);

	state = target->state;
	if (unlikely(!state))
		return -EAGAIN;

	ncsw = wait_task_inactive(target, state);
	if (unlikely(!ncsw) ||
	    unlikely(collect_syscall(target, callno, args, maxargs, sp, pc)) ||
	    unlikely(wait_task_inactive(target, state) != ncsw))
		return -EAGAIN;

	return 0;
}
EXPORT_SYMBOL_GPL(task_current_syscall);
back to top