Linux userland API discussions
 help / color / mirror / Atom feed
* Re: [PATCH v2 2/3] fbcon: use the cursor blink interval provided by vt
From: Thierry Reding @ 2015-05-21  8:00 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Kevin Hilman, Scot Doyle, Tomi Valkeinen, Michael Kerrisk,
	Jiri Slaby, Jean-Christophe Plagniol-Villard, Pavel Machek,
	Geert Uytterhoeven, lkml, linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	linux-man-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Tyler Baker, Olof Johansson,
	Daniel Stone, Arnd Bergmann
In-Reply-To: <20150521042638.GB22632-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 3731 bytes --]

On Wed, May 20, 2015 at 09:26:38PM -0700, Greg Kroah-Hartman wrote:
> On Wed, May 20, 2015 at 02:36:17PM +0200, Thierry Reding wrote:
> > On Tue, May 19, 2015 at 04:41:12PM -0700, Greg Kroah-Hartman wrote:
> > > On Tue, May 19, 2015 at 11:52:29PM +0200, Thierry Reding wrote:
> > > > On Tue, May 19, 2015 at 02:45:19PM -0700, Kevin Hilman wrote:
> > > > > On Tue, May 19, 2015 at 2:40 PM, Thierry Reding
> > > > > <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > > > > > On Tue, May 19, 2015 at 02:15:41PM -0700, Kevin Hilman wrote:
> > > > > >> On Thu, Mar 26, 2015 at 6:56 AM, Scot Doyle <lkml14@scotdoyle.com> wrote:
> > > > > >> > vt now provides a cursor blink interval via vc_data. Use this
> > > > > >> > interval instead of the currently hardcoded 200 msecs. Store it in
> > > > > >> > fbcon_ops to avoid locking the console in cursor_timer_handler().
> > > > > >> >
> > > > > >> > Signed-off-by: Scot Doyle <lkml14-enLWO88E2pdl57MIdRCFDg@public.gmane.org>
> > > > > >> > Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> > > > > >>
> > > > > >> This patch hit next-20150519 in the form of commit 27a4c827c34a
> > > > > >> (fbcon: use the cursor blink interval provided by vt) and has caused
> > > > > >> boot failure on a handful of ARM platforms when booting a MMC root
> > > > > >> filesystem.  This error was spotted by the kernelci.org bot on
> > > > > >> exynos5800-peach-pi[1] and Thierry and Daniel (Cc'd) have seen it on
> > > > > >> some tegra platforms too.
> > > > > >>
> > > > > >> Thierry spotted this commit as a potential cause, and both Daniel and
> > > > > >> I have reverted and boot tested on exynos5 and tegra respectively and
> > > > > >> the boot panics disappear.
> > > > > >
> > > > > > FWIW, if I apply the below on top of next-20150519 things seem to be
> > > > > > back to normal as well:
> > > > > >
> > > > > > diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
> > > > > > index 05b1d1a71ef9..658c34bb9076 100644
> > > > > > --- a/drivers/video/console/fbcon.c
> > > > > > +++ b/drivers/video/console/fbcon.c
> > > > > > @@ -1310,8 +1310,9 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
> > > > > >                 return;
> > > > > >
> > > > > >         ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
> > > > > > -       fbcon_del_cursor_timer(info);
> > > > > > -       if (!(vc->vc_cursor_type & 0x10))
> > > > > > +       if (vc->vc_cursor_type & 0x10)
> > > > > > +               fbcon_del_cursor_timer(info);
> > > > > > +       else
> > > > > >                 fbcon_add_cursor_timer(info);
> > > > > >
> > > > > >         ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
> > > > > 
> > > > > Applying this on next-20150519 makes my exynos board happily boot again as well.
> > > > > 
> > > > > Tested-by: Kevin Hilman <khilman-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > > > 
> > > > Excellent. Greg, Scot, any opinions on whether or not this is the right
> > > > thing to do? It restores a bit that looks suspiciously like it snuck in
> > > > in the original (at least it isn't documented in the commit message).
> > > > 
> > > > Greg, feel free to squash this in if everybody agrees this is good to
> > > > go. If you prefer a patch on top let me know and I'll come up with a
> > > > proper commit message.
> > > 
> > > Please send a real patch and I'll apply it on top, as I can't rebase my
> > > public tree.
> > 
> > Attached.
> 
> Ugh, no, please resend it as a stand-alone patch, I can't easily apply
> attachments.

Really? Your MUA can't dissect multipart messages? Anyway, sent
separately for your convenience.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* Re: [RFC PATCH 00/11] drm/i915: Expose OA metrics via perf PMU
From: Daniel Vetter @ 2015-05-21  8:24 UTC (permalink / raw)
  To: Robert Bragg
  Cc: Peter Zijlstra, linux-api, intel-gfx, linux-kernel, dri-devel,
	David Airlie, Ingo Molnar, Paul Mackerras,
	Arnaldo Carvalho de Melo, Daniel Vetter
In-Reply-To: <CAMou1-2Wgs9nvw9w8CHoacix8YSVAmuKu4MZJC=QQuCbLAx72w@mail.gmail.com>

On Thu, May 21, 2015 at 12:17:48AM +0100, Robert Bragg wrote:
> On Tue, May 19, 2015 at 3:53 PM, Peter Zijlstra <peterz@infradead.org> wrote:
> > On Fri, May 15, 2015 at 02:07:29AM +0100, Robert Bragg wrote:
> >> On Fri, May 8, 2015 at 5:24 PM, Peter Zijlstra <peterz@infradead.org> wrote:
> >> > On Thu, May 07, 2015 at 03:15:43PM +0100, Robert Bragg wrote:
> >> >
> >> >> I've changed the uapi for configuring the i915_oa specific attributes
> >> >> when calling perf_event_open(2) whereby instead of cramming lots of
> >> >> bitfields into the perf_event_attr config members, I'm now
> >> >> daisy-chaining a drm_i915_oa_event_attr_t structure off of a single
> >> >> config member that's extensible and validated in the same way as the
> >> >> perf_event_attr struct. I've found this much nicer to work with while
> >> >> being neatly extensible too.
> >> >
> >> > This worries me a bit.. is there more background for this?
> >>
> >> Would it maybe be helpful to see the before and after? I had kept this
> >> uapi change in a separate patch for a while locally but in the end
> >> decided to squash it before sending out my updated series.
> >>
> >> Although I did find it a bit awkward with the bitfields, I was mainly
> >> concerned about the extensibility of packing logically separate
> >> attributes into the config members and had heard similar concerns from
> >> a few others who had been experimenting with my patches too.
> >>
> >> A few simple attributes I can think of a.t.m that we might want to add
> >> in the future are:
> >> - control of the OABUFFER size
> >> - a way to ask the kernel to collect reports at the beginning and end
> >> of batch buffers, in addition to periodic reports
> >> - alternative ways to uniquely identify a context to support tools
> >> profiling a single context not necessarily owned by the current
> >> process
> >>
> >> It could also be interesting to expose some counter configuration
> >> through these attributes too. E.g. on Broadwell+ we have 14 'Flexible
> >> EU' counters included in the OA unit reports, each with a 16bit
> >> configuration.
> >>
> >> In a more extreme case it might also be useful to allow userspace to
> >> specify a complete counter config, which (depending on the
> >> configuration) could be over 100 32bit values to select the counter
> >> signals + configure the corresponding combining logic.
> >>
> >> Since this pmu is in a device driver it also seemed reasonably
> >> appropriate to de-couple it slightly from the core perf_event_attr
> >> structure by allowing driver extensible attributes.
> >>
> >> I wonder if it might be less worrisome if the i915_oa_copy_attr() code
> >> were instead a re-usable utility perhaps maintained in events/core.c,
> >> so if other pmu drivers were to follow suite there would be less risk
> >> of a mistake being made here?
> >
> >
> > So I had a peek at:
> >
> >   https://01.org/sites/default/files/documentation/observability_performance_counters_haswell.pdf
> >
> > In an attempt to inform myself of how the hardware worked. But the
> > document is rather sparse (and does not include broadwell).
> 
> Thanks. Sorry I can't easily fix this myself, but there is work
> ongoing to update this documentation. In the interim I can try and
> cover some of the key details here...

Yeah the docs are decidely less than stellar and especially lack
examples for how to use the flexible counters properly :( A few additional
comments from me below.

> > So from what I can gather there's two ways to observe the counters,
> > through MMIO or trough the ring-buffer, which in turn seems triggered by
> > a MI_REPORT_PERF_COUNT command.
> 
> There are three ways; mmio, MI_REPORT_PERF_COUNT via the ring-buffer
> and periodic sampling where the HW writes into a circular 'oabuffer'.
> 
> I think it's best to discount mmio as a debug feature since none of
> the counters are useful in isolation and mmio subverts the latching
> mechanism we get with the other two methods. We typically at least
> want to relate a counter to the number of clock cycles elapsed or the
> gpu time, or thread spawn counts.
> 
> This pmu  driver is primarily for exposing periodic metrics, while
> it's up to applications to choose to emit MI_REPORT_PERF_COUNT
> commands as part of their command streams so I think we can mostly
> ignore MI_REPORT_PERF_COUNT here too.

Yeah this is a crucial bit here - userspace inserts MI_REPORT_PERF_COUNT
into the gpu batchbuffer. And the gpu stores the samples at the userspace
provided address in the per-process gpu address space. Which means that
the kernel never ever sees these samples, nor can it get (efficiently at
least) at the target memory.

The mid-batchbuffer placement of perf samples is important since wrapping
just the entire batch is way too coarse. And timer-based sampling isn't
aligned to the different cmds, which means you can't restrict per sampling
to e.g. only a specific shader. Right now the gpu doesn't provide any
means to restrict sampling except emitting a full pipeline flush and then
wraping the interesting draw commands with MI_PEPORT_PERF.

> > [ Now the document talks about shortcomings of this scheme, where the
> > MI_REPORT_PERF_COUNT command can only be placed every other command, but
> > a single command can contain so much computation that this is not fine
> > grained enough -- leading to the suggestion of a timer/cycle based
> > reporting, but that is not actually mentioned afaict ]
> 
> It's in there, though unfortunately the documentation isn't very clear
> currently. The 'Performance Event Counting' section seems to be the
> appropriate place to introduce the periodic sampling feature, but just
> reading it myself it really only talks about the limitations of
> reporting like you say. I'll see if I can prod to get this improved.
> 
> If you see page 18 "Performance Statistics Registers":
> 
> OACONTROL has a 'Timer Period' field and 'Timer Enable'
> OABUFFER points to a circular buffer for periodic reports
> OASTATUS1/2 contain the head/tail pointers
> 
> 
> >
> > Now the MI_REPORT_PERF_COUNT can select a vector (Counter Select) of
> > which events it will write out.
> >
> > This covers the regular 'A' counters. Is this correct?
> 
> There isn't a counter select in MI_REPORT_PERF_COUNT commands. I guess
> you either saw 'GTT select' which is for dealing with the different
> address spaces that the destination buffer can reside in, or in the
> overview you saw the mention of the 'Counter Select' field following
> the description of MI_REPORT_PERF_COUNT but just missed that it was
> referring to the OACONTROL register.

Clarification: For userspace-inserted MI_REPORT_PERF the gpu forces the
access to the per-process address space, i.e. the GTT select bit isn't
obeyed.

> The counter configuration is shared by all three modes of reading the
> counters. (Though beware of confusing terms here, imho the above
> motioned 'Counter Select' would be better described as a 'Report
> Format' which is only relevant to MI_REPORT_PERF_COUNT and periodic
> sampling, not mmio reading)
> 
> The A counters have fixed semantics on Haswell so there's nothing to
> configure with these. On Broadwell some of these do become
> configurable as "Flexible EU Counters" which is something for us to
> keep in mind for later.
> 
> The semantics of the B counters are determined through the
> configuration of a MUX to select signals of interest and the
> configuration of some fixed-function ('boolean') logic that can affect
> how those signals are combined before feeding into one of the B
> counters. This configuration process is relatively slow, involving in
> the order of 100 register writes.
> 
> After configuring the counter semantics, then for periodic and
> MI_REPORT_PERF_COUNT usage (which work in terms of reports), we have
> to choose the layout of those reports.
> 
> OACONTROL has a report format field ('Counter Select') that gives us a
> limited way to trade off how many A or B counters are included, and
> the memory bandwidth consumed writing out reports. So it doesn't
> affect the configuration of counters per-se, it's just a way to ignore
> some of the currently configured counters by selecting smaller
> reports. Just looking at the OACONTROL documentation though I see
> something amiss, as this field isn't only pre-Haswell. The possible
> formats/layouts for Haswell are documented on page 10.

The tricky bit to keep in mind is that userspace and the kernel need to be
somewhat in sync about which sampling format is selected. Otherwise the
address in the MI_REPORT_PERF generated by userspace will not increment by
the correct amount (there's unfortunately no nice autoincrement support
for this).

> > Then there are the 'B' counters, which appear to be programmable through
> > the CEC MMIO registers.
> 
> The fixed-function logic affecting B counters is configured via those
> CEC registers as well as some per-counter 'report trigger' and 'start
> trigger' registers not currently described. Overall though programming
> the B counters is a combination of the fixed-function logic and the
> MUX configuration that determines the signals that feed into this
> logic, before counting.
> 
> >
> > These B events can also be part of the MI_REPORT_PERF_COUNT vector.
> >
> > Right?
> 
> Right, part of MI_REPORT_PERF_COUNT and periodic reports.

Imo that's a big reason for why the kernel should just forward the raw
samples to userspace. If we try to decode them in the kernel for the
timer-based ring, then userspace needs a dupe of that logic for the
MI_REPORT_PERF samples it collects.

If otoh we just forward the raw samples to userspace the same userspace
code can do the decoding for both the timer-based samples (collected
through perf) and the in-batch samples.

> > So for me the 'natural' way to represent this in perf would be through
> > event groups. Create a perf event for every single event -- yes this is
> > 53 events.
> 
> So when I was first looking at this work I had considered the
> possibility of separate events, and these are some of the things that
> in the end made me forward the hardware's raw report data via a single
> event instead...
> 
> There are 100s of possible B counters depending on the MUX
> configuration + fixed-function logic in addition to the A counters. A
> choice would need to be made about whether to expose events for the
> configurable counters that aren't inherently associated with any
> semantics, or instead defining events for counters with specific
> semantics (with 100s of possible counters to define). The later would
> seem more complex for userspace and the kernel if they both now have
> to understand the constraints on what counters can be used together. I
> guess with either approach we would also need to have some form of
> dedicated group leader event accepting attributes for configuring the
> state that affects the group as a whole, such as the counter
> configuration (3D vs GPGPU vs media etc). I'm not sure where we would
> handle the context-id + drm file descriptor attributes for initiating
> single context profiling but guess we'd need to authenticate each
> individual event open. It's not clear if we'd configure the report
> layout via the group leader, or try to automatically choose the most
> compact format based on the group members. I'm not sure how pmus
> currently handle the opening of enabled events on an enabled group but
> I think there would need to be limitations in our case that new
> members can't result in a reconfigure of the counters if that might
> loose the current counter values known to userspace.
> 
> From a user's pov, there's no real freedom to mix and match which
> counters are configured together, and there's only some limited
> ability to ignore some of the currently selected counters by not
> including them in reports.
> 
> Something to understand here is that we have to work with sets of
> pre-defined MUX + fixed-function logic configurations that have been
> validated to give useful metrics for specific use cases, such as
> benchmarking 3D rendering, GPGPU or media workloads.
> 
> As it is currently the kernel doesn't need to know anything about the
> semantics of individual counters being selected, so it's currently
> convenient that we can aim to maintain all the counter meta data we
> have in userspace according to the changing needs of tools or drivers
> (e.g. names, descriptions, units, max values, normalization
> equations), de-coupled from the kernel, instead of splitting it
> between the kernel and userspace.
> 
> A benefit of being able to change the report size is to reduce memory
> bandwidth usage that can skew measurements. It's possible to request
> the gpu to write out periodic snapshots at a very high frequency (we
> can program a period as low as 160 nanoseconds) and higher frequencies
> can start to expose some interesting details about how the gpu is
> utilized - though with notable observer effects too. How careful we
> are to not waste bandwidth is expected to determine what sampling
> resolutions we can achieve before significantly impacting what we are
> measuring.
> 
> Splitting the counters up looked like it could increase the bandwidth
> we use quite a bit. The main difference comes from requiring 64bit
> values instead of the 32bit values in our raw reports. This can be
> offset partly since there are quite a few 'reserved'/redundant A
> counters that don't need forwarding. As an example in the most extreme
> case, instead of an 8 byte perf_event_header + 4byte raw_size + 256
> byte reports + 4 byte padding every 160ns ~= 1.5GB/s, we might have 33
> A counters (ignoring redundant ones) + 16 configurable counters = 400
> byte struct read_format (using PERF_FORMAT_GROUP) + 8 byte
> perf_event_header every 160ns ~= 2.4GB/s. On the other hand though we
> could choose to forward only 2 or 3 counters of interest at these high
> frequencies which isn't possible currently.
> 
> >
> > Use the MMIO reads for the regular read() interface, and use a hrtimer
> > placing MI_REPORT_PERF_COUNT commands, with a counter select mask
> > covering the all events in the current group, for sampling.
> 
> Unfortunately due to the mmio limitations and the need to relate
> counters I can't imagine many use cases for directly accessing the
> counters individually via the read() interface.
> 
> MI_REPORT_PERF_COUNT commands are really only intended for collecting
> reports in sync with a command stream. We are experimenting currently
> with an extension of my PMU driver that emits MI_REPORT_PERF_COUNT
> commands automatically around the batches of commands submitted by
> userspace so we can do a better job of filtering metrics across many
> gpu contexts, but for now the expectation is that the kernel shouldn't
> be emitting MI_REPORT_PERF_COUNT commands. We emit
> MI_REPORT_PERF_COUNT commands within Mesa for example to implement the
> GL_INTEL_performance_query extension, at the start and end of a query
> around a sequence of commands that the application is interested in
> measuring.
> 
> >
> > Then obtain the vector values using PERF_SAMPLE_READ and
> > PERF_FORMAT_READ -- and use the read txn support to consume the
> > ring-buffer vectors instead of the MMIO registers.
> 
> It sounds potentially doable to consume periodic OABUFFER reports via
> the read_txn support.
> 
> >
> > You can use the perf_event_attr::config to select the counter (A0-A44,
> > B0-B7) and use perf_event_attr::config1 (low and high dword) for the
> > corresponding CEC registers.
> >
> 
> Hopefully covered above, but since the fixed-function state is so
> dependent on the MUX configuration I think it currently makes sense to
> treat the MUX plus logic state (including the CEC state) a tightly
> coupled unit.
> 
> The Flexible EU Counters for Broadwell+ could be more amenable to this
> kind of independent configuration, as I don't believe they are
> dependant on the MUX configuration.
> 
> One idea that's come up a lot though is having the possibility of
> being able to configure an event with a full MUX + fixed-function
> state description.
> 
> >
> > This does not require random per driver ABI extentions for
> > perf_event_attr, nor your custom output format.
> >
> > Am I missing something obvious here?
> 
> Definitely nothing 'obvious' since the current documentation is
> notably incomplete a.t.m, but I don't think we were on the same page
> about how the hardware works and our use cases.
> 
> Hopefully some of my above comments help clarify some details.
> 
> I think I'll hold off from looking at changing anything specific until
> you've had a chance to read my comments above in case you have more
> thoughts and feedback.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply

* Re: [PATCH 2/9] y2038: asm-generic: extend sysvipc data structures
From: Geert Uytterhoeven @ 2015-05-21  8:56 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: y2038, baolin.wang, albert.aribaud, John Stultz, bamvor.zhangjian,
	ruchandani.tina, linux-api@vger.kernel.org,
	linux-kernel@vger.kernel.org, libc-alpha, Linux-Arch,
	Manfred Spraul, Michael Kerrisk
In-Reply-To: <1432134445-804487-3-git-send-email-arnd@arndb.de>

Hi Arnd,

On Wed, May 20, 2015 at 5:07 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> --- a/include/uapi/asm-generic/sembuf.h
> +++ b/include/uapi/asm-generic/sembuf.h
> @@ -12,23 +12,29 @@
>   * everyone just ended up making identical copies without specific
>   * optimizations, so we may just as well all use the same one.
>   *
> - * 64 bit architectures typically define a 64 bit __kernel_time_t,
> + * 64 bit architectures use a 64-bit __kernel_time_t here, while
> + * 32 bit architectures have a pair of unsigned long values.
>   * so they do not need the first two padding words.
> - * On big-endian systems, the padding is in the wrong place.
>   *
> - * Pad space is left for:
> - * - 64-bit time_t to solve y2038 problem
> - * - 2 miscellaneous 32-bit values
> + * On big-endian systems, the padding is in the wrong place for
> + * historic reasons, so user space has to reconstruct a time_t
> + * value using
> + *
> + * user_semid_ds.sem_otime = kernel_semid64_ds.sem_otime +
> + *             (long long)(kernel_semid64_ds.sem_otime_high << 32)

The cast to "long long" should be inside the parentheses, to promote the
(32-bit) sem_otime_high to a first 64-bit integer first.
Else it will be shifted into oblivion (oh no, C undefined behavior).

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH] [RFC] fs, proc: don't guard /proc/<pid>/task/<tid>/children on CONFIG_CHECKPOINT_RESTORE
From: Alban Crequy @ 2015-05-21 10:30 UTC (permalink / raw)
  To: Cyrill Gorcunov
  Cc: Oleg Nesterov, Kees Cook, Pavel Emelyanov, Serge Hallyn,
	KAMEZAWA Hiroyuki, linux-api-u79uwXL29TY76Z2rM5mHXA,
	Alexander Viro, linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	Andrew Morton, Alban Crequy, Iago Lopez Galeiras

From: Alban Crequy <alban-973cpzSjLbNWk0Htik3J/w@public.gmane.org>

commit 818411616baf ("fs, proc: introduce
/proc/<pid>/task/<tid>/children entry") introduced the children entry
for checkpoint restore and the file is only available on kernels
configured with CONFIG_EXPERT and CONFIG_CHECKPOINT_RESTORE.

This is available in most distributions (Fedora, Debian, Ubuntu, CoreOS)
because they usually enable CONFIG_EXPERT and CONFIG_CHECKPOINT_RESTORE.
But Arch does not enable CONFIG_EXPERT or CONFIG_CHECKPOINT_RESTORE.

However, the children proc file is useful outside of checkpoint restore.
I would like to use it in rkt. The rkt process exec() another program it
does not control, and that other program will fork()+exec() a child
process. I would like to find the pid of the child process from an
external tool without iterating in /proc over all processes to find
which one has a parent pid equal to rkt.

Since the children proc file is useful outside of checkpoint-restore,
I am removing the guard on CONFIG_CHECKPOINT_RESTORE.

Signed-off-by: Alban Crequy <alban-973cpzSjLbNWk0Htik3J/w@public.gmane.org>
Cc: Iago Lopez Galeiras <iago-973cpzSjLbNWk0Htik3J/w@public.gmane.org>
---
 fs/proc/array.c | 2 --
 fs/proc/base.c  | 2 --
 2 files changed, 4 deletions(-)

diff --git a/fs/proc/array.c b/fs/proc/array.c
index fd02a9e..6edec57 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -569,7 +569,6 @@ int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
 	return 0;
 }
 
-#ifdef CONFIG_CHECKPOINT_RESTORE
 static struct pid *
 get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos)
 {
@@ -692,4 +691,3 @@ const struct file_operations proc_tid_children_operations = {
 	.llseek  = seq_lseek,
 	.release = children_seq_release,
 };
-#endif /* CONFIG_CHECKPOINT_RESTORE */
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 093ca14..b743007 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2922,9 +2922,7 @@ static const struct pid_entry tid_base_stuff[] = {
 	ONE("stat",      S_IRUGO, proc_tid_stat),
 	ONE("statm",     S_IRUGO, proc_pid_statm),
 	REG("maps",      S_IRUGO, proc_tid_maps_operations),
-#ifdef CONFIG_CHECKPOINT_RESTORE
 	REG("children",  S_IRUGO, proc_tid_children_operations),
-#endif
 #ifdef CONFIG_NUMA
 	REG("numa_maps", S_IRUGO, proc_tid_numa_maps_operations),
 #endif
-- 
2.1.4

^ permalink raw reply related

* [PATCH 0/8] Smack namespace
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk

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


===================================================================

--- 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 (8):
  kernel/exit.c: make sure current's nsproxy != NULL while checking caps
  user_ns: 3 new hooks for LSM 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 | 221 ++++++++++++
 MAINTAINERS                                |   1 +
 fs/proc/base.c                             |  57 ++++
 include/linux/security.h                   |  46 +++
 include/linux/user_namespace.h             |   9 +
 kernel/exit.c                              |   8 +-
 kernel/user.c                              |   3 +
 kernel/user_namespace.c                    |  18 +
 security/capability.c                      |  21 ++
 security/security.c                        |  20 ++
 security/smack/Kconfig                     |  12 +
 security/smack/Makefile                    |   1 +
 security/smack/smack.h                     | 187 +++++++++-
 security/smack/smack_access.c              | 191 +++++++++--
 security/smack/smack_lsm.c                 | 531 ++++++++++++++++++++---------
 security/smack/smack_ns.c                  | 484 ++++++++++++++++++++++++++
 security/smack/smackfs.c                   | 154 +++++----
 18 files changed, 1719 insertions(+), 247 deletions(-)
 create mode 100644 Documentation/security/Smack-namespace.txt
 create mode 100644 security/smack/smack_ns.c

-- 
2.1.0

^ permalink raw reply

* [PATCH 1/8] kernel/exit.c: make sure current's nsproxy != NULL while checking caps
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-1-git-send-email-l.pawelczyk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

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.

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);
-- 
2.1.0

^ permalink raw reply related

* [PATCH 2/8] user_ns: 3 new hooks for LSM namespace operations
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-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 3/8] smack: extend capability functions and fix 2 checks
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-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 4/8] smack: abstraction layer for 2 common Smack operations
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-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 5/8] smack: misc cleanups in preparation for a namespace patch
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-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 6/8] smack: namespace groundwork
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-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 7/8] smack: namespace implementation
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-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 8/8] smack: documentation for the Smack namespace
From: Lukasz Pawelczyk @ 2015-05-21 11:53 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, Christoph Hellwig,
	David Howells, Eric Dumazet, Fabian Frederick, Greg KH,
	Ingo Molnar, Ionut Alexa, James Morris, Jeff Layton, Joe Perches,
	Jonathan Corbet, Kees Cook, Lukasz Pawelczyk,
	Mauro Carvalho Chehab
  Cc: Lukasz Pawelczyk
In-Reply-To: <1432209222-8479-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 00/23] userfaultfd v4
From: Kirill Smelkov @ 2015-05-21 13:11 UTC (permalink / raw)
  To: Andrea Arcangeli
  Cc: Andrew Morton, linux-kernel, linux-mm, qemu-devel, kvm, linux-api,
	Pavel Emelyanov, Sanidhya Kashyap, zhang.zhanghailiang,
	Linus Torvalds, Kirill A. Shutemov, Andres Lagar-Cavilla,
	Dave Hansen, Paolo Bonzini, Rik van Riel, Mel Gorman,
	Andy Lutomirski, Hugh Dickins, Peter Feiner,
	Dr. David Alan Gilbert, Johannes Weiner, Huangpeng (Peter)
In-Reply-To: <1431624680-20153-1-git-send-email-aarcange@redhat.com>

Hello up there,

On Thu, May 14, 2015 at 07:30:57PM +0200, Andrea Arcangeli wrote:
> Hello everyone,
> 
> This is the latest userfaultfd patchset against mm-v4.1-rc3
> 2015-05-14-10:04.
> 
> The postcopy live migration feature on the qemu side is mostly ready
> to be merged and it entirely depends on the userfaultfd syscall to be
> merged as well. So it'd be great if this patchset could be reviewed
> for merging in -mm.
> 
> Userfaults allow to implement on demand paging from userland and more
> generally they allow userland to more efficiently take control of the
> behavior of page faults than what was available before
> (PROT_NONE + SIGSEGV trap).
> 
> The use cases are:

[...]

> Even though there wasn't a real use case requesting it yet, it also
> allows to implement distributed shared memory in a way that readonly
> shared mappings can exist simultaneously in different hosts and they
> can be become exclusive at the first wrprotect fault.

Sorry for maybe speaking up too late, but here is additional real
potential use-case which in my view is overlapping with the above:

Recently we needed to implement persistency for NumPy arrays - that is
to track made changes to array memory and transactionally either abandon
the changes on transaction abort, or store them back to storage on
transaction commit.

Since arrays can be large, it would be slow and thus not practical to
have original data copy and compare memory to original to find what
array parts have been changed.

So I've implemented a scheme where array data is initially PROT_READ
protected, then we catch SIGSEGV, if it is write and area belongs to array
data - we mark that page as PROT_WRITE and continue. On commit time we
know which parts were modified.

Also, since arrays could be large - bigger than RAM, and only sparse
parts of it could be needed to get needed information, for reading it
also makes sense to lazily load data in SIGSEGV handler with initial
PROT_NONE protection.

This is very similar to how memory mapped files work, but adds
transactionality which, as far as I know, is not provided by any
currently in-kernel filesystem on Linux.

The system is done as files, and arrays are then build on top of
this-way memory-mapped files. So from now on we can forget about NumPy
arrays and only talk about files, their mapping, lazy loading and
transactionally storing in-memory changes back to file storage.

To get this working, a custom user-space virtual memory manager is
unrolled, which manages RAM memory "pages", file mappings into virtual
address-space, tracks pages protection and does SIGSEGV handling
appropriately.


The gist of virtual memory-manager is this:

    https://lab.nexedi.cn/kirr/wendelin.core/blob/master/include/wendelin/bigfile/virtmem.h
    https://lab.nexedi.cn/kirr/wendelin.core/blob/master/bigfile/virtmem.c  (vma_on_pagefault)


For operations it currently needs

    - establishing virtual memory areas and connecting to tracking it

    - changing pages protection

        PROT_NONE or absent                             - initially
        PROT_NONE       -> PROT_READ                    - after read
        PROT_READ       -> PROT_READWRITE               - after write
        PROT_READWRITE  -> PROT_READ                    - after commit
        PROT_READWRITE  -> PROT_NONE or absent (again)  - after abort
        PROT_READ       -> PROT_NONE or absent (again)  - on reclaim

    - working with aliasable memory (thus taken from tmpfs)

        there could be two overlapping-in-file mapping for file (array)
        requested at different time, and changes from one mapping should
        propagate to another one -> for common parts only 1 page should
        be memory-mapped into 2 places in address-space.

so what is currently lacking on userfaultfd side is:

    - ability to remove / make PROT_NONE already mapped pages
      (UFFDIO_REMAP was recently dropped)

    - ability to arbitrarily change pages protection (e.g. RW -> R)

    - inject aliasable memory from tmpfs (or better hugetlbfs) and into
      several places (UFFDIO_REMAP + some mapping copy semantic).


The code is ugly because it is only a prototype. You can clone/read it
all from here:

    https://lab.nexedi.cn/kirr/wendelin.core

Virtual memory-manager even has tests, and from them it could be seen
how the system is supposed to work (after each access - what pages and
where are mapped and how):

    https://lab.nexedi.cn/kirr/wendelin.core/blob/master/bigfile/tests/test_virtmem.c

The performance currently is not great, partly because of page clearing
when getting ram from tmpfs, and partly because of mprotect/SIGSEGV/vmas
overhead and other dumb things on my side.

I still wanted to show the case, as userfaultd here has potential to
remove overhead related to kernel.

Thanks beforehand for feedback,

Kirill


P.S. some context

http://www.wendelin.io/NXD-Wendelin.Core.Non.Secret/asEntireHTML

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH 2/9] y2038: asm-generic: extend sysvipc data structures
From: Arnd Bergmann @ 2015-05-21 14:52 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: y2038, baolin.wang, albert.aribaud, John Stultz, bamvor.zhangjian,
	ruchandani.tina, linux-api@vger.kernel.org,
	linux-kernel@vger.kernel.org, libc-alpha, Linux-Arch,
	Manfred Spraul, Michael Kerrisk
In-Reply-To: <CAMuHMdUtJ2x+axBLj5qdsRwod=XdRkmeYJm1N7H5V_CXLo5J0g@mail.gmail.com>

On Thursday 21 May 2015 10:56:34 Geert Uytterhoeven wrote:
> > + * value using
> > + *
> > + * user_semid_ds.sem_otime = kernel_semid64_ds.sem_otime +
> > + *             (long long)(kernel_semid64_ds.sem_otime_high << 32)
> 
> The cast to "long long" should be inside the parentheses, to promote the
> (32-bit) sem_otime_high to a first 64-bit integer first.
> Else it will be shifted into oblivion (oh no, C undefined behavior).
> 
> 

Fixed now to say

 * user_semid_ds.sem_otime = kernel_semid64_ds.sem_otime +
 *             ((long long)kernel_semid64_ds.sem_otime_high << 32)

Thanks!

	Arnd

^ permalink raw reply

* Re: [PATCH 00/23] userfaultfd v4
From: Andrea Arcangeli @ 2015-05-21 15:52 UTC (permalink / raw)
  To: Kirill Smelkov
  Cc: Andrew Morton, linux-kernel, linux-mm, qemu-devel, kvm, linux-api,
	Pavel Emelyanov, Sanidhya Kashyap, zhang.zhanghailiang,
	Linus Torvalds, Kirill A. Shutemov, Andres Lagar-Cavilla,
	Dave Hansen, Paolo Bonzini, Rik van Riel, Mel Gorman,
	Andy Lutomirski, Hugh Dickins, Peter Feiner,
	Dr. David Alan Gilbert, Johannes Weiner,
	"Huangpeng (Peter)" <peter.huangpeng@
In-Reply-To: <20150521131111.GA8932@teco.navytux.spb.ru>

Hi Kirill,

On Thu, May 21, 2015 at 04:11:11PM +0300, Kirill Smelkov wrote:
> Sorry for maybe speaking up too late, but here is additional real

Not too late, in fact I don't think there's any change required for
this at this stage, but it'd be great if you could help me to review.

> Since arrays can be large, it would be slow and thus not practical to
[..]
> So I've implemented a scheme where array data is initially PROT_READ
> protected, then we catch SIGSEGV, if it is write and area belongs to array

In the case of postcopy live migration (for qemu and/or containers) and
postcopy live snapshotting, splitting the vmas is not an option
because we may run out of them.

If your PROT_READ areas are limited perhaps this isn't an issue but
with hundreds GB guests (currently plenty in production) that needs to
live migrate fully reliably and fast, the vmas could exceed the limit
if we were to use mprotect. If your arrays are very large and the
PROT_READ aren't limited, using userfaultfd this isn't only an
optimization for you too, it's actually a must to avoid a potential
-ENOMEM.

> Also, since arrays could be large - bigger than RAM, and only sparse
> parts of it could be needed to get needed information, for reading it
> also makes sense to lazily load data in SIGSEGV handler with initial
> PROT_NONE protection.

Similarly I heard somebody wrote a fastresume to load the suspended
(on disk) guest ram using userfaultfd. That is a slightly less
fundamental case than postcopy because you could do it also with
MAP_SHARED, but it's still interesting in allowing to compress or
decompress the suspended ram on the fly with lz4 for example,
something MAP_PRIVATE/MAP_SHARED wouldn't do (plus there's the
additional benefit of not having an orphaned inode left open even if
the file is deleted, that prevents to unmount the filesystem for the
whole lifetime of the guest).

> This is very similar to how memory mapped files work, but adds
> transactionality which, as far as I know, is not provided by any
> currently in-kernel filesystem on Linux.

That's another benefit yes.

> The gist of virtual memory-manager is this:
> 
>     https://lab.nexedi.cn/kirr/wendelin.core/blob/master/include/wendelin/bigfile/virtmem.h
>     https://lab.nexedi.cn/kirr/wendelin.core/blob/master/bigfile/virtmem.c  (vma_on_pagefault)

I'll check it more in detail ASAP, thanks for the pointers!

> For operations it currently needs
> 
>     - establishing virtual memory areas and connecting to tracking it

That's the UFFDIO_REGISTER/UNREGISTER.

>     - changing pages protection
> 
>         PROT_NONE or absent                             - initially

absent is what works with -mm already. The lazy loading already works.

>         PROT_NONE       -> PROT_READ                    - after read

Current UFFDIO_COPY will map it using vma->vm_page_prot.

We'll need a new flag for UFFDIO_COPY to map it readonly. This is
already contemplated:

	/*
	 * There will be a wrprotection flag later that allows to map
	 * pages wrprotected on the fly. And such a flag will be
	 * available if the wrprotection ioctl are implemented for the
	 * range according to the uffdio_register.ioctls.
	 */
#define UFFDIO_COPY_MODE_DONTWAKE		((__u64)1<<0)
	__u64 mode;

If the memory protection framework exists (either through the
uffdio_register.ioctl out value, or through uffdio_api.features
out-only value) you can pass a new flag (MODE_WP) above to transition
from "absent" to "PROT_READ".

>         PROT_READ       -> PROT_READWRITE               - after write

This will need to add UFFDIO_MPROTECT.

>         PROT_READWRITE  -> PROT_READ                    - after commit

UFFDIO_MPROTECT again (but harder if going from rw to ro, because of a
slight mess to solve with regard to FAULT_FLAG_TRIED, in case you want
to run this UFFDIO_MPROTECT without stopping the threads that are
accessing the memory concurrently).

And this should only work if the uffdio_register.mode had MODE_WP set,
so we don't run into the races created by COWs (gup vs fork race).

>         PROT_READWRITE  -> PROT_NONE or absent (again)  - after abort

UFFDIO_MPROTECT again, but you won't be able to read the page contents
inside the memory manager thread (the one working with
userfaultfd).

The manager at all times if forbidden to touch the memory it is
tracking with userfaultfd (if it does it'll deadlock, but kill -9 will
get rid of it). gdb ironically because it is using an underoptimized
access_process_vm wouldn't hang, because FAULT_FLAG_RETRY won't be set
in handle_userfault in the gdb context, and it'll just receive a
sigbus if by mistake the user tries to touch the memory. Even if it
will hung later as get_user_pages_locked|unlocked gets used there too,
kill -9 would solve gdb too.

Back to the problem of accessing the UFFDIO_MPROTECT(PROT_NONE)
memory: to do that a new ioctl should be required. I'd rather not go
back to the route of UFFDIO_REMAP, but it could copy the data using
the kernel address.

It could be simply a reverse UFFDIO_COPY. We could add a
UFFDIO_COPY_MODE_REVERSE flag to the "mode" of UFFDIO_COPY to mean
"read source from kernel address and write destination in user
address". By default it reads the source from user address and write
the destination in kernel address (to be atomic).

If you want to put data back before lifting the PROT_NONE, UFFDIO_COPY
could be used in the standard way but with a
UFFDIO_COPY_MODE_OVERWRITE flag that just overwrites the contents of
the old page if it's not mapped (protnone), or just get rid of the old
page (currently it'd return -EEXIST if the pte is not none).

So the process would be:

UFFDIO_COPY(dst_tmpaddr, src_addr, mode=REVERSE)
UFFDIO_COPY(src_addr, dst_tmpaddr, mode=OVERWRITE)

Then if you also set mode=READONLY in the last UFFDIO_COPY, it'll
create a wrprotected mapping atomically before giving visibility to
the new page contents:

UFFDIO_COPY(src_addr, dst_tmpaddr, mode=OVERWRITE|WP)

>         PROT_READ       -> PROT_NONE or absent (again)  - on reclaim

Same as above.

>     - working with aliasable memory (thus taken from tmpfs)
> 
>         there could be two overlapping-in-file mapping for file (array)
>         requested at different time, and changes from one mapping should
>         propagate to another one -> for common parts only 1 page should
>         be memory-mapped into 2 places in address-space.

Why isn't the manager thread taking care of calling UFFDIO_MPROTECT in
two places?

And UFFDIO_COPY would fill the page and replace the old page and the
effect would be visible as far as the "data" is concerned, but the
protection bits would be more naturally different for each
mapping, like a double mmap call is also required to map such an area
in two places.

You could have a MAP_PRIVATE vma with PROT_READ, you can't create a
writable pte into it, just because you called
UFFDIO_MPROTECT(PROT_READ|PROT_WRITE) in a different mapping of the
same tmpfs page.

NOTE: the availability of the UFFDIO_MPROTECT|COPY on tmpfs ares would
still depend on UFFDIO_REGISTER to return the respecteve ioctl id in
the uffdio_register.ioctl (out value of the register ioctl).

> so what is currently lacking on userfaultfd side is:
> 
>     - ability to remove / make PROT_NONE already mapped pages
>       (UFFDIO_REMAP was recently dropped)
> 
>     - ability to arbitrarily change pages protection (e.g. RW -> R)
> 
>     - inject aliasable memory from tmpfs (or better hugetlbfs) and into
>       several places (UFFDIO_REMAP + some mapping copy semantic).

I think UFFDIO_COPY if added with OVERWRITE|REVERSE|WP flags is an ok
substitute for UFFDIO_REMAP.

If UFFDIO_COPY sees the page is protnone during the REVERSE copy (to
extract the memory atomically), it can also skip the tlb flush (and
obviously there's no tlb flush in the reverse direction). If the page
was not protnone, it can turn it in protnone, do a tlb flush, and then
copy it to the destination address using the userland mapping.

UFFDIO_MPROTECT is definitely necessary for postcopy live snapshotting
too (the reverse UFFDIO_COPY is not, it never deals with
PROT_NONE and it never cares about missing faults).

MPROTECT(PROT_NONE) so far seems needed only by this and perhaps UML
(and perhaps qemu linux-user).

I posted in another email why these features aren't implemented yet 

==
There will be some complications in adding the wrprotection/protnone
feature: if faults could already happen when the wrprotect/protnone is
armed, the handle_userfault() could be invoked in a retry-fault, that
is not ok without allowing the userfault to return VM_FAULT_RETRY even
during a refault (i.e. FAULT_FLAG_TRIED set but FAULT_FLAG_ALLOW_RETRY
not set). The invariants of vma->vm_page_prot and pte/trans_huge_pmd
permissions must also not break anywhere. These are the two main
reasons why these features that requires to flip protection bits are
left implemented later and made visible later with uffdio_api.feature
flags and/or through uffdio_register.ioctl during UFFDIO_REGISTER.
==

> The performance currently is not great, partly because of page clearing
> when getting ram from tmpfs, and partly because of mprotect/SIGSEGV/vmas
> overhead and other dumb things on my side.

Also the page faults get slowed down when the rbtree grows a lot,
userfaultfd won't let the rbtree grow.

> I still wanted to show the case, as userfaultd here has potential to
> remove overhead related to kernel.

That's very useful and interesting feedback!

Could you review the API to be sure we don't have to modify it when we
extend it like described above?

1) tmpfs returning uffdio_register.ioctl |=
   UFFDIO_MPROTECT|UFFDIO_COPY when enabled

2) UFFDIO_MPROTECT(PROT_NONE|READ|WRITE|EXEC) and in turn
   UFFDIO_COPY_MODE_REVERSE|UFFDIO_COPY_MODE_OVERWRITE|UFFDIO_COPY_MODE_WP
   being available if uffdio_register.ioctl includes UFFDIO_MPROTECT
   (and uffdio_api.features will then include
   UFFD_FEATURE_PAGEFAULT_WP to signal the uffd_msg.pagefault.flag WP
   is available [bit 1], and UFFDIO_REGISTER_MODE_WP can be used in
   uffdio_register.mode)

All of it could just check for uffdio_api.features &
UFFD_FEATURE_PAGEFAULT_WP being set, but you'd still have to check for
UFFDIO_MPROTECT being set in uffdio_register.ioctl for tmpfs areas (or
to know it's not available yet on hugetlbfs), so I think it's more
robust to check UFFDIO_MPROTECT ioctl being set in
uffdio_register.ioctl to assume all mprotection and writeprotect
tracking features are available for that specific range. The feature
flag will just tell that UFFDIO_REGISTER_MODE_WP can be used in the
register ioctl, that is something you need to know before in order to
"arm" the VMA for wrprotect faults.

For your usage I think you probably want to set
UFFDIO_REGISTER_MODE_WP|UFFDIO_REGISTER_MODE_MISSING and you'll be
told through uffdio_msg.flags if it's a WP or MISSING fault. You won't
be told if it's missing because of PROT_NONE or absent.

On a side note: all of the above is completely orthognal from the
non-cooperative usage: as far as memory protection features it doesn't
need any, it just needs to track more events like fork/mremap to
adjust its offsets as the memory manager is not part of the app and it
has no way to orchestrate by other means.

Doing it all at once (non-cooperative + full memory protection) looked
too much. We should just try to get the API right in a way that won't
require an UFFD_API bump passed to uffdio_api.api. Even then, if an
api bump is required, that's not a big deal, until recently the
non-cooperative usage already did the API bumb but we accomodated the
read(2) API to avoid it.

Thinking at the worst case scenario, if the API gets bumped the only
thing that has to remain fixed is the ioctl number of the UFFDIO_API
and the uffdio_api structure. Everything else can be upgraded without
risk of ABI breakage, even the ioctl numbers can be reused (except the
very UFFDIO_API). When the non-cooperative usage bumped the API it
actually kept all ioctl the same except the read(2) format.

Comments welcome, thanks!
Andrea

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH net-next 1/4] bpf: allow bpf programs to tail-call other bpf programs
From: Daniel Borkmann @ 2015-05-21 16:17 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: David S. Miller, Ingo Molnar, Michael Holzheu, Zi Shen Lim,
	linux-api-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1432079946-9878-2-git-send-email-ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>

On 05/20/2015 01:59 AM, Alexei Starovoitov wrote:
> introduce bpf_tail_call(ctx, &jmp_table, index) helper function
> which can be used from BPF programs like:
> int bpf_prog(struct pt_regs *ctx)
> {
>    ...
>    bpf_tail_call(ctx, &jmp_table, index);
>    ...
> }
> that is roughly equivalent to:
> int bpf_prog(struct pt_regs *ctx)
> {
>    ...
>    if (jmp_table[index])
>      return (*jmp_table[index])(ctx);
>    ...
> }
> The important detail that it's not a normal call, but a tail call.
> The kernel stack is precious, so this helper reuses the current
> stack frame and jumps into another BPF program without adding
> extra call frame.
> It's trivially done in interpreter and a bit trickier in JITs.
> In case of x64 JIT the bigger part of generated assembler prologue
> is common for all programs, so it is simply skipped while jumping.
> Other JITs can do similar prologue-skipping optimization or
> do stack unwind before jumping into the next program.
>
...
> Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>

LGTM, thanks!

Acked-by: Daniel Borkmann <daniel-FeC+5ew28dpmcu3hnIyYJQ@public.gmane.org>

^ permalink raw reply

* Re: [PATCH net-next 1/4] bpf: allow bpf programs to tail-call other bpf programs
From: Andy Lutomirski @ 2015-05-21 16:20 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: David S. Miller, Ingo Molnar, Daniel Borkmann, Michael Holzheu,
	Zi Shen Lim, Linux API, Network Development,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <555BD2E4.5050608-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>

On Tue, May 19, 2015 at 5:18 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
> On 5/19/15 5:13 PM, Andy Lutomirski wrote:
>>
>>
>> IMO this is starting to get a bit ugly.  Would it be possible to have
>> the program dereference the subprogram reference itself from the jump
>> table?  There would have to be a verifier type that represents a
>> reference to a program tail-call entry point, but that seems better
>> than having this weird indirection.
>
>
> Which part? I don't think you've looked at examples yet.
> network parser has to call itself. Otherwise we cannot parse 10 mpls
> labels or TLVs.
> Indirection via jump_table also has to be there.
> We need to dynamically add and remove programs form this jump table.
> It cannot be all static.
>

What I mean is: why do we need the interface to be "look up this index
in an array and just to what it references" as a single atomic
instruction?  Can't we break it down into first "look up this index in
an array" and then "do this tail call"?

I don't see why everything needs to be a map.

--Andy

^ permalink raw reply

* Re: [PATCH net-next 1/4] bpf: allow bpf programs to tail-call other bpf programs
From: Alexei Starovoitov @ 2015-05-21 16:40 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: David S. Miller, Ingo Molnar, Daniel Borkmann, Michael Holzheu,
	Zi Shen Lim, Linux API, Network Development,
	linux-kernel@vger.kernel.org
In-Reply-To: <CALCETrVNwOVRJ4KH6mEo4hPq_QjTCb8mcwRf1sy5kd1nmnSZ+A@mail.gmail.com>

On 5/21/15 9:20 AM, Andy Lutomirski wrote:
>
> What I mean is: why do we need the interface to be "look up this index
> in an array and just to what it references" as a single atomic
> instruction?  Can't we break it down into first "look up this index in
> an array" and then "do this tail call"?

I've actually considered to do this split and do first part as map 
lookup and 2nd as 'tail call to this ptr' insn, but it turned out to be
painful: verifier gets more complicated, ctx pointer needs to kept
somewhere, JITs need to special case two things instead of one.
Also I couldn't see a use case for exposing program pointer to the
program itself. I've explored this path only because it felt more
traditional 'goto *ptr' like, but adding new PTR_TO_PROG type to
verifier looked wasteful.

> I don't see why everything needs to be a map.

I mentioned the reasons to use map abstraction in the commit log:
"- jump table is implemented as BPF_MAP_TYPE_PROG_ARRAY to reuse 'map'
   abstraction, its user space API and all of verifier logic.
   It's in the existing arraymap.c file, since several functions are
   shared with regular array map."

The other alternative would be to add new thing just for jump table,
but it means extending syscall commands and propagating the callchain
through several files plus adding all new interfaces to user space.
I think 'map' abstraction fits very well. We have 'array' map
which is one-to-one to normal C array. This is just different type
of array that stores prog_fds.
When in C you're creating 'void *jmptable[] = { &&label1, &&label2};'
it is still an array. So here you have special type PROG_ARRAY for it
to make verifier recognize it.

^ permalink raw reply

* [PATCH v5 00/11] Add simple NVMEM Framework via regmap.
From: Srinivas Kandagatla @ 2015-05-21 16:42 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter
In-Reply-To: <1427752492-17039-1-git-send-email-srinivas.kandagatla@linaro.org>

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.

This patchset adds a new simple NVMEM framework to kernel.

Up until now, NVMEM drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.
    
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
    
Introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
    
After learning few things about QCOM qfprom and other eeprom/efuses, which
has packed fields at bit level. Which makes it important to add support to
such memories. This version adds support to this type of non volatile
memories by adding support to bit level nvmem-cells.

Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.

patch 1-2 Introduces two regmap helper functions.
patch 3-6 Introduces the NVMEM framework.
Patch 7 Adds helper functions for nvmems based on mmio.
Patch 8 migrates an existing driver to nvmem framework.
Patch 9-10 Adds Qualcomm specific qfprom driver.
Patch 11 adds entry in MAINTAINERS.

Its also possible to migrate other nvmem drivers to this framework.

Providers APIs:
	nvmem_register/unregister();

Consumers APIs:
Cell based apis for both DT/Non-DT:
	nvmem_cell_get()/nvmem_cell_put();
	nvmem_cell_read()/nvmem_cell_write();

Raw byte access apis for both DT/non-DT.
	nvmem_device_get()/nvmem_device_put()
	nvmem_device_read()/nvmem_device_write();
	nvmem_device_cell_read()/nvmem_device_cell_write();

Device Tree:

	/* Provider */
	qfprom: qfprom@00700000 {
		...

		/* Data cells */
		tsens_calibration: calib@404 {
			reg = <0x404 0x10>;
		};

		tsens_calibration_bckp: calib_bckp@504 {
			reg = <0x504 0x11>;
			bit-offset = 6;
			nbits = 128;
		};

		pvs_version: pvs-version@6 {
			reg = <0x6 0x2>
			bit-offset = 7;
			nbits = 2;
		};

		speed_bin: speed-bin@c{
			reg = <0xc 0x1>;
			bit-offset = 2;
			nbits	= 3;

		};
		...
	};

userspace interface: binary file in /sys/class/nvmem/*/nvmem

ex:
hexdump /sys/class/nvmem/qfprom0/nvmem
                                                                                                                                                                                                                  
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000

Changes since v4(https://lkml.org/lkml/2015/3/30/725)
 * rename eeprom to nvmem suggested by Matt Porter
 * added bit level support to nvmem cells, if not framework is
 	not usable for qcom platforms.
 * removed ternary operator shortcut suggested by Mark B.
 * unified consumer/provider apis for both DT and non-DT.
 * added name support for cell.
 * added bit level bindings.
 * added read-only support suggested by Matt Porter and others.
 * added new nvmem_device based consumer apis.

Changes since v3(https://lkml.org/lkml/2015/3/24/1066)
 * simplified logic in bin_attr_eeprom_read/write spotted by Mark Brown.
 * moved from using regmap_bulk_read/write to regmap_raw_read/write
 spotted by Mark Brown
 * Fixed return error codes for the dummy wrappers spotted by Sascha Hauer
 * Fixed various error code checks in core spotted by Sascha Hauer.
 * Simplified consumer bindings suggested by Sascha Hauer.
 * Added eeprom-mmio helper functions.

Changes since v2(https://lkml.org/lkml/2015/3/13/168)
 * Fixed error handling in eeprom_register spotted by Mark Brown
 * Added new regmap_get_max_register() and regmap_get_reg_stride().
 * Fixed module build errors reported by kbuild robot.
 * recycle the ids when eeprom provider is released.

Changes since v1(https://lkml.org/lkml/2015/3/5/153)
 * Fix various Licencing issues spotted by Paul Bolle and Mark Brown
 * Allow eeprom core to build as module spotted by Paul Bolle.
 * Fix various kconfig issues spotted by Paul Bolle.
 * remove unessary atomic varible spotted by Mark Brown.
 * Few cleanups and common up some of the code in core.
 * Add qfprom bindings.

Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
 * Fix documentation and error checks in read/write spotted by Andrew Lunn
 * Kconfig fix suggested by Stephen Boyd.
 * Add module owner suggested by Stephen Boyd and others.
 * Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
 * seperate bindings patch as suggested by Rob.
 * Add MAINTAINERS as suggested by Rob.
 * Added support to allow reading eeprom for things like serial number which
 * canbe scatters across.
 * Added eeprom data using reg property suggested by Sascha and Stephen.
 * Added non-DT support.
 * Move kerneldoc to the src files spotted by Mark Brown.
 * Remove local list and do eeprom lookup by using class_find_device()


Thanks,
srini


Maxime Ripard (1):
  nvmem: sunxi: Move the SID driver to the nvmem framework

Srinivas Kandagatla (10):
  regmap: Introduce regmap_get_max_register.
  regmap: Introduce regmap_get_reg_stride.
  nvmem: Add a simple NVMEM framework for nvmem providers
  nvmem: Add a simple NVMEM framework for consumers
  nvmem: Add nvmem_device based consumer apis.
  nvmem: Add bindings for simple nvmem framework
  nvmem: Add simple nvmem-mmio consumer helper functions.
  nvmem: qfprom: Add Qualcomm QFPROM support.
  nvmem: qfprom: Add bindings for qfprom
  nvmem: Add to MAINTAINERS for nvmem framework

 Documentation/ABI/testing/sysfs-driver-sunxi-sid   |  22 -
 .../bindings/misc/allwinner,sunxi-sid.txt          |  17 -
 .../bindings/nvmem/allwinner,sunxi-sid.txt         |  21 +
 Documentation/devicetree/bindings/nvmem/nvmem.txt  |  84 ++
 Documentation/devicetree/bindings/nvmem/qfprom.txt |  35 +
 MAINTAINERS                                        |   9 +
 drivers/Kconfig                                    |   2 +
 drivers/Makefile                                   |   1 +
 drivers/base/regmap/regmap.c                       |  24 +
 drivers/misc/eeprom/Kconfig                        |  13 -
 drivers/misc/eeprom/Makefile                       |   1 -
 drivers/misc/eeprom/sunxi_sid.c                    | 156 ----
 drivers/nvmem/Kconfig                              |  36 +
 drivers/nvmem/Makefile                             |  13 +
 drivers/nvmem/core.c                               | 864 +++++++++++++++++++++
 drivers/nvmem/nvmem-mmio.c                         |  69 ++
 drivers/nvmem/nvmem-mmio.h                         |  41 +
 drivers/nvmem/qfprom.c                             |  51 ++
 drivers/nvmem/sunxi-sid.c                          |  64 ++
 include/linux/nvmem-consumer.h                     | 106 +++
 include/linux/nvmem-provider.h                     |  47 ++
 include/linux/regmap.h                             |  14 +
 22 files changed, 1481 insertions(+), 209 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
 create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt
 create mode 100644 Documentation/devicetree/bindings/nvmem/qfprom.txt
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
 create mode 100644 drivers/nvmem/Kconfig
 create mode 100644 drivers/nvmem/Makefile
 create mode 100644 drivers/nvmem/core.c
 create mode 100644 drivers/nvmem/nvmem-mmio.c
 create mode 100644 drivers/nvmem/nvmem-mmio.h
 create mode 100644 drivers/nvmem/qfprom.c
 create mode 100644 drivers/nvmem/sunxi-sid.c
 create mode 100644 include/linux/nvmem-consumer.h
 create mode 100644 include/linux/nvmem-provider.h

-- 
1.9.1

^ permalink raw reply

* [PATCH v5 01/11] regmap: Introduce regmap_get_max_register.
From: Srinivas Kandagatla @ 2015-05-21 16:42 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter
In-Reply-To: <1432226535-8640-1-git-send-email-srinivas.kandagatla@linaro.org>

This patch introduces regmap_get_max_register() function which would be
used by the infrastructures like nvmem framework built on top of
regmap.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 12 ++++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 6273ff0..d6c8404 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2613,6 +2613,18 @@ int regmap_get_val_bytes(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
 
+/**
+ * regmap_get_max_register(): Report the max register value
+ *
+ * Report the max register value, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_max_register(struct regmap *map)
+{
+	return map->max_register ? map->max_register : -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regmap_get_max_register);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 116655d..2d87ded 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -433,6 +433,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   unsigned int mask, unsigned int val,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
+int regmap_get_max_register(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -676,6 +677,12 @@ static inline int regmap_get_val_bytes(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_max_register(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1

^ permalink raw reply related

* [PATCH v5 02/11] regmap: Introduce regmap_get_reg_stride.
From: Srinivas Kandagatla @ 2015-05-21 16:42 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter
In-Reply-To: <1432226535-8640-1-git-send-email-srinivas.kandagatla@linaro.org>

This patch introduces regmap_get_reg_stride() function which would
be used by the infrastructures like nvmem framework built on top of
regmap. Mostly this function would be used for sanity checks on inputs
within such infrastructure.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/base/regmap/regmap.c | 12 ++++++++++++
 include/linux/regmap.h       |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d6c8404..e5eef6f 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -2625,6 +2625,18 @@ int regmap_get_max_register(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_get_max_register);
 
+/**
+ * regmap_get_reg_stride(): Report the register address stride
+ *
+ * Report the register address stride, mainly intended to for use by
+ * generic infrastructure built on top of regmap.
+ */
+int regmap_get_reg_stride(struct regmap *map)
+{
+	return map->reg_stride;
+}
+EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
+
 int regmap_parse_val(struct regmap *map, const void *buf,
 			unsigned int *val)
 {
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 2d87ded..59c55ea 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -434,6 +434,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 				   bool *change);
 int regmap_get_val_bytes(struct regmap *map);
 int regmap_get_max_register(struct regmap *map);
+int regmap_get_reg_stride(struct regmap *map);
 int regmap_async_complete(struct regmap *map);
 bool regmap_can_raw_write(struct regmap *map);
 
@@ -683,6 +684,12 @@ static inline int regmap_get_max_register(struct regmap *map)
 	return -EINVAL;
 }
 
+static inline int regmap_get_reg_stride(struct regmap *map)
+{
+	WARN_ONCE(1, "regmap API is disabled");
+	return -EINVAL;
+}
+
 static inline int regcache_sync(struct regmap *map)
 {
 	WARN_ONCE(1, "regmap API is disabled");
-- 
1.9.1

^ permalink raw reply related

* [PATCH v5 03/11] nvmem: Add a simple NVMEM framework for nvmem providers
From: Srinivas Kandagatla @ 2015-05-21 16:43 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown, s.hauer,
	Greg Kroah-Hartman, linux-api, linux-kernel, devicetree,
	linux-arm-msm, arnd, sboyd, Srinivas Kandagatla,
	pantelis.antoniou, mporter
In-Reply-To: <1432226535-8640-1-git-send-email-srinivas.kandagatla@linaro.org>

This patch adds just providers part of the framework just to enable easy
review.

Up until now, NVMEM drivers like eeprom were stored in drivers/misc,
where they all had to duplicate pretty much the same code to register
a sysfs file, allow in-kernel users to access the content of the devices
they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another,
there was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also
introduces DT representation for consumer devices to go get the data
they require (MAC Addresses, SoC/Revision ID, part numbers, and so on)
from the nvmems.

Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/Kconfig                |   2 +
 drivers/Makefile               |   1 +
 drivers/nvmem/Kconfig          |  10 ++
 drivers/nvmem/Makefile         |   6 +
 drivers/nvmem/core.c           | 398 +++++++++++++++++++++++++++++++++++++++++
 include/linux/nvmem-provider.h |  53 ++++++
 6 files changed, 470 insertions(+)
 create mode 100644 drivers/nvmem/Kconfig
 create mode 100644 drivers/nvmem/Makefile
 create mode 100644 drivers/nvmem/core.c
 create mode 100644 include/linux/nvmem-provider.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index c0cc96b..69d7305 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -182,4 +182,6 @@ source "drivers/thunderbolt/Kconfig"
 
 source "drivers/android/Kconfig"
 
+source "drivers/nvmem/Kconfig"
+
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 46d2554..f86b897 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_NVMEM)		+= nvmem/
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
new file mode 100644
index 0000000..f157b6d
--- /dev/null
+++ b/drivers/nvmem/Kconfig
@@ -0,0 +1,10 @@
+menuconfig NVMEM
+	tristate "NVMEM Support"
+	select REGMAP
+	help
+	  Support for NVMEM devices.
+
+	  This framework is designed to provide a generic interface to NVMEM
+	  from both the Linux Kernel and the userspace.
+
+	  If unsure, say no.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
new file mode 100644
index 0000000..6df2c69
--- /dev/null
+++ b/drivers/nvmem/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for nvmem drivers.
+#
+
+obj-$(CONFIG_NVMEM)		+= nvmem_core.o
+nvmem_core-y			:= core.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
new file mode 100644
index 0000000..6c2f0b1
--- /dev/null
+++ b/drivers/nvmem/core.c
@@ -0,0 +1,398 @@
+/*
+ * nvmem framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/nvmem-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+struct nvmem_device {
+	const char		*name;
+	struct regmap		*regmap;
+	struct module		*owner;
+	struct device		dev;
+	int			stride;
+	int			word_size;
+	int			ncells;
+	int			id;
+	int			users;
+	size_t			size;
+	bool			read_only;
+};
+
+struct nvmem_cell {
+	const char *name;
+	int			offset;
+	int			bytes;
+	int			bit_offset;
+	int			nbits;
+	struct nvmem_device	*nvmem;
+	struct list_head	node;
+};
+
+static DEFINE_MUTEX(nvmem_mutex);
+static DEFINE_IDA(nvmem_ida);
+
+static LIST_HEAD(nvmem_cells);
+static DEFINE_MUTEX(nvmem_cells_mutex);
+
+#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
+
+static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *attr,
+				    char *buf, loff_t pos, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nvmem_device *nvmem = to_nvmem_device(dev);
+	int rc;
+
+	/* Stop the user from reading */
+	if (pos > nvmem->size)
+		return 0;
+
+	if (pos + count > nvmem->size)
+		count = nvmem->size - pos;
+
+	count = count/nvmem->word_size * nvmem->word_size;
+
+	rc = regmap_raw_read(nvmem->regmap, pos, buf, count);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count;
+}
+
+static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *attr,
+				     char *buf, loff_t pos, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nvmem_device *nvmem = to_nvmem_device(dev);
+	int rc;
+
+	/* Stop the user from writing */
+	if (pos > nvmem->size)
+		return 0;
+
+	if (pos + count > nvmem->size)
+		count = nvmem->size - pos;
+
+	count = count/nvmem->word_size * nvmem->word_size;
+
+	rc = regmap_raw_write(nvmem->regmap, pos, buf, count);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return count;
+}
+
+/* default read/write permissions */
+static struct bin_attribute bin_attr_nvmem = {
+	.attr	= {
+		.name	= "nvmem",
+		.mode	= S_IWUSR | S_IRUGO,
+	},
+	.read	= bin_attr_nvmem_read,
+	.write	= bin_attr_nvmem_write,
+};
+
+static struct bin_attribute *nvmem_bin_attributes[] = {
+	&bin_attr_nvmem,
+	NULL,
+};
+
+static const struct attribute_group nvmem_bin_group = {
+	.bin_attrs	= nvmem_bin_attributes,
+};
+
+static const struct attribute_group *nvmem_dev_groups[] = {
+	&nvmem_bin_group,
+	NULL,
+};
+
+/* read only permission */
+static struct bin_attribute bin_attr_ro_nvmem = {
+	.attr	= {
+		.name	= "nvmem",
+		.mode	= S_IRUGO,
+	},
+	.read	= bin_attr_nvmem_read,
+};
+
+static struct bin_attribute *nvmem_bin_ro_attributes[] = {
+	&bin_attr_ro_nvmem,
+	NULL,
+};
+static const struct attribute_group nvmem_bin_ro_group = {
+	.bin_attrs	= nvmem_bin_ro_attributes,
+};
+
+static void nvmem_release(struct device *dev)
+{
+	struct nvmem_device *nvmem = to_nvmem_device(dev);
+
+	ida_simple_remove(&nvmem_ida, nvmem->id);
+	kfree(nvmem);
+}
+
+static struct class nvmem_class = {
+	.name		= "nvmem",
+	.dev_groups	= nvmem_dev_groups,
+	.dev_release	= nvmem_release,
+};
+
+static int of_nvmem_match(struct device *dev, const void *nvmem_np)
+{
+	return dev->of_node == nvmem_np;
+}
+
+static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
+{
+	struct device *d;
+
+	if (!nvmem_np)
+		return NULL;
+
+	d = class_find_device(&nvmem_class, NULL, nvmem_np, of_nvmem_match);
+
+	return d ? to_nvmem_device(d) : NULL;
+}
+
+static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
+{
+	struct nvmem_cell *p;
+
+	list_for_each_entry(p, &nvmem_cells, node) {
+		if (p && !strcmp(p->name, cell_id))
+			return p;
+	}
+
+	return NULL;
+}
+
+static void nvmem_cell_drop(struct nvmem_cell *cell)
+{
+	mutex_lock(&nvmem_cells_mutex);
+	list_del(&cell->node);
+	mutex_unlock(&nvmem_cells_mutex);
+	kfree(cell);
+}
+
+static void nvmem_device_remove_all_cells(struct nvmem_device *nvmem)
+{
+	struct nvmem_cell *cell = NULL;
+	struct list_head *p, *n;
+
+	list_for_each_safe(p, n, &nvmem_cells) {
+		cell = list_entry(p, struct nvmem_cell, node);
+		if (cell->nvmem == nvmem)
+			nvmem_cell_drop(cell);
+	}
+}
+
+static void nvmem_cell_add(struct nvmem_cell *cell)
+{
+	mutex_lock(&nvmem_cells_mutex);
+	list_add_tail(&cell->node, &nvmem_cells);
+	mutex_unlock(&nvmem_cells_mutex);
+}
+
+static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
+				   struct nvmem_cell_info *info,
+				   struct nvmem_cell *cell)
+{
+	cell->nvmem = nvmem;
+	cell->offset = info->offset;
+	cell->bytes = info->bytes;
+	cell->name = info->name;
+
+	cell->bit_offset = info->bit_offset;
+	cell->nbits = info->nbits;
+
+	if (cell->nbits)
+		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+					   BITS_PER_BYTE);
+
+	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+		dev_err(&nvmem->dev,
+			"cell %s unaligned to nvmem stride %d\n",
+			cell->name, nvmem->stride);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int nvmem_add_cells(struct nvmem_device *nvmem,
+			   struct nvmem_config *cfg)
+{
+	struct nvmem_cell **cells;
+	struct nvmem_cell_info *info = cfg->cells;
+	int i, rval;
+
+	cells = kzalloc(sizeof(*cells) * cfg->ncells, GFP_KERNEL);
+	if (!cells)
+		return -ENOMEM;
+
+	for (i = 0; i < cfg->ncells; i++) {
+		cells[i] = kzalloc(sizeof(struct nvmem_cell), GFP_KERNEL);
+		if (!cells[i]) {
+			rval = -ENOMEM;
+			goto err;
+		}
+
+		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
+		if (IS_ERR_VALUE(rval)) {
+			kfree(cells[i]);
+			goto err;
+		}
+
+		nvmem_cell_add(cells[i]);
+	}
+
+	nvmem->ncells = cfg->ncells;
+	/* remove tmp array */
+	kfree(cells);
+
+	return 0;
+err:
+	while (--i)
+		nvmem_cell_drop(cells[i]);
+
+	return rval;
+}
+
+/**
+ * nvmem_register(): Register a nvmem device for given nvmem.
+ * Also creates an binary entry in /sys/class/nvmem/dev-name/nvmem
+ *
+ * @nvmem: nvmem device that needs to be created
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to nvmem_device.
+ */
+
+struct nvmem_device *nvmem_register(struct nvmem_config *config)
+{
+	struct nvmem_device *nvmem;
+	struct regmap *rm;
+	int rval;
+
+	if (!config->dev)
+		return ERR_PTR(-EINVAL);
+
+	rm = dev_get_regmap(config->dev, NULL);
+	if (!rm) {
+		dev_err(config->dev, "Regmap not found\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
+	if (!nvmem)
+		return ERR_PTR(-ENOMEM);
+
+	nvmem->id = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
+	if (nvmem->id < 0) {
+		kfree(nvmem);
+		return ERR_PTR(nvmem->id);
+	}
+
+	nvmem->regmap = rm;
+	nvmem->owner = config->owner;
+	nvmem->stride = regmap_get_reg_stride(rm);
+	nvmem->word_size = regmap_get_val_bytes(rm);
+	nvmem->size = regmap_get_max_register(rm) + nvmem->stride;
+	nvmem->dev.class = &nvmem_class;
+	nvmem->dev.parent = config->dev;
+	nvmem->dev.of_node = config->dev->of_node;
+	dev_set_name(&nvmem->dev, "%s%d",
+		     config->name ? : "nvmem", config->id);
+
+	nvmem->read_only = of_property_read_bool(nvmem->dev.of_node,
+						 "read-only");
+
+	device_initialize(&nvmem->dev);
+
+	dev_dbg(&nvmem->dev, "Registering nvmem device %s\n",
+		dev_name(&nvmem->dev));
+
+	rval = device_add(&nvmem->dev);
+	if (rval) {
+		ida_simple_remove(&nvmem_ida, nvmem->id);
+		kfree(nvmem);
+		return ERR_PTR(rval);
+	}
+
+	/* update sysfs attributes */
+	if (nvmem->read_only)
+		sysfs_update_group(&nvmem->dev.kobj, &nvmem_bin_ro_group);
+
+	if (config->cells)
+		nvmem_add_cells(nvmem, config);
+
+	return nvmem;
+}
+EXPORT_SYMBOL_GPL(nvmem_register);
+
+/**
+ * nvmem_unregister(): Unregister previously registered nvmem device
+ *
+ * @nvmem: Pointer to previously registered nvmem device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int nvmem_unregister(struct nvmem_device *nvmem)
+{
+	mutex_lock(&nvmem_mutex);
+	if (nvmem->users) {
+		mutex_unlock(&nvmem_mutex);
+		return -EBUSY;
+	}
+	mutex_unlock(&nvmem_mutex);
+
+	nvmem_device_remove_all_cells(nvmem);
+	device_del(&nvmem->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_unregister);
+
+static int nvmem_init(void)
+{
+	return class_register(&nvmem_class);
+}
+
+static void nvmem_exit(void)
+{
+	class_unregister(&nvmem_class);
+}
+
+subsys_initcall(nvmem_init);
+module_exit(nvmem_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("nvmem Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
new file mode 100644
index 0000000..4908b37
--- /dev/null
+++ b/include/linux/nvmem-provider.h
@@ -0,0 +1,53 @@
+/*
+ * nvmem framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_NVMEM_PROVIDER_H
+#define _LINUX_NVMEM_PROVIDER_H
+
+struct nvmem_device;
+
+struct nvmem_cell_info {
+	const char		*name;
+	int			offset;
+	int			bytes;
+	int			bit_offset;
+	int			nbits;
+};
+
+struct nvmem_config {
+	struct device		*dev;
+	const char		*name;
+	int			id;
+	struct module		*owner;
+	struct nvmem_cell_info	*cells;
+	int			ncells;
+};
+
+#if IS_ENABLED(CONFIG_NVMEM)
+
+struct nvmem_device *nvmem_register(struct nvmem_config *cfg);
+int nvmem_unregister(struct nvmem_device *nvmem);
+
+#else
+
+static inline struct nvmem_device *nvmem_register(struct nvmem_config *cfg)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline int nvmem_unregister(struct nvmem_device *nvmem)
+{
+	return -ENOSYS;
+}
+
+#endif /* CONFIG_NVMEM */
+
+#endif  /* ifndef _LINUX_NVMEM_PROVIDER_H */
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH net-next 1/4] bpf: allow bpf programs to tail-call other bpf programs
From: Andy Lutomirski @ 2015-05-21 16:43 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: David S. Miller, Ingo Molnar, Daniel Borkmann, Michael Holzheu,
	Zi Shen Lim, Linux API, Network Development,
	linux-kernel@vger.kernel.org
In-Reply-To: <555E0A93.2020803@plumgrid.com>

On Thu, May 21, 2015 at 9:40 AM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> On 5/21/15 9:20 AM, Andy Lutomirski wrote:
>>
>>
>> What I mean is: why do we need the interface to be "look up this index
>> in an array and just to what it references" as a single atomic
>> instruction?  Can't we break it down into first "look up this index in
>> an array" and then "do this tail call"?
>
>
> I've actually considered to do this split and do first part as map lookup
> and 2nd as 'tail call to this ptr' insn, but it turned out to be
> painful: verifier gets more complicated, ctx pointer needs to kept
> somewhere, JITs need to special case two things instead of one.
> Also I couldn't see a use case for exposing program pointer to the
> program itself. I've explored this path only because it felt more
> traditional 'goto *ptr' like, but adding new PTR_TO_PROG type to
> verifier looked wasteful.

At some point, I think that it would be worth extending the verifier
to support more general non-integral scalar types. "Pointer to
tail-call target" would be just one of them.  "Pointer to skb" might
be nice as a real first-class scalar type that lives in a register as
opposed to just being magic typed context.

We'd still need some way to stick fds into a map, but that's not
really the verifier's problem.

--Andy

^ permalink raw reply

* [PATCH v5 04/11] nvmem: Add a simple NVMEM framework for consumers
From: Srinivas Kandagatla @ 2015-05-21 16:43 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Maxime Ripard, Rob Herring, Kumar Gala, Mark Brown,
	s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, Greg Kroah-Hartman,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
	sboyd-sgV2jX0FEOL9JmXXK+q4OQ, Srinivas Kandagatla,
	pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w,
	mporter-OWPKS81ov/FWk0Htik3J/w
In-Reply-To: <1432226535-8640-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

This patch adds just consumers part of the framework just to enable easy
review.

Up until now, nvmem drivers were stored in drivers/misc, where they all had to
duplicate pretty much the same code to register a sysfs file, allow in-kernel
users to access the content of the devices they were driving, etc.

This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.

This introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the nvmems.

Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.

Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 drivers/nvmem/core.c           | 346 +++++++++++++++++++++++++++++++++++++++++
 include/linux/nvmem-consumer.h |  49 ++++++
 2 files changed, 395 insertions(+)
 create mode 100644 include/linux/nvmem-consumer.h

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 6c2f0b1..8a4b358 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -16,6 +16,7 @@
 
 #include <linux/device.h>
 #include <linux/nvmem-provider.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/export.h>
 #include <linux/fs.h>
 #include <linux/idr.h>
@@ -379,6 +380,351 @@ int nvmem_unregister(struct nvmem_device *nvmem)
 }
 EXPORT_SYMBOL_GPL(nvmem_unregister);
 
+static struct nvmem_device *__nvmem_device_get(struct device_node *np,
+					       struct nvmem_cell **cellp,
+					       const char *cell_id)
+{
+	struct nvmem_device *nvmem = NULL;
+
+	mutex_lock(&nvmem_mutex);
+
+	if (np) {
+		nvmem = of_nvmem_find(np);
+		if (!nvmem) {
+			mutex_unlock(&nvmem_mutex);
+			return ERR_PTR(-EPROBE_DEFER);
+		}
+	} else {
+		struct nvmem_cell *cell = nvmem_find_cell(cell_id);
+
+		if (cell) {
+			nvmem = cell->nvmem;
+			*cellp = cell;
+		}
+
+		if (!nvmem) {
+			mutex_unlock(&nvmem_mutex);
+			return ERR_PTR(-ENOENT);
+		}
+	}
+
+	nvmem->users++;
+	mutex_unlock(&nvmem_mutex);
+
+	if (!try_module_get(nvmem->owner)) {
+		dev_err(&nvmem->dev,
+			"could not increase module refcount for cell %s\n",
+			nvmem->name);
+
+		mutex_lock(&nvmem_mutex);
+		nvmem->users--;
+		mutex_unlock(&nvmem_mutex);
+
+		return ERR_PTR(-EINVAL);
+	}
+
+	return nvmem;
+}
+
+static int __nvmem_device_put(struct nvmem_device *nvmem)
+{
+	module_put(nvmem->owner);
+	mutex_lock(&nvmem_mutex);
+	nvmem->users--;
+	mutex_unlock(&nvmem_mutex);
+
+	return 0;
+}
+
+static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
+{
+	struct nvmem_cell *cell = NULL;
+	struct nvmem_device *nvmem;
+
+	nvmem = __nvmem_device_get(NULL, &cell, cell_id);
+	if (IS_ERR(nvmem))
+		return (struct nvmem_cell *)nvmem;
+
+
+	return cell;
+
+}
+
+static struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
+					    const char *name)
+{
+	struct device_node *cell_np, *nvmem_np;
+	struct nvmem_cell *cell;
+	struct nvmem_device *nvmem;
+	const __be32 *addr;
+	int rval, len, index;
+
+	index = of_property_match_string(np, "nvmem-cell-names", name);
+
+	cell_np = of_parse_phandle(np, "nvmem-cell", index);
+	if (!cell_np)
+		return ERR_PTR(-EINVAL);
+
+	nvmem_np = of_get_next_parent(cell_np);
+	if (!nvmem_np)
+		return ERR_PTR(-EINVAL);
+
+	nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
+	if (IS_ERR(nvmem))
+		return (struct nvmem_cell *)nvmem;
+
+	addr = of_get_property(cell_np, "reg", &len);
+	if (!addr || (len < 2 * sizeof(int))) {
+		dev_err(&nvmem->dev, "of_i2c: invalid reg on %s\n",
+			cell_np->full_name);
+		rval  = -EINVAL;
+		goto err_mem;
+	}
+
+	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+	if (!cell) {
+		rval = -ENOMEM;
+		goto err_mem;
+	}
+
+	cell->nvmem = nvmem;
+	cell->offset = be32_to_cpup(addr++);
+	cell->bytes = be32_to_cpup(addr);
+	cell->name = cell_np->name;
+
+	of_property_read_u32(cell_np, "bit-offset", &cell->bit_offset);
+	of_property_read_u32(cell_np, "nbits", &cell->nbits);
+
+	if (cell->nbits)
+		cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+					   BITS_PER_BYTE);
+
+	if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+			dev_err(&nvmem->dev,
+				"cell %s unaligned to nvmem stride %d\n",
+				cell->name, nvmem->stride);
+		rval  = -EINVAL;
+		goto err_sanity;
+	}
+
+	nvmem_cell_add(cell);
+	
+	return cell;
+
+err_sanity:
+	kfree(cell);
+
+err_mem:
+	__nvmem_device_put(nvmem);
+
+	return ERR_PTR(rval);
+
+}
+
+/**
+ * nvmem_cell_get(): Get nvmem cell of device form a given index
+ *
+ * @dev node: Device tree node that uses the nvmem cell
+ * @index: nvmem index in nvmems property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_cell.  The nvmem_cell will be freed by the
+ * nvmem_cell_put().
+ */
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
+{
+	struct nvmem_cell *cell;
+
+	if (dev->of_node) { /* try dt first */
+		cell = of_nvmem_cell_get(dev->of_node, cell_id);
+		if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
+			return cell;
+	}
+
+	return nvmem_cell_get_from_list(cell_id);
+
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_get);
+
+/**
+ * nvmem_cell_put(): Release previously allocated nvmem cell.
+ *
+ * @cell: Previously allocated nvmem cell by nvmem_cell_get()
+ * or nvmem_cell_get().
+ */
+void nvmem_cell_put(struct nvmem_cell *cell)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+
+	__nvmem_device_put(nvmem);
+	nvmem_cell_drop(cell);
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_put);
+
+static inline void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell,
+						    void *buf)
+{
+	u8 *p, *b;
+	int i, bit_offset = cell->bit_offset;
+
+	p = b = buf;
+	if (bit_offset) {
+		/* First shift */
+		*b++ >>= bit_offset;
+
+		/* setup rest of the bytes if any */
+		for (i = 1; i < cell->bytes; i++) {
+			/* Get bits from next byte and shift them towards msb */
+			*p |= *b << (BITS_PER_BYTE - bit_offset);
+
+			p = b;
+			*b++ >>= bit_offset;
+		}
+
+		/* result fits in less bytes */
+		if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
+			*p-- = 0;
+	}
+	/* clear msb bits if any leftover in the last byte */
+	*p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
+}
+
+static int __nvmem_cell_read(struct nvmem_device *nvmem,
+		      struct nvmem_cell *cell,
+		      void *buf, ssize_t *len)
+{
+	int rc;
+
+	rc = regmap_raw_read(nvmem->regmap, cell->offset, buf, cell->bytes);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	/* shift bits in-place */
+	if (cell->bit_offset || cell->bit_offset)
+		nvmem_shift_read_buffer_in_place(cell, buf);
+
+	*len = cell->bytes;
+
+	return *len;
+}
+/**
+ * nvmem_cell_read(): Read a given nvmem cell
+ *
+ * @cell: nvmem cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer.  The buffer should be freed by the consumer with a
+ * kfree().
+ */
+void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+	u8 *buf;
+	int rc;
+
+	if (!nvmem || !nvmem->regmap)
+		return ERR_PTR(-EINVAL);
+
+	buf = kzalloc(cell->bytes, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	rc = __nvmem_cell_read(nvmem, cell, buf, len);
+	if (IS_ERR_VALUE(rc)) {
+		kfree(buf);
+		return ERR_PTR(rc);
+	}
+
+	return buf;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_read);
+
+static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
+						    u8 *_buf, int len)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+	int i, rc, nbits, bit_offset = cell->bit_offset;
+	u8 v, *p, *buf, *b, pbyte, pbits;
+
+	nbits = cell->nbits;
+	buf = kzalloc(cell->bytes, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	memcpy(buf, _buf, len);
+	p = b = buf;
+
+	if (bit_offset) {
+		pbyte = *b;
+		*b <<= bit_offset;
+
+		/* setup the first byte with lsb bits from nvmem */
+		rc = regmap_raw_read(nvmem->regmap, cell->offset, &v, 1);
+		*b++ |= GENMASK(bit_offset - 1, 0) & v;
+
+		/* setup rest of the byte if any */
+		for (i = 1; i < cell->bytes; i++) {
+			/* Get last byte bits and shift them towards lsb */
+			pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
+			pbyte = *b;
+			p = b;
+			*b <<= bit_offset;
+			*b++ |= pbits;
+		}
+	}
+
+	/* if it's not end on byte boundary */
+	if ((nbits + bit_offset) % BITS_PER_BYTE) {
+		/* setup the last byte with msb bits from nvmem */
+		rc = regmap_raw_read(nvmem->regmap,
+				    cell->offset + cell->bytes - 1, &v, 1);
+		*p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
+
+	}
+
+	return buf;
+}
+
+/**
+ * nvmem_cell_write(): Write to a given nvmem cell
+ *
+ * @cell: nvmem cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to nvmem cell.
+ *
+ * The return value will be an length of bytes written or non zero on failure.
+ */
+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len)
+{
+	struct nvmem_device *nvmem = cell->nvmem;
+	int rc;
+	void *wbuf = buf;
+
+	if (!nvmem || !nvmem->regmap || nvmem->read_only ||
+	    (cell->bit_offset == 0 && len != cell->bytes))
+		return -EINVAL;
+
+	if (cell->bit_offset || cell->nbits) {
+		wbuf = nvmem_cell_prepare_write_buffer(cell, buf, len);
+		if (IS_ERR(wbuf))
+			return PTR_ERR(wbuf);
+	}
+
+	rc = regmap_raw_write(nvmem->regmap, cell->offset, wbuf, cell->bytes);
+
+	/* free the tmp buffer */
+	if (cell->bit_offset)
+		kfree(wbuf);
+
+	if (IS_ERR_VALUE(rc))
+		return rc;
+
+	return len;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_write);
+
 static int nvmem_init(void)
 {
 	return class_register(&nvmem_class);
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
new file mode 100644
index 0000000..c3fa8c7
--- /dev/null
+++ b/include/linux/nvmem-consumer.h
@@ -0,0 +1,49 @@
+/*
+ * nvmem framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_NVMEM_CONSUMER_H
+#define _LINUX_NVMEM_CONSUMER_H
+
+/* consumer cookie */
+struct nvmem_cell;
+
+#if IS_ENABLED(CONFIG_NVMEM)
+
+/* Cell based interface */
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
+void nvmem_cell_put(struct nvmem_cell *cell);
+void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
+
+#else
+
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline void nvmem_cell_put(struct nvmem_cell *cell)
+{
+}
+
+static inline char *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline int nvmem_cell_write(struct nvmem_cell *cell,
+				    const char *buf, ssize_t len)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_NVMEM */
+
+#endif  /* ifndef _LINUX_NVMEM_CONSUMER_H */
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox