* Re: [PATCH 1/8] kernel/exit.c: make sure current's nsproxy != NULL while checking caps
From: Eric W. Biederman @ 2015-05-23 17:49 UTC (permalink / raw)
To: Lukasz Pawelczyk
Cc: David S. Miller, Kirill A. Shutemov, Serge E. Hallyn, Al Viro,
Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Casey Schaufler,
Christoph Hellwig, David Howells, Eric Dumazet, Fabian Frederick,
Greg KH, Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton,
Joe Perches, Jonathan Corbet, Kees Cook, Mauro Carvalho Chehab,
Michal Hocko, Miklos Szeredi, Nick
In-Reply-To: <1432209222-8479-2-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> writes:
> There is a rare case where current's nsproxy might be NULL but we are
> required to check for credentials and capabilities. It sometimes happens
> during an exit_group() syscall while destroying user's session (logging
> out).
>
> My understanding is that while we have to lock the task to get task's
> nsproxy and check whether it's NULL, for the 'current' we don't have to
> and it's expected not to be NULL. There is a code in the kernel
> currently that does current->nsproxy->user_ns without any checks.
> And include/linux/nsproxy.h confirms that:
>
> 2. when accessing (i.e. reading) current task's namespaces - no
> precautions should be taken - just dereference the pointers
>
> There seem to be no crash currently because of this, but with accessing
> nsproxy from LSM hooks there is. This is the backtrace:
>
> 0 smk_tskacc (task=0xffff88003b0b92e0, obj_known=0x2 <irq_stack_union+2>, mode=2, a=0xffff88003be53dd8) at security/smack/smack_access.c:261
> 1 0xffffffff8130e2aa in smk_curacc (obj_known=<optimized out>, mode=<optimized out>, a=<optimized out>) at security/smack/smack_access.c:318
> 2 0xffffffff8130a50d in smack_task_kill (p=0xffff88003b0b92e0, info=<optimized out>, sig=<optimized out>, secid=<optimized out>) at security/smack/smack_lsm.c:2071
> 3 0xffffffff812ea4f6 in security_task_kill (p=<optimized out>, info=<optimized out>, sig=<optimized out>, secid=<optimized out>) at security/security.c:952
> 4 0xffffffff8109ac80 in check_kill_permission (sig=15, info=0x0 <irq_stack_union>, t=0xffff88003b0b8000) at kernel/signal.c:796
> 5 0xffffffff8109d3ab in group_send_sig_info (sig=15, info=0x0 <irq_stack_union>, p=0xffff88003b0b8000) at kernel/signal.c:1296
> 6 0xffffffff8108e527 in forget_original_parent (father=<optimized out>) at kernel/exit.c:575
> 7 exit_notify (group_dead=<optimized out>, tsk=<optimized out>) at kernel/exit.c:606
> 8 do_exit (code=<optimized out>) at kernel/exit.c:775
> 9 0xffffffff8108ec0f in do_group_exit (exit_code=0) at kernel/exit.c:891
> 10 0xffffffff8108ec84 in SYSC_exit_group (error_code=<optimized out>) at kernel/exit.c:902
> 11 SyS_exit_group (error_code=<optimized out>) at kernel/exit.c:900
>
> This backtrace clearly shows that there is an LSM hook task_kill() that
> happens during an exit_group() syscall and that this happens after
> exit_task_namespaces(). LSM hooks with namespaces might need nsproxy to
> be able to check for capabilities. At this point this is impossible. The
> current's nsproxy is already NULL/destroyed.
>
> This is the case because exit_task_namespaces() is called before the
> exit_notify() where all of the above happens. This patch changes their
> order.
Nacked-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
current->nsproxy->user_ns does not exist,
and changing where exit_task_namespaces is fragile and I am really not
interested in messing with it right now, to solve a problem that does
not exist.
>
> Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
> kernel/exit.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/exit.c b/kernel/exit.c
> index 22fcc05..da1bb18 100644
> --- a/kernel/exit.c
> +++ b/kernel/exit.c
> @@ -742,7 +742,6 @@ void do_exit(long code)
> exit_fs(tsk);
> if (group_dead)
> disassociate_ctty(1);
> - exit_task_namespaces(tsk);
> exit_task_work(tsk);
> exit_thread();
>
> @@ -763,6 +762,13 @@ void do_exit(long code)
>
> TASKS_RCU(tasks_rcu_i = __srcu_read_lock(&tasks_rcu_exit_srcu));
> exit_notify(tsk, group_dead);
> +
> + /*
> + * This should be after all things that potentially require
> + * process's namespaces (e.g. capability checks).
> + */
> + exit_task_namespaces(tsk);
> +
> proc_exit_connector(tsk);
> #ifdef CONFIG_NUMA
> task_lock(tsk);
^ permalink raw reply
* Re: [RFC PATCH] percpu system call: fast userspace percpu critical sections
From: Andy Lutomirski @ 2015-05-23 19:15 UTC (permalink / raw)
To: Mathieu Desnoyers
Cc: Lai Jiangshan, Paul E. McKenney, Ben Maurer, Josh Triplett,
Ingo Molnar, Andrew Morton, Linux API, Michael Kerrisk,
Linux Kernel, Linus Torvalds, Peter Zijlstra, Paul Turner,
Steven Rostedt, Andrew Hunter
In-Reply-To: <1839774559.6579.1432400944032.JavaMail.zimbra@efficios.com>
On May 23, 2015 10:09 AM, "Mathieu Desnoyers"
<mathieu.desnoyers@efficios.com> wrote:
>
> ----- Original Message -----
> > On Fri, May 22, 2015 at 2:34 PM, Mathieu Desnoyers
> > <mathieu.desnoyers@efficios.com> wrote:
> > > ----- Original Message -----
> > >> On Fri, May 22, 2015 at 1:26 PM, Michael Kerrisk <mtk.manpages@gmail.com>
> > >> wrote:
> > >> > [CC += linux-api@]
> > >> >
> > >> > On Thu, May 21, 2015 at 4:44 PM, Mathieu Desnoyers
> > >> > <mathieu.desnoyers@efficios.com> wrote:
> > >> >> Expose a new system call allowing userspace threads to register
> > >> >> a TLS area used as an ABI between the kernel and userspace to
> > >> >> share information required to create efficient per-cpu critical
> > >> >> sections in user-space.
> > >> >>
> > >> >> This ABI consists of a thread-local structure containing:
> > >> >>
> > >> >> - a nesting count surrounding the critical section,
> > >> >> - a signal number to be sent to the thread when preempting a thread
> > >> >> with non-zero nesting count,
> > >> >> - a flag indicating whether the signal has been sent within the
> > >> >> critical section,
> > >> >> - an integer where to store the current CPU number, updated whenever
> > >> >> the thread is preempted. This CPU number cache is not strictly
> > >> >> needed, but performs better than getcpu vdso.
> > >> >>
> > >> >> This approach is inspired by Paul Turner and Andrew Hunter's work
> > >> >> on percpu atomics, which lets the kernel handle restart of critical
> > >> >> sections, ref.
> > >> >> http://www.linuxplumbersconf.org/2013/ocw/system/presentations/1695/original/LPC%20-%20PerCpu%20Atomics.pdf
> > >> >>
> > >> >> What is done differently here compared to percpu atomics: we track
> > >> >> a single nesting counter per thread rather than many ranges of
> > >> >> instruction pointer values. We deliver a signal to user-space and
> > >> >> let the logic of restart be handled in user-space, thus moving
> > >> >> the complexity out of the kernel. The nesting counter approach
> > >> >> allows us to skip the complexity of interacting with signals that
> > >> >> would be otherwise needed with the percpu atomics approach, which
> > >> >> needs to know which instruction pointers are preempted, including
> > >> >> when preemption occurs on a signal handler nested over an instruction
> > >> >> pointer of interest.
> > >> >>
> > >>
> > >> I talked about this kind of thing with PeterZ at LSF/MM, and I was
> > >> unable to convince myself that the kernel needs to help at all. To do
> > >> this without kernel help, I want to relax the requirements slightly.
> > >> With true per-cpu atomic sections, you have a guarantee that you are
> > >> either really running on the same CPU for the entire duration of the
> > >> atomic section or you abort. I propose a weaker primitive: you
> > >> acquire one of an array of locks (probably one per cpu), and you are
> > >> guaranteed that, if you don't abort, no one else acquires the same
> > >> lock while you hold it.
> > >
> > > In my proof of concept (https://github.com/compudj/percpu-dev) I
> > > actually implement an array of per-cpu lock. The issue here boils
> > > down to grabbing this per-cpu lock efficiently. Once the lock is taken,
> > > the thread has exclusive access to that per-cpu lock, even if it
> > > migrates.
> > >
> > >> Here's how:
> > >>
> > >> Create an array of user-managed locks, one per cpu. Call them lock[i]
> > >> for 0 <= i < ncpus.
> > >>
> > >> To acquire, look up your CPU number. Then, atomically, check that
> > >> lock[cpu] isn't held and, if so, mark it held and record both your tid
> > >> and your lock acquisition count. If you learn that the lock *was*
> > >> held after all, signal the holder (with kill or your favorite other
> > >> mechanism), telling it which lock acquisition count is being aborted.
> > >> Then atomically steal the lock, but only if the lock acquisition count
> > >> hasn't changed.
> > >>
> > >> This has a few benefits over the in-kernel approach:
> > >>
> > >> 1. No kernel patch.
> > >>
> > >> 2. No unnecessary abort if you are preempted in favor of a thread that
> > >> doesn't content for your lock.
> > >>
> > >> 3. Greatly improved debuggability.
> > >>
> > >> 4. With long critical sections and heavy load, you can improve
> > >> performance by having several locks per cpu and choosing one at
> > >> random.
> > >>
> > >> Is there a reason that a scheme like this doesn't work?
> > >
> > > What do you mean exactly by "atomically check that lock is not
> > > held and, if so, mark it held" ? Do you imply using a lock-prefixed
> > > atomic operation ?
> >
> > Yes.
> >
> > >
> > > The goal of this whole restart section approach is to allow grabbing
> > > a lock (or doing other sequences of operations ending with a single
> > > store) on per-cpu data without having to use slow lock-prefixed
> > > atomic operations.
> >
> > Ah, ok, I assumed it was to allow multiple threads to work in parallel.
> >
> > How arch-specific are you willing to be?
>
> I'd want this to be usable on every major architectures.
>
> > On x86, it might be possible
> > to play some GDT games so that an unlocked xchg relative
>
> AFAIK, there is no such thing as an unlocked xchg. xchg always
> imply the lock prefix on x86. I guess you mean cmpxchg here.
>
Right, got my special cases mixed up.
I wonder if we could instead have a vdso function that did something like:
unsigned long __vdso_cpu_local_exchange(unsigned long *base, int
shift, unsigned long newval)
{
unsigned long *ptr = base + (cpu << shift);
unsigned long old = *ptr;
*ptr = new;
return *ptr;
}
I think this primitive would be sufficient to let user code do the
rest. There might be other more simple primitives that would work.
It could be implemented by fiddling with IP ranges, but we could
change the implementation later without breaking anything. The only
really hard part would be efficiently figuring out what CPU we're on.
FWIW, 'xchg' to cache-hot memory is only about 20 cycles on my laptop,
and cmpxchg seems to be about 6 cycles. Both are faster than getcpu.
How much are we really saving with any of this over the pure userspace
approach? I think that the most that the kernel can possibly help us
is to give us a faster getcpu and to help us deal with being migrated
to a different cpu if we want to avoid expensive operations and don't
want to play unlocked cmpxchg tricks.
I was wrong about set_thread_area giving us efficient per-cpu data,
BTW, although it would be easy to add a similar feature that would
give us a per-cpu segment base on x86.
> > to gs would
> > work if you arranged for gs to refer to the GDT. On 32-bit userspace,
> > you can do this with set_thread_area and on 64-bit userspace you can
> > do it with arch_prctl. You'd be relying on nothing else in the
> > process using gs, but your proposal already relies on nothing else in
> > the process using your signal number.
>
> Ideally, and this is indeed a limitation of my own approach, I would
> like to be able to use this scheme from a library injected into
> processes for tracing purposes, which means that I would be tempted
> to stay away from solutions that affect the application too much.
> This includes sending a signal unfortunately.
>
> In addition, the gs approach you propose here would work as long
> as we use non-lock-prefixed atomic operations (e.g. cmpxchg), but
> it would not work for sequences of instructions that need to be
> performed over the same data (e.g. load, test, conditional branch,
> store), which performs slightly faster than non-lock-prefixed atomic
> ops.
>
> > >> >> - With Linux vdso: 12.7 ns
> > >> >> - With TLS-cached cpu number: 0.3 ns
> > >>
> > >> Slightly off-topic: try this again on a newer kernel. The vdso should
> > >> have gotten a bit faster in 3.19 or 4.0 IIRC.
> > >
> > > Those benchmarks were done on Linux 4.0.
> >
> > What cpu? I'm surprised it's that bad.
>
> Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
> (Haswell)
> Please note that I run this benchmark under a kvm guest VM, but
> I doubt it would impact these numbers.
Go figure. My laptop (SNB, 2.7GHz) can do it in 8ns or so.
>
> > (TLS-cached will always be
> > better, but still. Although I'm curious how you're making the
> > TLS-cached value work reliably enough.)
>
> What do you have in mind as possibility of having an unreliable TLS-cached
> value ?
Something like the old vdso getcpu cache -- re-read the cpu count if
it has expired since last time.
> In my approach, the tls-cached value is updated in the preempt in
> notifier, whenever the CPU number has changed compared to the value in
> user-space.
Ah, I missed that part.
This ABI is kind of unfortunate in that it can't be shared between
multiple libraries.
Accessing the TLS value from user-space is performed with the
> help of the compiler, including all the complexity involved in using a
> TLS from a library if need be (lazy allocation, internal glibc mutex, etc).
> However, since I control very precisely where in my critical section the
> execution flow can be restarted (it's only on the store operation that
> touch the write-protected memory range), there is no need to worry about
> restarting in the middle of a held lock. It also works if a system call
> is issued within the critical section (e.g. sys_futex due to lock), and
> works with function calls.
Oh, you're delivering a signal every time you're preempted, even
outside the critical section? That sounds expensive.
--Andy
^ permalink raw reply
* Re: [PATCH v2 1/2] capabilities: Ambient capabilities
From: Serge Hallyn @ 2015-05-23 19:37 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Serge Hallyn, Andrew Morton, Jarkko Sakkinen, Ted Ts'o,
Andrew G. Morgan, Linux API, Mimi Zohar, Michael Kerrisk,
Austin S Hemmelgarn, linux-security-module, Aaron Jones,
Serge Hallyn, LKML, Markku Savela, Kees Cook, Jonathan Corbet,
Christoph Lameter, Andy Lutomirski
In-Reply-To: <cc4749638a21079cce12f9f30c806170558e56e5.1431671529.git.luto-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Thanks very much, Andy. Comments and ack below.
Quoting Andy Lutomirski (luto-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org):
> Credit where credit is due: this idea comes from Christoph Lameter
> with a lot of valuable input from Serge Hallyn. This patch is
> heavily based on Christoph's patch.
>
> ===== The status quo =====
>
> On Linux, there are a number of capabilities defined by the kernel.
> To perform various privileged tasks, processes can wield
> capabilities that they hold.
>
> Each task has four capability masks: effective (pE), permitted (pP),
> inheritable (pI), and a bounding set (X). When the kernel checks
> for a capability, it checks pE. The other capability masks serve to
> modify what capabilities can be in pE.
>
> Any task can remove capabilities from pE, pP, or pI at any time. If
> a task has a capability in pP, it can add that capability to pE
> and/or pI. If a task has CAP_SETPCAP, then it can add any
> capability to pI, and it can remove capabilities from X.
>
> Tasks are not the only things that can have capabilities; files can
> also have capabilities. A file can have no capabilty information at
> all [1]. If a file has capability information, then it has a
> permitted mask (fP) and an inheritable mask (fI) as well as a single
> effective bit (fE) [2]. File capabilities modify the capabilities
> of tasks that execve(2) them.
>
> A task that successfully calls execve has its capabilities modified
> for the file ultimately being excecuted (i.e. the binary itself if
> that binary is ELF or for the interpreter if the binary is a
> script.) [3] In the capability evolution rules, for each mask Z, pZ
> represents the old value and pZ' represents the new value. The
> rules are:
>
> pP' = (X & fP) | (pI & fI)
> pI' = pI
> pE' = (fE ? pP' : 0)
> X is unchanged
>
> For setuid binaries, fP, fI, and fE are modified by a moderately
> complicated set of rules that emulate POSIX behavior. Similarly, if
> euid == 0 or ruid == 0, then fP, fI, and fE are modified differently
> (primary, fP and fI usually end up being the full set). For nonroot
> users executing binaries with neither setuid nor file caps, fI and
> fP are empty and fE is false.
>
> As an extra complication, if you execute a process as nonroot and fE
> is set, then the "secure exec" rules are in effect: AT_SECURE gets
> set, LD_PRELOAD doesn't work, etc.
>
> This is rather messy. We've learned that making any changes is
> dangerous, though: if a new kernel version allows an unprivileged
> program to change its security state in a way that persists cross
> execution of a setuid program or a program with file caps, this
> persistent state is surprisingly likely to allow setuid or
> file-capped programs to be exploited for privilege escalation.
>
> ===== The problem =====
>
> Capability inheritance is basically useless.
>
> If you aren't root and you execute an ordinary binary, fI is zero,
> so your capabilities have no effect whatsoever on pP'. This means
> that you can't usefully execute a helper process or a shell command
> with elevated capabilities if you aren't root.
>
> On current kernels, you can sort of work around this by setting fI
> to the full set for most or all non-setuid executable files. This
> causes pP' = pI for nonroot, and inheritance works. No one does
> this because it's a PITA and it isn't even supported on most
> filesystems.
>
> If you try this, you'll discover that every nonroot program ends up
> with secure exec rules, breaking many things.
PI would have worked great if most programs wanting privilege were
self-contained and compiled. Shell scripts and lots of fork+execing
make pI [much less useful] [completely useless]. See also golang's
predisposition to fork+exec.
> This is a problem that has bitten many people who have tried to use
> capabilities for anything useful.
>
> ===== The proposed change =====
>
> This patch adds a fifth capability mask called the ambient mask
> (pA). pA does what pI should have done.
Or at least what most people want it to do.
> pA obeys the invariant that no bit can ever be set in pA if it is
> not set in both pP and pI. Dropping a bit from pP or pI drops that
> bit from pA. This ensures that existing programs that try to drop
> capabilities still do so, with a complication. Because capability
> inheritance is so broken, setting KEEPCAPS, using setresuid to
Sorry, did you mean "... setting KEEPCAPS and then either using
setresuid to a nonroot uid or calling execve ..." ?
> switch to nonroot uids, or calling execve effectively drops
> capabilities. Therefore, setresuid from root to nonroot
> conditionally clears pA unless SECBIT_NO_SETUID_FIXUP is set.
> Processes that don't like this can re-add bits to pA afterwards.
>
> The capability evolution rules are changed:
>
> pA' = (file caps or setuid or setgid ? 0 : pA)
> pP' = (X & fP) | (pI & fI) | pA'
> pI' = pI
> pE' = (fE ? pP' : pA')
> X is unchanged
>
> If you are nonroot but you have a capability, you can add it to pA.
> If you do so, your children get that capability in pA, pP, and pE.
> For example, you can set pA = CAP_NET_BIND_SERVICE, and your
> children can automatically bind low-numbered ports. Hallelujah!
>
> Unprivileged users can create user namespaces, map themselves to a
> nonzero uid, and create both privileged (relative to their
> namespace) and unprivileged process trees. This is currently more
> or less impossible. Hallelujah!
>
> You cannot use pA to try to subvert a setuid, setgid, or file-capped
> program: if you execute any such program, pA gets cleared and the
> resulting evolution rules are unchanged by this patch.
Christoph, just to be sure, is this ^ going to suffice for you?
Seems like it should since any program which is setuid-root, i.e.
passwd, isn't likely to be designed to exec other programs.
> Users with nonzero pA are unlikely to unintentionally leak that
> capability. If they run programs that try to drop privileges,
> dropping privileges will still work.
>
> It's worth noting that the degree of paranoia in this patch could
> possibly be reduced without causing serious problems. Specifically,
> if we allowed pA to persist across executing non-pA-aware setuid
> binaries and across setresuid, then, naively, the only capabilities
> that could leak as a result would be the capabilities in pA, and any
> attacker *already* has those capabilities. This would make me
> nervous, though -- setuid binaries that tried to privilege-separate
> might fail to do so, and putting CAP_DAC_READ_SEARCH or
> CAP_DAC_OVERRIDE into pA could have unexpected side effects.
> (Whether these unexpected side effects would be exploitable is an
> open question.) I've therefore taken the more paranoid route.
I'm definitely open to revisiting this question after the current
patch has been in use for awhile.
> An alternative would be to require PR_SET_NO_NEW_PRIVS before
> setting ambient capabilities. I think that this would be annoying
> and would make granting otherwise unprivileged users minor ambient
> capabilities (CAP_NET_BIND_SERVICE or CAP_NET_RAW for example) much
> less useful than it is with this patch.
>
> ===== Footnotes =====
>
> [1] Files that are missing the "security.capability" xattr or that
> have unrecognized values for that xattr end up with has_cap set to
> false. The code that does that appears to be complicated for no
> good reason.
>
> [2] The libcap capability mask parsers and formatters are
> dangerously misleading and the documentation is flat-out wrong. fE
> is *not* a mask; it's a single bit. This has probably confused
> every single person who has tried to use file capabilities.
>
> [3] Linux very confusingly processes both the script and the
> interpreter if applicable, for reasons that elude me. The results
> from thinking about a script's file capabilities and/or setuid bits
> are mostly discarded.
Not quite sure what you mean here - setuid and fX are ignored on
shell scripts, but I think you're saying something less simple is
going on?
> Cc: Kees Cook <keescook-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Cc: Christoph Lameter <cl-vYTEC60ixJUAvxtiuMwx3w@public.gmane.org>
> Cc: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> Cc: Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org>
> Cc: Jonathan Corbet <corbet-T1hC0tSOHrs@public.gmane.org>
> Cc: Aaron Jones <aaronmdjones-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> CC: Ted Ts'o <tytso-3s7WtUTddSA@public.gmane.org>
> Cc: linux-security-module-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: akpm-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org
> Cc: Andrew G. Morgan <morgan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Mimi Zohar <zohar-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
> Cc: Austin S Hemmelgarn <ahferroin7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Markku Savela <msa-kXoF896ld44xHbG02/KK1g@public.gmane.org>
> Cc: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Cc: Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Andy Lutomirski <luto-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Acked-by: Serge E. Hallyn <serge.hallyn-GeWIH/nMZzLQT0dZR+AlfA@public.gmane.org>
> ---
> fs/proc/array.c | 5 ++-
> include/linux/cred.h | 8 ++++
> include/uapi/linux/prctl.h | 6 +++
> kernel/user_namespace.c | 1 +
> security/commoncap.c | 87 +++++++++++++++++++++++++++++++++++++++-----
> security/keys/process_keys.c | 1 +
> 6 files changed, 97 insertions(+), 11 deletions(-)
>
> diff --git a/fs/proc/array.c b/fs/proc/array.c
> index 1295a00ca316..bc15356d6551 100644
> --- a/fs/proc/array.c
> +++ b/fs/proc/array.c
> @@ -282,7 +282,8 @@ static void render_cap_t(struct seq_file *m, const char *header,
> static inline void task_cap(struct seq_file *m, struct task_struct *p)
> {
> const struct cred *cred;
> - kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset;
> + kernel_cap_t cap_inheritable, cap_permitted, cap_effective,
> + cap_bset, cap_ambient;
>
> rcu_read_lock();
> cred = __task_cred(p);
> @@ -290,12 +291,14 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p)
> cap_permitted = cred->cap_permitted;
> cap_effective = cred->cap_effective;
> cap_bset = cred->cap_bset;
> + cap_ambient = cred->cap_ambient;
> rcu_read_unlock();
>
> render_cap_t(m, "CapInh:\t", &cap_inheritable);
> render_cap_t(m, "CapPrm:\t", &cap_permitted);
> render_cap_t(m, "CapEff:\t", &cap_effective);
> render_cap_t(m, "CapBnd:\t", &cap_bset);
> + render_cap_t(m, "CapAmb:\t", &cap_ambient);
> }
>
> static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
> diff --git a/include/linux/cred.h b/include/linux/cred.h
> index 2fb2ca2127ed..05178874e771 100644
> --- a/include/linux/cred.h
> +++ b/include/linux/cred.h
> @@ -122,6 +122,7 @@ struct cred {
> kernel_cap_t cap_permitted; /* caps we're permitted */
> kernel_cap_t cap_effective; /* caps we can actually use */
> kernel_cap_t cap_bset; /* capability bounding set */
> + kernel_cap_t cap_ambient; /* Ambient capability set */
> #ifdef CONFIG_KEYS
> unsigned char jit_keyring; /* default keyring to attach requested
> * keys to */
> @@ -197,6 +198,13 @@ static inline void validate_process_creds(void)
> }
> #endif
>
> +static inline bool cap_ambient_invariant_ok(const struct cred *cred)
> +{
> + return cap_issubset(cred->cap_ambient,
> + cap_intersect(cred->cap_permitted,
> + cred->cap_inheritable));
> +}
> +
> /**
> * get_new_cred - Get a reference on a new set of credentials
> * @cred: The new credentials to reference
> diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
> index 31891d9535e2..65407f867e82 100644
> --- a/include/uapi/linux/prctl.h
> +++ b/include/uapi/linux/prctl.h
> @@ -190,4 +190,10 @@ struct prctl_mm_map {
> # define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
> # define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
>
> +/* Control the ambient capability set */
> +#define PR_CAP_AMBIENT 47
> +# define PR_CAP_AMBIENT_GET 1
> +# define PR_CAP_AMBIENT_RAISE 2
> +# define PR_CAP_AMBIENT_LOWER 3
> +
> #endif /* _LINUX_PRCTL_H */
> diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
> index 4109f8320684..dab0f808235a 100644
> --- a/kernel/user_namespace.c
> +++ b/kernel/user_namespace.c
> @@ -39,6 +39,7 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
> cred->cap_inheritable = CAP_EMPTY_SET;
> cred->cap_permitted = CAP_FULL_SET;
> cred->cap_effective = CAP_FULL_SET;
> + cred->cap_ambient = CAP_EMPTY_SET;
> cred->cap_bset = CAP_FULL_SET;
> #ifdef CONFIG_KEYS
> key_put(cred->request_key_auth);
> diff --git a/security/commoncap.c b/security/commoncap.c
> index f66713bd7450..09541a6a85a0 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -272,6 +272,16 @@ int cap_capset(struct cred *new,
> new->cap_effective = *effective;
> new->cap_inheritable = *inheritable;
> new->cap_permitted = *permitted;
> +
> + /*
> + * Mask off ambient bits that are no longer both permitted and
> + * inheritable.
> + */
> + new->cap_ambient = cap_intersect(new->cap_ambient,
> + cap_intersect(*permitted,
> + *inheritable));
> + if (WARN_ON(!cap_ambient_invariant_ok(new)))
This seems redundant (but safe) in this particular case since you've just
calculated it to be precisely (pA & pP & pI)
> + return -EINVAL;
> return 0;
> }
>
> @@ -352,6 +362,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
>
> /*
> * pP' = (X & fP) | (pI & fI)
> + * The addition of pA' is handled later.
> */
> new->cap_permitted.cap[i] =
> (new->cap_bset.cap[i] & permitted) |
> @@ -479,10 +490,13 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
> {
> const struct cred *old = current_cred();
> struct cred *new = bprm->cred;
> - bool effective, has_cap = false;
> + bool effective, has_cap = false, is_setid;
> int ret;
> kuid_t root_uid;
>
> + if (WARN_ON(!cap_ambient_invariant_ok(old)))
> + return -EPERM;
> +
> effective = false;
> ret = get_file_caps(bprm, &effective, &has_cap);
> if (ret < 0)
> @@ -527,8 +541,9 @@ skip:
> *
> * In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
> */
> - if ((!uid_eq(new->euid, old->uid) ||
> - !gid_eq(new->egid, old->gid) ||
> + is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid);
> +
> + if ((is_setid ||
> !cap_issubset(new->cap_permitted, old->cap_permitted)) &&
> bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
> /* downgrade; they get no more than they had, and maybe less */
> @@ -544,10 +559,24 @@ skip:
> new->suid = new->fsuid = new->euid;
> new->sgid = new->fsgid = new->egid;
>
> + /* File caps or setid cancels ambient. */
> + if (has_cap || is_setid)
> + cap_clear(new->cap_ambient);
> +
> + /*
> + * Now that we've computed pA', update pP' to give:
> + * pP' = (X & fP) | (pI & fI) | pA'
> + */
> + new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient);
> +
> if (effective)
> new->cap_effective = new->cap_permitted;
> else
> - cap_clear(new->cap_effective);
> + new->cap_effective = new->cap_ambient;
> +
> + if (WARN_ON(!cap_ambient_invariant_ok(new)))
> + return -EPERM;
> +
> bprm->cap_effective = effective;
>
> /*
> @@ -562,7 +591,7 @@ skip:
> * Number 1 above might fail if you don't have a full bset, but I think
> * that is interesting information to audit.
> */
> - if (!cap_isclear(new->cap_effective)) {
> + if (!cap_issubset(new->cap_effective, new->cap_ambient)) {
> if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
> !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
> issecure(SECURE_NOROOT)) {
> @@ -573,6 +602,10 @@ skip:
> }
>
> new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
> +
> + if (WARN_ON(!cap_ambient_invariant_ok(new)))
> + return -EPERM;
> +
> return 0;
> }
>
> @@ -594,7 +627,7 @@ int cap_bprm_secureexec(struct linux_binprm *bprm)
> if (!uid_eq(cred->uid, root_uid)) {
> if (bprm->cap_effective)
> return 1;
> - if (!cap_isclear(cred->cap_permitted))
> + if (!cap_issubset(cred->cap_permitted, cred->cap_ambient))
> return 1;
> }
>
> @@ -696,10 +729,18 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
> uid_eq(old->suid, root_uid)) &&
> (!uid_eq(new->uid, root_uid) &&
> !uid_eq(new->euid, root_uid) &&
> - !uid_eq(new->suid, root_uid)) &&
> - !issecure(SECURE_KEEP_CAPS)) {
> - cap_clear(new->cap_permitted);
> - cap_clear(new->cap_effective);
> + !uid_eq(new->suid, root_uid))) {
> + if (!issecure(SECURE_KEEP_CAPS)) {
> + cap_clear(new->cap_permitted);
> + cap_clear(new->cap_effective);
> + }
> +
> + /*
> + * Pre-ambient programs except setresuid to nonroot followed
[ I see 'except' has already been pointed out in the thread :) ]
> + * by exec to drop capabilities. We should make sure that
> + * this remains the case.
> + */
> + cap_clear(new->cap_ambient);
> }
> if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
> cap_clear(new->cap_effective);
> @@ -929,6 +970,32 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
> new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
> return commit_creds(new);
>
> + case PR_CAP_AMBIENT:
> + if (((!cap_valid(arg3)) | arg4 | arg5))
> + return -EINVAL;
> +
> + if (arg2 == PR_CAP_AMBIENT_GET) {
> + return !!cap_raised(current_cred()->cap_ambient, arg3);
> + } else if (arg2 != PR_CAP_AMBIENT_RAISE &&
> + arg2 != PR_CAP_AMBIENT_LOWER) {
> + return -EINVAL;
> + } else {
> + if (arg2 == PR_CAP_AMBIENT_RAISE &&
> + (!cap_raised(current_cred()->cap_permitted, arg3) ||
> + !cap_raised(current_cred()->cap_inheritable,
> + arg3)))
> + return -EPERM;
> +
> + new = prepare_creds();
> + if (!new)
> + return -ENOMEM;
> + if (arg2 == PR_CAP_AMBIENT_RAISE)
> + cap_raise(new->cap_ambient, arg3);
> + else
> + cap_lower(new->cap_ambient, arg3);
> + return commit_creds(new);
> + }
> +
> default:
> /* No functionality available - continue with default */
> return -ENOSYS;
> diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
> index bd536cb221e2..43b4cddbf2b3 100644
> --- a/security/keys/process_keys.c
> +++ b/security/keys/process_keys.c
> @@ -848,6 +848,7 @@ void key_change_session_keyring(struct callback_head *twork)
> new->cap_inheritable = old->cap_inheritable;
> new->cap_permitted = old->cap_permitted;
> new->cap_effective = old->cap_effective;
> + new->cap_ambient = old->cap_ambient;
> new->cap_bset = old->cap_bset;
>
> new->jit_keyring = old->jit_keyring;
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH v2 2/2] capabilities: Add a securebit to disable PR_CAP_AMBIENT_RAISE
From: Serge E. Hallyn @ 2015-05-23 19:45 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Serge Hallyn, Andrew Morton, Jarkko Sakkinen, Ted Ts'o,
Andrew G. Morgan, Linux API, Mimi Zohar, Michael Kerrisk,
Austin S Hemmelgarn, linux-security-module, Aaron Jones,
Serge Hallyn, LKML, Markku Savela, Kees Cook, Jonathan Corbet,
Christoph Lameter, Andy Lutomirski
In-Reply-To: <003b2a2d3e6ad9f4853e248d853f73448ca7b002.1431671529.git.luto-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On Thu, May 14, 2015 at 11:39:49PM -0700, Andy Lutomirski wrote:
> Per Andrew Morgan's request, add a securebit to allow admins to
> disable PR_CAP_AMBIENT_RAISE. This securebit will prevent processes
> from adding capabilities to their ambient set.
>
> For simplicity, this disables PR_CAP_AMBIENT_RAISE entirely rather
> than just disabling setting previously cleared bits.
>
> Requested-by: Andrew G. Morgan <morgan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Kees Cook <keescook-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Cc: Christoph Lameter <cl-vYTEC60ixJUAvxtiuMwx3w@public.gmane.org>
> Cc: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> Cc: Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org>
> Cc: Jonathan Corbet <corbet-T1hC0tSOHrs@public.gmane.org>
> Cc: Aaron Jones <aaronmdjones-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> CC: Ted Ts'o <tytso-3s7WtUTddSA@public.gmane.org>
> Cc: linux-security-module-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Cc: akpm-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org
> Cc: Andrew G. Morgan <morgan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Mimi Zohar <zohar-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
> Cc: Austin S Hemmelgarn <ahferroin7-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Markku Savela <msa-kXoF896ld44xHbG02/KK1g@public.gmane.org>
> Cc: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Cc: Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Andy Lutomirski <luto-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Interesting - at first I thought this wouldn't please Andrew as he'd
want the inverse, but I guess this way keeps the pure-capabilities
mode (with SECURE_ALL_BITS set) ambient-free which I suppose is
really the important thing.
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> ---
> include/uapi/linux/securebits.h | 11 ++++++++++-
> security/commoncap.c | 3 ++-
> 2 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/include/uapi/linux/securebits.h b/include/uapi/linux/securebits.h
> index 985aac9e6bf8..35ac35cef217 100644
> --- a/include/uapi/linux/securebits.h
> +++ b/include/uapi/linux/securebits.h
> @@ -43,9 +43,18 @@
> #define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS))
> #define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED))
>
> +/* When set, a process cannot add new capabilities to its ambient set. */
> +#define SECURE_NO_CAP_AMBIENT_RAISE 6
> +#define SECURE_NO_CAP_AMBIENT_RAISE_LOCKED 7 /* make bit-6 immutable */
> +
> +#define SECBIT_NO_CAP_AMBIENT_RAISE (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE))
> +#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED \
> + (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED))
> +
> #define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
> issecure_mask(SECURE_NO_SETUID_FIXUP) | \
> - issecure_mask(SECURE_KEEP_CAPS))
> + issecure_mask(SECURE_KEEP_CAPS) | \
> + issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE))
> #define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1)
>
> #endif /* _UAPI_LINUX_SECUREBITS_H */
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 09541a6a85a0..98aa1b129c12 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -983,7 +983,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
> if (arg2 == PR_CAP_AMBIENT_RAISE &&
> (!cap_raised(current_cred()->cap_permitted, arg3) ||
> !cap_raised(current_cred()->cap_inheritable,
> - arg3)))
> + arg3) ||
> + issecure(SECURE_NO_CAP_AMBIENT_RAISE)))
> return -EPERM;
>
> new = prepare_creds();
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH v2] Documentation/arch: Add kernel feature descriptions and arch support status under Documentation/features/
From: Jonathan Corbet @ 2015-05-24 18:44 UTC (permalink / raw)
To: Ingo Molnar
Cc: Andrew Morton, Josh Triplett, Borislav Petkov, Peter Zijlstra,
Andy Lutomirski, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Linus Torvalds, linux-api, linux-kernel, x86, linux-arch
In-Reply-To: <20150523080704.GA25893@gmail.com>
On Sat, 23 May 2015 10:07:05 +0200
Ingo Molnar <mingo@kernel.org> wrote:
> > This seems to have slowed down a bit; I've taken the liberty of
> > pulling it into the docs tree. [...]
>
> Please don't, I've got a different structure for it, so that the Git
> log becomes a lot more usable. I'll post it after the weekend.
OK, fine, dropped.
Thanks,
jon
^ permalink raw reply
* Re: [PATCH v2 2/2] capabilities: Add a securebit to disable PR_CAP_AMBIENT_RAISE
From: Andrew G. Morgan @ 2015-05-24 20:39 UTC (permalink / raw)
To: Serge E. Hallyn, Andy Lutomirski
Cc: Serge Hallyn, Andrew Morton, Jarkko Sakkinen, Ted Ts'o,
Linux API, Mimi Zohar, Michael Kerrisk, Austin S Hemmelgarn,
linux-security-module, Aaron Jones, Serge Hallyn, LKML,
Markku Savela, Kees Cook, Jonathan Corbet, Christoph Lameter,
Andy Lutomirski
In-Reply-To: <20150523194535.GB30563@mail.hallyn.com>
Thanks
Acked-By: Andrew G. Morgan <morgan@kernel.org>
On Sat, May 23, 2015 at 12:45 PM, Serge E. Hallyn <serge@hallyn.com> wrote:
> On Thu, May 14, 2015 at 11:39:49PM -0700, Andy Lutomirski wrote:
>> Per Andrew Morgan's request, add a securebit to allow admins to
>> disable PR_CAP_AMBIENT_RAISE. This securebit will prevent processes
>> from adding capabilities to their ambient set.
>>
>> For simplicity, this disables PR_CAP_AMBIENT_RAISE entirely rather
>> than just disabling setting previously cleared bits.
>>
>> Requested-by: Andrew G. Morgan <morgan@kernel.org>
>> Cc: Kees Cook <keescook@chromium.org>
>> Cc: Christoph Lameter <cl@linux.com>
>> Cc: Serge Hallyn <serge.hallyn@canonical.com>
>> Cc: Andy Lutomirski <luto@amacapital.net>
>> Cc: Jonathan Corbet <corbet@lwn.net>
>> Cc: Aaron Jones <aaronmdjones@gmail.com>
>> CC: Ted Ts'o <tytso@mit.edu>
>> Cc: linux-security-module@vger.kernel.org
>> Cc: linux-kernel@vger.kernel.org
>> Cc: linux-api@vger.kernel.org
>> Cc: akpm@linuxfoundation.org
>> Cc: Andrew G. Morgan <morgan@kernel.org>
>> Cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
>> Cc: Austin S Hemmelgarn <ahferroin7@gmail.com>
>> Cc: Markku Savela <msa@moth.iki.fi>
>> Cc: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
>> Cc: Michael Kerrisk <mtk.manpages@gmail.com>
>> Signed-off-by: Andy Lutomirski <luto@kernel.org>
>
> Interesting - at first I thought this wouldn't please Andrew as he'd
> want the inverse, but I guess this way keeps the pure-capabilities
> mode (with SECURE_ALL_BITS set) ambient-free which I suppose is
> really the important thing.
>
> Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
>
>> ---
>> include/uapi/linux/securebits.h | 11 ++++++++++-
>> security/commoncap.c | 3 ++-
>> 2 files changed, 12 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/uapi/linux/securebits.h b/include/uapi/linux/securebits.h
>> index 985aac9e6bf8..35ac35cef217 100644
>> --- a/include/uapi/linux/securebits.h
>> +++ b/include/uapi/linux/securebits.h
>> @@ -43,9 +43,18 @@
>> #define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS))
>> #define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED))
>>
>> +/* When set, a process cannot add new capabilities to its ambient set. */
>> +#define SECURE_NO_CAP_AMBIENT_RAISE 6
>> +#define SECURE_NO_CAP_AMBIENT_RAISE_LOCKED 7 /* make bit-6 immutable */
>> +
>> +#define SECBIT_NO_CAP_AMBIENT_RAISE (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE))
>> +#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED \
>> + (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED))
>> +
>> #define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
>> issecure_mask(SECURE_NO_SETUID_FIXUP) | \
>> - issecure_mask(SECURE_KEEP_CAPS))
>> + issecure_mask(SECURE_KEEP_CAPS) | \
>> + issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE))
>> #define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1)
>>
>> #endif /* _UAPI_LINUX_SECUREBITS_H */
>> diff --git a/security/commoncap.c b/security/commoncap.c
>> index 09541a6a85a0..98aa1b129c12 100644
>> --- a/security/commoncap.c
>> +++ b/security/commoncap.c
>> @@ -983,7 +983,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
>> if (arg2 == PR_CAP_AMBIENT_RAISE &&
>> (!cap_raised(current_cred()->cap_permitted, arg3) ||
>> !cap_raised(current_cred()->cap_inheritable,
>> - arg3)))
>> + arg3) ||
>> + issecure(SECURE_NO_CAP_AMBIENT_RAISE)))
>> return -EPERM;
>>
>> new = prepare_creds();
>> --
>> 2.1.0
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH v9 1/5] dt-bindings: Document the STM32 timer bindings
From: Daniel Lezcano @ 2015-05-24 21:07 UTC (permalink / raw)
To: Maxime Coquelin, Arnd Bergmann, Greg Kroah-Hartman,
Daniel Thompson, Kamil Lulko,
u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Russell King, Thomas Gleixner, Jiri Slaby,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1432328616-16964-2-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On 05/22/2015 11:03 PM, Maxime Coquelin wrote:
> This adds documentation of device tree bindings for the
> STM32 timer.
>
> Tested-by: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Applied to my tree for 4.2.
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH v9 2/5] clockevents/drivers: Add STM32 Timer driver
From: Daniel Lezcano @ 2015-05-24 21:07 UTC (permalink / raw)
To: Maxime Coquelin, Arnd Bergmann, Greg Kroah-Hartman,
Daniel Thompson, Kamil Lulko,
u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
geert-Td1EMuHUCqxL1ZNQvxDV9g
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Russell King, Thomas Gleixner, Jiri Slaby,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1432328616-16964-3-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On 05/22/2015 11:03 PM, Maxime Coquelin wrote:
> STM32 MCUs feature 16 and 32 bits general purpose timers with prescalers.
> The drivers detects whether the time is 16 or 32 bits, and applies a
> 1024 prescaler value if it is 16 bits.
>
> Reviewed-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Tested-by: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Applied to my tree for 4.2
Thanks !
-- Daniel
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH 1/8] kernel/exit.c: make sure current's nsproxy != NULL while checking caps
From: Lukasz Pawelczyk @ 2015-05-25 11:33 UTC (permalink / raw)
To: Eric W. Biederman
Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Howells, Eric Dumazet,
Ingo Molnar, Jonathan Corbet, Ionut Alexa, Lukasz Pawelczyk,
Christoph Hellwig, Jeff Layton, Stephen Smalley, Alexey Dobriyan,
Rik van Riel, Kees Cook, Mauro Carvalho Chehab, Fabian Frederick,
Casey Schaufler, Al Viro, James Morris, Kirill A. Shutemov,
Michal Hocko, Peter Hurley, Rafal Krypa, Greg KH
In-Reply-To: <878ucf2nh4.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>
On sob, 2015-05-23 at 12:49 -0500, Eric W. Biederman wrote:
> Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> writes:
>
> > There is a rare case where current's nsproxy might be NULL but we are
> > required to check for credentials and capabilities. It sometimes happens
> > during an exit_group() syscall while destroying user's session (logging
> > out).
> >
> > My understanding is that while we have to lock the task to get task's
> > nsproxy and check whether it's NULL, for the 'current' we don't have to
> > and it's expected not to be NULL. There is a code in the kernel
> > currently that does current->nsproxy->user_ns without any checks.
> > And include/linux/nsproxy.h confirms that:
> >
> > 2. when accessing (i.e. reading) current task's namespaces - no
> > precautions should be taken - just dereference the pointers
> >
> > There seem to be no crash currently because of this, but with accessing
> > nsproxy from LSM hooks there is. This is the backtrace:
> >
> > 0 smk_tskacc (task=0xffff88003b0b92e0, obj_known=0x2 <irq_stack_union+2>, mode=2, a=0xffff88003be53dd8) at security/smack/smack_access.c:261
> > 1 0xffffffff8130e2aa in smk_curacc (obj_known=<optimized out>, mode=<optimized out>, a=<optimized out>) at security/smack/smack_access.c:318
> > 2 0xffffffff8130a50d in smack_task_kill (p=0xffff88003b0b92e0, info=<optimized out>, sig=<optimized out>, secid=<optimized out>) at security/smack/smack_lsm.c:2071
> > 3 0xffffffff812ea4f6 in security_task_kill (p=<optimized out>, info=<optimized out>, sig=<optimized out>, secid=<optimized out>) at security/security.c:952
> > 4 0xffffffff8109ac80 in check_kill_permission (sig=15, info=0x0 <irq_stack_union>, t=0xffff88003b0b8000) at kernel/signal.c:796
> > 5 0xffffffff8109d3ab in group_send_sig_info (sig=15, info=0x0 <irq_stack_union>, p=0xffff88003b0b8000) at kernel/signal.c:1296
> > 6 0xffffffff8108e527 in forget_original_parent (father=<optimized out>) at kernel/exit.c:575
> > 7 exit_notify (group_dead=<optimized out>, tsk=<optimized out>) at kernel/exit.c:606
> > 8 do_exit (code=<optimized out>) at kernel/exit.c:775
> > 9 0xffffffff8108ec0f in do_group_exit (exit_code=0) at kernel/exit.c:891
> > 10 0xffffffff8108ec84 in SYSC_exit_group (error_code=<optimized out>) at kernel/exit.c:902
> > 11 SyS_exit_group (error_code=<optimized out>) at kernel/exit.c:900
> >
> > This backtrace clearly shows that there is an LSM hook task_kill() that
> > happens during an exit_group() syscall and that this happens after
> > exit_task_namespaces(). LSM hooks with namespaces might need nsproxy to
> > be able to check for capabilities. At this point this is impossible. The
> > current's nsproxy is already NULL/destroyed.
> >
> > This is the case because exit_task_namespaces() is called before the
> > exit_notify() where all of the above happens. This patch changes their
> > order.
>
> Nacked-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
>
> current->nsproxy->user_ns does not exist,
> and changing where exit_task_namespaces is fragile and I am really not
> interested in messing with it right now, to solve a problem that does
> not exist.
I must have missed the moment where current->nsproxy->user_ns was
removed. I obviously even don't use it in my patches anymore (replaced
with cred->user_ns).
Back when I started to write my patches and wanted to use
current->nsproxy->user_ns in LSM hooks the problem was real.
Fortunately current->cred->user_ns does not exhibit the same issue. I'll
drop this patch.
Sorry for the confusion.
>
> >
> > Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> > ---
> > kernel/exit.c | 8 +++++++-
> > 1 file changed, 7 insertions(+), 1 deletion(-)
> >
> > diff --git a/kernel/exit.c b/kernel/exit.c
> > index 22fcc05..da1bb18 100644
> > --- a/kernel/exit.c
> > +++ b/kernel/exit.c
> > @@ -742,7 +742,6 @@ void do_exit(long code)
> > exit_fs(tsk);
> > if (group_dead)
> > disassociate_ctty(1);
> > - exit_task_namespaces(tsk);
> > exit_task_work(tsk);
> > exit_thread();
> >
> > @@ -763,6 +762,13 @@ void do_exit(long code)
> >
> > TASKS_RCU(tasks_rcu_i = __srcu_read_lock(&tasks_rcu_exit_srcu));
> > exit_notify(tsk, group_dead);
> > +
> > + /*
> > + * This should be after all things that potentially require
> > + * process's namespaces (e.g. capability checks).
> > + */
> > + exit_task_namespaces(tsk);
> > +
> > proc_exit_connector(tsk);
> > #ifdef CONFIG_NUMA
> > task_lock(tsk);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Lukasz Pawelczyk
Samsung R&D Institute Poland
Samsung Electronics
^ permalink raw reply
* [PATCH v2 0/7] Smack namespace
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Hello,
Some time ago I sent a Smack namespace documentation and a preliminary
LSM namespace for RFC. I've been suggested that there shouldn't be a
separate LSM namespace and that it should live within user namespace.
And this version does. This is a complete set of patches required for
Smack namespace.
This was designed with a collaboration of Smack maintainer Casey
Schaufler.
Smack namespace have been implemented using user namespace hooks added
by one of the patches. To put some context to it I paste here a
documentation on what Smack namespace wants to achieve.
LSM hooks themselves are documented in the security.h file inside the
patch.
The patches are based on:
https://github.com/cschaufler/smack-next/tree/smack-for-4.2-stacked
The tree with them is avaiable here:
https://github.com/Havner/smack-namespace/tree/smack-namespace-for-4.2-stacked-v2
Changes from v1:
- "kernel/exit.c: make sure current's nsproxy != NULL while checking
caps" patch has been dropped
- fixed the title of the user_ns operations patch
===================================================================
--- What is a Smack namespace ---
Smack namespace was developed to make it possible for Smack to work
nicely with Linux containers where there is a full operating system
with its own init inside the namespace. Such a system working with
Smack expects to have at least partially working SMACK_MAC_ADMIN to be
able to change labels of processes and files. This is required to be
able to securely start applications under the control of Smack and
manage their access rights.
It was implemented using new LSM hooks added to the user namespace
that were developed together with Smack namespace.
--- Design ideas ---
"Smack namespace" is rather "Smack labels namespace" as not the whole
MAC is namespaced, only the labels. There is a great analogy between
Smack labels namespace and the user namespace part that remaps UIDs.
The idea is to create a map of labels for a namespace so the namespace
is only allowed to use those labels. Smack rules are always the same
as in the init namespace (limited only by what labels are mapped) and
cannot be manipulated from the child namespace. The map is actually
only for labels' names. The underlying structures for labels remain
the same. The filesystem also stores the "unmapped" labels from the
init namespace.
Let's say we have those labels in the init namespace:
label1
label2
label3
and those rules:
label1 label2 rwx
label1 label3 rwx
label2 label3 rwx
We create a map for a namespace:
label1 -> mapped1
label2 -> mapped2
This means that 'label3' is completely invisible in the namespace. As if
it didn't exist. All the rules that include it are ignored.
Effectively in the namespace we have only one rule:
mapped1 mapped2 rwx
Which in reality is:
label1 label2 rwx
All requests to access an object with a 'label3' will be denied. If it
ever comes to a situation where 'label3' would have to be printed
(e.g. reading an exec or mmap label from a file to which we have
access) then huh sign '?' will be printed instead.
All the operations in the namespace on the remaining labels will have
to be performed using their mapped names. Things like changing own
process's label, changing filesystem label. Labels will also be
printed with their mapped names.
You cannot import new labels in a namespace. Every operation that
would do so in an init namespace will return an error in the child
namespace. You cannot assign an unmapped or not existing label to an
object. You can only operate on labels that have been explicitly
mapped.
--- Capabilities ---
Enabling Smack related capabilities (CAP_MAC_ADMIN and
CAP_MAC_OVERRIDE) is main goal of Smack namespace, so it can work
properly in the container. And those capabilities do work to some
extent. In several places where capabilities are checked compatibility
with Smack namespace has been introduced. Capabilities are of course
limited to operate only on mapped labels.
CAP_MAC_OVERRIDE works fully, will allow you to ignore Smack access
rules, but only between objects that have labels mapped. So in the
example above having this CAP will allow e.g. label2 to write to
label1, but will not allow any access to label3.
With CAP_MAC_ADMIN the following operations has been allowed inside
the namespace:
- setting and removing xattr on files, including the security.* ones
- setting process's own label (/proc/self/attr/current)
- mounting in a privileged Smack mode, which means one can specify
additional mount options like: smackfsdef, smackfsfloor etc.
Again this is also allowed only on the mapped labels. Labels on the
filesystem will be stored in unmapped form so they are preserved
through reboots.
Such a namespace construct allows e.g. systemd (with Smack support)
working in a container to assign labels properly to daemons and other
processes.
--- Usage ---
Smack namespace is written using LSM hooks inside user namespace. That
means it's connected to it.
To create a new Smack namespace you need to unshare() user namespace
as usual. If that is all you do though, than there is no difference to
what is now. To activate the Smack namespace you need to fill the
labels' map. It is in a file /proc/$PID/smack_map.
By default the map is empty and Smack namespaces are inactive (labels
are taken directly from a parent namespace). It also means that the
Smack capabilities will be inactive. After you fill the map it starts
to take effect in the namespace and Smack capabilities (only on mapped
labels) start to work.
Due to the way Smack works only CAP_MAC_ADMIN from the parent
namespace (init_user_ns for now, see the "Current limitations" below)
is allowed to fill the map. That means that an unprivileged user is
still allowed to create the user namespace but it will not be able to
fill the labels' map (activate Smack namespace). An administrator
intervention is required.
The attr_map write format is:
unmapped_label mapped_label
When reading the file it shows an active map for a namespace the
process in question is in in the format:
unmapped_label -> mapped_label
If the smack_map file is empty it means the namespace is not mapped
and Smack namespace is inactive (no mappings, MAC related capabilities
behave as they did before, meaning they are active only in
init_user_ns). For init_user_ns the map will always be empty.
Writing to the map file is not disabled after the first write as it is
in uid_map. For Smack we have no means to map ranges of labels, hence
it can really be advantageous to be able to expand the map later
on. But you can only add to the map. You cannot remove already mapped
labels. You cannot change the already existing mappings. Also mappings
has to be 1-1. All requests to create a map where either the unmapped
or the mapped label already exists in the map will be denied.
setns() with Smack namespace active has an additional check that the
label of a process that is calling setns() has to be already mapped in
the target Smack namespace for the call to succeed.
--- Special labels ---
Smack is using some special labels that have built-in rules. Things
like floor '_', dash '^', star '*', etc. Those labels are not
automatically mapped to the namespace. Moreover, you can choose to map
a different label from the init namespace to behave e.g. like floor
inside the namespace.
Let's say we have no rules and those labels in the init namespace:
_
floor_to_be
label
Both 'label' and 'floor_to_be' can read objects with '_'. But they
have no access rights to each other.
Now let's create a map like this:
_ ordinary_label
floor_to_be _
label mapped
Right now label 'mapped' can read label '_' which means that
effectively inside this namespace label 'label' has gained read access
to the 'floor_to_be'. The label 'ordinary_label' is exactly it, an
ordinary label that the built-in rules no longer apply to inside the
namespace.
To sum up, special labels in the namespace behave the same as in the
init namespace. Not the original special labels though, but the ones
we map to specials. This is the only case where a namespace can have
access rights the init namespace does not have (like the 'label' to
'floor_to_be' in the example above).
Of course mappings like these are perfectly legal:
_ _
* *
^ ^
--- Current limitations ---
The Smack namespace is not hierarchical yet. It is currently not
possible to fill a smack_map of a nested user namespace (you can still
create nested user namespace, it will just inherit its parent's map
and won't have active Smack capabilities). When hierarchy will be
implemented the process creating another namespace will be allowed to
map only labels that it has permission to itself (those that it has in
its own map).
Special files inside the virtual smackfs needs to be reviewed whether
it's beneficial to have some of their functionality namespaced as well
(e.g. onlycap, syslog. ambient, etc). This would increase
CAP_MAC_ADMIN privileges inside the namespace.
Lukasz Pawelczyk (7):
user_ns: 3 new hooks for user namespace operations
smack: extend capability functions and fix 2 checks
smack: abstraction layer for 2 common Smack operations
smack: misc cleanups in preparation for a namespace patch
smack: namespace groundwork
smack: namespace implementation
smack: documentation for the Smack namespace
Documentation/security/00-INDEX | 2 +
Documentation/security/Smack-namespace.txt | 231 +++++++++++++
MAINTAINERS | 1 +
fs/proc/base.c | 57 +++
include/linux/lsm_hooks.h | 28 ++
include/linux/security.h | 23 ++
include/linux/user_namespace.h | 9 +
kernel/user.c | 3 +
kernel/user_namespace.c | 18 +
security/security.c | 28 ++
security/smack/Kconfig | 12 +
security/smack/Makefile | 1 +
security/smack/smack.h | 187 +++++++++-
security/smack/smack_access.c | 191 ++++++++--
security/smack/smack_lsm.c | 536 ++++++++++++++++++++---------
security/smack/smack_ns.c | 471 +++++++++++++++++++++++++
security/smack/smackfs.c | 154 +++++----
17 files changed, 1702 insertions(+), 250 deletions(-)
create mode 100644 Documentation/security/Smack-namespace.txt
create mode 100644 security/smack/smack_ns.c
--
2.1.0
^ permalink raw reply
* [PATCH v2 1/7] user_ns: 3 new hooks for user namespace operations
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
This commit implements 3 new LSM hooks that provide the means for LSMs
to embed their own security context within user namespace, effectively
creating some sort of a user_ns related security namespace.
The first one to take advantage of this mechanism is Smack.
The hooks has been documented in the in the security.h below.
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
include/linux/lsm_hooks.h | 28 ++++++++++++++++++++++++++++
include/linux/security.h | 23 +++++++++++++++++++++++
include/linux/user_namespace.h | 4 ++++
kernel/user.c | 3 +++
kernel/user_namespace.c | 18 ++++++++++++++++++
security/security.c | 28 ++++++++++++++++++++++++++++
6 files changed, 104 insertions(+)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index f014f25..b6e0c3d 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1260,6 +1260,23 @@
* audit_rule_init.
* @rule contains the allocated rule
*
+ * @userns_create:
+ * Allocates and fills the security part of a new user namespace.
+ * @ns points to a newly created user namespace.
+ * Returns 0 or an error code.
+ *
+ * @userns_free:
+ * Deallocates the security part of a user namespace.
+ * @ns points to a user namespace about to be destroyed.
+ *
+ * @userns_setns:
+ * Run during a setns syscall to add a process to an already existing
+ * user namespace. Returning failure here will block the operation
+ * requested from userspace (setns() with CLONE_NEWUSER).
+ * @nsproxy contains a nsproxy to which the user namespace will be assigned.
+ * @ns contains user namespace that is to be incorporated to the nsproxy.
+ * Returns 0 or an error code.
+ *
* @inode_notifysecctx:
* Notify the security module of what the security context of an inode
* should be. Initializes the incore security context managed by the
@@ -1611,6 +1628,12 @@ union security_list_options {
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
#endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_SECURITY
+ int (*userns_create)(struct user_namespace *ns);
+ void (*userns_free)(struct user_namespace *ns);
+ int (*userns_setns)(struct nsproxy *nsproxy, struct user_namespace *ns);
+#endif /* CONFIG_SECURITY */
};
struct security_hook_heads {
@@ -1822,6 +1845,11 @@ struct security_hook_heads {
struct list_head audit_rule_match;
struct list_head audit_rule_free;
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_SECURITY
+ struct list_head userns_create;
+ struct list_head userns_free;
+ struct list_head userns_setns;
+#endif /* CONFIG_SECURITY */
};
/*
diff --git a/include/linux/security.h b/include/linux/security.h
index 8c8175d..ec17ae1 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1583,6 +1583,29 @@ static inline void security_audit_rule_free(void *lsmrule)
#endif /* CONFIG_SECURITY */
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_SECURITY
+int security_userns_create(struct user_namespace *ns);
+void security_userns_free(struct user_namespace *ns);
+int security_userns_setns(struct nsproxy *nsproxy, struct user_namespace *ns);
+
+#else
+
+static inline int security_userns_create(struct user_namespace *ns)
+{
+ return 0;
+}
+
+static inline void security_userns_free(struct user_namespace *ns)
+{ }
+
+static inline int security_userns_setns(struct nsproxy *nsproxy,
+ struct user_namespace *ns)
+{
+ return 0;
+}
+
+#endif /* CONFIG_SECURITY */
+
#ifdef CONFIG_SECURITYFS
extern struct dentry *securityfs_create_file(const char *name, umode_t mode,
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 8297e5b..a9400cc 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -39,6 +39,10 @@ struct user_namespace {
struct key *persistent_keyring_register;
struct rw_semaphore persistent_keyring_register_sem;
#endif
+
+#ifdef CONFIG_SECURITY
+ void *security;
+#endif
};
extern struct user_namespace init_user_ns;
diff --git a/kernel/user.c b/kernel/user.c
index b069ccb..ce5419e 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -59,6 +59,9 @@ struct user_namespace init_user_ns = {
.persistent_keyring_register_sem =
__RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem),
#endif
+#ifdef CONFIG_SECURITY
+ .security = NULL,
+#endif
};
EXPORT_SYMBOL_GPL(init_user_ns);
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 4109f83..cadffb6 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -22,6 +22,7 @@
#include <linux/ctype.h>
#include <linux/projid.h>
#include <linux/fs_struct.h>
+#include <linux/security.h>
static struct kmem_cache *user_ns_cachep __read_mostly;
static DEFINE_MUTEX(userns_state_mutex);
@@ -108,6 +109,15 @@ int create_user_ns(struct cred *new)
set_cred_user_ns(new, ns);
+#ifdef CONFIG_SECURITY
+ ret = security_userns_create(ns);
+ if (ret) {
+ ns_free_inum(&ns->ns);
+ kmem_cache_free(user_ns_cachep, ns);
+ return ret;
+ }
+#endif
+
#ifdef CONFIG_PERSISTENT_KEYRINGS
init_rwsem(&ns->persistent_keyring_register_sem);
#endif
@@ -143,6 +153,9 @@ void free_user_ns(struct user_namespace *ns)
#ifdef CONFIG_PERSISTENT_KEYRINGS
key_put(ns->persistent_keyring_register);
#endif
+#ifdef CONFIG_SECURITY
+ security_userns_free(ns);
+#endif
ns_free_inum(&ns->ns);
kmem_cache_free(user_ns_cachep, ns);
ns = parent;
@@ -969,6 +982,7 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
{
struct user_namespace *user_ns = to_user_ns(ns);
struct cred *cred;
+ int err;
/* Don't allow gaining capabilities by reentering
* the same user namespace.
@@ -986,6 +1000,10 @@ static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns)
if (!ns_capable(user_ns, CAP_SYS_ADMIN))
return -EPERM;
+ err = security_userns_setns(nsproxy, user_ns);
+ if (err)
+ return err;
+
cred = prepare_creds();
if (!cred)
return -ENOMEM;
diff --git a/security/security.c b/security/security.c
index bd4c5f6..e902f3b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -25,6 +25,7 @@
#include <linux/mount.h>
#include <linux/personality.h>
#include <linux/backing-dev.h>
+#include <linux/user_namespace.h>
#include <net/flow.h>
#define MAX_LSM_EVM_XATTR 2
@@ -1541,6 +1542,25 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
}
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_SECURITY
+
+int security_userns_create(struct user_namespace *ns)
+{
+ return call_int_hook(userns_create, 0, ns);
+}
+
+void security_userns_free(struct user_namespace *ns)
+{
+ call_void_hook(userns_free, ns);
+}
+
+int security_userns_setns(struct nsproxy *nsproxy, struct user_namespace *ns)
+{
+ return call_int_hook(userns_setns, 0, nsproxy, ns);
+}
+
+#endif /* CONFIG_SECURITY */
+
struct security_hook_heads security_hook_heads = {
.binder_set_context_mgr =
LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr),
@@ -1885,4 +1905,12 @@ struct security_hook_heads security_hook_heads = {
.audit_rule_free =
LIST_HEAD_INIT(security_hook_heads.audit_rule_free),
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_SECURITY
+ .userns_create =
+ LIST_HEAD_INIT(security_hook_heads.userns_create),
+ .userns_free =
+ LIST_HEAD_INIT(security_hook_heads.userns_free),
+ .userns_setns =
+ LIST_HEAD_INIT(security_hook_heads.userns_setns),
+#endif /* CONFIG_SECURITY */
};
--
2.1.0
^ permalink raw reply related
* [PATCH v2 2/7] smack: extend capability functions and fix 2 checks
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
This patch extends smack capability functions to a full list to those
equivalent in the kernel
has_ns_capability -> smack_has_ns_privilege
has_capability -> smack_has_privilege
ns_capable -> smack_ns_privileged
capable -> smack_privileged
It also puts the smack related part to a common function:
smack_capability_allowed()
Those functions will be needed for capability checks in the upcoming
Smack namespace patches.
Additionally there were 2 smack capability checks that used generic
capability functions instead of specific Smack ones effectively ignoring
the onlycap rule. This has been fixed now with the introduction of those
new functions.
This has implications on the Smack namespace as well as the additional
Smack checks in smack_capability_allowed() will be extended beyond the
onlycap rule. Not using Smack specific checks in those 2 places could
mean breaking the Smack label namespace separation.
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
security/smack/smack.h | 63 +++++++++++++++++++++++++++++++++++++++++++---
security/smack/smack_lsm.c | 4 +--
2 files changed, 61 insertions(+), 6 deletions(-)
diff --git a/security/smack/smack.h b/security/smack/smack.h
index b8c1a86..fa8fa87 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -332,21 +332,76 @@ static inline struct smack_known *smk_of_current(void)
}
/*
+ * Internal smack capability check complimentary to the
+ * set of kernel capable() and has_capability() functions
+ *
+ * For a capability in smack related checks to be effective it needs to:
+ * - have empty onlycap or the current label be the same as onlycap
+ * - be in the initial user ns
+ */
+static inline int smack_capability_allowed(struct smack_known *skp,
+ struct user_namespace *user_ns)
+{
+ if (user_ns != &init_user_ns)
+ return 0;
+
+ if (smack_onlycap != NULL && smack_onlycap != skp)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Is the task privileged in a namespace and allowed to be privileged
+ * by additional smack rules.
+ */
+static inline int smack_has_ns_privilege(struct task_struct *task,
+ struct user_namespace *user_ns,
+ int cap)
+{
+ struct smack_known *skp = smk_of_task_struct(task);
+
+ if (!has_ns_capability(task, user_ns, cap))
+ return 0;
+ if (smack_capability_allowed(skp, user_ns))
+ return 1;
+ return 0;
+}
+
+/*
* Is the task privileged and allowed to be privileged
- * by the onlycap rule.
+ * by additional smack rules.
*/
-static inline int smack_privileged(int cap)
+static inline int smack_has_privilege(struct task_struct *task, int cap)
+{
+ return smack_has_ns_privilege(task, &init_user_ns, cap);
+}
+
+/*
+ * Is the current task privileged in a namespace and allowed to be privileged
+ * by additional smack rules.
+ */
+static inline int smack_ns_privileged(struct user_namespace *user_ns, int cap)
{
struct smack_known *skp = smk_of_current();
- if (!capable(cap))
+ if (!ns_capable(user_ns, cap))
return 0;
- if (smack_onlycap == NULL || smack_onlycap == skp)
+ if (smack_capability_allowed(skp, user_ns))
return 1;
return 0;
}
/*
+ * Is the current task privileged and allowed to be privileged
+ * by additional smack rules.
+ */
+static inline int smack_privileged(int cap)
+{
+ return smack_ns_privileged(&init_user_ns, cap);
+}
+
+/*
* logging functions
*/
#define SMACK_AUDIT_DENIED 0x1
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a143328..ee7bb63 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -403,7 +403,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
rc = 0;
else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
rc = -EACCES;
- else if (capable(CAP_SYS_PTRACE))
+ else if (smack_has_privilege(tracer, CAP_SYS_PTRACE))
rc = 0;
else
rc = -EACCES;
@@ -1646,7 +1646,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
skp = file->f_security;
rc = smk_access(skp, tkp, MAY_WRITE, NULL);
rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc);
- if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
+ if (rc != 0 && smack_has_privilege(tsk, CAP_MAC_OVERRIDE))
rc = 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
--
2.1.0
^ permalink raw reply related
* [PATCH v2 3/7] smack: abstraction layer for 2 common Smack operations
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
This patch adds two new functions that provide an abstraction layer for
two common internal Smack operations:
smk_find_label_name() - returns a label name (char*) from a struct
smack_known pointer
smk_get_label() - either finds or imports a label from a raw label
name (char*) and returns struct smack_known point
This patch also simplifies some pieces of code due to addition of those
2 functions (e.g. smack_inode_post_setxattr, smk_fill_rule,
smk_write_revoke_subj).
It is meant as a preparation for namespaces patches. Those 2 functions
will serve as entry points for namespace operations.
This patch should not change the Smack behaviour in any way.
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
security/smack/smack.h | 2 +
security/smack/smack_access.c | 40 ++++++++++++
security/smack/smack_lsm.c | 76 ++++++++++++-----------
security/smack/smackfs.c | 137 ++++++++++++++++++++++--------------------
4 files changed, 155 insertions(+), 100 deletions(-)
diff --git a/security/smack/smack.h b/security/smack/smack.h
index fa8fa87..fa32495 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -249,6 +249,8 @@ int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
+char *smk_find_label_name(struct smack_known *skp);
+struct smack_known *smk_get_label(const char *string, int len, bool import);
/*
* Shared data.
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 408e20b..3bf4cad 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -617,3 +617,43 @@ struct smack_known *smack_from_secid(const u32 secid)
rcu_read_unlock();
return &smack_known_invalid;
}
+
+/**
+ * smk_find_label_name - A helper to get a string value of a label
+ * @skp: a label we want a string value from
+ *
+ * Returns a pointer to a label name or NULL if label name not found.
+ */
+char *smk_find_label_name(struct smack_known *skp)
+{
+ return skp->smk_known;
+}
+
+/**
+ * smk_get_label - A helper to get the smack_known value from a string using
+ * either import or find functions if it already exists
+ * @string: a name of a label we look for or want to import
+ * @len: the string size, or zero if it is NULL terminated
+ * @import: whether we should import the label if not found
+ *
+ * Returns a smack_known label that is either imported or found.
+ * NULL if label not found (only when import == false).
+ * Error code otherwise.
+ */
+struct smack_known *smk_get_label(const char *string, int len, bool import)
+{
+ struct smack_known *skp;
+ char *cp;
+
+ if (import) {
+ skp = smk_import_entry(string, len);
+ } else {
+ cp = smk_parse_smack(string, len);
+ if (IS_ERR(cp))
+ return ERR_CAST(cp);
+
+ skp = smk_find_entry(cp);
+ }
+
+ return skp;
+}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ee7bb63..4a197b6 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -608,7 +608,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
op += strlen(SMK_FSHAT);
- skp = smk_import_entry(op, 0);
+ skp = smk_get_label(op, 0, true);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_hat = skp;
@@ -616,7 +616,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
op += strlen(SMK_FSFLOOR);
- skp = smk_import_entry(op, 0);
+ skp = smk_get_label(op, 0, true);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_floor = skp;
@@ -625,7 +625,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSDEFAULT,
strlen(SMK_FSDEFAULT)) == 0) {
op += strlen(SMK_FSDEFAULT);
- skp = smk_import_entry(op, 0);
+ skp = smk_get_label(op, 0, true);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_default = skp;
@@ -633,7 +633,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
op += strlen(SMK_FSROOT);
- skp = smk_import_entry(op, 0);
+ skp = smk_get_label(op, 0, true);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp;
@@ -641,7 +641,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
op += strlen(SMK_FSTRANS);
- skp = smk_import_entry(op, 0);
+ skp = smk_get_label(op, 0, true);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp;
@@ -1125,7 +1125,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
rc = -EPERM;
if (rc == 0 && check_import) {
- skp = size ? smk_import_entry(value, size) : NULL;
+ skp = size ? smk_get_label(value, size, true) : NULL;
if (IS_ERR(skp))
rc = PTR_ERR(skp);
else if (skp == NULL || (check_star &&
@@ -1159,6 +1159,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
struct smack_known *skp;
+ struct smack_known **skpp = NULL;
struct inode_smack *isp = d_backing_inode(dentry)->i_security;
if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
@@ -1166,27 +1167,21 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
- if (strcmp(name, XATTR_NAME_SMACK) == 0) {
- skp = smk_import_entry(value, size);
- if (!IS_ERR(skp))
- isp->smk_inode = skp;
- else
- isp->smk_inode = &smack_known_invalid;
- } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
- skp = smk_import_entry(value, size);
- if (!IS_ERR(skp))
- isp->smk_task = skp;
- else
- isp->smk_task = &smack_known_invalid;
- } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
- skp = smk_import_entry(value, size);
+ if (strcmp(name, XATTR_NAME_SMACK) == 0)
+ skpp = &isp->smk_inode;
+ else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
+ skpp = &isp->smk_task;
+ else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
+ skpp = &isp->smk_mmap;
+
+ if (skpp) {
+ skp = smk_get_label(value, size, true);
+
if (!IS_ERR(skp))
- isp->smk_mmap = skp;
+ *skpp = skp;
else
- isp->smk_mmap = &smack_known_invalid;
+ *skpp = &smack_known_invalid;
}
-
- return;
}
/**
@@ -1280,15 +1275,17 @@ static int smack_inode_getsecurity(const struct inode *inode,
struct socket *sock;
struct super_block *sbp;
struct inode *ip = (struct inode *)inode;
- struct smack_known *isp;
- int ilen;
+ struct smack_known *isp = NULL;
int rc = 0;
- if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+ if (strcmp(name, XATTR_SMACK_SUFFIX) == 0)
isp = smk_of_inode(inode);
- ilen = strlen(isp->smk_known);
- *buffer = isp->smk_known;
- return ilen;
+
+ if (isp) {
+ *buffer = smk_find_label_name(isp);
+ if (*buffer == NULL)
+ *buffer = smack_known_huh.smk_known;
+ return strlen(*buffer);
}
/*
@@ -1311,10 +1308,11 @@ static int smack_inode_getsecurity(const struct inode *inode,
else
return -EOPNOTSUPP;
- ilen = strlen(isp->smk_known);
if (rc == 0) {
- *buffer = isp->smk_known;
- rc = ilen;
+ *buffer = smk_find_label_name(isp);
+ if (*buffer == NULL)
+ *buffer = smack_known_huh.smk_known;
+ rc = strlen(*buffer);
}
return rc;
@@ -3270,7 +3268,10 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
if (strcmp(name, "current") != 0)
return -EINVAL;
- cp = kstrdup(skp->smk_known, GFP_KERNEL);
+ cp = smk_find_label_name(skp);
+ if (cp == NULL)
+ cp = smack_known_huh.smk_known;
+ cp = kstrdup(cp, GFP_KERNEL);
if (cp == NULL)
return -ENOMEM;
@@ -3314,7 +3315,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (strcmp(name, "current") != 0)
return -EINVAL;
- skp = smk_import_entry(value, size);
+ skp = smk_get_label(value, size, true);
if (IS_ERR(skp))
return PTR_ERR(skp);
@@ -4042,7 +4043,10 @@ static int smack_key_getsecurity(struct key *key, char **_buffer)
return 0;
}
- copy = kstrdup(skp->smk_known, GFP_KERNEL);
+ copy = smk_find_label_name(skp);
+ if (copy == NULL)
+ copy = smack_known_huh.smk_known;
+ copy = kstrdup(copy, GFP_KERNEL);
if (copy == NULL)
return -ENOMEM;
length = strlen(copy) + 1;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 3e42426..5ec1e8e 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -345,36 +345,17 @@ static int smk_fill_rule(const char *subject, const char *object,
struct smack_parsed_rule *rule, int import,
int len)
{
- const char *cp;
- struct smack_known *skp;
-
- if (import) {
- rule->smk_subject = smk_import_entry(subject, len);
- if (IS_ERR(rule->smk_subject))
- return PTR_ERR(rule->smk_subject);
-
- rule->smk_object = smk_import_entry(object, len);
- if (IS_ERR(rule->smk_object))
- return PTR_ERR(rule->smk_object);
- } else {
- cp = smk_parse_smack(subject, len);
- if (IS_ERR(cp))
- return PTR_ERR(cp);
- skp = smk_find_entry(cp);
- kfree(cp);
- if (skp == NULL)
- return -ENOENT;
- rule->smk_subject = skp;
-
- cp = smk_parse_smack(object, len);
- if (IS_ERR(cp))
- return PTR_ERR(cp);
- skp = smk_find_entry(cp);
- kfree(cp);
- if (skp == NULL)
- return -ENOENT;
- rule->smk_object = skp;
- }
+ rule->smk_subject = smk_get_label(subject, len, import);
+ if (IS_ERR(rule->smk_subject))
+ return PTR_ERR(rule->smk_subject);
+ if (rule->smk_subject == NULL)
+ return -ENOENT;
+
+ rule->smk_object = smk_get_label(object, len, import);
+ if (IS_ERR(rule->smk_object))
+ return PTR_ERR(rule->smk_object);
+ if (rule->smk_object == NULL)
+ return -ENOENT;
rule->smk_access1 = smk_perm_from_str(access1);
if (access2)
@@ -605,6 +586,9 @@ static void smk_seq_stop(struct seq_file *s, void *v)
static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
{
+ char *sbj;
+ char *obj;
+
/*
* Don't show any rules with label names too long for
* interface file (/smack/load or /smack/load2)
@@ -618,9 +602,13 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
if (srp->smk_access == 0)
return;
- seq_printf(s, "%s %s",
- srp->smk_subject->smk_known,
- srp->smk_object->smk_known);
+ sbj = smk_find_label_name(srp->smk_subject);
+ obj = smk_find_label_name(srp->smk_object);
+
+ if (sbj == NULL || obj == NULL)
+ return;
+
+ seq_printf(s, "%s %s", sbj, obj);
seq_putc(s, ' ');
@@ -811,6 +799,7 @@ static int cipso_seq_show(struct seq_file *s, void *v)
list_entry(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
char sep = '/';
+ char *cp;
int i;
/*
@@ -824,7 +813,11 @@ static int cipso_seq_show(struct seq_file *s, void *v)
if (strlen(skp->smk_known) >= SMK_LABELLEN)
return 0;
- seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
+ cp = smk_find_label_name(skp);
+ if (cp == NULL)
+ return 0;
+
+ seq_printf(s, "%s %3d", cp, skp->smk_netlabel.attr.mls.lvl);
for (i = netlbl_catmap_walk(cmp, 0); i >= 0;
i = netlbl_catmap_walk(cmp, i + 1)) {
@@ -913,7 +906,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
*/
mutex_lock(&smack_cipso_lock);
- skp = smk_import_entry(rule, 0);
+ skp = smk_get_label(rule, 0, true);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto out;
@@ -1002,9 +995,14 @@ static int cipso2_seq_show(struct seq_file *s, void *v)
list_entry(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
char sep = '/';
+ char *cp;
int i;
- seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
+ cp = smk_find_label_name(skp);
+ if (cp == NULL)
+ return 0;
+
+ seq_printf(s, "%s %3d", cp, skp->smk_netlabel.attr.mls.lvl);
for (i = netlbl_catmap_walk(cmp, 0); i >= 0;
i = netlbl_catmap_walk(cmp, i + 1)) {
@@ -1087,11 +1085,15 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
int maskn;
u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
+ char *label = smk_find_label_name(skp->smk_label);
+
+ if (label == NULL)
+ return 0;
for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++);
seq_printf(s, "%u.%u.%u.%u/%d %s\n",
- hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known);
+ hp[0], hp[1], hp[2], hp[3], maskn, label);
return 0;
}
@@ -1237,7 +1239,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
* If smack begins with '-', it is an option, don't import it
*/
if (smack[0] != '-') {
- skp = smk_import_entry(smack, 0);
+ skp = smk_get_label(smack, 0, true);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto free_out;
@@ -1566,6 +1568,7 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
size_t cn, loff_t *ppos)
{
ssize_t rc;
+ char *cp;
int asize;
if (*ppos != 0)
@@ -1576,12 +1579,14 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
*/
mutex_lock(&smack_ambient_lock);
- asize = strlen(smack_net_ambient->smk_known) + 1;
+ cp = smk_find_label_name(smack_net_ambient);
+ if (cp == NULL)
+ cp = smack_known_huh.smk_known;
+
+ asize = strlen(cp) + 1;
if (cn >= asize)
- rc = simple_read_from_buffer(buf, cn, ppos,
- smack_net_ambient->smk_known,
- asize);
+ rc = simple_read_from_buffer(buf, cn, ppos, cp, asize);
else
rc = -EINVAL;
@@ -1619,7 +1624,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
goto out;
}
- skp = smk_import_entry(data, count);
+ skp = smk_get_label(data, count, true);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto out;
@@ -1663,8 +1668,11 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
if (*ppos != 0)
return 0;
- if (smack_onlycap != NULL)
- smack = smack_onlycap->smk_known;
+ if (smack_onlycap != NULL) {
+ smack = smk_find_label_name(smack_onlycap);
+ if (smack == NULL)
+ smack = smack_known_huh.smk_known;
+ }
asize = strlen(smack) + 1;
@@ -1719,7 +1727,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
*
* But do so only on invalid label, not on system errors.
*/
- skp = smk_import_entry(data, count);
+ skp = smk_get_label(data, count, true);
if (PTR_ERR(skp) == -EINVAL)
skp = NULL;
else if (IS_ERR(skp)) {
@@ -1760,8 +1768,11 @@ static ssize_t smk_read_unconfined(struct file *filp, char __user *buf,
if (*ppos != 0)
return 0;
- if (smack_unconfined != NULL)
- smack = smack_unconfined->smk_known;
+ if (smack_unconfined != NULL) {
+ smack = smk_find_label_name(smack_unconfined);
+ if (smack == NULL)
+ smack = smack_known_huh.smk_known;
+ }
asize = strlen(smack) + 1;
@@ -1808,7 +1819,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
*
* But do so only on invalid label, not on system errors.
*/
- skp = smk_import_entry(data, count);
+ skp = smk_get_label(data, count, true);
if (PTR_ERR(skp) == -EINVAL)
skp = NULL;
else if (IS_ERR(skp)) {
@@ -2205,7 +2216,6 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *data = NULL;
- const char *cp = NULL;
struct smack_known *skp;
struct smack_rule *sp;
struct list_head *rule_list;
@@ -2230,13 +2240,11 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
goto free_out;
}
- cp = smk_parse_smack(data, count);
- if (IS_ERR(cp)) {
- rc = PTR_ERR(cp);
+ skp = smk_get_label(data, count, false);
+ if (IS_ERR(skp)) {
+ rc = PTR_ERR(skp);
goto free_out;
}
-
- skp = smk_find_entry(cp);
if (skp == NULL)
goto free_out;
@@ -2252,7 +2260,6 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
free_out:
kfree(data);
- kfree(cp);
return rc;
}
@@ -2315,23 +2322,25 @@ static const struct file_operations smk_change_rule_ops = {
static ssize_t smk_read_syslog(struct file *filp, char __user *buf,
size_t cn, loff_t *ppos)
{
- struct smack_known *skp;
ssize_t rc = -EINVAL;
+ char *cp;
int asize;
if (*ppos != 0)
return 0;
if (smack_syslog_label == NULL)
- skp = &smack_known_star;
- else
- skp = smack_syslog_label;
+ cp = smack_known_star.smk_known;
+ else {
+ cp = smk_find_label_name(smack_syslog_label);
+ if (cp == NULL)
+ cp = smack_known_huh.smk_known;
+ }
- asize = strlen(skp->smk_known) + 1;
+ asize = strlen(cp) + 1;
if (cn >= asize)
- rc = simple_read_from_buffer(buf, cn, ppos, skp->smk_known,
- asize);
+ rc = simple_read_from_buffer(buf, cn, ppos, cp, asize);
return rc;
}
@@ -2362,7 +2371,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
if (copy_from_user(data, buf, count) != 0)
rc = -EFAULT;
else {
- skp = smk_import_entry(data, count);
+ skp = smk_get_label(data, count, true);
if (IS_ERR(skp))
rc = PTR_ERR(skp);
else
--
2.1.0
^ permalink raw reply related
* [PATCH v2 4/7] smack: misc cleanups in preparation for a namespace patch
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
This patch does some small miscellaneous cleanups and additions that
should not change the code behaviour in any way. Its only purpose is to
shape the code in a way that the smack namespace patches would be
smaller and easier to understand.
Changes:
- two small functions added
- one macro has been moved to a header
- minor code reformatting in several places for readability
- unnecessarily increasing string size has been fixed
This patch should not change the behaviour of the Smack in any way.
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
security/smack/smack.h | 25 ++++++++++++++++++-
security/smack/smack_access.c | 18 +++++++++-----
security/smack/smack_lsm.c | 58 ++++++++++++++++---------------------------
3 files changed, 58 insertions(+), 43 deletions(-)
diff --git a/security/smack/smack.h b/security/smack/smack.h
index fa32495..3818d19 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -229,6 +229,7 @@ struct smk_audit_info {
struct smack_audit_data sad;
#endif
};
+
/*
* These functions are in smack_lsm.c
*/
@@ -240,7 +241,7 @@ struct inode_smack *new_inode_smack(struct smack_known *);
int smk_access_entry(char *, char *, struct list_head *);
int smk_access(struct smack_known *, struct smack_known *,
int, struct smk_audit_info *);
-int smk_tskacc(struct task_smack *, struct smack_known *,
+int smk_tskacc(struct task_struct *, struct smack_known *,
u32, struct smk_audit_info *);
int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
struct smack_known *smack_from_secid(const u32);
@@ -287,6 +288,7 @@ extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
static inline int smk_inode_transmutable(const struct inode *isp)
{
struct inode_smack *sip = isp->i_security;
+
return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
}
@@ -296,10 +298,31 @@ static inline int smk_inode_transmutable(const struct inode *isp)
static inline struct smack_known *smk_of_inode(const struct inode *isp)
{
struct inode_smack *sip = isp->i_security;
+
return sip->smk_inode;
}
/*
+ * Present a pointer to the smack label entry in an inode blob for an exec.
+ */
+static inline struct smack_known *smk_of_exec(const struct inode *isp)
+{
+ struct inode_smack *sip = isp->i_security;
+
+ return sip->smk_task;
+}
+
+/*
+ * Present a pointer to the smack label entry in an inode blob for an mmap.
+ */
+static inline struct smack_known *smk_of_mmap(const struct inode *isp)
+{
+ struct inode_smack *sip = isp->i_security;
+
+ return sip->smk_mmap;
+}
+
+/*
* Present a pointer to the smack label entry in an task blob.
*/
static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 3bf4cad..47a9c92 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -167,6 +167,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
if (subject == &smack_known_hat)
goto out_audit;
}
+
/*
* Beyond here an explicit relationship is required.
* If the requested access is contained in the available
@@ -183,6 +184,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
rc = -EACCES;
goto out_audit;
}
+
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
/*
* Return a positive value if using bringup mode.
@@ -225,10 +227,10 @@ out_audit:
* non zero otherwise. It allows that the task may have the capability
* to override the rules.
*/
-int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
+int smk_tskacc(struct task_struct *task, struct smack_known *obj_known,
u32 mode, struct smk_audit_info *a)
{
- struct smack_known *sbj_known = smk_of_task(tsp);
+ struct smack_known *sbj_known = smk_of_task_struct(task);
int may;
int rc;
@@ -237,13 +239,19 @@ int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
*/
rc = smk_access(sbj_known, obj_known, mode, NULL);
if (rc >= 0) {
+ struct task_smack *tsp;
+
/*
* If there is an entry in the task's rule list
* it can further restrict access.
*/
+ rcu_read_lock();
+ tsp = __task_cred(task)->security;
may = smk_access_entry(sbj_known->smk_known,
obj_known->smk_known,
&tsp->smk_rules);
+ rcu_read_unlock();
+
if (may < 0)
goto out_audit;
if ((mode & may) == mode)
@@ -280,9 +288,7 @@ out_audit:
int smk_curacc(struct smack_known *obj_known,
u32 mode, struct smk_audit_info *a)
{
- struct task_smack *tsp = current_security();
-
- return smk_tskacc(tsp, obj_known, mode, a);
+ return smk_tskacc(current, obj_known, mode, a);
}
#ifdef CONFIG_AUDIT
@@ -456,7 +462,7 @@ char *smk_parse_smack(const char *string, int len)
int i;
if (len <= 0)
- len = strlen(string) + 1;
+ len = strlen(string);
/*
* Reserve a leading '-' as an indicator that
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 4a197b6..bb74ca9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -383,8 +383,6 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
{
int rc;
struct smk_audit_info ad, *saip = NULL;
- struct task_smack *tsp;
- struct smack_known *tracer_known;
if ((mode & PTRACE_MODE_NOAUDIT) == 0) {
smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK);
@@ -392,13 +390,12 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
saip = &ad;
}
- rcu_read_lock();
- tsp = __task_cred(tracer)->security;
- tracer_known = smk_of_task(tsp);
if ((mode & PTRACE_MODE_ATTACH) &&
(smack_ptrace_rule == SMACK_PTRACE_EXACT ||
smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
+ struct smack_known *tracer_known = smk_of_task_struct(tracer);
+
if (tracer_known->smk_known == tracee_known->smk_known)
rc = 0;
else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
@@ -406,22 +403,18 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
else if (smack_has_privilege(tracer, CAP_SYS_PTRACE))
rc = 0;
else
- rc = -EACCES;
+ rc = -EPERM;
if (saip)
smack_log(tracer_known->smk_known,
tracee_known->smk_known,
0, rc, saip);
- rcu_read_unlock();
return rc;
}
/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
- rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
-
- rcu_read_unlock();
- return rc;
+ return smk_tskacc(tracer, tracee_known, smk_ptrace_mode(mode), saip);
}
/*
@@ -440,9 +433,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
*/
static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
- struct smack_known *skp;
-
- skp = smk_of_task_struct(ctp);
+ struct smack_known *skp = smk_of_task_struct(ctp);
return smk_ptrace_rule_check(current, skp, mode, __func__);
}
@@ -457,13 +448,9 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
*/
static int smack_ptrace_traceme(struct task_struct *ptp)
{
- int rc;
- struct smack_known *skp;
-
- skp = smk_of_task(current_security());
+ struct smack_known *skp = smk_of_current();
- rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
- return rc;
+ return smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
}
/**
@@ -1529,13 +1516,14 @@ static int smack_mmap_file(struct file *file,
if (file == NULL)
return 0;
+ tsp = current_security();
+ skp = smk_of_task(tsp);
isp = file_inode(file)->i_security;
- if (isp->smk_mmap == NULL)
- return 0;
mkp = isp->smk_mmap;
- tsp = current_security();
- skp = smk_of_current();
+ if (mkp == NULL)
+ return 0;
+
rc = 0;
rcu_read_lock();
@@ -3348,11 +3336,13 @@ static int smack_setprocattr(struct task_struct *p, char *name,
static int smack_unix_stream_connect(struct sock *sock,
struct sock *other, struct sock *newsk)
{
- struct smack_known *skp;
- struct smack_known *okp;
struct socket_smack *ssp = sock->sk_security;
struct socket_smack *osp = other->sk_security;
struct socket_smack *nsp = newsk->sk_security;
+ struct smack_known *skp_out = ssp->smk_out;
+ struct smack_known *okp_out = osp->smk_out;
+ struct smack_known *skp_in = ssp->smk_in;
+ struct smack_known *okp_in = osp->smk_in;
struct smk_audit_info ad;
int rc = 0;
#ifdef CONFIG_AUDIT
@@ -3360,19 +3350,15 @@ static int smack_unix_stream_connect(struct sock *sock,
#endif
if (!smack_privileged(CAP_MAC_OVERRIDE)) {
- skp = ssp->smk_out;
- okp = osp->smk_in;
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
smk_ad_setfield_u_net_sk(&ad, other);
#endif
- rc = smk_access(skp, okp, MAY_WRITE, &ad);
- rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
+ rc = smk_access(skp_out, okp_in, MAY_WRITE, &ad);
+ rc = smk_bu_note("UDS connect", skp_out, okp_in, MAY_WRITE, rc);
if (rc == 0) {
- okp = osp->smk_out;
- skp = ssp->smk_in;
- rc = smk_access(okp, skp, MAY_WRITE, &ad);
- rc = smk_bu_note("UDS connect", okp, skp,
+ rc = smk_access(okp_out, skp_in, MAY_WRITE, &ad);
+ rc = smk_bu_note("UDS connect", okp_out, skp_in,
MAY_WRITE, rc);
}
}
@@ -3381,8 +3367,8 @@ static int smack_unix_stream_connect(struct sock *sock,
* Cross reference the peer labels for SO_PEERSEC.
*/
if (rc == 0) {
- nsp->smk_packet = ssp->smk_out;
- ssp->smk_packet = osp->smk_out;
+ nsp->smk_packet = skp_out;
+ ssp->smk_packet = okp_out;
}
return rc;
--
2.1.0
^ permalink raw reply related
* [PATCH v2 5/7] smack: namespace groundwork
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
This commit introduces several changes to Smack to prepare it for
namespace implementation. All the changes are related to namespaces.
Overview of the changes:
- Adds required data structures for mapped labels and functions to
operate on them.
- Implements the proc interface /proc/$PID/smack_map that can be used for
remapping of labels for a specific namespace. Also for checking the map.
- Modifies handling of special built-in labels. Detects them on import
and assigns the same char* pointer regardless whether it's used in a
normal or a mapped label. This way we can always compare them by ==
instead of strcmp().
- Adds User namespace hooks implementation
This patch introduces both internal and user-space visible APIs to
handle namespaced labels and Smack namespaces but the behaviour of Smack
should not be changed. The APIs are there, but they have no impact yet.
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
fs/proc/base.c | 57 ++++++
include/linux/user_namespace.h | 5 +
security/smack/Kconfig | 10 +
security/smack/Makefile | 1 +
security/smack/smack.h | 42 +++-
security/smack/smack_access.c | 46 ++++-
security/smack/smack_lsm.c | 76 ++++++++
security/smack/smack_ns.c | 432 +++++++++++++++++++++++++++++++++++++++++
8 files changed, 662 insertions(+), 7 deletions(-)
create mode 100644 security/smack/smack_ns.c
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 093ca14..22dde1c 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2529,6 +2529,57 @@ static const struct file_operations proc_setgroups_operations = {
};
#endif /* CONFIG_USER_NS */
+#ifdef CONFIG_SECURITY_SMACK_NS
+static int proc_smack_map_open(struct inode *inode, struct file *file)
+{
+ struct user_namespace *ns = NULL;
+ struct task_struct *task;
+ struct seq_file *seq;
+ int ret = -EINVAL;
+
+ task = get_proc_task(inode);
+ if (task) {
+ rcu_read_lock();
+ ns = get_user_ns(task_cred_xxx(task, user_ns));
+ rcu_read_unlock();
+ put_task_struct(task);
+ }
+ if (!ns)
+ goto err;
+
+ ret = seq_open(file, &proc_smack_map_seq_operations);
+ if (ret)
+ goto err_put_ns;
+
+ seq = file->private_data;
+ seq->private = ns;
+
+ return 0;
+
+err_put_ns:
+ put_user_ns(ns);
+err:
+ return ret;
+}
+
+static int proc_smack_map_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct user_namespace *ns = seq->private;
+
+ put_user_ns(ns);
+ return seq_release(inode, file);
+}
+
+static const struct file_operations proc_smack_map_operations = {
+ .open = proc_smack_map_open,
+ .write = proc_smack_map_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = proc_smack_map_release,
+};
+#endif /* CONFIG_SECURITY_SMACK_NS */
+
static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
@@ -2637,6 +2688,9 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations),
#endif
+#ifdef CONFIG_SECURITY_SMACK_NS
+ REG("smack_map", S_IRUGO|S_IWUSR, proc_smack_map_operations),
+#endif
#ifdef CONFIG_CHECKPOINT_RESTORE
REG("timers", S_IRUGO, proc_timers_operations),
#endif
@@ -2982,6 +3036,9 @@ static const struct pid_entry tid_base_stuff[] = {
REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations),
#endif
+#ifdef CONFIG_SECURITY_SMACK_NS
+ REG("smack_map", S_IRUGO|S_IWUSR, proc_smack_map_operations),
+#endif
};
static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index a9400cc..a8941a5 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -76,6 +76,11 @@ extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t,
extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
extern int proc_setgroups_show(struct seq_file *m, void *v);
extern bool userns_may_setgroups(const struct user_namespace *ns);
+#ifdef CONFIG_SECURITY_SMACK_NS
+extern const struct seq_operations proc_smack_map_seq_operations;
+ssize_t proc_smack_map_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *ppos);
+#endif /* CONFIG_SECURITY_SMACK_NS */
#else
static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
diff --git a/security/smack/Kconfig b/security/smack/Kconfig
index 271adae..b19a7fb 100644
--- a/security/smack/Kconfig
+++ b/security/smack/Kconfig
@@ -40,3 +40,13 @@ config SECURITY_SMACK_NETFILTER
This enables security marking of network packets using
Smack labels.
If you are unsure how to answer this question, answer N.
+
+config SECURITY_SMACK_NS
+ bool "Smack namespace"
+ depends on SECURITY_SMACK
+ depends on USER_NS
+ help
+ This enables Smack namespace that makes it possible to map
+ specific labels within user namespace (analogously to mapping
+ UIDs) and to gain MAC capabilities over them.
+ If you are unsure how to answer this question, answer N.
diff --git a/security/smack/Makefile b/security/smack/Makefile
index ee2ebd5..5faebd7 100644
--- a/security/smack/Makefile
+++ b/security/smack/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_SECURITY_SMACK) := smack.o
smack-y := smack_lsm.o smack_access.o smackfs.o
smack-$(CONFIG_SECURITY_SMACK_NETFILTER) += smack_netfilter.o
+smack-$(CONFIG_SECURITY_SMACK_NS) += smack_ns.o
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 3818d19..a53623a 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -21,6 +21,7 @@
#include <linux/list.h>
#include <linux/rculist.h>
#include <linux/lsm_audit.h>
+#include <linux/user_namespace.h>
/*
* Smack labels were limited to 23 characters for a long time.
@@ -59,8 +60,36 @@ struct smack_known {
struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */
struct list_head smk_rules; /* access rules */
struct mutex smk_rules_lock; /* lock for rules */
+#ifdef CONFIG_SECURITY_SMACK_NS
+ struct list_head smk_mapped; /* namespaced labels */
+ struct mutex smk_mapped_lock;
+#endif /* CONFIG_SECURITY_SMACK_NS */
};
+#ifdef CONFIG_SECURITY_SMACK_NS
+
+/*
+ * User namespace security pointer content.
+ */
+struct smack_ns {
+ struct list_head smk_mapped; /* namespaced labels */
+ struct mutex smk_mapped_lock;
+};
+
+/*
+ * A single entry for a namespaced/mapped label.
+ */
+struct smack_known_ns {
+ struct list_head smk_list_known;
+ struct list_head smk_list_ns;
+ struct user_namespace *smk_ns;
+ char *smk_mapped;
+ struct smack_known *smk_unmapped;
+ bool smk_allocated;
+};
+
+#endif /* CONFIG_SECURITY_SMACK_NS */
+
/*
* Maximum number of bytes for the levels in a CIPSO IP option.
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
@@ -245,7 +274,7 @@ int smk_tskacc(struct task_struct *, struct smack_known *,
u32, struct smk_audit_info *);
int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
struct smack_known *smack_from_secid(const u32);
-char *smk_parse_smack(const char *string, int len);
+char *smk_parse_smack(const char *string, int len, bool *allocated);
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp);
@@ -254,6 +283,17 @@ char *smk_find_label_name(struct smack_known *skp);
struct smack_known *smk_get_label(const char *string, int len, bool import);
/*
+ * These functions are in smack_ns.c
+ */
+#ifdef CONFIG_SECURITY_SMACK_NS
+struct user_namespace *smk_find_mapped_ns(struct user_namespace *ns);
+struct smack_known_ns *smk_find_mapped(struct smack_known *skp,
+ struct user_namespace *ns);
+struct smack_known *smk_find_unmapped(const char *string, int len,
+ struct user_namespace *ns);
+#endif /* CONFIG_SECURITY_SMACK_NS */
+
+/*
* Shared data.
*/
extern int smack_enabled;
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 47a9c92..c4d90d2 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -452,13 +452,16 @@ struct smack_known *smk_find_entry(const char *string)
/**
* smk_parse_smack - parse smack label from a text string
* @string: a text string that might contain a Smack label
- * @len: the maximum size, or zero if it is NULL terminated.
+ * @len: the maximum size, or zero if it is NULL terminated
+ * @allocated: (out) indicates whether the return string has been
+ * allocated and has to be freed with kfree() later
+ * (built-in labels returned are not allocated)
*
* Returns a pointer to the clean label or an error code.
*/
-char *smk_parse_smack(const char *string, int len)
+char *smk_parse_smack(const char *string, int len, bool *allocated)
{
- char *smack;
+ char *smack = NULL;
int i;
if (len <= 0)
@@ -480,11 +483,33 @@ char *smk_parse_smack(const char *string, int len)
if (i == 0 || i >= SMK_LONGLABEL)
return ERR_PTR(-EINVAL);
+ /*
+ * Look for special labels. This way we guarantee that we can compare
+ * special labels in mapped entries by ==, without strcmp().
+ */
+ if (len == 1 && !strcmp(string, smack_known_huh.smk_known))
+ smack = smack_known_huh.smk_known;
+ else if (len == 1 && !strcmp(string, smack_known_hat.smk_known))
+ smack = smack_known_hat.smk_known;
+ else if (len == 1 && !strcmp(string, smack_known_star.smk_known))
+ smack = smack_known_star.smk_known;
+ else if (len == 1 && !strcmp(string, smack_known_floor.smk_known))
+ smack = smack_known_floor.smk_known;
+ else if (len == 1 && !strcmp(string, smack_known_web.smk_known))
+ smack = smack_known_web.smk_known;
+
+ if (smack) {
+ *allocated = false;
+
+ return smack;
+ }
+
smack = kzalloc(i + 1, GFP_KERNEL);
if (smack == NULL)
return ERR_PTR(-ENOMEM);
strncpy(smack, string, i);
+ *allocated = true;
return smack;
}
@@ -540,8 +565,9 @@ struct smack_known *smk_import_entry(const char *string, int len)
char *smack;
int slen;
int rc;
+ bool allocated;
- smack = smk_parse_smack(string, len);
+ smack = smk_parse_smack(string, len, &allocated);
if (IS_ERR(smack))
return ERR_CAST(smack);
@@ -577,6 +603,10 @@ struct smack_known *smk_import_entry(const char *string, int len)
if (rc >= 0) {
INIT_LIST_HEAD(&skp->smk_rules);
mutex_init(&skp->smk_rules_lock);
+#ifdef CONFIG_SECURITY_SMACK_NS
+ INIT_LIST_HEAD(&skp->smk_mapped);
+ mutex_init(&skp->smk_mapped_lock);
+#endif /* CONFIG_SECURITY_SMACK_NS */
/*
* Make sure that the entry is actually
* filled before putting it on the list.
@@ -590,7 +620,8 @@ struct smack_known *smk_import_entry(const char *string, int len)
kfree(skp);
skp = ERR_PTR(rc);
freeout:
- kfree(smack);
+ if (allocated)
+ kfree(smack);
unlockout:
mutex_unlock(&smack_known_lock);
@@ -649,16 +680,19 @@ char *smk_find_label_name(struct smack_known *skp)
struct smack_known *smk_get_label(const char *string, int len, bool import)
{
struct smack_known *skp;
+ bool allocated;
char *cp;
if (import) {
skp = smk_import_entry(string, len);
} else {
- cp = smk_parse_smack(string, len);
+ cp = smk_parse_smack(string, len, &allocated);
if (IS_ERR(cp))
return ERR_CAST(cp);
skp = smk_find_entry(cp);
+ if (allocated)
+ kfree(cp);
}
return skp;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index bb74ca9..4ae9a9a 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -41,6 +41,7 @@
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/binfmts.h>
+#include <linux/user_namespace.h>
#include "smack.h"
#define TRANS_TRUE "TRUE"
@@ -4165,6 +4166,53 @@ static void smack_audit_rule_free(void *vrule)
#endif /* CONFIG_AUDIT */
+#ifdef CONFIG_SECURITY_SMACK_NS
+
+static inline int smack_userns_create(struct user_namespace *ns)
+{
+ struct smack_ns *snsp;
+
+ snsp = kzalloc(sizeof(*snsp), GFP_KERNEL);
+ if (snsp == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&snsp->smk_mapped);
+ mutex_init(&snsp->smk_mapped_lock);
+
+ ns->security = snsp;
+ return 0;
+}
+
+static inline void smack_userns_free(struct user_namespace *ns)
+{
+ struct smack_ns *snsp = ns->security;
+ struct smack_known *skp;
+ struct smack_known_ns *sknp, *n;
+
+ list_for_each_entry_safe(sknp, n, &snsp->smk_mapped, smk_list_ns) {
+ skp = sknp->smk_unmapped;
+
+ mutex_lock(&skp->smk_mapped_lock);
+ list_del_rcu(&sknp->smk_list_known);
+ if (sknp->smk_allocated)
+ kfree(sknp->smk_mapped);
+ kfree(sknp);
+ mutex_unlock(&skp->smk_mapped_lock);
+
+ list_del(&sknp->smk_list_ns);
+ }
+
+ kfree(snsp);
+}
+
+static inline int smack_userns_setns(struct nsproxy *nsproxy,
+ struct user_namespace *ns)
+{
+ return 0;
+}
+
+#endif /* CONFIG_SECURITY_SMACK_NS */
+
/**
* smack_ismaclabel - check if xattr @name references a smack MAC label
* @name: Full xattr name to check.
@@ -4376,6 +4424,13 @@ struct security_hook_list smack_hooks[] = {
LSM_HOOK_INIT(audit_rule_free, smack_audit_rule_free),
#endif /* CONFIG_AUDIT */
+ /* Namespace hooks */
+#ifdef CONFIG_SECURITY_SMACK_NS
+ LSM_HOOK_INIT(userns_create, smack_userns_create),
+ LSM_HOOK_INIT(userns_free, smack_userns_free),
+ LSM_HOOK_INIT(userns_setns, smack_userns_setns),
+#endif /* CONFIG_SECURITY_SMACK_NS */
+
LSM_HOOK_INIT(ismaclabel, smack_ismaclabel),
LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx),
LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid),
@@ -4388,6 +4443,27 @@ struct security_hook_list smack_hooks[] = {
static __init void init_smack_known_list(void)
{
+#ifdef CONFIG_SECURITY_SMACK_NS
+ /*
+ * Initialize mapped list locks
+ */
+ mutex_init(&smack_known_huh.smk_mapped_lock);
+ mutex_init(&smack_known_hat.smk_mapped_lock);
+ mutex_init(&smack_known_floor.smk_mapped_lock);
+ mutex_init(&smack_known_star.smk_mapped_lock);
+ mutex_init(&smack_known_invalid.smk_mapped_lock);
+ mutex_init(&smack_known_web.smk_mapped_lock);
+ /*
+ * Initialize mapped lists
+ */
+ INIT_LIST_HEAD(&smack_known_huh.smk_mapped);
+ INIT_LIST_HEAD(&smack_known_hat.smk_mapped);
+ INIT_LIST_HEAD(&smack_known_star.smk_mapped);
+ INIT_LIST_HEAD(&smack_known_floor.smk_mapped);
+ INIT_LIST_HEAD(&smack_known_invalid.smk_mapped);
+ INIT_LIST_HEAD(&smack_known_web.smk_mapped);
+#endif /* CONFIG_SECURITY_SMACK_NS */
+
/*
* Initialize rule list locks
*/
diff --git a/security/smack/smack_ns.c b/security/smack/smack_ns.c
new file mode 100644
index 0000000..141a836
--- /dev/null
+++ b/security/smack/smack_ns.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics.
+ *
+ * Smack namespaces
+ *
+ * Author(s):
+ * Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software, you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/file.h>
+#include <linux/ctype.h>
+#include <linux/rculist.h>
+#include <linux/seq_file.h>
+#include <linux/user_namespace.h>
+#include "smack.h"
+
+/**
+ * smk_find_mapped_ns - Finds a first namespace from this one through
+ * its parrents that has a map. This map is the effective map in this
+ * namespace.
+ * @ns: a user namespace for which we search for a mapped ns
+ *
+ * Returns a namespace that has a non-NULL map, or NULL if there is
+ * no mapped namespace.
+ *
+ * Can be effectively used to answer a question: "is there a Smack
+ * map for this namespace?"
+ */
+struct user_namespace *smk_find_mapped_ns(struct user_namespace *ns)
+{
+ struct user_namespace *user_ns = ns;
+
+ do {
+ struct smack_ns *sns = user_ns->security;
+
+ if (sns && !list_empty(&sns->smk_mapped))
+ break;
+
+ user_ns = user_ns->parent;
+ } while (user_ns);
+
+ return user_ns;
+}
+
+/**
+ * __smk_find_mapped - an internal version of smk_find_mapped
+ * that doesn't use smk_find_mapped_ns, but
+ * operates directly on the passed one.
+ */
+static struct smack_known_ns *__smk_find_mapped(struct smack_known *skp,
+ struct user_namespace *ns)
+{
+ struct smack_known_ns *sknp;
+
+ if (ns == NULL)
+ return NULL;
+
+ list_for_each_entry_rcu(sknp, &skp->smk_mapped, smk_list_known)
+ if (sknp->smk_ns == ns)
+ return sknp;
+
+ return NULL;
+}
+
+/**
+ * smk_find_mapped - Finds a mapped label on the smack_known's mapped list
+ * @skp: a label which mapped label we look for
+ * @ns: a user namespace the label we search for is assigned to
+ *
+ * Returns a pointer to the mapped label if one exists that is
+ * assigned to the specified user namespace or NULL if not found.
+ */
+struct smack_known_ns *smk_find_mapped(struct smack_known *skp,
+ struct user_namespace *ns)
+{
+ struct user_namespace *user_ns = smk_find_mapped_ns(ns);
+
+ return __smk_find_mapped(skp, user_ns);
+}
+
+/**
+ * __smk_find_unmapped - an internal version of smk_find_unmapped
+ * that doesn't use smk_find_mapped_ns, but
+ * operates directly on the passed one.
+ */
+static struct smack_known *__smk_find_unmapped(const char *string, int len,
+ struct user_namespace *ns)
+{
+ struct smack_ns *snsp;
+ struct smack_known *skp = NULL;
+ struct smack_known_ns *sknp;
+ char *smack;
+ bool allocated = false;
+
+ if (ns == NULL)
+ return NULL;
+
+ snsp = ns->security;
+
+ smack = smk_parse_smack(string, len, &allocated);
+ if (IS_ERR(smack))
+ return ERR_CAST(smack);
+
+ list_for_each_entry_rcu(sknp, &snsp->smk_mapped, smk_list_ns) {
+ if (strcmp(smack, sknp->smk_mapped) == 0) {
+ skp = sknp->smk_unmapped;
+ break;
+ }
+ }
+
+ if (allocated)
+ kfree(smack);
+ return skp;
+}
+
+/**
+ * smk_find_unmapped - Finds an original label by a mapped label string
+ * and the namespace it could be mapped in
+ * @string: a name of a mapped label we look for
+ * @len: the string size, or zero if it is NULL terminated.
+ * @ns: a namespace the looked for label should be mapped in
+ *
+ * Returns a smack_known label that is mapped as 'string' in 'ns',
+ * NULL if not found or an error code.
+ */
+struct smack_known *smk_find_unmapped(const char *string, int len,
+ struct user_namespace *ns)
+{
+ struct user_namespace *user_ns = smk_find_mapped_ns(ns);
+
+ return __smk_find_unmapped(string, len, user_ns);
+}
+
+/**
+ * smk_import_mapped - Imports a mapped label effectively creating a mapping.
+ * @skp: a label we map
+ * @ns: a user namespace this label will be mapped in
+ * @string: a text string of the mapped label
+ * @len: the maximum size, or zero if it is NULL terminanted
+ *
+ * Returns a pointer to the mapped label entry or an error code.
+ *
+ * The mapped label will be added to 2 lists:
+ * - a list of mapped labels of skp
+ * - a list of labels mapped in ns
+ */
+static struct smack_known_ns *smk_import_mapped(struct smack_known *skp,
+ struct user_namespace *ns,
+ const char *string, int len)
+{
+ struct smack_ns *snsp = ns->security;
+ struct smack_known_ns *sknp;
+ char *mapped;
+ bool allocated;
+
+ /* Mapping init_user_ns is against the design and pointless */
+ if (ns == &init_user_ns)
+ return ERR_PTR(-EBADR);
+
+ mapped = smk_parse_smack(string, len, &allocated);
+ if (IS_ERR(mapped))
+ return ERR_CAST(mapped);
+
+ mutex_lock(&skp->smk_mapped_lock);
+
+ /*
+ * Don't allow one<->many mappings in namespace, rename.
+ * This code won't get triggered for now as trying to assign
+ * a duplicate is forbidden in proc_smack_map_write().
+ * Leaving this as this function might be also used elsewhere.
+ */
+ sknp = smk_find_mapped(skp, ns);
+ if (sknp != NULL) {
+ if (sknp->smk_allocated)
+ kfree(sknp->smk_mapped);
+ sknp->smk_mapped = mapped;
+ sknp->smk_allocated = allocated;
+ goto unlockout;
+ }
+
+ sknp = kzalloc(sizeof(*sknp), GFP_KERNEL);
+ if (sknp == NULL) {
+ sknp = ERR_PTR(-ENOMEM);
+ if (allocated)
+ kfree(mapped);
+ goto unlockout;
+ }
+
+ sknp->smk_ns = ns;
+ sknp->smk_mapped = mapped;
+ sknp->smk_allocated = allocated;
+ sknp->smk_unmapped = skp;
+ list_add_rcu(&sknp->smk_list_known, &skp->smk_mapped);
+
+ mutex_lock(&snsp->smk_mapped_lock);
+ list_add_rcu(&sknp->smk_list_ns, &snsp->smk_mapped);
+ mutex_unlock(&snsp->smk_mapped_lock);
+
+unlockout:
+ mutex_unlock(&skp->smk_mapped_lock);
+
+ return sknp;
+}
+
+static void *proc_smack_map_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct smack_known *skp;
+ struct user_namespace *ns = seq->private;
+ loff_t counter = *pos;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(skp, &smack_known_list, list)
+ if (smk_find_mapped(skp, ns) && counter-- == 0)
+ return skp;
+
+ return NULL;
+}
+
+static void proc_smack_map_seq_stop(struct seq_file *seq, void *v)
+{
+ rcu_read_unlock();
+}
+
+static void *proc_smack_map_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct smack_known *skp = v;
+ struct user_namespace *ns = seq->private;
+
+ list_for_each_entry_continue_rcu(skp, &smack_known_list, list) {
+ if (smk_find_mapped(skp, ns)) {
+ (*pos)++;
+ return skp;
+ }
+ }
+
+ return NULL;
+}
+
+static int proc_smack_map_seq_show(struct seq_file *seq, void *v)
+{
+ struct smack_known *skp = v;
+ struct user_namespace *ns = seq->private;
+ struct smack_known_ns *sknp;
+
+ /*
+ * QUESTION: linux-api
+ * What to print when in init_map_ns where the map is empty
+ * effectively meaning identity? Unfortunately it's impossible
+ * to show identity in this syntax without printing all the labels.
+ */
+ if (smk_find_mapped_ns(ns) == NULL) {
+ seq_puts("This namespace is not mapped.\n");
+ } else {
+ sknp = smk_find_mapped(skp, ns);
+ if (sknp)
+ seq_printf(seq, "%s -> %s\n",
+ skp->smk_known, sknp->smk_mapped);
+ }
+
+ return 0;
+}
+
+const struct seq_operations proc_smack_map_seq_operations = {
+ .start = proc_smack_map_seq_start,
+ .stop = proc_smack_map_seq_stop,
+ .next = proc_smack_map_seq_next,
+ .show = proc_smack_map_seq_show,
+};
+
+static DEFINE_MUTEX(smk_map_mutex);
+
+static bool mapping_permitted(const struct file *file,
+ struct user_namespace *user_ns)
+{
+ /*
+ * Do not allow mapping own label. This is in contrast to user
+ * namespace where you can always map your own UID. In Smack having
+ * administrative privileges over your own label (which Smack
+ * namespace effectively gives you) is not equivalent to user
+ * namespace. E.g. things like setting exec/transmute labels that
+ * otherwise would be denied. Hence no own_label param here.
+ */
+
+ /*
+ * Adjusting namespace settings requires capabilities on the target.
+ */
+ if (!file_ns_capable(file, user_ns, CAP_MAC_ADMIN))
+ return false;
+
+ /*
+ * And it requires capabilities in the parent.
+ *
+ * If the Smack namespace was properly hierarchical the user_ns to
+ * check against could be 'user_ns->parent'. Right now because of
+ * security concerns only privileged initial namespace is allowed
+ * to fill the map. For a hierarchical namespaces one would
+ * implement mapping (in the child namespaces) of only mapped labels
+ * (in parent namespace) and change '&init_user_ns' to
+ * 'user_ns->parent'. This will be added in the future.
+ */
+ if (smack_ns_privileged(&init_user_ns, CAP_MAC_ADMIN) &&
+ file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN))
+ return true;
+
+ return false;
+}
+
+ssize_t proc_smack_map_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ struct seq_file *seq = file->private_data;
+ struct user_namespace *ns = seq->private;
+ struct user_namespace *seq_ns = seq_user_ns(seq);
+ struct smack_known *skp;
+ struct smack_known_ns *sknp;
+ unsigned long page = 0;
+ char *kbuf, *pos, *next_line, *tok[2];
+ ssize_t ret;
+ int i;
+
+ /* Mapping labels for the init ns makes no sense */
+ if (ns == &init_user_ns)
+ return -EBADR;
+
+ if ((seq_ns != ns) && (seq_ns != ns->parent))
+ return -EPERM;
+
+ mutex_lock(&smk_map_mutex);
+
+ ret = -EPERM;
+ if (!mapping_permitted(file, ns))
+ goto out;
+
+ /* Get a buffer */
+ ret = ENOMEM;
+ page = __get_free_page(GFP_TEMPORARY);
+ if (!page)
+ goto out;
+ kbuf = (char *)page;
+
+ /* Only allow <= page size writes at the beginning of the file */
+ ret = -EINVAL;
+ if ((*ppos != 0) || (size >= PAGE_SIZE))
+ goto out;
+
+ /* Slurp in the user data */
+ ret = -EFAULT;
+ if (copy_from_user(kbuf, buf, size))
+ goto out;
+ kbuf[size] = '\0';
+
+ /* Parse the user data */
+ pos = kbuf;
+
+ for (; pos; pos = next_line) {
+ ret = -EINVAL;
+
+ /* Find the end of line and ensure I don't look past it */
+ next_line = strchr(pos, '\n');
+ if (next_line) {
+ *next_line = '\0';
+ next_line++;
+ if (*next_line == '\0')
+ next_line = NULL;
+ }
+
+ /* Find tokens in line */
+ for (i = 0; i < 2; ++i) {
+ while (isspace(*pos))
+ *(pos++) = '\0';
+
+ /* unexpected end of file */
+ if (*pos == '\0')
+ goto out;
+
+ tok[i] = pos;
+
+ /* find the end of the token */
+ while (*pos != '\0' && !isspace(*pos))
+ ++pos;
+ }
+
+ /* NUL terminate the last token if not EOL */
+ while (isspace(*pos))
+ *(pos++) = '\0';
+
+ /* there should not be any trailing data */
+ if (*pos != '\0')
+ goto out;
+
+ /* do not allow to map 2 different labels to one name */
+ skp = __smk_find_unmapped(tok[1], 0, ns);
+ if (IS_ERR(skp)) {
+ ret = PTR_ERR(skp);
+ goto out;
+ }
+ if (skp != NULL) {
+ ret = -EEXIST;
+ goto out;
+ }
+
+ skp = smk_import_entry(tok[0], 0);
+ if (IS_ERR(skp)) {
+ ret = PTR_ERR(skp);
+ goto out;
+ }
+
+ /* do not allow remapping */
+ ret = -EEXIST;
+ if (__smk_find_mapped(skp, ns))
+ goto out;
+
+ sknp = smk_import_mapped(skp, ns, tok[1], 0);
+ if (IS_ERR(sknp)) {
+ ret = PTR_ERR(sknp);
+ goto out;
+ }
+ }
+
+ ret = size;
+
+out:
+ mutex_unlock(&smk_map_mutex);
+ if (page)
+ free_page(page);
+
+ return ret;
+}
--
2.1.0
^ permalink raw reply related
* [PATCH v2 6/7] smack: namespace implementation
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
This commit uses all the changes introduced in "namespace groundwork"
and previous preparation patches and makes smack aware of its namespace
and mapped labels.
It modifies the following functions to be namespace aware:
- smk_access
- smk_find_label_name
- smk_get_label
And all functions that use them (e.g. smk_tskacc).
It also adds another function that is used throughout Smack LSM hooks:
- smk_labels_valid - it checks whether both, subject and object labels
are properly mapped in a namespace where they are to be used. This
function is used mostly together with a capability check when there is
no proper access check that usually checks for that.
All the Smack LSM hooks have been adapted to be namespace aware.
The capabilities (CAP_MAC_ADMIN, CAP_MAC_OVERRIDE) has been allowed in
the namespace for few cases. Check the documentation for the details.
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
security/smack/smack.h | 61 ++++++-
security/smack/smack_access.c | 99 ++++++++++--
security/smack/smack_lsm.c | 358 ++++++++++++++++++++++++++++++------------
security/smack/smack_ns.c | 41 ++++-
security/smack/smackfs.c | 57 ++++---
5 files changed, 474 insertions(+), 142 deletions(-)
diff --git a/security/smack/smack.h b/security/smack/smack.h
index a53623a..b8ed852 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -104,6 +104,7 @@ struct superblock_smack {
struct smack_known *smk_floor;
struct smack_known *smk_hat;
struct smack_known *smk_default;
+ struct user_namespace *smk_ns;
int smk_initialized;
};
@@ -111,6 +112,7 @@ struct socket_smack {
struct smack_known *smk_out; /* outbound label */
struct smack_known *smk_in; /* inbound label */
struct smack_known *smk_packet; /* TCP peer label */
+ struct user_namespace *smk_ns; /* user namespace */
};
/*
@@ -131,6 +133,14 @@ struct task_smack {
struct mutex smk_rules_lock; /* lock for the rules */
};
+/*
+ * Used for IPC objects (sem, shm, etc)
+ */
+struct ipc_smack {
+ struct smack_known *smk_known; /* label for access control */
+ struct user_namespace *smk_ns; /* user namespace */
+};
+
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */
#define SMK_INODE_CHANGED 0x04 /* smack was transmuted */
@@ -269,18 +279,20 @@ struct inode_smack *new_inode_smack(struct smack_known *);
*/
int smk_access_entry(char *, char *, struct list_head *);
int smk_access(struct smack_known *, struct smack_known *,
- int, struct smk_audit_info *);
+ struct user_namespace *, int, struct smk_audit_info *);
int smk_tskacc(struct task_struct *, struct smack_known *,
+ struct user_namespace *, u32, struct smk_audit_info *);
+int smk_curacc(struct smack_known *, struct user_namespace *,
u32, struct smk_audit_info *);
-int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
struct smack_known *smack_from_secid(const u32);
char *smk_parse_smack(const char *string, int len, bool *allocated);
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
-char *smk_find_label_name(struct smack_known *skp);
-struct smack_known *smk_get_label(const char *string, int len, bool import);
+char *smk_find_label_name(struct smack_known *skp, struct user_namespace *ns);
+struct smack_known *smk_get_label(const char *string, int len, bool import,
+ struct user_namespace *ns);
/*
* These functions are in smack_ns.c
@@ -291,6 +303,15 @@ struct smack_known_ns *smk_find_mapped(struct smack_known *skp,
struct user_namespace *ns);
struct smack_known *smk_find_unmapped(const char *string, int len,
struct user_namespace *ns);
+bool smk_labels_valid(struct smack_known *sbj, struct smack_known *obj,
+ struct user_namespace *ns);
+#else
+static inline bool smk_labels_valid(struct smack_known *sbj,
+ struct smack_known *obj,
+ struct user_namespace *ns)
+{
+ return true;
+}
#endif /* CONFIG_SECURITY_SMACK_NS */
/*
@@ -397,18 +418,48 @@ static inline struct smack_known *smk_of_current(void)
}
/*
+ * Present a pointer to the user namespace entry in an task blob.
+ */
+static inline
+struct user_namespace *ns_of_task_struct(const struct task_struct *t)
+{
+ struct user_namespace *ns;
+
+ rcu_read_lock();
+ ns = __task_cred(t)->user_ns;
+ rcu_read_unlock();
+
+ return ns;
+}
+
+/*
+ * Present a pointer to the user namespace entry in the current task blob.
+ */
+static inline struct user_namespace *ns_of_current(void)
+{
+ return current->cred->user_ns;
+}
+
+/*
* Internal smack capability check complimentary to the
* set of kernel capable() and has_capability() functions
*
* For a capability in smack related checks to be effective it needs to:
* - have empty onlycap or the current label be the same as onlycap
- * - be in the initial user ns
+ * - be in the initial user ns or have a filled map in the child ns
*/
static inline int smack_capability_allowed(struct smack_known *skp,
struct user_namespace *user_ns)
{
+#ifdef CONFIG_SECURITY_SMACK_NS
+ struct smack_ns *sns = user_ns->security;
+
+ if (user_ns != &init_user_ns && list_empty(&sns->smk_mapped))
+ return 0;
+#else
if (user_ns != &init_user_ns)
return 0;
+#endif /* CONFIG_SECURITY_SMACK_NS */
if (smack_onlycap != NULL && smack_onlycap != skp)
return 0;
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index c4d90d2..600e95c 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/sched.h>
+#include <linux/user_namespace.h>
#include "smack.h"
struct smack_known smack_known_huh = {
@@ -113,6 +114,7 @@ int smk_access_entry(char *subject_label, char *object_label,
* smk_access - determine if a subject has a specific access to an object
* @subject: a pointer to the subject's Smack label entry
* @object: a pointer to the object's Smack label entry
+ * @ns: user namespace to check against (usually subject's)
* @request: the access requested, in "MAY" format
* @a : a pointer to the audit data
*
@@ -123,10 +125,34 @@ int smk_access_entry(char *subject_label, char *object_label,
* Smack labels are shared on smack_list
*/
int smk_access(struct smack_known *subject, struct smack_known *object,
- int request, struct smk_audit_info *a)
+ struct user_namespace *ns, int request, struct smk_audit_info *a)
{
int may = MAY_NOT;
int rc = 0;
+ char *subject_label = subject->smk_known;
+ char *object_label = object->smk_known;
+#ifdef CONFIG_SECURITY_SMACK_NS
+ struct smack_known_ns *sknp;
+ struct smack_known_ns *oknp;
+
+ /*
+ * For the namespaced case we need to check whether the labels
+ * are mapped. If not, refuse. If yes check the builtin rules
+ * on the mapped label strings so the builtin labels can
+ * work properly inside the namespace.
+ */
+ if (smk_find_mapped_ns(ns)) {
+ sknp = smk_find_mapped(subject, ns);
+ oknp = smk_find_mapped(object, ns);
+ if (!sknp || !oknp) {
+ rc = -EACCES;
+ goto out_audit;
+ }
+
+ subject_label = sknp->smk_mapped;
+ object_label = oknp->smk_mapped;
+ }
+#endif
/*
* Hardcoded comparisons.
@@ -134,7 +160,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
/*
* A star subject can't access any object.
*/
- if (subject == &smack_known_star) {
+ if (subject_label == smack_known_star.smk_known) {
rc = -EACCES;
goto out_audit;
}
@@ -143,18 +169,19 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
* Tasks cannot be assigned the internet label.
* An internet subject can access any object.
*/
- if (object == &smack_known_web || subject == &smack_known_web)
+ if (object_label == smack_known_web.smk_known ||
+ subject_label == smack_known_web.smk_known)
goto out_audit;
/*
* A star object can be accessed by any subject.
*/
- if (object == &smack_known_star)
+ if (object_label == smack_known_star.smk_known)
goto out_audit;
/*
* An object can be accessed in any way by a subject
* with the same label.
*/
- if (subject->smk_known == object->smk_known)
+ if (subject_label == object_label)
goto out_audit;
/*
* A hat subject can read or lock any object.
@@ -162,9 +189,9 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
*/
if ((request & MAY_ANYREAD) == request ||
(request & MAY_LOCK) == request) {
- if (object == &smack_known_floor)
+ if (object_label == smack_known_floor.smk_known)
goto out_audit;
- if (subject == &smack_known_hat)
+ if (subject_label == smack_known_hat.smk_known)
goto out_audit;
}
@@ -174,6 +201,7 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
* access (e.g. read is included in readwrite) it's
* good. A negative response from smk_access_entry()
* indicates there is no entry for this pair.
+ * For this check we need real, not mapped labels.
*/
rcu_read_lock();
may = smk_access_entry(subject->smk_known, object->smk_known,
@@ -219,6 +247,7 @@ out_audit:
* smk_tskacc - determine if a task has a specific access to an object
* @tsp: a pointer to the subject's task
* @obj_known: a pointer to the object's label entry
+ * @obj_ns: an object's namespace to check the caps against
* @mode: the access requested, in "MAY" format
* @a : common audit data
*
@@ -228,16 +257,18 @@ out_audit:
* to override the rules.
*/
int smk_tskacc(struct task_struct *task, struct smack_known *obj_known,
- u32 mode, struct smk_audit_info *a)
+ struct user_namespace *obj_ns, u32 mode,
+ struct smk_audit_info *a)
{
struct smack_known *sbj_known = smk_of_task_struct(task);
+ struct user_namespace *sbj_ns = ns_of_task_struct(task);
int may;
int rc;
/*
* Check the global rule list
*/
- rc = smk_access(sbj_known, obj_known, mode, NULL);
+ rc = smk_access(sbj_known, obj_known, sbj_ns, mode, NULL);
if (rc >= 0) {
struct task_smack *tsp;
@@ -261,8 +292,10 @@ int smk_tskacc(struct task_struct *task, struct smack_known *obj_known,
/*
* Allow for priviliged to override policy.
+ * Either in init_ns or when both labels are mapped.
*/
- if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE))
+ if (rc != 0 && smk_labels_valid(sbj_known, obj_known, sbj_ns)
+ && smack_has_ns_privilege(task, obj_ns, CAP_MAC_OVERRIDE))
rc = 0;
out_audit:
@@ -277,6 +310,7 @@ out_audit:
/**
* smk_curacc - determine if current has a specific access to an object
* @obj_known: a pointer to the object's Smack label entry
+ * @obj_ns: an object's namespace to check the caps against
* @mode: the access requested, in "MAY" format
* @a : common audit data
*
@@ -285,10 +319,10 @@ out_audit:
* non zero otherwise. It allows that current may have the capability
* to override the rules.
*/
-int smk_curacc(struct smack_known *obj_known,
+int smk_curacc(struct smack_known *obj_known, struct user_namespace *obj_ns,
u32 mode, struct smk_audit_info *a)
{
- return smk_tskacc(current, obj_known, mode, a);
+ return smk_tskacc(current, obj_known, obj_ns, mode, a);
}
#ifdef CONFIG_AUDIT
@@ -656,14 +690,32 @@ struct smack_known *smack_from_secid(const u32 secid)
}
/**
- * smk_find_label_name - A helper to get a string value of a label
+ * smk_find_label_name - A helper to get a string value of either a label or a
+ * mapped label when inside a namespace
* @skp: a label we want a string value from
+ * @ns: namespace against which we want to get the value
*
* Returns a pointer to a label name or NULL if label name not found.
*/
-char *smk_find_label_name(struct smack_known *skp)
+char *smk_find_label_name(struct smack_known *skp, struct user_namespace *ns)
{
- return skp->smk_known;
+ char *name = NULL;
+
+#ifdef CONFIG_SECURITY_SMACK_NS
+ struct smack_known_ns *sknp;
+
+ if (smk_find_mapped_ns(ns)) {
+ sknp = smk_find_mapped(skp, ns);
+ if (sknp != NULL)
+ name = sknp->smk_mapped;
+ } else {
+ name = skp->smk_known;
+ }
+#else
+ name = skp->smk_known;
+#endif
+
+ return name;
}
/**
@@ -672,17 +724,32 @@ char *smk_find_label_name(struct smack_known *skp)
* @string: a name of a label we look for or want to import
* @len: the string size, or zero if it is NULL terminated
* @import: whether we should import the label if not found
+ * @ns: a namespace the looked for label should be in
*
* Returns a smack_known label that is either imported or found.
* NULL if label not found (only when import == false).
* Error code otherwise.
*/
-struct smack_known *smk_get_label(const char *string, int len, bool import)
+struct smack_known *smk_get_label(const char *string, int len, bool import,
+ struct user_namespace *ns)
{
struct smack_known *skp;
bool allocated;
char *cp;
+#ifdef CONFIG_SECURITY_SMACK_NS
+ if (smk_find_mapped_ns(ns)) {
+ skp = smk_find_unmapped(string, len, ns);
+
+ /* Label not found but we can't import in namespaces */
+ if (skp == NULL && import)
+ skp = ERR_PTR(-EBADR);
+
+ /* will also return error codes from smk_find_unmapped() */
+ return skp;
+ }
+#endif
+
if (import) {
skp = smk_import_entry(string, len);
} else {
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 4ae9a9a..af0a5fd 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -373,6 +373,7 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode)
* smk_ptrace_rule_check - helper for ptrace access
* @tracer: tracer process
* @tracee_known: label entry of the process that's about to be traced
+ * @tracee_ns: a tracee's namespace to check the caps against
* @mode: ptrace attachment mode (PTRACE_MODE_*)
* @func: name of the function that called us, used for audit
*
@@ -380,6 +381,7 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode)
*/
static int smk_ptrace_rule_check(struct task_struct *tracer,
struct smack_known *tracee_known,
+ struct user_namespace *tracee_ns,
unsigned int mode, const char *func)
{
int rc;
@@ -391,21 +393,28 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
saip = &ad;
}
-
if ((mode & PTRACE_MODE_ATTACH) &&
(smack_ptrace_rule == SMACK_PTRACE_EXACT ||
smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
struct smack_known *tracer_known = smk_of_task_struct(tracer);
+ struct user_namespace *tracer_ns = ns_of_task_struct(tracer);
+
+ if (!smk_labels_valid(tracer_known, tracee_known, tracer_ns)) {
+ rc = -EACCES;
+ goto out;
+ }
if (tracer_known->smk_known == tracee_known->smk_known)
rc = 0;
else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
rc = -EACCES;
- else if (smack_has_privilege(tracer, CAP_SYS_PTRACE))
+ else if (smack_has_ns_privilege(tracer, tracee_ns,
+ CAP_SYS_PTRACE))
rc = 0;
else
rc = -EPERM;
+out:
if (saip)
smack_log(tracer_known->smk_known,
tracee_known->smk_known,
@@ -415,7 +424,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
}
/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
- return smk_tskacc(tracer, tracee_known, smk_ptrace_mode(mode), saip);
+ return smk_tskacc(tracer, tracee_known, tracee_ns,
+ smk_ptrace_mode(mode), saip);
}
/*
@@ -435,8 +445,9 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
struct smack_known *skp = smk_of_task_struct(ctp);
+ struct user_namespace *ns = ns_of_task_struct(ctp);
- return smk_ptrace_rule_check(current, skp, mode, __func__);
+ return smk_ptrace_rule_check(current, skp, ns, mode, __func__);
}
/**
@@ -450,8 +461,10 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
static int smack_ptrace_traceme(struct task_struct *ptp)
{
struct smack_known *skp = smk_of_current();
+ struct user_namespace *ns = ns_of_current();
- return smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
+ return smk_ptrace_rule_check(ptp, skp, ns, PTRACE_MODE_ATTACH,
+ __func__);
}
/**
@@ -498,6 +511,7 @@ static int smack_sb_alloc_security(struct super_block *sb)
sbsp->smk_default = &smack_known_floor;
sbsp->smk_floor = &smack_known_floor;
sbsp->smk_hat = &smack_known_hat;
+ sbsp->smk_ns = get_user_ns(&init_user_ns);
/*
* smk_initialized will be zero from kzalloc.
*/
@@ -513,6 +527,9 @@ static int smack_sb_alloc_security(struct super_block *sb)
*/
static void smack_sb_free_security(struct super_block *sb)
{
+ struct superblock_smack *sbsp = sb->s_security;
+
+ put_user_ns(sbsp->smk_ns);
kfree(sb->s_security);
sb->s_security = NULL;
}
@@ -579,6 +596,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
struct superblock_smack *sp = sb->s_security;
struct inode_smack *isp;
struct smack_known *skp;
+ struct user_namespace *ns = ns_of_current();
char *op;
char *commap;
int transmute = 0;
@@ -596,7 +614,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
op += strlen(SMK_FSHAT);
- skp = smk_get_label(op, 0, true);
+ skp = smk_get_label(op, 0, true, ns);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_hat = skp;
@@ -604,7 +622,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
op += strlen(SMK_FSFLOOR);
- skp = smk_get_label(op, 0, true);
+ skp = smk_get_label(op, 0, true, ns);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_floor = skp;
@@ -613,7 +631,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSDEFAULT,
strlen(SMK_FSDEFAULT)) == 0) {
op += strlen(SMK_FSDEFAULT);
- skp = smk_get_label(op, 0, true);
+ skp = smk_get_label(op, 0, true, ns);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_default = skp;
@@ -621,7 +639,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
op += strlen(SMK_FSROOT);
- skp = smk_get_label(op, 0, true);
+ skp = smk_get_label(op, 0, true, ns);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp;
@@ -629,7 +647,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
op += strlen(SMK_FSTRANS);
- skp = smk_get_label(op, 0, true);
+ skp = smk_get_label(op, 0, true, ns);
if (IS_ERR(skp))
return PTR_ERR(skp);
sp->smk_root = skp;
@@ -638,7 +656,12 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
}
}
- if (!smack_privileged(CAP_MAC_ADMIN)) {
+ /*
+ * Check for non-privileged case. If current is inside the namespace
+ * and the it has privileges the validity of labels has already been
+ * checked during smk_get_label()
+ */
+ if (!smack_ns_privileged(ns, CAP_MAC_ADMIN)) {
/*
* Unprivileged mounts don't get to specify Smack values.
*/
@@ -651,6 +674,13 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
sp->smk_root = skp;
sp->smk_default = skp;
}
+
+ /*
+ * Set the superblock namespace from a mounting process
+ */
+ put_user_ns(sp->smk_ns);
+ sp->smk_ns = get_user_ns(ns);
+
/*
* Initialize the root inode.
*/
@@ -685,7 +715,7 @@ static int smack_sb_statfs(struct dentry *dentry)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
+ rc = smk_curacc(sbp->smk_floor, sbp->smk_ns, MAY_READ, &ad);
rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc);
return rc;
}
@@ -705,6 +735,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
struct inode *inode = file_inode(bprm->file);
struct task_smack *bsp = bprm->cred->security;
struct inode_smack *isp;
+ struct user_namespace *ns = ns_of_current();
int rc;
if (bprm->cred_prepared)
@@ -714,6 +745,13 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
return 0;
+#ifdef CONFIG_SECURITY_SMACK_NS
+ /* one label version of smk_labels_valid() */
+ if (smk_find_mapped_ns(ns) &&
+ smk_find_mapped(isp->smk_task, ns) == NULL)
+ return -EACCES;
+#endif
+
if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
struct task_struct *tracer;
rc = 0;
@@ -721,9 +759,8 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
rcu_read_lock();
tracer = ptrace_parent(current);
if (likely(tracer != NULL))
- rc = smk_ptrace_rule_check(tracer,
- isp->smk_task,
- PTRACE_MODE_ATTACH,
+ rc = smk_ptrace_rule_check(tracer, isp->smk_task,
+ ns, PTRACE_MODE_ATTACH,
__func__);
rcu_read_unlock();
@@ -864,6 +901,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
struct smack_known *isp;
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
int rc;
@@ -871,13 +909,13 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
isp = smk_of_inode(d_backing_inode(old_dentry));
- rc = smk_curacc(isp, MAY_WRITE, &ad);
+ rc = smk_curacc(isp, ns, MAY_WRITE, &ad);
rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_WRITE, rc);
if (rc == 0 && d_is_positive(new_dentry)) {
isp = smk_of_inode(d_backing_inode(new_dentry));
smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
- rc = smk_curacc(isp, MAY_WRITE, &ad);
+ rc = smk_curacc(isp, ns, MAY_WRITE, &ad);
rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_WRITE, rc);
}
@@ -895,6 +933,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *ip = d_backing_inode(dentry);
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
int rc;
@@ -904,7 +943,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
/*
* You need write access to the thing you're unlinking
*/
- rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(ip), ns, MAY_WRITE, &ad);
rc = smk_bu_inode(ip, MAY_WRITE, rc);
if (rc == 0) {
/*
@@ -912,7 +951,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
*/
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, dir);
- rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(dir), ns, MAY_WRITE, &ad);
rc = smk_bu_inode(dir, MAY_WRITE, rc);
}
return rc;
@@ -928,6 +967,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
*/
static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
{
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
int rc;
@@ -937,7 +977,8 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
/*
* You need write access to the thing you're removing
*/
- rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns,
+ MAY_WRITE, &ad);
rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
if (rc == 0) {
/*
@@ -945,7 +986,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
*/
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, dir);
- rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(dir), ns, MAY_WRITE, &ad);
rc = smk_bu_inode(dir, MAY_WRITE, rc);
}
@@ -969,21 +1010,22 @@ static int smack_inode_rename(struct inode *old_inode,
struct inode *new_inode,
struct dentry *new_dentry)
{
- int rc;
struct smack_known *isp;
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
+ int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
isp = smk_of_inode(d_backing_inode(old_dentry));
- rc = smk_curacc(isp, MAY_READWRITE, &ad);
+ rc = smk_curacc(isp, ns, MAY_READWRITE, &ad);
rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_READWRITE, rc);
if (rc == 0 && d_is_positive(new_dentry)) {
isp = smk_of_inode(d_backing_inode(new_dentry));
smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
- rc = smk_curacc(isp, MAY_READWRITE, &ad);
+ rc = smk_curacc(isp, ns, MAY_READWRITE, &ad);
rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_READWRITE, rc);
}
return rc;
@@ -1000,6 +1042,7 @@ static int smack_inode_rename(struct inode *old_inode,
*/
static int smack_inode_permission(struct inode *inode, int mask)
{
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
int no_block = mask & MAY_NOT_BLOCK;
int rc;
@@ -1016,7 +1059,7 @@ static int smack_inode_permission(struct inode *inode, int mask)
return -ECHILD;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, inode);
- rc = smk_curacc(smk_of_inode(inode), mask, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, mask, &ad);
rc = smk_bu_inode(inode, mask, rc);
return rc;
}
@@ -1030,6 +1073,7 @@ static int smack_inode_permission(struct inode *inode, int mask)
*/
static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
int rc;
@@ -1041,7 +1085,8 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns,
+ MAY_WRITE, &ad);
rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
return rc;
}
@@ -1055,13 +1100,14 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
*/
static int smack_inode_getattr(const struct path *path)
{
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
struct inode *inode = d_backing_inode(path->dentry);
int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, *path);
- rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, MAY_READ, &ad);
rc = smk_bu_inode(inode, MAY_READ, rc);
return rc;
}
@@ -1083,6 +1129,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
{
struct smk_audit_info ad;
struct smack_known *skp;
+ struct smack_known *sbj = smk_of_current();
+ struct smack_known *obj = smk_of_inode(d_backing_inode(dentry));
+ struct user_namespace *ns = ns_of_current();
int check_priv = 0;
int check_import = 0;
int check_star = 0;
@@ -1109,11 +1158,12 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
} else
rc = cap_inode_setxattr(dentry, name, value, size, flags);
- if (check_priv && !smack_privileged(CAP_MAC_ADMIN))
+ if (check_priv && !(smk_labels_valid(sbj, obj, ns) &&
+ smack_ns_privileged(ns, CAP_MAC_ADMIN)))
rc = -EPERM;
if (rc == 0 && check_import) {
- skp = size ? smk_get_label(value, size, true) : NULL;
+ skp = size ? smk_get_label(value, size, true, ns) : NULL;
if (IS_ERR(skp))
rc = PTR_ERR(skp);
else if (skp == NULL || (check_star &&
@@ -1125,7 +1175,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
if (rc == 0) {
- rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_curacc(obj, ns, MAY_WRITE, &ad);
rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
}
@@ -1149,6 +1199,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
struct smack_known *skp;
struct smack_known **skpp = NULL;
struct inode_smack *isp = d_backing_inode(dentry)->i_security;
+ struct user_namespace *ns = ns_of_current();
if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
isp->smk_flags |= SMK_INODE_TRANSMUTE;
@@ -1163,12 +1214,24 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
skpp = &isp->smk_mmap;
if (skpp) {
- skp = smk_get_label(value, size, true);
+ skp = smk_get_label(value, size, true, ns);
if (!IS_ERR(skp))
*skpp = skp;
else
*skpp = &smack_known_invalid;
+
+ /*
+ * The label we get above might be a different than the one
+ * kernel has already set before calling this function.
+ * Be consistent and set the final value in the filesystem.
+ * The cases for this are errors and labels being used
+ * in a namespace where we want to store an unmapped
+ * value in the filesystem.
+ */
+ dentry->d_inode->i_op->setxattr(dentry, name,
+ (*skpp)->smk_known,
+ size, flags);
}
}
@@ -1181,13 +1244,15 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
*/
static int smack_inode_getxattr(struct dentry *dentry, const char *name)
{
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_READ, &ad);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), ns,
+ MAY_READ, &ad);
rc = smk_bu_inode(d_backing_inode(dentry), MAY_READ, rc);
return rc;
}
@@ -1204,6 +1269,9 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
static int smack_inode_removexattr(struct dentry *dentry, const char *name)
{
struct inode_smack *isp;
+ struct smack_known *sbj = smk_of_current();
+ struct smack_known *obj = smk_of_inode(d_backing_inode(dentry));
+ struct user_namespace *ns = ns_of_current();
struct smk_audit_info ad;
int rc = 0;
@@ -1213,7 +1281,8 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 ||
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
- if (!smack_privileged(CAP_MAC_ADMIN))
+ if (!smk_labels_valid(sbj, obj, ns) ||
+ !smack_ns_privileged(ns, CAP_MAC_ADMIN))
rc = -EPERM;
} else
rc = cap_inode_removexattr(dentry, name);
@@ -1224,7 +1293,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_curacc(obj, ns, MAY_WRITE, &ad);
rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
if (rc != 0)
return rc;
@@ -1264,13 +1333,18 @@ static int smack_inode_getsecurity(const struct inode *inode,
struct super_block *sbp;
struct inode *ip = (struct inode *)inode;
struct smack_known *isp = NULL;
+ struct user_namespace *ns = ns_of_current();
int rc = 0;
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0)
isp = smk_of_inode(inode);
+ else if (strcmp(name, XATTR_SMACK_EXEC) == 0)
+ isp = smk_of_exec(inode);
+ else if (strcmp(name, XATTR_SMACK_MMAP) == 0)
+ isp = smk_of_mmap(inode);
if (isp) {
- *buffer = smk_find_label_name(isp);
+ *buffer = smk_find_label_name(isp, ns);
if (*buffer == NULL)
*buffer = smack_known_huh.smk_known;
return strlen(*buffer);
@@ -1297,7 +1371,7 @@ static int smack_inode_getsecurity(const struct inode *inode,
return -EOPNOTSUPP;
if (rc == 0) {
- *buffer = smk_find_label_name(isp);
+ *buffer = smk_find_label_name(isp, ns);
if (*buffer == NULL)
*buffer = smack_known_huh.smk_known;
rc = strlen(*buffer);
@@ -1408,18 +1482,19 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
{
int rc = 0;
struct smk_audit_info ad;
+ struct user_namespace *ns = ns_of_current();
struct inode *inode = file_inode(file);
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
if (_IOC_DIR(cmd) & _IOC_WRITE) {
- rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, MAY_WRITE, &ad);
rc = smk_bu_file(file, MAY_WRITE, rc);
}
if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
- rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, MAY_READ, &ad);
rc = smk_bu_file(file, MAY_READ, rc);
}
@@ -1437,11 +1512,12 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
{
struct smk_audit_info ad;
int rc;
+ struct user_namespace *ns = ns_of_current();
struct inode *inode = file_inode(file);
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
- rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, MAY_LOCK, &ad);
rc = smk_bu_file(file, MAY_LOCK, rc);
return rc;
}
@@ -1463,6 +1539,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
{
struct smk_audit_info ad;
int rc = 0;
+ struct user_namespace *ns = ns_of_current();
struct inode *inode = file_inode(file);
switch (cmd) {
@@ -1472,14 +1549,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
case F_SETLKW:
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
- rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, MAY_LOCK, &ad);
rc = smk_bu_file(file, MAY_LOCK, rc);
break;
case F_SETOWN:
case F_SETSIG:
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
- rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, MAY_WRITE, &ad);
rc = smk_bu_file(file, MAY_WRITE, rc);
break;
default:
@@ -1509,6 +1586,7 @@ static int smack_mmap_file(struct file *file,
struct task_smack *tsp;
struct smack_known *okp;
struct inode_smack *isp;
+ struct user_namespace *sns;
int may;
int mmay;
int tmay;
@@ -1519,12 +1597,16 @@ static int smack_mmap_file(struct file *file,
tsp = current_security();
skp = smk_of_task(tsp);
+ sns = ns_of_current();
isp = file_inode(file)->i_security;
mkp = isp->smk_mmap;
if (mkp == NULL)
return 0;
+ if (!smk_labels_valid(skp, mkp, sns))
+ return -EACCES;
+
rc = 0;
rcu_read_lock();
@@ -1540,6 +1622,7 @@ static int smack_mmap_file(struct file *file,
*/
if (mkp->smk_known == okp->smk_known)
continue;
+
/*
* If there is a matching local rule take
* that into account as well.
@@ -1619,8 +1702,10 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
struct smack_known *skp;
- struct smack_known *tkp = smk_of_task(tsk->cred->security);
+ struct smack_known *tkp;
struct file *file;
+ struct user_namespace *sns;
+ struct user_namespace *tns;
int rc;
struct smk_audit_info ad;
@@ -1628,12 +1713,17 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
* struct fown_struct is never outside the context of a struct file
*/
file = container_of(fown, struct file, f_owner);
+ skp = file->f_security;
+ sns = file->f_cred->user_ns;
+
+ tkp = smk_of_task_struct(tsk);
+ tns = ns_of_task_struct(tsk);
/* we don't log here as rc can be overriden */
- skp = file->f_security;
- rc = smk_access(skp, tkp, MAY_WRITE, NULL);
+ rc = smk_access(skp, tkp, sns, MAY_WRITE, NULL);
rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc);
- if (rc != 0 && smack_has_privilege(tsk, CAP_MAC_OVERRIDE))
+ if (rc != 0 && smk_labels_valid(skp, tkp, sns)
+ && smack_has_ns_privilege(tsk, tns, CAP_MAC_OVERRIDE))
rc = 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
@@ -1653,6 +1743,7 @@ static int smack_file_receive(struct file *file)
int rc;
int may = 0;
struct smk_audit_info ad;
+ struct user_namespace *ns = ns_of_current();
struct inode *inode = file_inode(file);
if (unlikely(IS_PRIVATE(inode)))
@@ -1668,7 +1759,7 @@ static int smack_file_receive(struct file *file)
if (file->f_mode & FMODE_WRITE)
may |= MAY_WRITE;
- rc = smk_curacc(smk_of_inode(inode), may, &ad);
+ rc = smk_curacc(smk_of_inode(inode), ns, may, &ad);
rc = smk_bu_file(file, may, rc);
return rc;
}
@@ -1688,16 +1779,19 @@ static int smack_file_receive(struct file *file)
static int smack_file_open(struct file *file, const struct cred *cred)
{
struct task_smack *tsp = cred->security;
+ struct user_namespace *ns = cred->user_ns;
struct inode *inode = file_inode(file);
+ struct inode_smack *isp = file_inode(file)->i_security;
struct smk_audit_info ad;
int rc;
- if (smack_privileged(CAP_MAC_OVERRIDE))
+ if (smk_labels_valid(tsp->smk_task, isp->smk_inode, ns) &&
+ smack_ns_privileged(ns, CAP_MAC_OVERRIDE))
return 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
- rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad);
+ rc = smk_access(tsp->smk_task, smk_of_inode(inode), ns, MAY_READ, &ad);
rc = smk_bu_credfile(cred, file, MAY_READ, rc);
return rc;
@@ -1852,12 +1946,13 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
const char *caller)
{
struct smk_audit_info ad;
- struct smack_known *skp = smk_of_task_struct(p);
+ struct smack_known *tkp = smk_of_task_struct(p);
+ struct user_namespace *tns = ns_of_task_struct(p);
int rc;
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
- rc = smk_curacc(skp, access, &ad);
+ rc = smk_curacc(tkp, tns, access, &ad);
rc = smk_bu_task(p, access, rc);
return rc;
}
@@ -1998,6 +2093,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
struct smk_audit_info ad;
struct smack_known *skp;
struct smack_known *tkp = smk_of_task_struct(p);
+ struct user_namespace *tns = ns_of_task_struct(p);
int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
@@ -2007,7 +2103,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* can write the receiver.
*/
if (secid == 0) {
- rc = smk_curacc(tkp, MAY_WRITE, &ad);
+ rc = smk_curacc(tkp, tns, MAY_WRITE, &ad);
rc = smk_bu_task(p, MAY_WRITE, rc);
return rc;
}
@@ -2017,8 +2113,10 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* we can't take privilege into account.
*/
skp = smack_from_secid(secid);
- rc = smk_access(skp, tkp, MAY_WRITE, &ad);
+
+ rc = smk_access(skp, tkp, tns, MAY_WRITE, &ad);
rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc);
+
return rc;
}
@@ -2073,6 +2171,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
{
struct smack_known *skp = smk_of_current();
+ struct user_namespace *ns = ns_of_current();
struct socket_smack *ssp;
ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
@@ -2082,6 +2181,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
ssp->smk_in = skp;
ssp->smk_out = skp;
ssp->smk_packet = NULL;
+ ssp->smk_ns = get_user_ns(ns);
sk->sk_security = ssp;
@@ -2096,7 +2196,11 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
*/
static void smack_sk_free_security(struct sock *sk)
{
+ struct socket_smack *ssp = sk->sk_security;
+
+ put_user_ns(ssp->smk_ns);
kfree(sk->sk_security);
+ sk->sk_security = NULL;
}
/**
@@ -2191,6 +2295,7 @@ static int smack_netlabel(struct sock *sk, int labeled)
static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
{
struct smack_known *skp;
+ struct user_namespace *sns;
int rc;
int sk_lbl;
struct smack_known *hkp;
@@ -2210,7 +2315,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
#endif
sk_lbl = SMACK_UNLABELED_SOCKET;
skp = ssp->smk_out;
- rc = smk_access(skp, hkp, MAY_WRITE, &ad);
+ sns = ssp->smk_ns;
+ rc = smk_access(skp, hkp, sns, MAY_WRITE, &ad);
rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc);
} else {
sk_lbl = SMACK_CIPSO_SOCKET;
@@ -2312,6 +2418,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
struct smk_port_label *spp;
struct socket_smack *ssp = sk->sk_security;
struct smack_known *skp;
+ struct user_namespace *sns = ssp->smk_ns;
unsigned short port = 0;
struct smack_known *object;
struct smk_audit_info ad;
@@ -2369,7 +2476,7 @@ auditout:
else
ad.a.u.net->v6info.daddr = address->sin6_addr;
#endif
- rc = smk_access(skp, object, MAY_WRITE, &ad);
+ rc = smk_access(skp, object, sns, MAY_WRITE, &ad);
rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
return rc;
}
@@ -2394,12 +2501,13 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
struct inode_smack *nsp = inode->i_security;
struct socket_smack *ssp;
struct socket *sock;
+ struct user_namespace *ns = ns_of_current();
int rc = 0;
if (value == NULL || size > SMK_LONGLABEL || size == 0)
return -EINVAL;
- skp = smk_import_entry(value, size);
+ skp = smk_get_label(value, size, true, ns);
if (IS_ERR(skp))
return PTR_ERR(skp);
@@ -2584,14 +2692,14 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
}
/**
- * smack_of_shm - the smack pointer for the shm
+ * security_of_shm - the smack pointer for the shm
* @shp: the object
*
- * Returns a pointer to the smack value
+ * Returns a pointer to the security_smack struct
*/
-static struct smack_known *smack_of_shm(struct shmid_kernel *shp)
+static struct ipc_smack *security_of_shm(struct shmid_kernel *shp)
{
- return (struct smack_known *)shp->shm_perm.security;
+ return (struct ipc_smack *)shp->shm_perm.security;
}
/**
@@ -2603,9 +2711,16 @@ static struct smack_known *smack_of_shm(struct shmid_kernel *shp)
static int smack_shm_alloc_security(struct shmid_kernel *shp)
{
struct kern_ipc_perm *isp = &shp->shm_perm;
- struct smack_known *skp = smk_of_current();
+ struct ipc_smack *ssp;
- isp->security = skp;
+ ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL);
+ if (ssp == NULL)
+ return -ENOMEM;
+
+ ssp->smk_known = smk_of_current();
+ ssp->smk_ns = get_user_ns(ns_of_current());
+
+ isp->security = ssp;
return 0;
}
@@ -2618,7 +2733,10 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
static void smack_shm_free_security(struct shmid_kernel *shp)
{
struct kern_ipc_perm *isp = &shp->shm_perm;
+ struct ipc_smack *ssp = isp->security;
+ put_user_ns(ssp->smk_ns);
+ kfree(isp->security);
isp->security = NULL;
}
@@ -2631,7 +2749,7 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
*/
static int smk_curacc_shm(struct shmid_kernel *shp, int access)
{
- struct smack_known *ssp = smack_of_shm(shp);
+ struct ipc_smack *ssp = security_of_shm(shp);
struct smk_audit_info ad;
int rc;
@@ -2639,8 +2757,8 @@ static int smk_curacc_shm(struct shmid_kernel *shp, int access)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = shp->shm_perm.id;
#endif
- rc = smk_curacc(ssp, access, &ad);
- rc = smk_bu_current("shm", ssp, access, rc);
+ rc = smk_curacc(ssp->smk_known, ssp->smk_ns, access, &ad);
+ rc = smk_bu_current("shm", ssp->smk_known, access, rc);
return rc;
}
@@ -2711,14 +2829,14 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
}
/**
- * smack_of_sem - the smack pointer for the sem
+ * security_of_sem - the smack pointer for the sem
* @sma: the object
*
- * Returns a pointer to the smack value
+ * Returns a pointer to the ipc_smack struct
*/
-static struct smack_known *smack_of_sem(struct sem_array *sma)
+static struct ipc_smack *security_of_sem(struct sem_array *sma)
{
- return (struct smack_known *)sma->sem_perm.security;
+ return (struct ipc_smack *)sma->sem_perm.security;
}
/**
@@ -2730,9 +2848,16 @@ static struct smack_known *smack_of_sem(struct sem_array *sma)
static int smack_sem_alloc_security(struct sem_array *sma)
{
struct kern_ipc_perm *isp = &sma->sem_perm;
- struct smack_known *skp = smk_of_current();
+ struct ipc_smack *ssp;
- isp->security = skp;
+ ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL);
+ if (ssp == NULL)
+ return -ENOMEM;
+
+ ssp->smk_known = smk_of_current();
+ ssp->smk_ns = get_user_ns(ns_of_current());
+
+ isp->security = ssp;
return 0;
}
@@ -2745,7 +2870,10 @@ static int smack_sem_alloc_security(struct sem_array *sma)
static void smack_sem_free_security(struct sem_array *sma)
{
struct kern_ipc_perm *isp = &sma->sem_perm;
+ struct ipc_smack *ssp = isp->security;
+ put_user_ns(ssp->smk_ns);
+ kfree(isp->security);
isp->security = NULL;
}
@@ -2758,7 +2886,7 @@ static void smack_sem_free_security(struct sem_array *sma)
*/
static int smk_curacc_sem(struct sem_array *sma, int access)
{
- struct smack_known *ssp = smack_of_sem(sma);
+ struct ipc_smack *ssp = security_of_sem(sma);
struct smk_audit_info ad;
int rc;
@@ -2766,8 +2894,8 @@ static int smk_curacc_sem(struct sem_array *sma, int access)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = sma->sem_perm.id;
#endif
- rc = smk_curacc(ssp, access, &ad);
- rc = smk_bu_current("sem", ssp, access, rc);
+ rc = smk_curacc(ssp->smk_known, ssp->smk_ns, access, &ad);
+ rc = smk_bu_current("sem", ssp->smk_known, access, rc);
return rc;
}
@@ -2852,9 +2980,16 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
static int smack_msg_queue_alloc_security(struct msg_queue *msq)
{
struct kern_ipc_perm *kisp = &msq->q_perm;
- struct smack_known *skp = smk_of_current();
+ struct ipc_smack *ssp;
+
+ ssp = kzalloc(sizeof(struct ipc_smack), GFP_KERNEL);
+ if (ssp == NULL)
+ return -ENOMEM;
+
+ ssp->smk_known = smk_of_current();
+ ssp->smk_ns = get_user_ns(ns_of_current());
- kisp->security = skp;
+ kisp->security = ssp;
return 0;
}
@@ -2867,19 +3002,22 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
static void smack_msg_queue_free_security(struct msg_queue *msq)
{
struct kern_ipc_perm *kisp = &msq->q_perm;
+ struct ipc_smack *ssp = kisp->security;
+ put_user_ns(ssp->smk_ns);
+ kfree(kisp->security);
kisp->security = NULL;
}
/**
- * smack_of_msq - the smack pointer for the msq
+ * security_of_msq - the smack pointer for the msq
* @msq: the object
*
- * Returns a pointer to the smack label entry
+ * Returns a pointer to the ipc_smack struct
*/
-static struct smack_known *smack_of_msq(struct msg_queue *msq)
+static struct ipc_smack *security_of_msq(struct msg_queue *msq)
{
- return (struct smack_known *)msq->q_perm.security;
+ return (struct ipc_smack *)msq->q_perm.security;
}
/**
@@ -2891,7 +3029,7 @@ static struct smack_known *smack_of_msq(struct msg_queue *msq)
*/
static int smk_curacc_msq(struct msg_queue *msq, int access)
{
- struct smack_known *msp = smack_of_msq(msq);
+ struct ipc_smack *msp = security_of_msq(msq);
struct smk_audit_info ad;
int rc;
@@ -2899,8 +3037,8 @@ static int smk_curacc_msq(struct msg_queue *msq, int access)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = msq->q_perm.id;
#endif
- rc = smk_curacc(msp, access, &ad);
- rc = smk_bu_current("msq", msp, access, rc);
+ rc = smk_curacc(msp->smk_known, msp->smk_ns, access, &ad);
+ rc = smk_bu_current("msq", msp->smk_known, access, rc);
return rc;
}
@@ -2994,7 +3132,7 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
*/
static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
{
- struct smack_known *iskp = ipp->security;
+ struct ipc_smack *isp = ipp->security;
int may = smack_flags_to_may(flag);
struct smk_audit_info ad;
int rc;
@@ -3003,8 +3141,8 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = ipp->id;
#endif
- rc = smk_curacc(iskp, may, &ad);
- rc = smk_bu_current("svipc", iskp, may, rc);
+ rc = smk_curacc(isp->smk_known, isp->smk_ns, may, &ad);
+ rc = smk_bu_current("svipc", isp->smk_known, may, rc);
return rc;
}
@@ -3015,9 +3153,9 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
*/
static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
{
- struct smack_known *iskp = ipp->security;
+ struct ipc_smack *iskp = ipp->security;
- *secid = iskp->smk_secid;
+ *secid = iskp->smk_known->smk_secid;
}
/**
@@ -3251,13 +3389,14 @@ unlockandout:
static int smack_getprocattr(struct task_struct *p, char *name, char **value)
{
struct smack_known *skp = smk_of_task_struct(p);
+ struct user_namespace *ns = ns_of_current();
char *cp;
int slen;
if (strcmp(name, "current") != 0)
return -EINVAL;
- cp = smk_find_label_name(skp);
+ cp = smk_find_label_name(skp, ns);
if (cp == NULL)
cp = smack_known_huh.smk_known;
cp = kstrdup(cp, GFP_KERNEL);
@@ -3287,6 +3426,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
struct task_smack *tsp;
struct cred *new;
struct smack_known *skp;
+ struct user_namespace *ns;
/*
* Changing another process' Smack value is too dangerous
@@ -3295,7 +3435,9 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (p != current)
return -EPERM;
- if (!smack_privileged(CAP_MAC_ADMIN))
+ ns = ns_of_current();
+
+ if (!smack_ns_privileged(ns, CAP_MAC_ADMIN))
return -EPERM;
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
@@ -3304,7 +3446,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (strcmp(name, "current") != 0)
return -EINVAL;
- skp = smk_get_label(value, size, true);
+ skp = smk_get_label(value, size, true, ns);
if (IS_ERR(skp))
return PTR_ERR(skp);
@@ -3344,23 +3486,27 @@ static int smack_unix_stream_connect(struct sock *sock,
struct smack_known *okp_out = osp->smk_out;
struct smack_known *skp_in = ssp->smk_in;
struct smack_known *okp_in = osp->smk_in;
+ struct user_namespace *sns = ssp->smk_ns;
+ struct user_namespace *ons = osp->smk_ns;
struct smk_audit_info ad;
int rc = 0;
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
#endif
- if (!smack_privileged(CAP_MAC_OVERRIDE)) {
+ if (!smack_ns_privileged(ons, CAP_MAC_OVERRIDE) ||
+ !smk_labels_valid(skp_out, okp_in, sns) ||
+ !smk_labels_valid(okp_out, skp_in, ons)) {
#ifdef CONFIG_AUDIT
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
smk_ad_setfield_u_net_sk(&ad, other);
#endif
- rc = smk_access(skp_out, okp_in, MAY_WRITE, &ad);
+ rc = smk_access(skp_out, okp_in, sns, MAY_WRITE, &ad);
rc = smk_bu_note("UDS connect", skp_out, okp_in, MAY_WRITE, rc);
if (rc == 0) {
- rc = smk_access(okp_out, skp_in, MAY_WRITE, &ad);
+ rc = smk_access(okp_out, skp_in, ons, MAY_WRITE, &ad);
rc = smk_bu_note("UDS connect", okp_out, skp_in,
- MAY_WRITE, rc);
+ MAY_WRITE, rc);
}
}
@@ -3387,6 +3533,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
{
struct socket_smack *ssp = sock->sk->sk_security;
struct socket_smack *osp = other->sk->sk_security;
+ struct user_namespace *sns = ssp->smk_ns;
+ struct user_namespace *ons = osp->smk_ns;
struct smk_audit_info ad;
int rc;
@@ -3397,10 +3545,11 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
smk_ad_setfield_u_net_sk(&ad, other->sk);
#endif
- if (smack_privileged(CAP_MAC_OVERRIDE))
+ if (smk_labels_valid(ssp->smk_out, osp->smk_in, sns) &&
+ smack_ns_privileged(ons, CAP_MAC_OVERRIDE))
return 0;
- rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+ rc = smk_access(ssp->smk_out, osp->smk_in, sns, MAY_WRITE, &ad);
rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc);
return rc;
}
@@ -3640,7 +3789,7 @@ access_check:
* This is the simplist possible security model
* for networking.
*/
- rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+ rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad);
rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
MAY_WRITE, rc);
if (rc != 0)
@@ -3662,7 +3811,7 @@ access_check:
ad.a.u.net->netif = skb->skb_iif;
ipv6_skb_to_auditdata(skb, &ad.a, NULL);
#endif /* CONFIG_AUDIT */
- rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+ rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad);
rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in,
MAY_WRITE, rc);
#else /* CONFIG_SECURITY_SMACK_NETFILTER */
@@ -3875,7 +4024,7 @@ access_check:
* Receiving a packet requires that the other end be able to write
* here. Read access is not required.
*/
- rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+ rc = smk_access(skp, ssp->smk_in, ssp->smk_ns, MAY_WRITE, &ad);
rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc);
if (rc != 0)
return rc;
@@ -3979,6 +4128,7 @@ static int smack_key_permission(key_ref_t key_ref,
struct key *keyp;
struct smk_audit_info ad;
struct smack_known *tkp = smk_of_task(cred->security);
+ struct user_namespace *tns = cred->user_ns;
int request = 0;
int rc;
@@ -4005,7 +4155,7 @@ static int smack_key_permission(key_ref_t key_ref,
request = MAY_READ;
if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
request = MAY_WRITE;
- rc = smk_access(tkp, keyp->security, request, &ad);
+ rc = smk_access(tkp, keyp->security, tns, request, &ad);
rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
return rc;
}
@@ -4022,6 +4172,7 @@ static int smack_key_permission(key_ref_t key_ref,
static int smack_key_getsecurity(struct key *key, char **_buffer)
{
struct smack_known *skp = key->security;
+ struct user_namespace *ns = ns_of_current();
size_t length;
char *copy;
@@ -4030,7 +4181,7 @@ static int smack_key_getsecurity(struct key *key, char **_buffer)
return 0;
}
- copy = smk_find_label_name(skp);
+ copy = smk_find_label_name(skp, ns);
if (copy == NULL)
copy = smack_known_huh.smk_known;
copy = kstrdup(copy, GFP_KERNEL);
@@ -4208,6 +4359,11 @@ static inline void smack_userns_free(struct user_namespace *ns)
static inline int smack_userns_setns(struct nsproxy *nsproxy,
struct user_namespace *ns)
{
+ struct smack_known *skp = smk_of_current();
+
+ if (smk_find_mapped(skp, ns) == NULL)
+ return -EACCES;
+
return 0;
}
diff --git a/security/smack/smack_ns.c b/security/smack/smack_ns.c
index 141a836..819c490 100644
--- a/security/smack/smack_ns.c
+++ b/security/smack/smack_ns.c
@@ -206,6 +206,45 @@ unlockout:
return sknp;
}
+/**
+ * smk_labels_valid - A helper to check whether labels are valid/mapped
+ * in the namespace and can be used there
+ * @sbj: a subject label to be checked
+ * @obj: an object label to be checked
+ * @ns: user namespace to check against (usually subject's)
+ *
+ * Returns true if both valid/mapped, false otherwise.
+ * This helper is mostly used while checking capabilities.
+ * The access functions check the validity of labels by themselves.
+ */
+bool smk_labels_valid(struct smack_known *sbj, struct smack_known *obj,
+ struct user_namespace *ns)
+{
+ struct user_namespace *user_ns;
+
+ /*
+ * labels are always valid if there is no map
+ * (init_user_ns or unmapped descendants)
+ */
+ user_ns = smk_find_mapped_ns(ns);
+ if (user_ns == NULL)
+ return true;
+
+ /*
+ * If we have a map though, both labels need to be mapped.
+ */
+ if (__smk_find_mapped(sbj, user_ns) == NULL)
+ return false;
+ if (__smk_find_mapped(obj, user_ns) == NULL)
+ return false;
+
+ return true;
+}
+
+/*
+ * proc mapping operations
+ */
+
static void *proc_smack_map_seq_start(struct seq_file *seq, loff_t *pos)
{
struct smack_known *skp;
@@ -253,7 +292,7 @@ static int proc_smack_map_seq_show(struct seq_file *seq, void *v)
* to show identity in this syntax without printing all the labels.
*/
if (smk_find_mapped_ns(ns) == NULL) {
- seq_puts("This namespace is not mapped.\n");
+ seq_puts(seq, "This namespace is not mapped.\n");
} else {
sknp = smk_find_mapped(skp, ns);
if (sknp)
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 5ec1e8e..7196861 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -345,13 +345,15 @@ static int smk_fill_rule(const char *subject, const char *object,
struct smack_parsed_rule *rule, int import,
int len)
{
- rule->smk_subject = smk_get_label(subject, len, import);
+ struct user_namespace *ns = ns_of_current();
+
+ rule->smk_subject = smk_get_label(subject, len, import, ns);
if (IS_ERR(rule->smk_subject))
return PTR_ERR(rule->smk_subject);
if (rule->smk_subject == NULL)
return -ENOENT;
- rule->smk_object = smk_get_label(object, len, import);
+ rule->smk_object = smk_get_label(object, len, import, ns);
if (IS_ERR(rule->smk_object))
return PTR_ERR(rule->smk_object);
if (rule->smk_object == NULL)
@@ -586,6 +588,7 @@ static void smk_seq_stop(struct seq_file *s, void *v)
static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
{
+ struct user_namespace *ns = ns_of_current();
char *sbj;
char *obj;
@@ -594,6 +597,7 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
* interface file (/smack/load or /smack/load2)
* because you should expect to be able to write
* anything you read back.
+ * Show only fully mapped rules in a namespace (both labels mapped).
*/
if (strlen(srp->smk_subject->smk_known) >= max ||
strlen(srp->smk_object->smk_known) >= max)
@@ -602,8 +606,8 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
if (srp->smk_access == 0)
return;
- sbj = smk_find_label_name(srp->smk_subject);
- obj = smk_find_label_name(srp->smk_object);
+ sbj = smk_find_label_name(srp->smk_subject, ns);
+ obj = smk_find_label_name(srp->smk_object, ns);
if (sbj == NULL || obj == NULL)
return;
@@ -798,6 +802,7 @@ static int cipso_seq_show(struct seq_file *s, void *v)
struct smack_known *skp =
list_entry(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
+ struct user_namespace *ns = ns_of_current();
char sep = '/';
char *cp;
int i;
@@ -813,7 +818,7 @@ static int cipso_seq_show(struct seq_file *s, void *v)
if (strlen(skp->smk_known) >= SMK_LABELLEN)
return 0;
- cp = smk_find_label_name(skp);
+ cp = smk_find_label_name(skp, ns);
if (cp == NULL)
return 0;
@@ -866,6 +871,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
{
struct smack_known *skp;
struct netlbl_lsm_secattr ncats;
+ struct user_namespace *ns = ns_of_current();
char mapcatset[SMK_CIPSOLEN];
int maplevel;
unsigned int cat;
@@ -906,7 +912,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
*/
mutex_lock(&smack_cipso_lock);
- skp = smk_get_label(rule, 0, true);
+ skp = smk_get_label(rule, 0, true, ns);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto out;
@@ -994,11 +1000,12 @@ static int cipso2_seq_show(struct seq_file *s, void *v)
struct smack_known *skp =
list_entry(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
+ struct user_namespace *ns = ns_of_current();
char sep = '/';
char *cp;
int i;
- cp = smk_find_label_name(skp);
+ cp = smk_find_label_name(skp, ns);
if (cp == NULL)
return 0;
@@ -1085,7 +1092,8 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
int maskn;
u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
- char *label = smk_find_label_name(skp->smk_label);
+ struct user_namespace *ns = ns_of_current();
+ char *label = smk_find_label_name(skp->smk_label, ns);
if (label == NULL)
return 0;
@@ -1182,6 +1190,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
int rc;
struct netlbl_audit audit_info;
struct in_addr mask;
+ struct user_namespace *ns = ns_of_current();
unsigned int m;
int found;
u32 mask_bits = (1<<31);
@@ -1239,7 +1248,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
* If smack begins with '-', it is an option, don't import it
*/
if (smack[0] != '-') {
- skp = smk_get_label(smack, 0, true);
+ skp = smk_get_label(smack, 0, true, ns);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto free_out;
@@ -1567,6 +1576,7 @@ static const struct file_operations smk_mapped_ops = {
static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
size_t cn, loff_t *ppos)
{
+ struct user_namespace *ns = ns_of_current();
ssize_t rc;
char *cp;
int asize;
@@ -1579,7 +1589,7 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
*/
mutex_lock(&smack_ambient_lock);
- cp = smk_find_label_name(smack_net_ambient);
+ cp = smk_find_label_name(smack_net_ambient, ns);
if (cp == NULL)
cp = smack_known_huh.smk_known;
@@ -1608,6 +1618,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct smack_known *skp;
+ struct user_namespace *ns = ns_of_current();
char *oldambient;
char *data;
int rc = count;
@@ -1624,7 +1635,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
goto out;
}
- skp = smk_get_label(data, count, true);
+ skp = smk_get_label(data, count, true, ns);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto out;
@@ -1664,12 +1675,13 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
char *smack = "";
ssize_t rc = -EINVAL;
int asize;
+ struct user_namespace *ns = ns_of_current();
if (*ppos != 0)
return 0;
if (smack_onlycap != NULL) {
- smack = smk_find_label_name(smack_onlycap);
+ smack = smk_find_label_name(smack_onlycap, ns);
if (smack == NULL)
smack = smack_known_huh.smk_known;
}
@@ -1696,6 +1708,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
{
char *data;
struct smack_known *skp = smk_of_task(current->cred->security);
+ struct user_namespace *ns = ns_of_current();
int rc = count;
if (!smack_privileged(CAP_MAC_ADMIN))
@@ -1727,7 +1740,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
*
* But do so only on invalid label, not on system errors.
*/
- skp = smk_get_label(data, count, true);
+ skp = smk_get_label(data, count, true, ns);
if (PTR_ERR(skp) == -EINVAL)
skp = NULL;
else if (IS_ERR(skp)) {
@@ -1764,12 +1777,13 @@ static ssize_t smk_read_unconfined(struct file *filp, char __user *buf,
char *smack = "";
ssize_t rc = -EINVAL;
int asize;
+ struct user_namespace *ns = ns_of_current();
if (*ppos != 0)
return 0;
if (smack_unconfined != NULL) {
- smack = smk_find_label_name(smack_unconfined);
+ smack = smk_find_label_name(smack_unconfined, ns);
if (smack == NULL)
smack = smack_known_huh.smk_known;
}
@@ -1796,6 +1810,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
{
char *data;
struct smack_known *skp;
+ struct user_namespace *ns = ns_of_current();
int rc = count;
if (!smack_privileged(CAP_MAC_ADMIN))
@@ -1819,7 +1834,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
*
* But do so only on invalid label, not on system errors.
*/
- skp = smk_get_label(data, count, true);
+ skp = smk_get_label(data, count, true, ns);
if (PTR_ERR(skp) == -EINVAL)
skp = NULL;
else if (IS_ERR(skp)) {
@@ -1991,6 +2006,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
size_t count, loff_t *ppos, int format)
{
struct smack_parsed_rule rule;
+ struct user_namespace *ns = ns_of_current();
char *data;
int res;
@@ -2010,7 +2026,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
}
if (res >= 0)
- res = smk_access(rule.smk_subject, rule.smk_object,
+ res = smk_access(rule.smk_subject, rule.smk_object, ns,
rule.smk_access1, NULL);
else if (res != -ENOENT)
return res;
@@ -2220,6 +2236,7 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
struct smack_rule *sp;
struct list_head *rule_list;
struct mutex *rule_lock;
+ struct user_namespace *ns = ns_of_current();
int rc = count;
if (*ppos != 0)
@@ -2240,7 +2257,7 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
goto free_out;
}
- skp = smk_get_label(data, count, false);
+ skp = smk_get_label(data, count, false, ns);
if (IS_ERR(skp)) {
rc = PTR_ERR(skp);
goto free_out;
@@ -2322,6 +2339,7 @@ static const struct file_operations smk_change_rule_ops = {
static ssize_t smk_read_syslog(struct file *filp, char __user *buf,
size_t cn, loff_t *ppos)
{
+ struct user_namespace *ns = ns_of_current();
ssize_t rc = -EINVAL;
char *cp;
int asize;
@@ -2332,7 +2350,7 @@ static ssize_t smk_read_syslog(struct file *filp, char __user *buf,
if (smack_syslog_label == NULL)
cp = smack_known_star.smk_known;
else {
- cp = smk_find_label_name(smack_syslog_label);
+ cp = smk_find_label_name(smack_syslog_label, ns);
if (cp == NULL)
cp = smack_known_huh.smk_known;
}
@@ -2359,6 +2377,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
{
char *data;
struct smack_known *skp;
+ struct user_namespace *ns = ns_of_current();
int rc = count;
if (!smack_privileged(CAP_MAC_ADMIN))
@@ -2371,7 +2390,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
if (copy_from_user(data, buf, count) != 0)
rc = -EFAULT;
else {
- skp = smk_get_label(data, count, true);
+ skp = smk_get_label(data, count, true, ns);
if (IS_ERR(skp))
rc = PTR_ERR(skp);
else
--
2.1.0
^ permalink raw reply related
* [PATCH v2 7/7] smack: documentation for the Smack namespace
From: Lukasz Pawelczyk @ 2015-05-25 12:32 UTC (permalink / raw)
To: David S. Miller, Eric W. Biederman, Kirill A. Shutemov,
Serge E. Hallyn, Al Viro, Alexey Dobriyan, Andrew Morton,
Andy Lutomirski, Casey Schaufler, David Howells, Fabian Frederick,
Greg KH, James Morris, Jeff Layton, Jingoo Han, Joe Perches,
John Johansen, Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Adds Documentation/smack-namespace.txt.
Signed-off-by: Lukasz Pawelczyk <l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
Documentation/security/00-INDEX | 2 +
Documentation/security/Smack-namespace.txt | 231 +++++++++++++++++++++++++++++
MAINTAINERS | 1 +
security/smack/Kconfig | 2 +
4 files changed, 236 insertions(+)
create mode 100644 Documentation/security/Smack-namespace.txt
diff --git a/Documentation/security/00-INDEX b/Documentation/security/00-INDEX
index 45c82fd..c03a220 100644
--- a/Documentation/security/00-INDEX
+++ b/Documentation/security/00-INDEX
@@ -6,6 +6,8 @@ SELinux.txt
- how to get started with the SELinux security enhancement.
Smack.txt
- documentation on the Smack Linux Security Module.
+Smack-namespace.txt
+ - documentation on the Smack namespace implementation.
Yama.txt
- documentation on the Yama Linux Security Module.
apparmor.txt
diff --git a/Documentation/security/Smack-namespace.txt b/Documentation/security/Smack-namespace.txt
new file mode 100644
index 0000000..85197ff
--- /dev/null
+++ b/Documentation/security/Smack-namespace.txt
@@ -0,0 +1,231 @@
+
+ "Quis custodiet ipsos custodes?"
+ - Satires of Juvenal
+
+
+--- What is a Smack namespace ---
+
+Smack namespace was developed to make it possible for Smack to work
+nicely with Linux containers where there is a full operating system
+with its own init inside the namespace. Such a system working with
+Smack expects to have at least partially working SMACK_MAC_ADMIN to be
+able to change labels of processes and files. This is required to be
+able to securely start applications under the control of Smack and
+manage their access rights.
+
+It was implemented using new LSM hooks added to the user namespace
+that were developed together with Smack namespace.
+
+
+--- Design ideas ---
+
+"Smack namespace" is rather "Smack labels namespace" as not the whole
+MAC is namespaced, only the labels. There is a great analogy between
+Smack labels namespace and the user namespace part that remaps UIDs.
+
+The idea is to create a map of labels for a namespace so the namespace
+is only allowed to use those labels. Smack rules are always the same
+as in the init namespace (limited only by what labels are mapped) and
+cannot be manipulated from the child namespace. The map is actually
+only for labels' names. The underlying structures for labels remain
+the same. The filesystem also stores the "unmapped" labels from the
+init namespace.
+
+Let's say we have those labels in the init namespace:
+label1
+label2
+label3
+
+and those rules:
+label1 label2 rwx
+label1 label3 rwx
+label2 label3 rwx
+
+We create a map for a namespace:
+label1 -> mapped1
+label2 -> mapped2
+
+This means that 'label3' is completely invisible in the namespace. As if
+it didn't exist. All the rules that include it are ignored.
+
+Effectively in the namespace we have only one rule:
+mapped1 mapped2 rwx
+
+Which in reality is:
+label1 label2 rwx
+
+All requests to access an object with a 'label3' will be denied. If it
+ever comes to a situation where 'label3' would have to be printed
+(e.g. reading an exec or mmap label from a file to which we have
+access) then huh sign '?' will be printed instead.
+
+All the operations in the namespace on the remaining labels will have
+to be performed using their mapped names. Things like changing own
+process's label, changing filesystem label. Labels will also be
+printed with their mapped names.
+
+You cannot import new labels in a namespace. Every operation that
+would do so in an init namespace will return an error in the child
+namespace. You cannot assign an unmapped or not existing label to an
+object. You can only operate on labels that have been explicitly
+mapped.
+
+
+--- Capabilities ---
+
+Enabling Smack related capabilities (CAP_MAC_ADMIN and
+CAP_MAC_OVERRIDE) is main goal of Smack namespace, so it can work
+properly in the container. And those capabilities do work to some
+extent. In several places where capabilities are checked compatibility
+with Smack namespace has been introduced. Capabilities are of course
+limited to operate only on mapped labels.
+
+CAP_MAC_OVERRIDE works fully, will allow you to ignore Smack access
+rules, but only between objects that have labels mapped. So in the
+example above having this CAP will allow e.g. label2 to write to
+label1, but will not allow any access to label3.
+
+With CAP_MAC_ADMIN the following operations has been allowed inside
+the namespace:
+- setting and removing xattr on files, including the security.* ones
+- setting process's own label (/proc/self/attr/current)
+- mounting in a privileged Smack mode, which means one can specify
+ additional mount options like: smackfsdef, smackfsfloor etc.
+
+Again this is also allowed only on the mapped labels. Labels on the
+filesystem will be stored in unmapped form so they are preserved
+through reboots.
+
+Such a namespace construct allows e.g. systemd (with Smack support)
+working in a container to assign labels properly to daemons and other
+processes.
+
+
+--- Usage ---
+
+Smack namespace is written using LSM hooks inside user namespace. That
+means it's connected to it.
+
+To create a new Smack namespace you need to unshare() user namespace
+as usual. If that is all you do though, than there is no difference to
+what is now. To activate the Smack namespace you need to fill the
+labels' map. It is in a file /proc/$PID/smack_map.
+
+By default the map is empty and Smack namespaces are inactive (labels
+are taken directly from a parent namespace). It also means that the
+Smack capabilities will be inactive. After you fill the map it starts
+to take effect in the namespace and Smack capabilities (only on mapped
+labels) start to work.
+
+Due to the way Smack works only CAP_MAC_ADMIN from the parent
+namespace (init_user_ns for now, see the "Current limitations" below)
+is allowed to fill the map. That means that an unprivileged user is
+still allowed to create the user namespace but it will not be able to
+fill the labels' map (activate Smack namespace). An administrator
+intervention is required.
+
+The attr_map write format is:
+unmapped_label mapped_label
+
+When reading the file it shows an active map for a namespace the
+process in question is in in the format:
+unmapped_label -> mapped_label
+
+If the smack_map file is empty it means the namespace is not mapped
+and Smack namespace is inactive (no mappings, MAC related capabilities
+behave as they did before, meaning they are active only in
+init_user_ns). For init_user_ns the map will always be empty.
+
+Writing to the map file is not disabled after the first write as it is
+in uid_map. For Smack we have no means to map ranges of labels, hence
+it can really be advantageous to be able to expand the map later
+on. But you can only add to the map. You cannot remove already mapped
+labels. You cannot change the already existing mappings. Also mappings
+has to be 1-1. All requests to create a map where either the unmapped
+or the mapped label already exists in the map will be denied.
+
+setns() with Smack namespace active has an additional check that the
+label of a process that is calling setns() has to be already mapped in
+the target Smack namespace for the call to succeed.
+
+
+--- Special labels ---
+
+Smack is using some special labels that have built-in rules. Things
+like floor '_', dash '^', star '*', etc. Those labels are not
+automatically mapped to the namespace. Moreover, you can choose to map
+a different label from the init namespace to behave e.g. like floor
+inside the namespace.
+
+Let's say we have no rules and those labels in the init namespace:
+_
+floor_to_be
+label
+
+Both 'label' and 'floor_to_be' can read objects with '_'. But they
+have no access rights to each other.
+
+Now let's create a map like this:
+_ ordinary_label
+floor_to_be _
+label mapped
+
+Right now label 'mapped' can read label '_' which means that
+effectively inside this namespace label 'label' has gained read access
+to the 'floor_to_be'. The label 'ordinary_label' is exactly it, an
+ordinary label that the built-in rules no longer apply to inside the
+namespace.
+
+To sum up, special labels in the namespace behave the same as in the
+init namespace. Not the original special labels though, but the ones
+we map to specials. This is the only case where a namespace can have
+access rights the init namespace does not have (like the 'label' to
+'floor_to_be' in the example above).
+
+Of course mappings like these are perfectly legal:
+_ _
+* *
+^ ^
+
+
+--- Current limitations ---
+
+The Smack namespace is not hierarchical yet. It is currently not
+possible to fill a smack_map of a nested user namespace (you can still
+create nested user namespace, it will just inherit its parent's map
+and won't have active Smack capabilities). When hierarchy will be
+implemented the process creating another namespace will be allowed to
+map only labels that it has permission to itself (those that it has in
+its own map).
+
+Special files inside the virtual smackfs needs to be reviewed whether
+it's beneficial to have some of their functionality namespaced as well
+(e.g. onlycap, syslog. ambient, etc). This would increase
+CAP_MAC_ADMIN privileges inside the namespace.
+
+
+--- Error codes ---
+
+While working in the namespace patches the error codes has been made
+to propagate properly from a place they occurred. New error codes has
+also been introduced for Smack in the context of namespace usage. This
+is a complete summary of error codes used throughout the Smack now:
+
+ENOMEM and other system errors that might come from low level
+ kernel functions like memory allocations
+EOPNOTSUPP means the underlying system operation is not
+ supported (eg. getxattr)
+EINVAL means invalid syntax (e.g. empty label or one starting
+ with '-')
+EEXIST when creating map means that a label is already mapped
+EBADR is used for wrong namespace usage:
+ - trying to import a label inside a namespace (like trying
+ to use an unmapped label that would otherwise be imported)
+ - trying to create a Smack label map in the init namespace
+ENOENT when failed to find a label we expected to exist (will not
+ be propagated to user-space)
+EPERM means no permission to operate on an object, e.g. due to
+ insufficient capabilities or simply because the object
+ cannot be operated on in the current context
+EACCESS when access has been denied due to Smack access checks
+ (including object being outside of a namespace)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2e5bbc0..66ab25b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9059,6 +9059,7 @@ W: http://schaufler-ca.com
T: git git://git.gitorious.org/smack-next/kernel.git
S: Maintained
F: Documentation/security/Smack.txt
+F: Documentation/security/Smack-namespace.txt
F: security/smack/
DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
diff --git a/security/smack/Kconfig b/security/smack/Kconfig
index b19a7fb..a6e0f3f 100644
--- a/security/smack/Kconfig
+++ b/security/smack/Kconfig
@@ -49,4 +49,6 @@ config SECURITY_SMACK_NS
This enables Smack namespace that makes it possible to map
specific labels within user namespace (analogously to mapping
UIDs) and to gain MAC capabilities over them.
+ Documentation is availabile here:
+ Documentation/security/Smack-namespace.txt
If you are unsure how to answer this question, answer N.
--
2.1.0
^ permalink raw reply related
* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
From: Pantelis Antoniou @ 2015-05-25 16:51 UTC (permalink / raw)
To: Srinivas Kandagatla
Cc: linux-arm-kernel, Maxime Ripard, Rob Herring, Kumar Gala,
Mark Brown, Sascha Hauer, Greg Kroah-Hartman, linux-api,
Linux Kernel Mailing List, devicetree, linux-arm-msm,
Arnd Bergmann, sboyd, Matt Porter
In-Reply-To: <1432226535-8640-1-git-send-email-srinivas.kandagatla@linaro.org>
Hi Srinivas,
> On May 21, 2015, at 19:42 , Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
>
> Thankyou all for providing inputs and comments on previous versions of this patchset.
> Here is the v5 of the patchset addressing all the issues raised as
> part of previous versions review.
>
>
[snip]
I tried to use the updated patchset with my at24 & beaglebone capemanager patches.
I have a big problem with the removal of the raw of_* access APIs.
Take for instance the case where you have multiple slot accessing different EEPROMs.
> slots {
> slot@0 {
> eeprom = <&cape0_data>;
> };
>
> slot@1 {
> eeprom = <&cape1_data>;
> };
> };
In that case there is no per-device node mapping; it’s a per-sub node.
For now I’m exporting the of_* accessors again, please consider exposing the of_* API again.
> --
> 1.9.1
>
Regards
— Pantelis
^ permalink raw reply
* Re: [RFC PATCH] percpu system call: fast userspace percpu critical sections
From: Mathieu Desnoyers @ 2015-05-25 18:30 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Lai Jiangshan, Paul E. McKenney, Ben Maurer, Josh Triplett,
Ingo Molnar, Andrew Morton, Linux API, Michael Kerrisk,
Linux Kernel, Linus Torvalds, Peter Zijlstra, Paul Turner,
Steven Rostedt, Andrew Hunter
In-Reply-To: <CALCETrWzoFX7hXqvQqDEq=r=7PNaGKVjZeHEBWxPvC28Zi1AKA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
----- Original Message -----
> On May 23, 2015 10:09 AM, "Mathieu Desnoyers"
> <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org> wrote:
> >
> > ----- Original Message -----
> > > On Fri, May 22, 2015 at 2:34 PM, Mathieu Desnoyers
> > > <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org> wrote:
> > > > ----- Original Message -----
> > > >> On Fri, May 22, 2015 at 1:26 PM, Michael Kerrisk
> > > >> <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> > > >> wrote:
> > > >> > [CC += linux-api@]
> > > >> >
> > > >> > On Thu, May 21, 2015 at 4:44 PM, Mathieu Desnoyers
> > > >> > <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org> wrote:
> > > >> >> Expose a new system call allowing userspace threads to register
> > > >> >> a TLS area used as an ABI between the kernel and userspace to
> > > >> >> share information required to create efficient per-cpu critical
> > > >> >> sections in user-space.
> > > >> >>
> > > >> >> This ABI consists of a thread-local structure containing:
> > > >> >>
> > > >> >> - a nesting count surrounding the critical section,
> > > >> >> - a signal number to be sent to the thread when preempting a thread
> > > >> >> with non-zero nesting count,
> > > >> >> - a flag indicating whether the signal has been sent within the
> > > >> >> critical section,
> > > >> >> - an integer where to store the current CPU number, updated
> > > >> >> whenever
> > > >> >> the thread is preempted. This CPU number cache is not strictly
> > > >> >> needed, but performs better than getcpu vdso.
> > > >> >>
> > > >> >> This approach is inspired by Paul Turner and Andrew Hunter's work
> > > >> >> on percpu atomics, which lets the kernel handle restart of critical
> > > >> >> sections, ref.
> > > >> >> http://www.linuxplumbersconf.org/2013/ocw/system/presentations/1695/original/LPC%20-%20PerCpu%20Atomics.pdf
> > > >> >>
> > > >> >> What is done differently here compared to percpu atomics: we track
> > > >> >> a single nesting counter per thread rather than many ranges of
> > > >> >> instruction pointer values. We deliver a signal to user-space and
> > > >> >> let the logic of restart be handled in user-space, thus moving
> > > >> >> the complexity out of the kernel. The nesting counter approach
> > > >> >> allows us to skip the complexity of interacting with signals that
> > > >> >> would be otherwise needed with the percpu atomics approach, which
> > > >> >> needs to know which instruction pointers are preempted, including
> > > >> >> when preemption occurs on a signal handler nested over an
> > > >> >> instruction
> > > >> >> pointer of interest.
> > > >> >>
> > > >>
> > > >> I talked about this kind of thing with PeterZ at LSF/MM, and I was
> > > >> unable to convince myself that the kernel needs to help at all. To do
> > > >> this without kernel help, I want to relax the requirements slightly.
> > > >> With true per-cpu atomic sections, you have a guarantee that you are
> > > >> either really running on the same CPU for the entire duration of the
> > > >> atomic section or you abort. I propose a weaker primitive: you
> > > >> acquire one of an array of locks (probably one per cpu), and you are
> > > >> guaranteed that, if you don't abort, no one else acquires the same
> > > >> lock while you hold it.
> > > >
> > > > In my proof of concept (https://github.com/compudj/percpu-dev) I
> > > > actually implement an array of per-cpu lock. The issue here boils
> > > > down to grabbing this per-cpu lock efficiently. Once the lock is taken,
> > > > the thread has exclusive access to that per-cpu lock, even if it
> > > > migrates.
> > > >
> > > >> Here's how:
> > > >>
> > > >> Create an array of user-managed locks, one per cpu. Call them lock[i]
> > > >> for 0 <= i < ncpus.
> > > >>
> > > >> To acquire, look up your CPU number. Then, atomically, check that
> > > >> lock[cpu] isn't held and, if so, mark it held and record both your tid
> > > >> and your lock acquisition count. If you learn that the lock *was*
> > > >> held after all, signal the holder (with kill or your favorite other
> > > >> mechanism), telling it which lock acquisition count is being aborted.
> > > >> Then atomically steal the lock, but only if the lock acquisition count
> > > >> hasn't changed.
> > > >>
> > > >> This has a few benefits over the in-kernel approach:
> > > >>
> > > >> 1. No kernel patch.
> > > >>
> > > >> 2. No unnecessary abort if you are preempted in favor of a thread that
> > > >> doesn't content for your lock.
> > > >>
> > > >> 3. Greatly improved debuggability.
> > > >>
> > > >> 4. With long critical sections and heavy load, you can improve
> > > >> performance by having several locks per cpu and choosing one at
> > > >> random.
> > > >>
> > > >> Is there a reason that a scheme like this doesn't work?
> > > >
> > > > What do you mean exactly by "atomically check that lock is not
> > > > held and, if so, mark it held" ? Do you imply using a lock-prefixed
> > > > atomic operation ?
> > >
> > > Yes.
> > >
> > > >
> > > > The goal of this whole restart section approach is to allow grabbing
> > > > a lock (or doing other sequences of operations ending with a single
> > > > store) on per-cpu data without having to use slow lock-prefixed
> > > > atomic operations.
> > >
> > > Ah, ok, I assumed it was to allow multiple threads to work in parallel.
> > >
> > > How arch-specific are you willing to be?
> >
> > I'd want this to be usable on every major architectures.
> >
> > > On x86, it might be possible
> > > to play some GDT games so that an unlocked xchg relative
> >
> > AFAIK, there is no such thing as an unlocked xchg. xchg always
> > imply the lock prefix on x86. I guess you mean cmpxchg here.
> >
>
> Right, got my special cases mixed up.
>
> I wonder if we could instead have a vdso function that did something like:
>
> unsigned long __vdso_cpu_local_exchange(unsigned long *base, int
> shift, unsigned long newval)
> {
> unsigned long *ptr = base + (cpu << shift);
> unsigned long old = *ptr;
> *ptr = new;
> return *ptr;
> }
>
> I think this primitive would be sufficient to let user code do the
> rest. There might be other more simple primitives that would work.
> It could be implemented by fiddling with IP ranges, but we could
> change the implementation later without breaking anything. The only
> really hard part would be efficiently figuring out what CPU we're on.
The "fiddling with IP ranges" is where the restart sections come into
play. Paul Turner's approach indeed knows about IP ranges, and performs
the restart from the kernel. My alternative approach uses a signal and
page protection in user-space to reach the same result. It appears that
CONFIG_PREEMPT kernels are difficult to handle with Paul's approach, so
perhaps we could combine our approaches to get the best of both.
>
> FWIW, 'xchg' to cache-hot memory is only about 20 cycles on my laptop,
> and cmpxchg seems to be about 6 cycles. Both are faster than getcpu.
> How much are we really saving with any of this over the pure userspace
> approach? I think that the most that the kernel can possibly help us
> is to give us a faster getcpu and to help us deal with being migrated
> to a different cpu if we want to avoid expensive operations and don't
> want to play unlocked cmpxchg tricks.
You appear to summarize the two things that are added to the kernel with
this RFC patch:
- faster getcpu(): 12.7 ns -> 0.3 ns
- allow using less expensive operations to perform per-cpu-atomic ops:
(on my system):
- lock; cmpxchg (18 ns) -> load-test-branch-store (5.4 ns)
>
> I was wrong about set_thread_area giving us efficient per-cpu data,
> BTW, although it would be easy to add a similar feature that would
> give us a per-cpu segment base on x86.
ok
>
> > > to gs would
> > > work if you arranged for gs to refer to the GDT. On 32-bit userspace,
> > > you can do this with set_thread_area and on 64-bit userspace you can
> > > do it with arch_prctl. You'd be relying on nothing else in the
> > > process using gs, but your proposal already relies on nothing else in
> > > the process using your signal number.
> >
> > Ideally, and this is indeed a limitation of my own approach, I would
> > like to be able to use this scheme from a library injected into
> > processes for tracing purposes, which means that I would be tempted
> > to stay away from solutions that affect the application too much.
> > This includes sending a signal unfortunately.
> >
> > In addition, the gs approach you propose here would work as long
> > as we use non-lock-prefixed atomic operations (e.g. cmpxchg), but
> > it would not work for sequences of instructions that need to be
> > performed over the same data (e.g. load, test, conditional branch,
> > store), which performs slightly faster than non-lock-prefixed atomic
> > ops.
> >
>
> > > >> >> - With Linux vdso: 12.7 ns
> > > >> >> - With TLS-cached cpu number: 0.3 ns
> > > >>
> > > >> Slightly off-topic: try this again on a newer kernel. The vdso should
> > > >> have gotten a bit faster in 3.19 or 4.0 IIRC.
> > > >
> > > > Those benchmarks were done on Linux 4.0.
> > >
> > > What cpu? I'm surprised it's that bad.
> >
> > Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
> > (Haswell)
> > Please note that I run this benchmark under a kvm guest VM, but
> > I doubt it would impact these numbers.
>
> Go figure. My laptop (SNB, 2.7GHz) can do it in 8ns or so.
>
> >
> > > (TLS-cached will always be
> > > better, but still. Although I'm curious how you're making the
> > > TLS-cached value work reliably enough.)
> >
> > What do you have in mind as possibility of having an unreliable TLS-cached
> > value ?
>
> Something like the old vdso getcpu cache -- re-read the cpu count if
> it has expired since last time.
>
> > In my approach, the tls-cached value is updated in the preempt in
> > notifier, whenever the CPU number has changed compared to the value in
> > user-space.
>
> Ah, I missed that part.
>
> This ABI is kind of unfortunate in that it can't be shared between
> multiple libraries.
Well ideally you'd want one library to implement this (e.g. glibc), and
other libraries to use it. I'm not sure doing a linked list of TLS entries
per thread would really be useful here.
>
> Accessing the TLS value from user-space is performed with the
> > help of the compiler, including all the complexity involved in using a
> > TLS from a library if need be (lazy allocation, internal glibc mutex, etc).
> > However, since I control very precisely where in my critical section the
> > execution flow can be restarted (it's only on the store operation that
> > touch the write-protected memory range), there is no need to worry about
> > restarting in the middle of a held lock. It also works if a system call
> > is issued within the critical section (e.g. sys_futex due to lock), and
> > works with function calls.
>
> Oh, you're delivering a signal every time you're preempted, even
> outside the critical section? That sounds expensive.
No, the signal is only delivered if the kernel preempts the critical
section.
Thanks for the feedback!
Mathieu
>
> --Andy
>
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply
* Re: [RFC PATCH] percpu system call: fast userspace percpu critical sections
From: Andy Lutomirski @ 2015-05-25 18:54 UTC (permalink / raw)
To: Mathieu Desnoyers, H. Peter Anvin, Andi Kleen, Borislav Petkov
Cc: Lai Jiangshan, Paul E. McKenney, Ben Maurer, Josh Triplett,
Ingo Molnar, Andrew Morton, Linux API, Michael Kerrisk,
Linux Kernel, Linus Torvalds, Peter Zijlstra, Paul Turner,
Steven Rostedt, Andrew Hunter
In-Reply-To: <1184354091.7499.1432578613872.JavaMail.zimbra-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org>
[cc: hpa, Borislav and Andi]
On Mon, May 25, 2015 at 11:30 AM, Mathieu Desnoyers
<mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org> wrote:
> ----- Original Message -----
>> On May 23, 2015 10:09 AM, "Mathieu Desnoyers"
>> <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org> wrote:
>> >
>> > ----- Original Message -----
>> > > On Fri, May 22, 2015 at 2:34 PM, Mathieu Desnoyers
>> > > <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org> wrote:
>> > > > ----- Original Message -----
>> > > >> On Fri, May 22, 2015 at 1:26 PM, Michael Kerrisk
>> > > >> <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> > > >> wrote:
>> > > >> > [CC += linux-api@]
>> > > >> >
>> > > >> > On Thu, May 21, 2015 at 4:44 PM, Mathieu Desnoyers
>> > > >> > <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org> wrote:
>> > > >> >> Expose a new system call allowing userspace threads to register
>> > > >> >> a TLS area used as an ABI between the kernel and userspace to
>> > > >> >> share information required to create efficient per-cpu critical
>> > > >> >> sections in user-space.
>> > > >> >>
>> > > >> >> This ABI consists of a thread-local structure containing:
>> > > >> >>
>> > > >> >> - a nesting count surrounding the critical section,
>> > > >> >> - a signal number to be sent to the thread when preempting a thread
>> > > >> >> with non-zero nesting count,
>> > > >> >> - a flag indicating whether the signal has been sent within the
>> > > >> >> critical section,
>> > > >> >> - an integer where to store the current CPU number, updated
>> > > >> >> whenever
>> > > >> >> the thread is preempted. This CPU number cache is not strictly
>> > > >> >> needed, but performs better than getcpu vdso.
>> > > >> >>
>> > > >> >> This approach is inspired by Paul Turner and Andrew Hunter's work
>> > > >> >> on percpu atomics, which lets the kernel handle restart of critical
>> > > >> >> sections, ref.
>> > > >> >> http://www.linuxplumbersconf.org/2013/ocw/system/presentations/1695/original/LPC%20-%20PerCpu%20Atomics.pdf
>> > > >> >>
>> > > >> >> What is done differently here compared to percpu atomics: we track
>> > > >> >> a single nesting counter per thread rather than many ranges of
>> > > >> >> instruction pointer values. We deliver a signal to user-space and
>> > > >> >> let the logic of restart be handled in user-space, thus moving
>> > > >> >> the complexity out of the kernel. The nesting counter approach
>> > > >> >> allows us to skip the complexity of interacting with signals that
>> > > >> >> would be otherwise needed with the percpu atomics approach, which
>> > > >> >> needs to know which instruction pointers are preempted, including
>> > > >> >> when preemption occurs on a signal handler nested over an
>> > > >> >> instruction
>> > > >> >> pointer of interest.
>> > > >> >>
>> > > >>
>> > > >> I talked about this kind of thing with PeterZ at LSF/MM, and I was
>> > > >> unable to convince myself that the kernel needs to help at all. To do
>> > > >> this without kernel help, I want to relax the requirements slightly.
>> > > >> With true per-cpu atomic sections, you have a guarantee that you are
>> > > >> either really running on the same CPU for the entire duration of the
>> > > >> atomic section or you abort. I propose a weaker primitive: you
>> > > >> acquire one of an array of locks (probably one per cpu), and you are
>> > > >> guaranteed that, if you don't abort, no one else acquires the same
>> > > >> lock while you hold it.
>> > > >
>> > > > In my proof of concept (https://github.com/compudj/percpu-dev) I
>> > > > actually implement an array of per-cpu lock. The issue here boils
>> > > > down to grabbing this per-cpu lock efficiently. Once the lock is taken,
>> > > > the thread has exclusive access to that per-cpu lock, even if it
>> > > > migrates.
>> > > >
>> > > >> Here's how:
>> > > >>
>> > > >> Create an array of user-managed locks, one per cpu. Call them lock[i]
>> > > >> for 0 <= i < ncpus.
>> > > >>
>> > > >> To acquire, look up your CPU number. Then, atomically, check that
>> > > >> lock[cpu] isn't held and, if so, mark it held and record both your tid
>> > > >> and your lock acquisition count. If you learn that the lock *was*
>> > > >> held after all, signal the holder (with kill or your favorite other
>> > > >> mechanism), telling it which lock acquisition count is being aborted.
>> > > >> Then atomically steal the lock, but only if the lock acquisition count
>> > > >> hasn't changed.
>> > > >>
>> > > >> This has a few benefits over the in-kernel approach:
>> > > >>
>> > > >> 1. No kernel patch.
>> > > >>
>> > > >> 2. No unnecessary abort if you are preempted in favor of a thread that
>> > > >> doesn't content for your lock.
>> > > >>
>> > > >> 3. Greatly improved debuggability.
>> > > >>
>> > > >> 4. With long critical sections and heavy load, you can improve
>> > > >> performance by having several locks per cpu and choosing one at
>> > > >> random.
>> > > >>
>> > > >> Is there a reason that a scheme like this doesn't work?
>> > > >
>> > > > What do you mean exactly by "atomically check that lock is not
>> > > > held and, if so, mark it held" ? Do you imply using a lock-prefixed
>> > > > atomic operation ?
>> > >
>> > > Yes.
>> > >
>> > > >
>> > > > The goal of this whole restart section approach is to allow grabbing
>> > > > a lock (or doing other sequences of operations ending with a single
>> > > > store) on per-cpu data without having to use slow lock-prefixed
>> > > > atomic operations.
>> > >
>> > > Ah, ok, I assumed it was to allow multiple threads to work in parallel.
>> > >
>> > > How arch-specific are you willing to be?
>> >
>> > I'd want this to be usable on every major architectures.
>> >
>> > > On x86, it might be possible
>> > > to play some GDT games so that an unlocked xchg relative
>> >
>> > AFAIK, there is no such thing as an unlocked xchg. xchg always
>> > imply the lock prefix on x86. I guess you mean cmpxchg here.
>> >
>>
>> Right, got my special cases mixed up.
>>
>> I wonder if we could instead have a vdso function that did something like:
>>
>> unsigned long __vdso_cpu_local_exchange(unsigned long *base, int
>> shift, unsigned long newval)
>> {
>> unsigned long *ptr = base + (cpu << shift);
>> unsigned long old = *ptr;
>> *ptr = new;
>> return *ptr;
>> }
>>
>> I think this primitive would be sufficient to let user code do the
>> rest. There might be other more simple primitives that would work.
>> It could be implemented by fiddling with IP ranges, but we could
>> change the implementation later without breaking anything. The only
>> really hard part would be efficiently figuring out what CPU we're on.
>
> The "fiddling with IP ranges" is where the restart sections come into
> play. Paul Turner's approach indeed knows about IP ranges, and performs
> the restart from the kernel. My alternative approach uses a signal and
> page protection in user-space to reach the same result. It appears that
> CONFIG_PREEMPT kernels are difficult to handle with Paul's approach, so
> perhaps we could combine our approaches to get the best of both.
I'm not sure why CONFIG_PREEMPT would matter. What am I missing?
Doing this in the vdso has some sneaky benefits: rather than aborting
a very short vdso-based primitive on context switch, we could just fix
it up in the kernel and skip ahead to the end.
>
>>
>> FWIW, 'xchg' to cache-hot memory is only about 20 cycles on my laptop,
>> and cmpxchg seems to be about 6 cycles. Both are faster than getcpu.
>> How much are we really saving with any of this over the pure userspace
>> approach? I think that the most that the kernel can possibly help us
>> is to give us a faster getcpu and to help us deal with being migrated
>> to a different cpu if we want to avoid expensive operations and don't
>> want to play unlocked cmpxchg tricks.
>
> You appear to summarize the two things that are added to the kernel with
> this RFC patch:
> - faster getcpu(): 12.7 ns -> 0.3 ns
Yeah, I figured that out the second time I read your email and re-read
the original message, but I apparently forgot to fix up the email I
was typing.
> - allow using less expensive operations to perform per-cpu-atomic ops:
> (on my system):
> - lock; cmpxchg (18 ns) -> load-test-branch-store (5.4 ns)
>
When you say "load-test-branch-store", do you mean that sequence of
normal code or a literal cmpxchg? On x86, we really can pull off the
sneaky trick of gs-relative cmpxchg in a single instruction, which
gives us per-cpu atomic locking without any special kernel fixups,
although that locks down gs and isn't currently supported.
IIRC some other OS's use gs as a userspace per-cpu pointer instead of
a per-thread pointer. Would we want to consider enabling that?
This may interact oddly with the WIP wrgsbase stuff. (Grr, Intel, why
couldn't you have made wrgsbase reset the gs selector to zero? That
would have been so much nicer.)
>>
>> I was wrong about set_thread_area giving us efficient per-cpu data,
>> BTW, although it would be easy to add a similar feature that would
>> give us a per-cpu segment base on x86.
>
> ok
>
>>
>> This ABI is kind of unfortunate in that it can't be shared between
>> multiple libraries.
>
> Well ideally you'd want one library to implement this (e.g. glibc), and
> other libraries to use it. I'm not sure doing a linked list of TLS entries
> per thread would really be useful here.
True, but that may not play so well with tracing injection.
At least a pure vdso approach is guaranteed not to have this problem.
>> Oh, you're delivering a signal every time you're preempted, even
>> outside the critical section? That sounds expensive.
>
> No, the signal is only delivered if the kernel preempts the critical
> section.
As noted above, I meant to delete this before sending :)
--Andy
^ permalink raw reply
* Re: [PATCH v6 0/3] Enable PPI sysfs interface for TPM 2.0
From: Jarkko Sakkinen @ 2015-05-26 8:22 UTC (permalink / raw)
To: tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: peterhuewe-Mmb7MZpHnFY, gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/, Guenter Roeck,
open list:ABI/API, NeilBrown, Simon Wunderlich, Tejun Heo,
Vivien Didelot
In-Reply-To: <1432129766-7289-1-git-send-email-jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Hi
Any feedback on this?
/Jarkko
On Wed, May 20, 2015 at 04:49:21PM +0300, Jarkko Sakkinen wrote:
> Changes since v5:
> * Updated documentation.
>
> Changes since v4:
> * Removed dangling export of kernfs_remove_by_name_ns() from the sysfs
> patch.
>
> Changes since v3:
> * Use sysfs_remove_link()
>
> Changes since v2:
> * Fixed to_tpm_chip() macro.
> * Split into two patches.
> * Renamed sysfs_link_group_to_kobj to sysfs_link_entry_to_kobj
> * Only create the "backwards compatibility" symlink for TPM 1.x devices.
>
> Jarkko Sakkinen (3):
> sysfs: added sysfs_link_entry_to_kobj()
> tpm: move the PPI attributes to character device directory.
> tpm: update PPI documentation to address the location change.
>
> Documentation/ABI/testing/sysfs-driver-ppi | 19 +++++++++-----
> drivers/char/tpm/tpm-chip.c | 24 +++++++++++------
> drivers/char/tpm/tpm.h | 17 +++++-------
> drivers/char/tpm/tpm_ppi.c | 34 ++++++++----------------
> fs/sysfs/group.c | 42 ++++++++++++++++++++++++++++++
> include/linux/sysfs.h | 8 ++++++
> 6 files changed, 95 insertions(+), 49 deletions(-)
>
> --
> 2.1.4
>
^ permalink raw reply
* Re: [PATCH v6 0/8] vhost: support for cross endian guests
From: Greg Kurz @ 2015-05-26 9:09 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Thomas Huth, kvm, linux-api, linux-kernel, virtualization
In-Reply-To: <20150512125104-mutt-send-email-mst@redhat.com>
On Tue, 12 May 2015 12:52:55 +0200
"Michael S. Tsirkin" <mst@redhat.com> wrote:
> On Tue, May 12, 2015 at 12:44:26PM +0200, Greg Kurz wrote:
> > On Fri, 24 Apr 2015 15:31:54 +0200
> > "Michael S. Tsirkin" <mst@redhat.com> wrote:
> >
> > > On Fri, Apr 24, 2015 at 02:24:15PM +0200, Greg Kurz wrote:
> > > > Only cosmetic and documentation changes since v5.
> > > >
> > > > ---
> > >
> > > Looks sane to me. I plan to review and apply next week.
> > >
> >
> > Hi Michael,
> >
> > I realize you just got back and have tons of things to do... Do
> > you still plan to apply shortly ? Would you also have time to
> > comment the QEMU part ?
> >
> > Thanks.
> >
> > --
> > Greg
>
> Yes, sorry about the delay - I also got virtio upstream landed on my lap.
> I'll do my best to prioritize.
>
Hi Michael,
This is just a friendly reminder. Are there chances you pick up this
kernel series before virtio 1.0 is in upstream QEMU ?
Cheers.
--
Greg
> > > > Greg Kurz (8):
> > > > virtio: introduce virtio_is_little_endian() helper
> > > > tun: add tun_is_little_endian() helper
> > > > macvtap: introduce macvtap_is_little_endian() helper
> > > > vringh: introduce vringh_is_little_endian() helper
> > > > vhost: introduce vhost_is_little_endian() helper
> > > > virtio: add explicit big-endian support to memory accessors
> > > > vhost: cross-endian support for legacy devices
> > > > macvtap/tun: cross-endian support for little-endian hosts
> > > >
> > > >
> > > > drivers/net/Kconfig | 14 ++++++
> > > > drivers/net/macvtap.c | 66 +++++++++++++++++++++++++++++-
> > > > drivers/net/tun.c | 68 ++++++++++++++++++++++++++++++
> > > > drivers/vhost/Kconfig | 15 +++++++
> > > > drivers/vhost/vhost.c | 85 ++++++++++++++++++++++++++++++++++++++
> > > > drivers/vhost/vhost.h | 25 ++++++++---
> > > > include/linux/virtio_byteorder.h | 24 ++++++-----
> > > > include/linux/virtio_config.h | 18 +++++---
> > > > include/linux/vringh.h | 18 +++++---
> > > > include/uapi/linux/if_tun.h | 6 +++
> > > > include/uapi/linux/vhost.h | 14 ++++++
> > > > 11 files changed, 320 insertions(+), 33 deletions(-)
> > > >
> > > > --
> > > > Greg
> > >
>
^ permalink raw reply
* Re: [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
From: Srinivas Kandagatla @ 2015-05-26 9:12 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: linux-arm-msm, devicetree, Arnd Bergmann, Greg Kroah-Hartman,
Sascha Hauer, sboyd, Linux Kernel Mailing List, Rob Herring,
Mark Brown, Kumar Gala, Matt Porter, Maxime Ripard, linux-api,
linux-arm-kernel
In-Reply-To: <E5772084-6CF5-41DE-B68B-073D9F75F0BC@konsulko.com>
Hi Pantelis,
On 25/05/15 17:51, Pantelis Antoniou wrote:
> Hi Srinivas,
>
>> On May 21, 2015, at 19:42 , Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote:
>>
>> Thankyou all for providing inputs and comments on previous versions of this patchset.
>> Here is the v5 of the patchset addressing all the issues raised as
>> part of previous versions review.
>>
>
>>
>
> [snip]
>
> I tried to use the updated patchset with my at24 & beaglebone capemanager patches.
Thanks for trying it out and migrating at24 to it.
>
> I have a big problem with the removal of the raw of_* access APIs.
Ok,
>
> Take for instance the case where you have multiple slot accessing different EEPROMs.
>
>> slots {
>> slot@0 {
>> eeprom = <&cape0_data>;
>> };
>>
>> slot@1 {
>> eeprom = <&cape1_data>;
>> };
>> };
Can I ask you why should the slots be in sub-nodes?
Do you expect to have more properties associated with each slot in future?
Or is it just to get hold of eeprom data?
>
> In that case there is no per-device node mapping; it’s a per-sub node.
>
> For now I’m exporting the of_* accessors again, please consider exposing the of_* API again.
Sure, we can export of_nvmem_cell_get symbol for usecases like this.
Having said that, I got one comment on the way the nvmem is used in your
case. You should try to use nvmem_device_get() and then use
nvmem_device_read() apis, These apis are for consumers like this one.
The advantage of this would be you do not need read and store all data
in the driver and parse them internally. Basically your ee_field_get
would just do nvmem_device_read(); Does it make sense?
We can work on how to get the of_*based once you decide to move to this api.
--srini
>
>> --
>> 1.9.1
>>
>
> Regards
>
> — Pantelis
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 0/7] Smack namespace
From: Stephen Smalley @ 2015-05-26 14:35 UTC (permalink / raw)
To: Lukasz Pawelczyk, David S. Miller, Eric W. Biederman,
Kirill A. Shutemov, Serge E. Hallyn, Al Viro, Alexey Dobriyan,
Andrew Morton, Andy Lutomirski, Casey Schaufler, David Howells,
Fabian Frederick, Greg KH, James Morris, Jeff Layton, Jingoo Han,
Joe Perches, John Johansen, Jonathan Corbet, Kees Cook,
Mauro Carvalho Chehab, Miklos Szeredi, Oleg
Cc: Lukasz Pawelczyk
In-Reply-To: <1432557162-19123-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
On 05/25/2015 08:32 AM, Lukasz Pawelczyk wrote:
> --- Design ideas ---
>
> "Smack namespace" is rather "Smack labels namespace" as not the whole
> MAC is namespaced, only the labels. There is a great analogy between
> Smack labels namespace and the user namespace part that remaps UIDs.
>
> The idea is to create a map of labels for a namespace so the namespace
> is only allowed to use those labels. Smack rules are always the same
> as in the init namespace (limited only by what labels are mapped) and
> cannot be manipulated from the child namespace. The map is actually
> only for labels' names. The underlying structures for labels remain
> the same. The filesystem also stores the "unmapped" labels from the
> init namespace.
How do you achieve that without introducing additional hooks or
reworking the current hooks in the setxattr code path? At present, the
security module is allowed to rewrite getxattr requests on the
security.* namespace but it isn't allowed to do that for setxattr, so if
the process invokes setxattr with a mapped label, then it will be the
mapped label that gets passed to the filesystem implementation, not the
unmapped label. The security module may internally store it in unmapped
form and may even return that upon getxattr() calls, but if you then
reboot the system and later fetch from the filesystem, it will get the
mapped label value.
> --- Usage ---
>
> Smack namespace is written using LSM hooks inside user namespace. That
> means it's connected to it.
>
> To create a new Smack namespace you need to unshare() user namespace
> as usual. If that is all you do though, than there is no difference to
> what is now. To activate the Smack namespace you need to fill the
> labels' map. It is in a file /proc/$PID/smack_map.
This should be /proc/$PID/attr/label_map or similar, modeled after the
existing /proc/$PID/attr/current and similar nodes. Then it isn't
module-specific and can be reused for other modules.
> Writing to the map file is not disabled after the first write as it is
> in uid_map. For Smack we have no means to map ranges of labels, hence
> it can really be advantageous to be able to expand the map later
> on. But you can only add to the map. You cannot remove already mapped
> labels. You cannot change the already existing mappings. Also mappings
> has to be 1-1. All requests to create a map where either the unmapped
> or the mapped label already exists in the map will be denied.
Isn't it a concern that I can then add additional labels to the mapping
for which I am not authorized? Or is this mitigated by the fact that I
cannot alter the rules? What about the situation for the predefined
labels in Smack - are you assuming that they will always be mapped up
front in the mapping file?
^ permalink raw reply
* Re: [PATCH] fs, proc: introduce CONFIG_PROC_CHILDREN
From: Djalal Harouni @ 2015-05-26 15:07 UTC (permalink / raw)
To: Cyrill Gorcunov
Cc: Iago López Galeiras, Oleg Nesterov, Kees Cook,
Pavel Emelyanov, Serge Hallyn, KAMEZAWA Hiroyuki, linux-api,
Alexander Viro, linux-fsdevel, Andrew Morton, Andy Lutomirski,
Alban Crequy
In-Reply-To: <20150522153705.GI16716@uranus>
On Fri, May 22, 2015 at 06:37:05PM +0300, Cyrill Gorcunov wrote:
> On Fri, May 22, 2015 at 02:47:39PM +0200, Iago López Galeiras wrote:
> > --- a/init/Kconfig
> > +++ b/init/Kconfig
> > @@ -1145,6 +1145,7 @@ endif # CGROUPS
> >
> > config CHECKPOINT_RESTORE
> > bool "Checkpoint/restore support" if EXPERT
> > + depends on PROC_CHILDREN
> > default n
> > help
> > Enables additional kernel features in a sake of checkpoint/restore.
>
> Maybe better select PROC_CHILDREN here? Also I must admit I don't understand
> why similar patch from Andy has not been merged earlier? Andy, there was
> some problem I forgot about?
From the linked thread, it seems that it was just lost... The discussion
ended up about task/<tid> and /proc/<pid>... That patch should have been
applied.
BTW this patch adds the CONFIG guard that was requested by Andrew. There
is a v3 coming to make it "select" as suggested.
Thanks!
--
Djalal Harouni
http://opendz.org
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox