2012-11-12 06:15:34

by Dave Quigley

[permalink] [raw]
Subject: Labeled NFS [v5]

The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
specification and it has been decided that a reposting of the Labeled NFS code
for inclusion into mainline was a good idea. The patches have been rebased onto
v3.7-rc2 and have been tested against the SELinux testsuite with the only
failures being for features not supported by NFS.


2012-11-30 13:35:15

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 08:28, Stephen Smalley wrote:
> On 11/30/2012 08:17 AM, David Quigley wrote:
>> On 11/30/2012 07:57, David Quigley wrote:
>>> On 11/30/2012 07:14, J. Bruce Fields wrote:
>>>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>>>> >>>I would think that were it not for the case that access is
>>>>> denied
>>>>> >>>and I get an audit record for nfsd that reports a subject
>>>>> >>>label of "_"
>>>>> >>>(which is correct for nfsd but not the process attempting
>>>>> >>>access) and
>>>>> >>>an object label of "WhooHoo", which is correct. The server
>>>>> side
>>>>> >>>looks like it might be working right, given the information
>>>>> that it
>>>>> >>>has.
>>>>> >>>
>>>>> >>
>>>>> >>Ok so this is the problem. nfsd is a kernel thread I believe.
>>>>> In
>>>>> >>SELinux land it has the type kernel_t which is all powerful. We
>>>>> >>don't
>>>>> >>have client label transport yet (That requires RPCSECGSSv3). Is
>>>>> >>there
>>>>> >>a way you can have that kernel thread running as a type that
>>>>> has
>>>>> >>access to everything?
>>>>> >
>>>>> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in
>>>>> Smackese.
>>>>> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
>>>>> >which
>>>>> >is to say, all capabilities.
>>>>> >
>>>>>
>>>>> Hmm thats interesting then. You could try using rpcdebug -m nfsd
>>>>> to
>>>>> turn on some of the debugging to look around the internals and
>>>>> figure out whats going on. If you pass -v it will give you all of
>>>>> the potential flags.
>>>>>
>>>>> >
>>>>> >>I think that is the current problem. Which makes perfect sense.
>>>>> If
>>>>> >>your kernel threads don't get started with max privilege then
>>>>> the
>>>>> >>server would be denied access on all of the file attributes and
>>>>> >>wouldn't be able to ship it over the wire properly.
>>>>> >
>>>>> >OK. I haven't had to do anything with kernel threads so far.
>>>>> >Where is NFS setting these up? Poking around fs/nfsd looks like
>>>>> >the place, but I haven't seen anything there that makes it look
>>>>> >like they would be running without capabilities. Clearly, that's
>>>>> >what I'm seeing. It looks as if the credential of nfsd does not
>>>>> >match what /proc reports. Bother.
>>>>> >
>>>>>
>>>>> I'm not entirely sure whats up either. If you want to look for
>>>>> the
>>>>> NFSd threads they are in fs/nfsd/nfssvc.c. The main function
>>>>> starts
>>>>> on line 487.
>>>>
>>>> I'm not following the discussion, but: maybe you want to look at
>>>> fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
>>>> cap_{drop/raise}_nfsd_set() calls at the end.
>>>>
>>>> --b.
>>>
>>>
>>> I'm not as familiar with the capabilities code as Casey is so I'll
>>> leave this ball in his court. I think you are correct though and
>>> the
>>> problem is that NFSd is dropping and raising caps and we need to
>>> make
>>> sure that MAC_ADMIN and MAC_OVERRIDE is in there in the SMACK case.
>>>
>>> --
>>> This message was distributed to subscribers of the selinux mailing
>>> list.
>>> If you no longer wish to subscribe, send mail to
>>> [email protected] with
>>> the words "unsubscribe selinux" without quotes as the message.
>>
>>
>> I think I found the offending code. I can't test it for a while so
>> hopefully Casey can.
>>
>> In include/linux/capability.h we have the following defines
>>
>>
>> # define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
>> | CAP_TO_MASK(CAP_MKNOD) \
>> | CAP_TO_MASK(CAP_DAC_OVERRIDE) \
>> | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
>> | CAP_TO_MASK(CAP_FOWNER) \
>> | CAP_TO_MASK(CAP_FSETID))
>>
>> # define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
>>
>> #if _KERNEL_CAPABILITY_U32S != 2
>> # error Fix up hand-coded capability macro initializers
>> #else /* HAND-CODED capability initializers */
>>
>> # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
>> # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
>> # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>> |
>> CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
>> CAP_FS_MASK_B1 } })
>> # define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>> |
>> CAP_TO_MASK(CAP_SYS_RESOURCE), \
>> CAP_FS_MASK_B1 } })
>>
>> So raise and drop nfsd caps uses CAP_NFSD_SET. In CAP_NFSD_SET we
>> have
>> CAP_MAC_OVERRIDE but we don't have CAP_MAC_ADMIN. I think maybe if
>> we
>> had both then Casey should be able to use the code with SMACK.
>> However
>> I'm not sure what implications this has for every other LSM.
>> Honestly
>> I'm not sure if we use either of those caps for SELinux at all (I
>> think
>> we ignore them completely).
>
> CAP_MAC_ADMIN is used by SELinux these days, but only to control the
> ability to get or set security contexts that are not yet defined in
> the policy (for package managers that lay down the security contexts
> before reloading policy and for installing a distro within a chroot
> on
> a build host running a different policy).


Do you think its reasonable to add that cap into the NFSd thread then?
I'm not sure what other solution there would be. Casey needs it just so
SMACK can work with it at all (assuming what I think is happening is
actually happening).

2012-11-14 13:56:43

by David Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/13/2012 23:32, Dave Quigley wrote:
> On 11/13/2012 7:55 AM, Steve Dickson wrote:
>>
>>
>> On 12/11/12 20:39, Dave Quigley wrote:
>>> If you're ok with non Fedora kernel images I can try to put up a
>>> tree either tonight or tomorrow with the patches that you just need
>>> to build and install. That plus the one patch for nfs-utils should
>>> make everything work.
>> I'm good with that....
>>
>> steved.
>>
>
> Ok so if you go to http://www.selinuxproject.org/git you will see a
> repo for lnfs and lnfs-patchset. The instructions at
> http://www.selinuxproject.org/page/Labeled_NFS give you a better
> indication on how to pull the trees. I've attached a patch for NFS
> utils which gives support for security_label/nosecurity_label in your
> /etc/exports file. I've also attached a script called setup which
> should build a test directory called /export with a copy of /var/www
> under it which should be labeled properly. It does all the proper
> SELinux commands to make sure labeling is correct. Once you have that
> setup just mount -t nfs localhost:/ /mnt/lnfs (or wherever you want)
> and you should be good to go. Just ls -Z in /mnt/lnfs/var and check
> to
> make sure the labels are the same as /export/var. It should have the
> labels showing up in the network transfer. If you have any problems
> just let me know and I can try to help figure them out.
>
> Dave

If you want to run the testsuite we used Serge has a repo on the git
page above for the selinux-testsuite. Just copy it onto the nfs export
and follow the instructions in the readme.

2012-11-13 01:40:04

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

If you're ok with non Fedora kernel images I can try to put up a tree
either tonight or tomorrow with the patches that you just need to build
and install. That plus the one patch for nfs-utils should make
everything work.

Dave

2012-11-28 18:56:56

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/20/2012 7:28 PM, Dave Quigley wrote:
> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>> ...
>>>
>>>
>>> Or I could just give you this link and you should be good to go ;)
>>>
>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>
>>> I haven't tried it but it should work. If it doesn't let me know and
>>> i'll try to fix it on my end. I'd imagine you might need to yum remove
>>> nfs-utils first before adding this new one or you could also try an
>>> rpm with the upgrade flag for this instead. Good luck.
>>
...


I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
attached stack trace on mount. After mounting I'm getting
denials when I should, but also when I shouldn't.

I've tried tracking down the issue, but there's a lot going on
that I don't find obvious. I added a dentry_init hook just for
grins, but it's not getting called.

.



Attachments:
nfs-trace-20121128 (3.68 kB)

2012-11-20 21:09:57

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/11/2012 10:15 PM, David Quigley wrote:
> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
> specification and it has been decided that a reposting of the Labeled NFS code
> for inclusion into mainline was a good idea. The patches have been rebased onto
> v3.7-rc2 and have been tested against the SELinux testsuite with the only
> failures being for features not supported by NFS.

I'm trying to get the user space tools built so that I can
do Smack testing. The instructions on selinuxproject.org
seen out of date with regard to the packages required to
build the NFS tools. I have failed to build on Fedora 17
and Ubuntu 12.04. Any pointers beyond what's on the wiki?

Thank you.


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.



2012-11-12 21:44:08

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 02/13] Security: Add Hook to test if the particular xattr is part of a MAC model.

On Mon, Nov 12, 2012 at 02:36:09PM -0500, David P. Quigley wrote:
> On 11/12/2012 11:36 AM, J. Bruce Fields wrote:
> >On Mon, Nov 12, 2012 at 09:56:37AM -0500, Dave Quigley wrote:
> >>On 11/12/2012 7:15 AM, J. Bruce Fields wrote:
> >>>On Mon, Nov 12, 2012 at 01:15:36AM -0500, David Quigley wrote:
> >>>>From: David Quigley<[email protected]>
> >>>>
> >>>>The interface to request security labels from user space is the xattr
> >>>>interface. When requesting the security label from an NFS server it is
> >>>>important to make sure the requested xattr
> >>>I'm confused--clients can't request xattrs from NFS servers. I must be
> >>>reading this wrong, but I'm not sure what you meant.
> >>>
> >>>--b.
> >>>
> >>Generically clients can't use xattrs from NFS servers but the LSM
> >>method for getting labels is through the xattr interface. THe point
> >>of this is if someone selects security.capability that we don't
> >>translate that into a call in labeled nfs to get the security label.
> >>We only want label based LSMs to cause a getfattr on the server to
> >>grab the label and populate the inode with that information.
> >>Currently if you use security.selinux or security.smack then labeled
> >>nfs will handle the translation of that into a get/setfattr on the
> >>security_label attribute in NFSv4.
> >OK, I think I understand: so this is to help the NFS client implement
> >the necessary xattr interface for userspace that get and sets security
> >labels on NFS filesystems?
> >
> >--b.
>
> Exactly. The problem is we don't want to have LSM specific logic in
> so the best we can do is ask if the security.* xattr being accessed
> has the proper semantics to be used with Labeled NFS.

OK, thanks. The changelog could probably be clarified (at least make it
clear that this is for the client side.)

Delaying this patch till right before the patch that actually uses it
might also help (and/or even combining those two patches).

--b.

>
> >
> >>
> >>>>actually is a MAC label. This allows
> >>>>us to make sure that we get the desired semantics from the attribute instead of
> >>>>something else such as capabilities or a time based LSM.
> >>>>
> >>>>Signed-off-by: Matthew N. Dodd<[email protected]>
> >>>>Signed-off-by: Miguel Rodel Felipe<[email protected]>
> >>>>Signed-off-by: Phua Eu Gene<[email protected]>
> >>>>Signed-off-by: Khin Mi Mi Aung<[email protected]>
> >>>>Signed-off-by: David Quigley<[email protected]>
> >>>>---
> >>>> include/linux/security.h | 14 ++++++++++++++
> >>>> security/capability.c | 6 ++++++
> >>>> security/security.c | 6 ++++++
> >>>> security/selinux/hooks.c | 6 ++++++
> >>>> security/smack/smack_lsm.c | 11 +++++++++++
> >>>> 5 files changed, 43 insertions(+)
> >>>>
> >>>>diff --git a/include/linux/security.h b/include/linux/security.h
> >>>>index c9f5eec..167bdd5 100644
> >>>>--- a/include/linux/security.h
> >>>>+++ b/include/linux/security.h
> >>>>@@ -1301,6 +1301,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> >>>> * @pages contains the number of pages.
> >>>> * Return 0 if permission is granted.
> >>>> *
> >>>>+ * @ismaclabel:
> >>>>+ * Check if the extended attribute specified by @name
> >>>>+ * represents a MAC label. Returns 0 if name is a MAC
> >>>>+ * attribute otherwise returns non-zero.
> >>>>+ * @name full extended attribute name to check against
> >>>>+ * LSM as a MAC label.
> >>>>+ *
> >>>> * @secid_to_secctx:
> >>>> * Convert secid to security context. If secdata is NULL the length of
> >>>> * the result will be returned in seclen, but no secdata will be returned.
> >>>>@@ -1581,6 +1588,7 @@ struct security_operations {
> >>>>
> >>>> int (*getprocattr) (struct task_struct *p, char *name, char **value);
> >>>> int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
> >>>>+ int (*ismaclabel) (const char *name);
> >>>> int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
> >>>> int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> >>>> void (*release_secctx) (char *secdata, u32 seclen);
> >>>>@@ -1829,6 +1837,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
> >>>> int security_getprocattr(struct task_struct *p, char *name, char **value);
> >>>> int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
> >>>> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
> >>>>+int security_ismaclabel(const char *name);
> >>>> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> >>>> int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> >>>> void security_release_secctx(char *secdata, u32 seclen);
> >>>>@@ -2512,6 +2521,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
> >>>> return cap_netlink_send(sk, skb);
> >>>> }
> >>>>
> >>>>+static inline int security_ismaclabel(const char *name)
> >>>>+{
> >>>>+ return 0;
> >>>>+}
> >>>>+
> >>>> static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >>>> {
> >>>> return -EOPNOTSUPP;
> >>>>diff --git a/security/capability.c b/security/capability.c
> >>>>index f1eb284..9071447 100644
> >>>>--- a/security/capability.c
> >>>>+++ b/security/capability.c
> >>>>@@ -797,6 +797,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
> >>>> return -EINVAL;
> >>>> }
> >>>>
> >>>>+static int cap_ismaclabel(const char *name)
> >>>>+{
> >>>>+ return 0;
> >>>>+}
> >>>>+
> >>>> static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >>>> {
> >>>> return -EOPNOTSUPP;
> >>>>@@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
> >>>> set_to_cap_if_null(ops, d_instantiate);
> >>>> set_to_cap_if_null(ops, getprocattr);
> >>>> set_to_cap_if_null(ops, setprocattr);
> >>>>+ set_to_cap_if_null(ops, ismaclabel);
> >>>> set_to_cap_if_null(ops, secid_to_secctx);
> >>>> set_to_cap_if_null(ops, secctx_to_secid);
> >>>> set_to_cap_if_null(ops, release_secctx);
> >>>>diff --git a/security/security.c b/security/security.c
> >>>>index b4b2017..a7bee7b 100644
> >>>>--- a/security/security.c
> >>>>+++ b/security/security.c
> >>>>@@ -1047,6 +1047,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
> >>>> return security_ops->netlink_send(sk, skb);
> >>>> }
> >>>>
> >>>>+int security_ismaclabel(const char *name)
> >>>>+{
> >>>>+ return security_ops->ismaclabel(name);
> >>>>+}
> >>>>+EXPORT_SYMBOL(security_ismaclabel);
> >>>>+
> >>>> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >>>> {
> >>>> return security_ops->secid_to_secctx(secid, secdata, seclen);
> >>>>diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> >>>>index 22d9adf..f7c4899 100644
> >>>>--- a/security/selinux/hooks.c
> >>>>+++ b/security/selinux/hooks.c
> >>>>@@ -5401,6 +5401,11 @@ abort_change:
> >>>> return error;
> >>>> }
> >>>>
> >>>>+static int selinux_ismaclabel(const char *name)
> >>>>+{
> >>>>+ return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
> >>>>+}
> >>>>+
> >>>> static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >>>> {
> >>>> return security_sid_to_context(secid, secdata, seclen);
> >>>>@@ -5639,6 +5644,7 @@ static struct security_operations selinux_ops = {
> >>>> .getprocattr = selinux_getprocattr,
> >>>> .setprocattr = selinux_setprocattr,
> >>>>
> >>>>+ .ismaclabel = selinux_ismaclabel,
> >>>> .secid_to_secctx = selinux_secid_to_secctx,
> >>>> .secctx_to_secid = selinux_secctx_to_secid,
> >>>> .release_secctx = selinux_release_secctx,
> >>>>diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> >>>>index 38be92c..82c3c72 100644
> >>>>--- a/security/smack/smack_lsm.c
> >>>>+++ b/security/smack/smack_lsm.c
> >>>>@@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void *vrule)
> >>>> #endif /* CONFIG_AUDIT */
> >>>>
> >>>> /**
> >>>>+ * smack_ismaclabel - check if xattr @name references a smack MAC label
> >>>>+ * @name: Full xattr name to check.
> >>>>+ */
> >>>>+static int smack_ismaclabel(const char *name)
> >>>>+{
> >>>>+ return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
> >>>>+}
> >>>>+
> >>>>+
> >>>>+/**
> >>>> * smack_secid_to_secctx - return the smack label for a secid
> >>>> * @secid: incoming integer
> >>>> * @secdata: destination
> >>>>@@ -3530,6 +3540,7 @@ struct security_operations smack_ops = {
> >>>> .audit_rule_free = smack_audit_rule_free,
> >>>> #endif /* CONFIG_AUDIT */
> >>>>
> >>>>+ .ismaclabel = smack_ismaclabel,
> >>>> .secid_to_secctx = smack_secid_to_secctx,
> >>>> .secctx_to_secid = smack_secctx_to_secid,
> >>>> .release_secctx = smack_release_secctx,
> >>>>--
> >>>>1.7.11.7
> >>>>
>

2012-11-16 03:40:53

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/15/2012 12:28 PM, David Quigley wrote:
> On 11/15/2012 11:00, Casey Schaufler wrote:
>> On 11/14/2012 6:30 AM, David Quigley wrote:
>>> On 11/14/2012 09:24, J. Bruce Fields wrote:
>>>> On Wed, Nov 14, 2012 at 09:04:18AM -0500, David Quigley wrote:
>>>>> On 11/14/2012 08:59, J. Bruce Fields wrote:
>>>>> >On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
>>>>> >>On 11/14/2012 08:45, J. Bruce Fields wrote:
>>>>> >>>On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>>>>> >>>>Ok so if you go to http://www.selinuxproject.org/git you will
>>>>> >>see a
>>>>> >>>>repo for lnfs and lnfs-patchset. The instructions at
>>>>> >>>>http://www.selinuxproject.org/page/Labeled_NFS give you a better
>>>>> >>>>indication on how to pull the trees. I've attached a patch for
>>>>> NFS
>>>>> >>>>utils which gives support for security_label/nosecurity_label in
>>>>> >>>>your /etc/exports file.
>>>>> >>>
>>>>> >>>Do we need an export option? Is there any reason not to make the
>>>>> >>>feature available whenever there's support available for it?
>>>>> >>
>>>>> >>I guess we could build it in but I figured an export option allowed
>>>>> >>someone to turn off security labeling support if they didn't
>>>>> want it
>>>>> >>on that export. What happens to clients when the server returns a
>>>>> >>cap that they don't support? Do they mask the bits out?
>>>>> >
>>>>> >Yeah, they should just ignore it.
>>>>> >
>>>>> >While this is still experimental it's still nice to have a way to
>>>>> >turn
>>>>> >this on and off at runtime so people can experiment without
>>>>> having to
>>>>> >have it on for everyone all the time. But
>>>>> >nfsd_supported_minorversion
>>>>> >should be sufficient for that.
>>>>> >
>>>>> >(I don't think your patches actually dealt yet with the fact that
>>>>> >this
>>>>> >is part of minor version 2? Another for the todo list.)
>>>>> >
>>>>> >--b.
>>>>>
>>>>> If we use nfsd_supported_minorversion which I'm guessing is an
>>>>> export option
>>>>
>>>> That's just a variable in the code. It's controlled by
>>>> /proc/fs/nfsd/versions.
>>>>
>>>>> what happens if someone wants to use other 4.2
>>>>> features but not labeling?
>>>>
>>>> We'll cross that bridge when we come to it, maybe by adding some new
>>>> global paramater.
>>>>
>>>> There's no reason this really needs to be per-export, is there?
>>>>
>>>> --b.
>>>
>>> At the moment I can't really think of a reason to have it be
>>> per-export. I think we need a new LSM patch though to determine if the
>>> LSM supports labeling over NFS unless Steve can think of a better way
>>> to tell if the LSM supports labeling.
>>
>> If the LSM has a secid_to_secctx hook it supports labeling.
>> Today that's SELinux and Smack. You already have support in
>> for SELinux, and providing Smack's review and possibly updates
>> is #2 on my gotta do list. On the whole, I think that, except
>> for the fundamental philosophical difference between label
>> support and xattr support, it should be a simple matter to
>> get support in for any LSM that has secid_to_secctx.
>>
>> But I'm still working on the review.
>>
>
> I believe SMACK already works out of the box since we abstracted the
> call to obtain labels and your implementation currently works.

I'm looking to do a little verification. I hate assuming that something
will work only to discover otherwise in the wild.

> The call that is needed is not secid_to_secctx but inode_getsecctx.

I was pointing out that secid_to_secctx pretty well defines that the LSM
is using labels.

> You asked for this because SMACK labels can span multiple xattrs. I
> don't think its right to expect NFS to poke around the security
> structure to check if there is a valid hook(and it isn't really
> possible either).

Yeah, I can see that.

> Maybe we can have an LSM hook where the LSM categorizes itself and
> returns a value and if the value it returns is label based then NFS
> can use it.

I'm not sure what the proposed hook would be for except to identify it
as concerned with nfs. Perhaps the hook could return the names of
attributes that it wants nfs to provide.


>
>>>
>>>
>>>>
>>>>> I'll switch it over if you guys want it
>>>>> done that way, I think though that this provides more flexibility.
>>>>> Although anything that makes me carry around fewer patches is good
>>>>> in my book.
>>>>>
>>>>> Dave
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe
>>> linux-security-module" in
>>> the body of a message to [email protected]
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>>
>>
>> --
>> This message was distributed to subscribers of the selinux mailing list.
>> If you no longer wish to subscribe, send mail to
>> [email protected] with
>> the words "unsubscribe selinux" without quotes as the message.
>
>


2012-11-21 00:29:27

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

From the spec file these are the BuildRequires statements. I'm trying
to build an rpm for it right now. Should be done soon.

BuildRequires: libgssglue-devel libevent-devel libcap-devel
BuildRequires: libnfsidmap-devel libtirpc-devel libblkid-devel
BuildRequires: krb5-libs >= 1.4 autoconf >= 2.57 openldap-devel >= 2.2
BuildRequires: automake, libtool, glibc-headers, device-mapper-devel
BuildRequires: krb5-devel, tcp_wrappers-devel, libmount-devel


2012-11-12 15:23:37

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Mon, Nov 12, 2012 at 01:15:34AM -0500, David Quigley wrote:
> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
> specification and it has been decided that a reposting of the Labeled NFS code
> for inclusion into mainline was a good idea. The patches have been rebased onto
> v3.7-rc2 and have been tested against the SELinux testsuite with the only
> failures being for features not supported by NFS.

By the way, is there wireshark support anywhere for the labeled NFS
protocol?

--b.

2012-11-30 00:07:59

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/29/2012 17:28, Casey Schaufler wrote:
> On 11/28/2012 6:08 PM, Casey Schaufler wrote:
>> On 11/28/2012 5:14 PM, Dave Quigley wrote:
>>> On 11/28/2012 1:57 PM, Casey Schaufler wrote:
>>>> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>>>>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>>>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>>>>> ...
>>>>>>>
>>>>>>>
>>>>>>> Or I could just give you this link and you should be good to go
>>>>>>> ;)
>>>>>>>
>>>>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>>>>
>>>>>>> I haven't tried it but it should work. If it doesn't let me
>>>>>>> know and
>>>>>>> i'll try to fix it on my end. I'd imagine you might need to yum
>>>>>>> remove
>>>>>>> nfs-utils first before adding this new one or you could also
>>>>>>> try an
>>>>>>> rpm with the upgrade flag for this instead. Good luck.
>>>> ...
>>>>
>>>>
>>>> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
>>>> attached stack trace on mount. After mounting I'm getting
>>>> denials when I should, but also when I shouldn't.
>>>>
>>>> I've tried tracking down the issue, but there's a lot going on
>>>> that I don't find obvious. I added a dentry_init hook just for
>>>> grins, but it's not getting called.
>>>>
>>>> .
>>>>
>>>>
>>> Any chance of you throwing a kickstart file my way that's
>>> configured
>>> with SMACK so I can use it for a test box (both server and client)?
>>> I
>>> can have the guys working with me test for SMACK as well if you
>>> provide an appropriate test harness and image for testing.
>> I've attached the .config from my Fedora17 machine. Who knows, maybe
>> I got something wrong there. I get the error doing the test on the
>> loopback interface (mount -t nfs4 localhist:/ /mnt).
>
> I've done some instrumentation and security_ismaclabel() is getting
> called with "selinux", but never "SMACK64". I would guess that
> somewhere
> in the tools you're telling the kernel to expect "selinux". Where is
> that, so that I can tell it to try "SMACK64" instead?
>
>
>
> --
> This message was distributed to subscribers of the selinux mailing
> list.
> If you no longer wish to subscribe, send mail to
> [email protected] with
> the words "unsubscribe selinux" without quotes as the message.


What tools do you use in SMACK to see the labels? Do you just use
getxattr? If so can you try calling that and seeing what happens? I'm
concerned that you aren't getting any attribute information on that
file. Do you have a disto that I can use that has full smack integration
and is easy to setup?

Dave

2012-11-12 22:29:50

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/11/2012 10:15 PM, David Quigley wrote:
> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
> specification and it has been decided that a reposting of the Labeled NFS code
> for inclusion into mainline was a good idea. The patches have been rebased onto
> v3.7-rc2 and have been tested against the SELinux testsuite with the only
> failures being for features not supported by NFS.

It's going to take a few days (I'm traveling among other issues)
before I can have the Smack project comments ready. They are coming.

If you have pointers to test suites you found especially helpful
I could sure use them.

Thank you.


2012-11-30 13:20:59

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

That last part should have read


Maybe if CAP_FS_MASK_B1 was like this it would work.

# define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE) \
| CAP_TO_MASK(CAP_MAC_ADMIN))

2012-11-30 16:59:14

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 11:55, J. Bruce Fields wrote:
> On Fri, Nov 30, 2012 at 08:50:55AM -0500, Stephen Smalley wrote:
>> On the SELinux side, we don't require CAP_MAC_ADMIN to set the
>> SELinux attribute on a file in the normal case, only when the
>> SELinux attribute is not known to the security policy yet. So
>> granting CAP_MAC_ADMIN there means that a client will be able to set
>> security contexts on files that are unknown to the server. I guess
>> that might even be desirable in some instances where client and
>> server policy are different.
>
> Note (as you probably know) this first pass at labeled NFS only lets
> us
> label files, not rpc calls--if we want the server to know who's doing
> something (beyond the information the rpc headers already carry),
> we'll
> need to implement rpcsec_gss v3, and that's a project for another
> day.
>
> I've been assuming that makes server-side enforcement less useful for
> now.
>
> --b.

Ideally what will happen is that when we get RPCSECGSSv3 in we'll set
the security context in the same place that we set uid and gid for the
process in the auth code. Until then you're right server side
enforcement really isn't possible because we have whatever context the
kernel gives to the thread being our security context. In the SELinux
case this is the all powerful kernel_t in the smack case its the floor
context.

Dave

2012-11-13 03:16:09

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/12/2012 5:23 PM, Casey Schaufler wrote:
> On 11/11/2012 10:15 PM, David Quigley wrote:
>> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
>> specification and it has been decided that a reposting of the Labeled NFS code
>> for inclusion into mainline was a good idea. The patches have been rebased onto
>> v3.7-rc2 and have been tested against the SELinux testsuite with the only
>> failures being for features not supported by NFS.
>
> It's going to take a few days (I'm traveling among other issues)
> before I can have the Smack project comments ready. They are coming.
>
> If you have pointers to test suites you found especially helpful
> I could sure use them.
>
> Thank you.
>

The only testsuite I have is the SELinux one. Unfortunately you're on
your own for a smack testsuite.

2012-11-14 04:32:56

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/13/2012 7:55 AM, Steve Dickson wrote:
>
>
> On 12/11/12 20:39, Dave Quigley wrote:
>> If you're ok with non Fedora kernel images I can try to put up a tree either tonight or tomorrow with the patches that you just need to build and install. That plus the one patch for nfs-utils should make everything work.
> I'm good with that....
>
> steved.
>

Ok so if you go to http://www.selinuxproject.org/git you will see a repo
for lnfs and lnfs-patchset. The instructions at
http://www.selinuxproject.org/page/Labeled_NFS give you a better
indication on how to pull the trees. I've attached a patch for NFS utils
which gives support for security_label/nosecurity_label in your
/etc/exports file. I've also attached a script called setup which should
build a test directory called /export with a copy of /var/www under it
which should be labeled properly. It does all the proper SELinux
commands to make sure labeling is correct. Once you have that setup just
mount -t nfs localhost:/ /mnt/lnfs (or wherever you want) and you should
be good to go. Just ls -Z in /mnt/lnfs/var and check to make sure the
labels are the same as /export/var. It should have the labels showing up
in the network transfer. If you have any problems just let me know and I
can try to help figure them out.

Dave


Attachments:
0001-Add-support-to-specify-which-exports-will-provide-La.patch (2.34 kB)
setup.sh (324.00 B)
Download all attachments

2012-11-30 13:52:30

by Stephen Smalley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 08:35 AM, David Quigley wrote:
> On 11/30/2012 08:28, Stephen Smalley wrote:
>> On 11/30/2012 08:17 AM, David Quigley wrote:
>>> On 11/30/2012 07:57, David Quigley wrote:
>>>> On 11/30/2012 07:14, J. Bruce Fields wrote:
>>>>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>>>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>>>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>>>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>>>>> >>>I would think that were it not for the case that access is denied
>>>>>> >>>and I get an audit record for nfsd that reports a subject
>>>>>> >>>label of "_"
>>>>>> >>>(which is correct for nfsd but not the process attempting
>>>>>> >>>access) and
>>>>>> >>>an object label of "WhooHoo", which is correct. The server side
>>>>>> >>>looks like it might be working right, given the information
>>>>>> that it
>>>>>> >>>has.
>>>>>> >>>
>>>>>> >>
>>>>>> >>Ok so this is the problem. nfsd is a kernel thread I believe. In
>>>>>> >>SELinux land it has the type kernel_t which is all powerful. We
>>>>>> >>don't
>>>>>> >>have client label transport yet (That requires RPCSECGSSv3). Is
>>>>>> >>there
>>>>>> >>a way you can have that kernel thread running as a type that has
>>>>>> >>access to everything?
>>>>>> >
>>>>>> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in Smackese.
>>>>>> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
>>>>>> >which
>>>>>> >is to say, all capabilities.
>>>>>> >
>>>>>>
>>>>>> Hmm thats interesting then. You could try using rpcdebug -m nfsd to
>>>>>> turn on some of the debugging to look around the internals and
>>>>>> figure out whats going on. If you pass -v it will give you all of
>>>>>> the potential flags.
>>>>>>
>>>>>> >
>>>>>> >>I think that is the current problem. Which makes perfect sense. If
>>>>>> >>your kernel threads don't get started with max privilege then the
>>>>>> >>server would be denied access on all of the file attributes and
>>>>>> >>wouldn't be able to ship it over the wire properly.
>>>>>> >
>>>>>> >OK. I haven't had to do anything with kernel threads so far.
>>>>>> >Where is NFS setting these up? Poking around fs/nfsd looks like
>>>>>> >the place, but I haven't seen anything there that makes it look
>>>>>> >like they would be running without capabilities. Clearly, that's
>>>>>> >what I'm seeing. It looks as if the credential of nfsd does not
>>>>>> >match what /proc reports. Bother.
>>>>>> >
>>>>>>
>>>>>> I'm not entirely sure whats up either. If you want to look for the
>>>>>> NFSd threads they are in fs/nfsd/nfssvc.c. The main function starts
>>>>>> on line 487.
>>>>>
>>>>> I'm not following the discussion, but: maybe you want to look at
>>>>> fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
>>>>> cap_{drop/raise}_nfsd_set() calls at the end.
>>>>>
>>>>> --b.
>>>>
>>>>
>>>> I'm not as familiar with the capabilities code as Casey is so I'll
>>>> leave this ball in his court. I think you are correct though and the
>>>> problem is that NFSd is dropping and raising caps and we need to make
>>>> sure that MAC_ADMIN and MAC_OVERRIDE is in there in the SMACK case.
>>>>
>>>> --
>>>> This message was distributed to subscribers of the selinux mailing
>>>> list.
>>>> If you no longer wish to subscribe, send mail to
>>>> [email protected] with
>>>> the words "unsubscribe selinux" without quotes as the message.
>>>
>>>
>>> I think I found the offending code. I can't test it for a while so
>>> hopefully Casey can.
>>>
>>> In include/linux/capability.h we have the following defines
>>>
>>>
>>> # define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
>>> | CAP_TO_MASK(CAP_MKNOD) \
>>> | CAP_TO_MASK(CAP_DAC_OVERRIDE) \
>>> | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
>>> | CAP_TO_MASK(CAP_FOWNER) \
>>> | CAP_TO_MASK(CAP_FSETID))
>>>
>>> # define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
>>>
>>> #if _KERNEL_CAPABILITY_U32S != 2
>>> # error Fix up hand-coded capability macro initializers
>>> #else /* HAND-CODED capability initializers */
>>>
>>> # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
>>> # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
>>> # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>>> |
>>> CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
>>> CAP_FS_MASK_B1 } })
>>> # define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>>> | CAP_TO_MASK(CAP_SYS_RESOURCE), \
>>> CAP_FS_MASK_B1 } })
>>>
>>> So raise and drop nfsd caps uses CAP_NFSD_SET. In CAP_NFSD_SET we have
>>> CAP_MAC_OVERRIDE but we don't have CAP_MAC_ADMIN. I think maybe if we
>>> had both then Casey should be able to use the code with SMACK. However
>>> I'm not sure what implications this has for every other LSM. Honestly
>>> I'm not sure if we use either of those caps for SELinux at all (I think
>>> we ignore them completely).
>>
>> CAP_MAC_ADMIN is used by SELinux these days, but only to control the
>> ability to get or set security contexts that are not yet defined in
>> the policy (for package managers that lay down the security contexts
>> before reloading policy and for installing a distro within a chroot on
>> a build host running a different policy).
>
>
> Do you think its reasonable to add that cap into the NFSd thread then?
> I'm not sure what other solution there would be. Casey needs it just so
> SMACK can work with it at all (assuming what I think is happening is
> actually happening).

Looks like Smack requires CAP_MAC_ADMIN in order to set Smack attributes
on a file at all. So nfsd would require that capability for Smack. I
think this means however that setting Smack labels on NFS files won't
work in any case where root is squashed, which seems unfortunate.

On the SELinux side, we don't require CAP_MAC_ADMIN to set the SELinux
attribute on a file in the normal case, only when the SELinux attribute
is not known to the security policy yet. So granting CAP_MAC_ADMIN
there means that a client will be able to set security contexts on files
that are unknown to the server. I guess that might even be desirable in
some instances where client and server policy are different. We do have
the option of denying mac_admin permission in policy for nfsd
(kernel_t?), in which case we would block such attempts to set unknown
contexts but would still support setting of known security contexts.

So I think it is workable, albeit a bit confusing.


2012-11-30 16:21:34

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 6:02 AM, David Quigley wrote:

There are times when living by the correct ocean makes
life so much easier. Thanks all for the early morning
brain work.

> On 11/30/2012 08:50, Stephen Smalley wrote:
>> On 11/30/2012 08:35 AM, David Quigley wrote:
>>> On 11/30/2012 08:28, Stephen Smalley wrote:
>>>> On 11/30/2012 08:17 AM, David Quigley wrote:
>>>>> On 11/30/2012 07:57, David Quigley wrote:
>>>>>> On 11/30/2012 07:14, J. Bruce Fields wrote:
>>>>>>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>>>>>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>>>>>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>>>>>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>>>>>>> >... Whole bunch snipped ...
>>
>> Looks like Smack requires CAP_MAC_ADMIN in order to set Smack
>> attributes on a file at all. So nfsd would require that capability
>> for Smack. I think this means however that setting Smack labels on
>> NFS files won't work in any case where root is squashed, which seems
>> unfortunate.

I'm building a kernel with CAP_MAC_ADMIN set for nfsd.
I am reasonably sure that this will get me past the current
issue. As far as a squashed root goes, well, doing things
that the security policy doesn't allow requires privilege.

>
> I'll leave that problem to Casey to figure out. However it seems to me
> that regardless of Labeled NFS Casey should have problems with the NFS
> server not being able to serve up files that are dominated by floor. I
> wonder if he has every tried NFSv4 on a SMACK enabled server before.
> It may have just worked because all files implicitly get labeled floor.

CAP_MAC_OVERRIDE, which nfsd does have, is sufficient for
reading and writing files. A Smack enabled server is able
to serve to Smack and Smackless clients, but of course all
label enforcement is lost. Thus it will "work", but it will
be bad. I haven't used NFS much lately, in part because of
the lack of labeling and the security issues inherent in
serving labeled files to clueless clients.


>
>>
>> On the SELinux side, we don't require CAP_MAC_ADMIN to set the
>> SELinux attribute on a file in the normal case, only when the SELinux
>> attribute is not known to the security policy yet. So granting
>> CAP_MAC_ADMIN there means that a client will be able to set security
>> contexts on files that are unknown to the server. I guess that might
>> even be desirable in some instances where client and server policy are
>> different. We do have the option of denying mac_admin permission in
>> policy for nfsd (kernel_t?), in which case we would block such
>> attempts to set unknown contexts but would still support setting of
>> known security contexts.
>>
>> So I think it is workable, albeit a bit confusing.
>
> Yea it is unfortunate that we have to go mucking around in capability
> land but it seems that adding CAP_MAC_ADMIN should be fine and we can
> deal with it in policy if we like.

Worst case we could add a security_set_nfsd_capabilities hook.
Maybe make the capability set an export option?

>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to
> [email protected] with
> the words "unsubscribe selinux" without quotes as the message.
>


2012-11-16 04:58:13

by David Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

>> I'm not sure what the proposed hook would be for except to identify it
>> as concerned with nfs. Perhaps the hook could return the names of
>> attributes that it wants nfs to provide.
>>
>
> I'm not quite sure what you're proposing? I'm sure someone would find
> another use for this hook though. The inode_getsecctx hook we made for
> Labeled NFS was already merged because it was needed for providing
> "persistent" label support for sysfs (meaning that it persisted inode
> eviction from memory). The problem is that we have no real way to ask in
> the NFS code if this is an LSM that can be used with Labeled NFS. In the
> xattr code we have the new ismaclabel hook we add which allows us to
> verify the xattr used as belonging to a label based LSM however we need
> an xattr from userspace for that. The reason this is required is that
> the server will need to fill out its capability mask to indicate it
> supports security labeling. In addition the client also needs to know if
> its running a security label based LSM because it will need to mask out
> the label fattr bit from its getattr calls if it doesn't support it. We
> can override this in SELinux by giving it a context mount but if we
> don't then it will need to know whether or not to be pulling security
> labels back.
>


I think the point I'm trying to make is that we need to define the
interface which if you implement it you are supported. For label
import/export we have inode_{get,set,notify}secctx. For checking for
xattr suitibility we have the new ismaclabel lsm call. Now the final
thing we need to do is a call to determine if the lsm is suitable for
Labeled NFS export meaning that it agrees to the semantics. Is
inode{get,set,notify}_secctx and ismaclabel sufficient? I'm tempted to
say we can make a call to inode_getsecctx and if it failes with
EOPNOTSUPP we say we don't support it but then we need an initial file
to call that on. This is why I'd rather have a LSM call that we can make
that gives us a yes/no answer.

Dave


2012-11-30 13:45:02

by Stephen Smalley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 08:17 AM, David Quigley wrote:
> On 11/30/2012 07:57, David Quigley wrote:
>> On 11/30/2012 07:14, J. Bruce Fields wrote:
>>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>>> >>>I would think that were it not for the case that access is denied
>>>> >>>and I get an audit record for nfsd that reports a subject
>>>> >>>label of "_"
>>>> >>>(which is correct for nfsd but not the process attempting
>>>> >>>access) and
>>>> >>>an object label of "WhooHoo", which is correct. The server side
>>>> >>>looks like it might be working right, given the information that it
>>>> >>>has.
>>>> >>>
>>>> >>
>>>> >>Ok so this is the problem. nfsd is a kernel thread I believe. In
>>>> >>SELinux land it has the type kernel_t which is all powerful. We
>>>> >>don't
>>>> >>have client label transport yet (That requires RPCSECGSSv3). Is
>>>> >>there
>>>> >>a way you can have that kernel thread running as a type that has
>>>> >>access to everything?
>>>> >
>>>> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in Smackese.
>>>> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
>>>> >which
>>>> >is to say, all capabilities.
>>>> >
>>>>
>>>> Hmm thats interesting then. You could try using rpcdebug -m nfsd to
>>>> turn on some of the debugging to look around the internals and
>>>> figure out whats going on. If you pass -v it will give you all of
>>>> the potential flags.
>>>>
>>>> >
>>>> >>I think that is the current problem. Which makes perfect sense. If
>>>> >>your kernel threads don't get started with max privilege then the
>>>> >>server would be denied access on all of the file attributes and
>>>> >>wouldn't be able to ship it over the wire properly.
>>>> >
>>>> >OK. I haven't had to do anything with kernel threads so far.
>>>> >Where is NFS setting these up? Poking around fs/nfsd looks like
>>>> >the place, but I haven't seen anything there that makes it look
>>>> >like they would be running without capabilities. Clearly, that's
>>>> >what I'm seeing. It looks as if the credential of nfsd does not
>>>> >match what /proc reports. Bother.
>>>> >
>>>>
>>>> I'm not entirely sure whats up either. If you want to look for the
>>>> NFSd threads they are in fs/nfsd/nfssvc.c. The main function starts
>>>> on line 487.
>>>
>>> I'm not following the discussion, but: maybe you want to look at
>>> fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
>>> cap_{drop/raise}_nfsd_set() calls at the end.
>>>
>>> --b.
>>
>>
>> I'm not as familiar with the capabilities code as Casey is so I'll
>> leave this ball in his court. I think you are correct though and the
>> problem is that NFSd is dropping and raising caps and we need to make
>> sure that MAC_ADMIN and MAC_OVERRIDE is in there in the SMACK case.
>>
>> --
>> This message was distributed to subscribers of the selinux mailing list.
>> If you no longer wish to subscribe, send mail to
>> [email protected] with
>> the words "unsubscribe selinux" without quotes as the message.
>
>
> I think I found the offending code. I can't test it for a while so
> hopefully Casey can.
>
> In include/linux/capability.h we have the following defines
>
>
> # define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
> | CAP_TO_MASK(CAP_MKNOD) \
> | CAP_TO_MASK(CAP_DAC_OVERRIDE) \
> | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
> | CAP_TO_MASK(CAP_FOWNER) \
> | CAP_TO_MASK(CAP_FSETID))
>
> # define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
>
> #if _KERNEL_CAPABILITY_U32S != 2
> # error Fix up hand-coded capability macro initializers
> #else /* HAND-CODED capability initializers */
>
> # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
> # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
> # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
> | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
> CAP_FS_MASK_B1 } })
> # define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
> | CAP_TO_MASK(CAP_SYS_RESOURCE), \
> CAP_FS_MASK_B1 } })
>
> So raise and drop nfsd caps uses CAP_NFSD_SET. In CAP_NFSD_SET we have
> CAP_MAC_OVERRIDE but we don't have CAP_MAC_ADMIN. I think maybe if we
> had both then Casey should be able to use the code with SMACK. However
> I'm not sure what implications this has for every other LSM. Honestly
> I'm not sure if we use either of those caps for SELinux at all (I think
> we ignore them completely).

CAP_MAC_ADMIN is used by SELinux these days, but only to control the
ability to get or set security contexts that are not yet defined in the
policy (for package managers that lay down the security contexts before
reloading policy and for installing a distro within a chroot on a build
host running a different policy).


2012-11-12 15:13:19

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 07/13] NFSv4: Introduce new label structure

On Mon, Nov 12, 2012 at 01:15:41AM -0500, David Quigley wrote:
> From: David Quigley <[email protected]>
>
> In order to mimic the way that NFSv4 ACLs are implemented we have created a
> structure to be used to pass label data up and down the call chain. This patch
> adds the new structure and new members to the required NFSv4 call structures.
>
> Signed-off-by: Matthew N. Dodd <[email protected]>
> Signed-off-by: Miguel Rodel Felipe <[email protected]>
> Signed-off-by: Phua Eu Gene <[email protected]>
> Signed-off-by: Khin Mi Mi Aung <[email protected]>
> Signed-off-by: David Quigley <[email protected]>
> ---
> fs/nfs/inode.c | 40 ++++++++++++++++++++++++++++++++++++++++
> fs/nfsd/xdr4.h | 3 +++
> include/linux/nfs4.h | 8 ++++++++
> include/linux/nfs_fs.h | 14 ++++++++++++++
> include/linux/nfs_xdr.h | 20 ++++++++++++++++++++
> 5 files changed, 85 insertions(+)
>
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 5c7325c..0963ad9 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -246,6 +246,46 @@ nfs_init_locked(struct inode *inode, void *opaque)
> return 0;
> }
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +struct nfs4_label *nfs4_label_alloc(gfp_t flags)
> +{
> + struct nfs4_label *label = NULL;
> +
> + label = kzalloc(sizeof(struct nfs4_label) + NFS4_MAXLABELLEN, flags);

NFS4_MAXLABELLEN is 4096, but we usually try to avoid allocating more
than that in a single allocation.

> + if (label == NULL)
> + return NULL;
> +
> + label->label = (void *)(label + 1);
> + label->len = NFS4_MAXLABELLEN;
> + /* 0 is the null format meaning that the data is not to be translated */
> + label->lfs = 0;
> + label->pi = 0;

What's "pi"?

--b.

> + return label;
> +}
> +EXPORT_SYMBOL_GPL(nfs4_label_alloc);
> +
> +void nfs4_label_init(struct nfs4_label *label)
> +{
> + if (label && label->label) {
> + *(unsigned char *)label->label = 0;
> + label->len = NFS4_MAXLABELLEN;
> + /* 0 is the null format meaning that the data is not
> + to be translated */
> + label->lfs = 0;
> + label->pi = 0;
> + }
> + return;
> +}
> +EXPORT_SYMBOL_GPL(nfs4_label_init);
> +
> +void nfs4_label_free(struct nfs4_label *label)
> +{
> + kfree(label);
> + return;
> +}
> +EXPORT_SYMBOL_GPL(nfs4_label_free);
> +#endif
> +
> /*
> * This is our front-end to iget that looks up inodes by file handle
> * instead of inode number.
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index acd127d..ca8f30b 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -118,6 +118,7 @@ struct nfsd4_create {
> struct iattr cr_iattr; /* request */
> struct nfsd4_change_info cr_cinfo; /* response */
> struct nfs4_acl *cr_acl;
> + struct nfs4_label *cr_label;
> };
> #define cr_linklen u.link.namelen
> #define cr_linkname u.link.name
> @@ -246,6 +247,7 @@ struct nfsd4_open {
> struct nfs4_file *op_file; /* used during processing */
> struct nfs4_ol_stateid *op_stp; /* used during processing */
> struct nfs4_acl *op_acl;
> + struct nfs4_label *op_label;
> };
> #define op_iattr iattr
>
> @@ -330,6 +332,7 @@ struct nfsd4_setattr {
> u32 sa_bmval[3]; /* request */
> struct iattr sa_iattr; /* request */
> struct nfs4_acl *sa_acl;
> + struct nfs4_label *sa_label;
> };
>
> struct nfsd4_setclientid {
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index f9235b4..862471f 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -28,6 +28,14 @@ struct nfs4_acl {
> struct nfs4_ace aces[0];
> };
>
> +struct nfs4_label {
> + uint32_t lfs;
> + uint32_t pi;
> + u32 len;
> + void *label;
> +};
> +
> +
> typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
>
> struct nfs_stateid4 {
> diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> index 1cc2568..37a862c 100644
> --- a/include/linux/nfs_fs.h
> +++ b/include/linux/nfs_fs.h
> @@ -489,6 +489,20 @@ extern int nfs_mountpoint_expiry_timeout;
> extern void nfs_release_automount_timer(void);
>
> /*
> + * linux/fs/nfs/nfs4proc.c
> + */
> +
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +extern struct nfs4_label *nfs4_label_alloc(gfp_t flags);
> +extern void nfs4_label_init(struct nfs4_label *);
> +extern void nfs4_label_free(struct nfs4_label *);
> +#else
> +static inline struct nfs4_label *nfs4_label_alloc(gfp_t flags) { return NULL; }
> +static inline void nfs4_label_init(struct nfs4_label *) {}
> +static inline void nfs4_label_free(struct nfs4_label *label) {}
> +#endif
> +
> +/*
> * linux/fs/nfs/unlink.c
> */
> extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
> diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> index a0669d3..7e9347a 100644
> --- a/include/linux/nfs_xdr.h
> +++ b/include/linux/nfs_xdr.h
> @@ -352,6 +352,7 @@ struct nfs_openargs {
> const u32 * bitmask;
> const u32 * open_bitmap;
> __u32 claim;
> + const struct nfs4_label *label;
> struct nfs4_sequence_args seq_args;
> };
>
> @@ -361,6 +362,7 @@ struct nfs_openres {
> struct nfs4_change_info cinfo;
> __u32 rflags;
> struct nfs_fattr * f_attr;
> + struct nfs4_label *f_label;
> struct nfs_seqid * seqid;
> const struct nfs_server *server;
> fmode_t delegation_type;
> @@ -405,6 +407,7 @@ struct nfs_closeargs {
> struct nfs_closeres {
> nfs4_stateid stateid;
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> struct nfs_seqid * seqid;
> const struct nfs_server *server;
> struct nfs4_sequence_res seq_res;
> @@ -478,6 +481,7 @@ struct nfs4_delegreturnargs {
>
> struct nfs4_delegreturnres {
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> const struct nfs_server *server;
> struct nfs4_sequence_res seq_res;
> };
> @@ -498,6 +502,7 @@ struct nfs_readargs {
>
> struct nfs_readres {
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> __u32 count;
> int eof;
> struct nfs4_sequence_res seq_res;
> @@ -566,6 +571,7 @@ struct nfs_removeargs {
> struct nfs_removeres {
> const struct nfs_server *server;
> struct nfs_fattr *dir_attr;
> + struct nfs4_label *dir_label;
> struct nfs4_change_info cinfo;
> struct nfs4_sequence_res seq_res;
> };
> @@ -578,6 +584,8 @@ struct nfs_renameargs {
> const struct nfs_fh *new_dir;
> const struct qstr *old_name;
> const struct qstr *new_name;
> + const struct nfs4_label *old_label;
> + const struct nfs4_label *new_label;
> struct nfs4_sequence_args seq_args;
> };
>
> @@ -585,8 +593,10 @@ struct nfs_renameres {
> const struct nfs_server *server;
> struct nfs4_change_info old_cinfo;
> struct nfs_fattr *old_fattr;
> + struct nfs4_label *old_label;
> struct nfs4_change_info new_cinfo;
> struct nfs_fattr *new_fattr;
> + struct nfs4_label *new_label;
> struct nfs4_sequence_res seq_res;
> };
>
> @@ -634,6 +644,7 @@ struct nfs_setattrargs {
> struct iattr * iap;
> const struct nfs_server * server; /* Needed for name mapping */
> const u32 * bitmask;
> + const struct nfs4_label *label;
> struct nfs4_sequence_args seq_args;
> };
>
> @@ -669,6 +680,7 @@ struct nfs_getaclres {
>
> struct nfs_setattrres {
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> const struct nfs_server * server;
> struct nfs4_sequence_res seq_res;
> };
> @@ -715,6 +727,7 @@ struct nfs3_setaclargs {
> struct nfs_diropok {
> struct nfs_fh * fh;
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> };
>
> struct nfs_readlinkargs {
> @@ -844,6 +857,7 @@ struct nfs4_accessargs {
> struct nfs4_accessres {
> const struct nfs_server * server;
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> u32 supported;
> u32 access;
> struct nfs4_sequence_res seq_res;
> @@ -866,6 +880,7 @@ struct nfs4_create_arg {
> const struct iattr * attrs;
> const struct nfs_fh * dir_fh;
> const u32 * bitmask;
> + const struct nfs4_label *label;
> struct nfs4_sequence_args seq_args;
> };
>
> @@ -873,6 +888,7 @@ struct nfs4_create_res {
> const struct nfs_server * server;
> struct nfs_fh * fh;
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> struct nfs4_change_info dir_cinfo;
> struct nfs4_sequence_res seq_res;
> };
> @@ -898,6 +914,7 @@ struct nfs4_getattr_res {
> const struct nfs_server * server;
> struct nfs_fattr * fattr;
> struct nfs4_sequence_res seq_res;
> + struct nfs4_label *label;
> };
>
> struct nfs4_link_arg {
> @@ -911,8 +928,10 @@ struct nfs4_link_arg {
> struct nfs4_link_res {
> const struct nfs_server * server;
> struct nfs_fattr * fattr;
> + struct nfs4_label *label;
> struct nfs4_change_info cinfo;
> struct nfs_fattr * dir_attr;
> + struct nfs4_label *dir_label;
> struct nfs4_sequence_res seq_res;
> };
>
> @@ -928,6 +947,7 @@ struct nfs4_lookup_res {
> const struct nfs_server * server;
> struct nfs_fattr * fattr;
> struct nfs_fh * fh;
> + struct nfs4_label *label;
> struct nfs4_sequence_res seq_res;
> };
>
> --
> 1.7.11.7
>

2012-11-12 15:40:51

by David Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/12/2012 10:23 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 01:15:34AM -0500, David Quigley wrote:
>> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
>> specification and it has been decided that a reposting of the Labeled NFS code
>> for inclusion into mainline was a good idea. The patches have been rebased onto
>> v3.7-rc2 and have been tested against the SELinux testsuite with the only
>> failures being for features not supported by NFS.
> By the way, is there wireshark support anywhere for the labeled NFS
> protocol?
>
> --b.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

Unfortunately I never got a chance to add it. You can see the label
pretty clearly in wireshark but it comes up as an unknown attribute in
the fattr decomposition. If someone knows how to do it I'd be glad to help.

2012-11-30 00:33:56

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/29/2012 4:07 PM, David Quigley wrote:
> On 11/29/2012 17:28, Casey Schaufler wrote:
>> On 11/28/2012 6:08 PM, Casey Schaufler wrote:
>>> On 11/28/2012 5:14 PM, Dave Quigley wrote:
>>>> On 11/28/2012 1:57 PM, Casey Schaufler wrote:
>>>>> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>>>>>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>>>>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>>>>>> ...
>>>>>>>>
>>>>>>>>
>>>>>>>> Or I could just give you this link and you should be good to go ;)
>>>>>>>>
>>>>>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>>>>>
>>>>>>>> I haven't tried it but it should work. If it doesn't let me
>>>>>>>> know and
>>>>>>>> i'll try to fix it on my end. I'd imagine you might need to yum
>>>>>>>> remove
>>>>>>>> nfs-utils first before adding this new one or you could also
>>>>>>>> try an
>>>>>>>> rpm with the upgrade flag for this instead. Good luck.
>>>>> ...
>>>>>
>>>>>
>>>>> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
>>>>> attached stack trace on mount. After mounting I'm getting
>>>>> denials when I should, but also when I shouldn't.
>>>>>
>>>>> I've tried tracking down the issue, but there's a lot going on
>>>>> that I don't find obvious. I added a dentry_init hook just for
>>>>> grins, but it's not getting called.
>>>>>
>>>>> .
>>>>>
>>>>>
>>>> Any chance of you throwing a kickstart file my way that's configured
>>>> with SMACK so I can use it for a test box (both server and client)? I
>>>> can have the guys working with me test for SMACK as well if you
>>>> provide an appropriate test harness and image for testing.
>>> I've attached the .config from my Fedora17 machine. Who knows, maybe
>>> I got something wrong there. I get the error doing the test on the
>>> loopback interface (mount -t nfs4 localhist:/ /mnt).
>>
>> I've done some instrumentation and security_ismaclabel() is getting
>> called with "selinux", but never "SMACK64". I would guess that somewhere
>> in the tools you're telling the kernel to expect "selinux". Where is
>> that, so that I can tell it to try "SMACK64" instead?
>>
>>
>>
>> --
>> This message was distributed to subscribers of the selinux mailing list.
>> If you no longer wish to subscribe, send mail to
>> [email protected] with
>> the words "unsubscribe selinux" without quotes as the message.
>
>
> What tools do you use in SMACK to see the labels?

attr -S -g SMACK64 <path>

> Do you just use getxattr? If so can you try calling that and seeing
> what happens? I'm concerned that you aren't getting any attribute
> information on that file.

I would think that were it not for the case that access is denied
and I get an audit record for nfsd that reports a subject label of "_"
(which is correct for nfsd but not the process attempting access) and
an object label of "WhooHoo", which is correct. The server side
looks like it might be working right, given the information that it
has.

> Do you have a disto that I can use that has full smack integration and
> is easy to setup?

There's no full integration, but Ubuntu is easy to set up because they
compile in all the LSMs.
Set "security=smack" on the boot line in grub.cfg and reboot.

All processes and files will get the floor ("_") label unless you change
one. You can change
a file label with:
# attr -S -s SMACK64 WhooHoo path
or execute at a different label with:
# (echo WhooHoo > /proc/self/attr/current ; command)


>
> Dave
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


2012-11-12 16:10:02

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Mon, Nov 12, 2012 at 10:34:08AM -0500, David P. Quigley wrote:
> On 11/12/2012 10:23 AM, J. Bruce Fields wrote:
> >On Mon, Nov 12, 2012 at 01:15:34AM -0500, David Quigley wrote:
> >>The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
> >>specification and it has been decided that a reposting of the Labeled NFS code
> >>for inclusion into mainline was a good idea. The patches have been rebased onto
> >>v3.7-rc2 and have been tested against the SELinux testsuite with the only
> >>failures being for features not supported by NFS.
> >By the way, is there wireshark support anywhere for the labeled NFS
> >protocol?
> >
> >--b.
> >--
> >To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> >the body of a message to [email protected]
> >More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
>
> Unfortunately I never got a chance to add it. You can see the label
> pretty clearly in wireshark but it comes up as an unknown attribute
> in the fattr decomposition. If someone knows how to do it I'd be
> glad to help.

It's usually not too hard: last time I needed something I did a

git clone http://code.wireshark.org/git/wireshark

then grepped through epan/dissectors/packet-nfs.c for something similar
to imitate. It wa easy to build and run the result from the build
directory. Then I submitted a patch following:

http://www.wireshark.org/docs/wsdg_html_chunked/ChSrcContribute.html#ChSrcSend

and the response was quick and helpful.

(But yeah I don't have time to volunteer right now either.)

--b.

2012-11-21 02:52:14

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/20/2012 4:37 PM, Dave Quigley wrote:
> ...
>
>
> Or I could just give you this link and you should be good to go ;)
>
> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>
> I haven't tried it but it should work. If it doesn't let me know and
> i'll try to fix it on my end. I'd imagine you might need to yum remove
> nfs-utils first before adding this new one or you could also try an
> rpm with the upgrade flag for this instead. Good luck.

I don't care what Eric says, you're OK with me.

The behavior is interesting with a Smack kernel:

I create an export using the recommended options (sec=unix,security_label, ...)
of /pub. Then , I create a directory sub with the floor ("_") label and a file
named Pop labeled "Pop". I mount the filesystem at /mnt.

# ls -l /mnt
ls: cannot access /mnt/Pop: Permission Denied
total 4
?????????? ? ? ? ? ? Pop
drwxr-xr-x 2 root root 4096 Nov 20 17:57 sub

which is exactly correct!

Unfortunately, I get the exact same result if the process
is run with the Pop label. A process run with the Pop label
should be able to see the attributes of the file Pop.

It looks as if the basic mechanism is working, but that there
is some detail that is not working right. I will have to dig
deeper to understand what's up. Let me know if you have ideas.


>
> Dave
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to
> [email protected] with
> the words "unsubscribe selinux" without quotes as the message.
>


2012-11-29 01:14:41

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/28/2012 1:57 PM, Casey Schaufler wrote:
> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>> ...
>>>>
>>>>
>>>> Or I could just give you this link and you should be good to go ;)
>>>>
>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>
>>>> I haven't tried it but it should work. If it doesn't let me know and
>>>> i'll try to fix it on my end. I'd imagine you might need to yum remove
>>>> nfs-utils first before adding this new one or you could also try an
>>>> rpm with the upgrade flag for this instead. Good luck.
>>>
> ...
>
>
> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
> attached stack trace on mount. After mounting I'm getting
> denials when I should, but also when I shouldn't.
>
> I've tried tracking down the issue, but there's a lot going on
> that I don't find obvious. I added a dentry_init hook just for
> grins, but it's not getting called.
>
> .
>
>

Any chance of you throwing a kickstart file my way that's configured
with SMACK so I can use it for a test box (both server and client)? I
can have the guys working with me test for SMACK as well if you provide
an appropriate test harness and image for testing.

Dave

2012-11-30 00:02:31

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/29/2012 17:49, David Quigley wrote:
> I have an idea of what it is then. I'm cloning the tree so I can take
> a look really quick but I have a feeling that I didn't convey
> something properly and it got messed up in the implementation. If
> that's the case I'll make sure to be clearer next time to avoid
> confusion.
>
> --
> This message was distributed to subscribers of the selinux mailing
> list.
> If you no longer wish to subscribe, send mail to
> [email protected] with
> the words "unsubscribe selinux" without quotes as the message.


So the problem isn't clear to me. If we look in fs/nfs/nfs4proc.c we'll
see the xattr handlers for the security namespace. This will strip off
the security and should pass the second part to the security_ismaclabel
call on the key.

The code in question is below.


static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char
*key,
void *buf, size_t buflen, int type)
{
if (security_ismaclabel(key))
return nfs4_get_security_label(dentry->d_inode, buf,
buflen);
return -EOPNOTSUPP;
}

This means whatever is making the getxattr call from userspace is
requesting security.selinux instead of security.smack. Is there a
different command to ls that will give you security.smack (or whatever
it is)? what happens if you install getfattr and do getfattr -n
security.whatever -m security.* /mnt/file


2012-11-30 13:17:37

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 07:57, David Quigley wrote:
> On 11/30/2012 07:14, J. Bruce Fields wrote:
>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>> >>>I would think that were it not for the case that access is
>>> denied
>>> >>>and I get an audit record for nfsd that reports a subject
>>> >>>label of "_"
>>> >>>(which is correct for nfsd but not the process attempting
>>> >>>access) and
>>> >>>an object label of "WhooHoo", which is correct. The server side
>>> >>>looks like it might be working right, given the information that
>>> it
>>> >>>has.
>>> >>>
>>> >>
>>> >>Ok so this is the problem. nfsd is a kernel thread I believe. In
>>> >>SELinux land it has the type kernel_t which is all powerful. We
>>> >>don't
>>> >>have client label transport yet (That requires RPCSECGSSv3). Is
>>> >>there
>>> >>a way you can have that kernel thread running as a type that has
>>> >>access to everything?
>>> >
>>> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in
>>> Smackese.
>>> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
>>> >which
>>> >is to say, all capabilities.
>>> >
>>>
>>> Hmm thats interesting then. You could try using rpcdebug -m nfsd to
>>> turn on some of the debugging to look around the internals and
>>> figure out whats going on. If you pass -v it will give you all of
>>> the potential flags.
>>>
>>> >
>>> >>I think that is the current problem. Which makes perfect sense.
>>> If
>>> >>your kernel threads don't get started with max privilege then the
>>> >>server would be denied access on all of the file attributes and
>>> >>wouldn't be able to ship it over the wire properly.
>>> >
>>> >OK. I haven't had to do anything with kernel threads so far.
>>> >Where is NFS setting these up? Poking around fs/nfsd looks like
>>> >the place, but I haven't seen anything there that makes it look
>>> >like they would be running without capabilities. Clearly, that's
>>> >what I'm seeing. It looks as if the credential of nfsd does not
>>> >match what /proc reports. Bother.
>>> >
>>>
>>> I'm not entirely sure whats up either. If you want to look for the
>>> NFSd threads they are in fs/nfsd/nfssvc.c. The main function starts
>>> on line 487.
>>
>> I'm not following the discussion, but: maybe you want to look at
>> fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
>> cap_{drop/raise}_nfsd_set() calls at the end.
>>
>> --b.
>
>
> I'm not as familiar with the capabilities code as Casey is so I'll
> leave this ball in his court. I think you are correct though and the
> problem is that NFSd is dropping and raising caps and we need to make
> sure that MAC_ADMIN and MAC_OVERRIDE is in there in the SMACK case.
>
> --
> This message was distributed to subscribers of the selinux mailing
> list.
> If you no longer wish to subscribe, send mail to
> [email protected] with
> the words "unsubscribe selinux" without quotes as the message.


I think I found the offending code. I can't test it for a while so
hopefully Casey can.

In include/linux/capability.h we have the following defines


# define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
| CAP_TO_MASK(CAP_MKNOD) \
| CAP_TO_MASK(CAP_DAC_OVERRIDE) \
| CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
| CAP_TO_MASK(CAP_FOWNER) \
| CAP_TO_MASK(CAP_FSETID))

# define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))

#if _KERNEL_CAPABILITY_U32S != 2
# error Fix up hand-coded capability macro initializers
#else /* HAND-CODED capability initializers */

# define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
# define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
| CAP_TO_MASK(CAP_LINUX_IMMUTABLE),
\
CAP_FS_MASK_B1 } })
# define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
| CAP_TO_MASK(CAP_SYS_RESOURCE), \
CAP_FS_MASK_B1 } })

So raise and drop nfsd caps uses CAP_NFSD_SET. In CAP_NFSD_SET we have
CAP_MAC_OVERRIDE but we don't have CAP_MAC_ADMIN. I think maybe if we
had both then Casey should be able to use the code with SMACK. However
I'm not sure what implications this has for every other LSM. Honestly
I'm not sure if we use either of those caps for SELinux at all (I think
we ignore them completely).


Maybe if CAP_FS_MASK_B1 was like this it would work.

# define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE) \
)




2012-11-13 12:55:51

by Steve Dickson

[permalink] [raw]
Subject: Re: Labeled NFS [v5]



On 12/11/12 20:39, Dave Quigley wrote:
> If you're ok with non Fedora kernel images I can try to put up a tree either tonight or tomorrow with the patches that you just need to build and install. That plus the one patch for nfs-utils should make everything work.
I'm good with that....

steved.


2012-11-16 04:59:02

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

>> I'm not sure what the proposed hook would be for except to identify it
>> as concerned with nfs. Perhaps the hook could return the names of
>> attributes that it wants nfs to provide.
>>
>
> I'm not quite sure what you're proposing? I'm sure someone would find
> another use for this hook though. The inode_getsecctx hook we made for
> Labeled NFS was already merged because it was needed for providing
> "persistent" label support for sysfs (meaning that it persisted inode
> eviction from memory). The problem is that we have no real way to ask in
> the NFS code if this is an LSM that can be used with Labeled NFS. In the
> xattr code we have the new ismaclabel hook we add which allows us to
> verify the xattr used as belonging to a label based LSM however we need
> an xattr from userspace for that. The reason this is required is that
> the server will need to fill out its capability mask to indicate it
> supports security labeling. In addition the client also needs to know if
> its running a security label based LSM because it will need to mask out
> the label fattr bit from its getattr calls if it doesn't support it. We
> can override this in SELinux by giving it a context mount but if we
> don't then it will need to know whether or not to be pulling security
> labels back.
>

[Resending because I sent it from the wrong identity.]

I think the point I'm trying to make is that we need to define the
interface which if you implement it you are supported. For label
import/export we have inode_{get,set,notify}secctx. For checking for
xattr suitibility we have the new ismaclabel lsm call. Now the final
thing we need to do is a call to determine if the lsm is suitable for
Labeled NFS export meaning that it agrees to the semantics. Is
inode{get,set,notify}_secctx and ismaclabel sufficient? I'm tempted to
say we can make a call to inode_getsecctx and if it failes with
EOPNOTSUPP we say we don't support it but then we need an initial file
to call that on. This is why I'd rather have a LSM call that we can make
that gives us a yes/no answer.

Dave


2012-11-12 15:03:15

by Dave Quigley

[permalink] [raw]
Subject: Re: [PATCH 02/13] Security: Add Hook to test if the particular xattr is part of a MAC model.

On 11/12/2012 7:15 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 01:15:36AM -0500, David Quigley wrote:
>> From: David Quigley <[email protected]>
>>
>> The interface to request security labels from user space is the xattr
>> interface. When requesting the security label from an NFS server it is
>> important to make sure the requested xattr
>
> I'm confused--clients can't request xattrs from NFS servers. I must be
> reading this wrong, but I'm not sure what you meant.
>
> --b.
>

Generically clients can't use xattrs from NFS servers but the LSM method
for getting labels is through the xattr interface. THe point of this is
if someone selects security.capability that we don't translate that into
a call in labeled nfs to get the security label. We only want label
based LSMs to cause a getfattr on the server to grab the label and
populate the inode with that information. Currently if you use
security.selinux or security.smack then labeled nfs will handle the
translation of that into a get/setfattr on the security_label attribute
in NFSv4.


>> actually is a MAC label. This allows
>> us to make sure that we get the desired semantics from the attribute instead of
>> something else such as capabilities or a time based LSM.
>>
>> Signed-off-by: Matthew N. Dodd <[email protected]>
>> Signed-off-by: Miguel Rodel Felipe <[email protected]>
>> Signed-off-by: Phua Eu Gene <[email protected]>
>> Signed-off-by: Khin Mi Mi Aung <[email protected]>
>> Signed-off-by: David Quigley <[email protected]>
>> ---
>> include/linux/security.h | 14 ++++++++++++++
>> security/capability.c | 6 ++++++
>> security/security.c | 6 ++++++
>> security/selinux/hooks.c | 6 ++++++
>> security/smack/smack_lsm.c | 11 +++++++++++
>> 5 files changed, 43 insertions(+)
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index c9f5eec..167bdd5 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -1301,6 +1301,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>> * @pages contains the number of pages.
>> * Return 0 if permission is granted.
>> *
>> + * @ismaclabel:
>> + * Check if the extended attribute specified by @name
>> + * represents a MAC label. Returns 0 if name is a MAC
>> + * attribute otherwise returns non-zero.
>> + * @name full extended attribute name to check against
>> + * LSM as a MAC label.
>> + *
>> * @secid_to_secctx:
>> * Convert secid to security context. If secdata is NULL the length of
>> * the result will be returned in seclen, but no secdata will be returned.
>> @@ -1581,6 +1588,7 @@ struct security_operations {
>>
>> int (*getprocattr) (struct task_struct *p, char *name, char **value);
>> int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
>> + int (*ismaclabel) (const char *name);
>> int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
>> int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
>> void (*release_secctx) (char *secdata, u32 seclen);
>> @@ -1829,6 +1837,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
>> int security_getprocattr(struct task_struct *p, char *name, char **value);
>> int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
>> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
>> +int security_ismaclabel(const char *name);
>> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
>> int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
>> void security_release_secctx(char *secdata, u32 seclen);
>> @@ -2512,6 +2521,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
>> return cap_netlink_send(sk, skb);
>> }
>>
>> +static inline int security_ismaclabel(const char *name)
>> +{
>> + return 0;
>> +}
>> +
>> static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>> {
>> return -EOPNOTSUPP;
>> diff --git a/security/capability.c b/security/capability.c
>> index f1eb284..9071447 100644
>> --- a/security/capability.c
>> +++ b/security/capability.c
>> @@ -797,6 +797,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
>> return -EINVAL;
>> }
>>
>> +static int cap_ismaclabel(const char *name)
>> +{
>> + return 0;
>> +}
>> +
>> static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>> {
>> return -EOPNOTSUPP;
>> @@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
>> set_to_cap_if_null(ops, d_instantiate);
>> set_to_cap_if_null(ops, getprocattr);
>> set_to_cap_if_null(ops, setprocattr);
>> + set_to_cap_if_null(ops, ismaclabel);
>> set_to_cap_if_null(ops, secid_to_secctx);
>> set_to_cap_if_null(ops, secctx_to_secid);
>> set_to_cap_if_null(ops, release_secctx);
>> diff --git a/security/security.c b/security/security.c
>> index b4b2017..a7bee7b 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -1047,6 +1047,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
>> return security_ops->netlink_send(sk, skb);
>> }
>>
>> +int security_ismaclabel(const char *name)
>> +{
>> + return security_ops->ismaclabel(name);
>> +}
>> +EXPORT_SYMBOL(security_ismaclabel);
>> +
>> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>> {
>> return security_ops->secid_to_secctx(secid, secdata, seclen);
>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> index 22d9adf..f7c4899 100644
>> --- a/security/selinux/hooks.c
>> +++ b/security/selinux/hooks.c
>> @@ -5401,6 +5401,11 @@ abort_change:
>> return error;
>> }
>>
>> +static int selinux_ismaclabel(const char *name)
>> +{
>> + return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
>> +}
>> +
>> static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>> {
>> return security_sid_to_context(secid, secdata, seclen);
>> @@ -5639,6 +5644,7 @@ static struct security_operations selinux_ops = {
>> .getprocattr = selinux_getprocattr,
>> .setprocattr = selinux_setprocattr,
>>
>> + .ismaclabel = selinux_ismaclabel,
>> .secid_to_secctx = selinux_secid_to_secctx,
>> .secctx_to_secid = selinux_secctx_to_secid,
>> .release_secctx = selinux_release_secctx,
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index 38be92c..82c3c72 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void *vrule)
>> #endif /* CONFIG_AUDIT */
>>
>> /**
>> + * smack_ismaclabel - check if xattr @name references a smack MAC label
>> + * @name: Full xattr name to check.
>> + */
>> +static int smack_ismaclabel(const char *name)
>> +{
>> + return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
>> +}
>> +
>> +
>> +/**
>> * smack_secid_to_secctx - return the smack label for a secid
>> * @secid: incoming integer
>> * @secdata: destination
>> @@ -3530,6 +3540,7 @@ struct security_operations smack_ops = {
>> .audit_rule_free = smack_audit_rule_free,
>> #endif /* CONFIG_AUDIT */
>>
>> + .ismaclabel = smack_ismaclabel,
>> .secid_to_secctx = smack_secid_to_secctx,
>> .secctx_to_secid = smack_secctx_to_secid,
>> .release_secctx = smack_release_secctx,
>> --
>> 1.7.11.7
>>
>


2012-11-12 14:46:00

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 05/13] KConfig: Add KConfig entries for Labeled NFS

On Mon, Nov 12, 2012 at 01:15:39AM -0500, David Quigley wrote:
> From: David Quigley <[email protected]>
>
> This patch adds two entries into the fs/KConfig file. The first entry
> NFS_V4_SECURITY_LABEL enables security label support for the NFSv4 client while
> the second entry NFSD_V4_SECURITY_LABEL enables security labeling support on
> the server side.
>
> Signed-off-by: Matthew N. Dodd <[email protected]>
> Signed-off-by: Miguel Rodel Felipe <[email protected]>
> Signed-off-by: Phua Eu Gene <[email protected]>
> Signed-off-by: Khin Mi Mi Aung <[email protected]>
> Signed-off-by: David Quigley <[email protected]>
> ---
> fs/nfs/Kconfig | 16 ++++++++++++++++
> fs/nfsd/Kconfig | 13 +++++++++++++
> 2 files changed, 29 insertions(+)
>
> diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
> index 13ca196..0077197 100644
> --- a/fs/nfs/Kconfig
> +++ b/fs/nfs/Kconfig
> @@ -131,6 +131,22 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
> If the NFS client is unchanged from the upstream kernel, this
> option should be set to the default "kernel.org".
>
> +config NFS_V4_SECURITY_LABEL
> + bool "Provide Security Label support for NFSv4 client"
> + depends on NFS_V4 && SECURITY
> + help
> +
> + Say Y here if you want enable fine-grained security label attribute
> + support for NFS version 4. Security labels allow security modules like
> + SELinux and Smack to label files to facilitate enforcement of their policies.
> + Without this an NFSv4 mount will have the same label on each file.
> +
> + If you do not wish to enable fine-grained security labels SELinux or
> + Smack policies on NFSv4 files, say N.

Here and below we also need some warning abouot the current state of
this: we definitely want to warn any distro that might be tempted to
turn this on by default that there's still a chance of
backwards-incompatible protocol changes.

--b.

> +
> +
> + If unsure, say N.
> +
> config ROOT_NFS
> bool "Root file system on NFS"
> depends on NFS_FS=y && IP_PNP
> diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
> index 8df1ea4..75ba894 100644
> --- a/fs/nfsd/Kconfig
> +++ b/fs/nfsd/Kconfig
> @@ -81,6 +81,19 @@ config NFSD_V4
>
> If unsure, say N.
>
> +config NFSD_V4_SECURITY_LABEL
> + bool "Provide Security Label support for NFSv4 server"
> + depends on NFSD_V4 && SECURITY
> + help
> +
> + Say Y here if you want enable fine-grained security label attribute
> + support for NFS version 4. Security labels allow security modules like
> + SELinux and Smack to label files to facilitate enforcement of their policies.
> + Without this an NFSv4 mount will have the same label on each file.
> +
> + If you do not wish to enable fine-grained security labels SELinux or
> + Smack policies on NFSv4 files, say N.
> +
> config NFSD_FAULT_INJECTION
> bool "NFS server manual fault injection"
> depends on NFSD_V4 && DEBUG_KERNEL
> --
> 1.7.11.7
>

2012-11-12 15:43:19

by David Quigley

[permalink] [raw]
Subject: Re: [PATCH 10/13] NFS: Add label lifecycle management

On 11/12/2012 10:33 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 01:15:44AM -0500, David Quigley wrote:
>> > From David Quigley<[email protected]>
>>
>> This patch adds the lifecycle management for the security label structure
>> introduced in an earlier patch. The label is not used yet but allocations and
>> freeing of the structure is handled.
>>
>> Signed-off-by: Matthew N. Dodd<[email protected]>
>> Signed-off-by: Miguel Rodel Felipe<[email protected]>
>> Signed-off-by: Phua Eu Gene<[email protected]>
>> Signed-off-by: Khin Mi Mi Aung<[email protected]>
>> Signed-off-by: David Quigley<[email protected]>
>> ---
>> fs/nfs/dir.c | 30 +++++++++++++-
>> fs/nfs/getroot.c | 1 -
>> fs/nfs/inode.c | 13 ++++++
>> fs/nfs/nfs4proc.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
>> 4 files changed, 156 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
>> index 1339e44..561d2fb 100644
>> --- a/fs/nfs/dir.c
>> +++ b/fs/nfs/dir.c
>> @@ -581,7 +581,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
>> entry.fh = nfs_alloc_fhandle();
>> entry.fattr = nfs_alloc_fattr();
>> entry.server = NFS_SERVER(inode);
>> - if (entry.fh == NULL || entry.fattr == NULL)
>> + entry.label = nfs4_label_alloc(GFP_NOWAIT);
>> + if (entry.fh == NULL || entry.fattr == NULL || entry.label == NULL)
>> goto out;
>>
>> array = nfs_readdir_get_array(page);
>> @@ -616,6 +617,7 @@ out_release_array:
>> out:
>> nfs_free_fattr(entry.fattr);
>> nfs_free_fhandle(entry.fh);
>> + nfs4_label_free(entry.label);
>> return status;
>> }
>>
>> @@ -1077,6 +1079,14 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
>> if (fhandle == NULL || fattr == NULL)
>> goto out_error;
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
>> + label = nfs4_label_alloc(GFP_NOWAIT);
>> + if (label == NULL)
>> + goto out_error;
>> + }
>> +#endif
> We usually try to avoid sprinkling too many #ifdef's around the code.
> Do we really need these? (E.g. can't we ensure that
> nfs_server_capable() will return the right thing when labelled NFS is
> compiled out?)
>
> --b.

That is probably a better way of handling this. We'll look into putting
the check into nfs_server_capable instead.


>> +
>> error = NFS_PROTO(dir)->lookup(dir,&dentry->d_name, fhandle, fattr, label);
>> if (error)
>> goto out_bad;
>> @@ -1087,6 +1097,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
>>
>> nfs_free_fattr(fattr);
>> nfs_free_fhandle(fhandle);
>> +
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
>> + nfs4_label_free(label);
>> +#endif
>> +
>> out_set_verifier:
>> nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
>> out_valid:
>> @@ -1123,6 +1139,7 @@ out_zap_parent:
>> out_error:
>> nfs_free_fattr(fattr);
>> nfs_free_fhandle(fhandle);
>> + nfs4_label_free(label);
>> dput(parent);
>> dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n",
>> __func__, dentry->d_parent->d_name.name,
>> @@ -1235,6 +1252,13 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
>> if (fhandle == NULL || fattr == NULL)
>> goto out;
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
>> + label = nfs4_label_alloc(GFP_NOWAIT);
>> + if (label == NULL)
>> + goto out;
>> + }
>> +#endif
>> parent = dentry->d_parent;
>> /* Protect against concurrent sillydeletes */
>> nfs_block_sillyrename(parent);
>> @@ -1264,6 +1288,10 @@ no_entry:
>> out_unblock_sillyrename:
>> nfs_unblock_sillyrename(parent);
>> out:
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
>> + nfs4_label_free(label);
>> +#endif
>> nfs_free_fattr(fattr);
>> nfs_free_fhandle(fhandle);
>> return res;
>> diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
>> index 3b68bb6..14bd667 100644
>> --- a/fs/nfs/getroot.c
>> +++ b/fs/nfs/getroot.c
>> @@ -75,7 +75,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
>> struct nfs_fsinfo fsinfo;
>> struct dentry *ret;
>> struct inode *inode;
>> - struct nfs4_label *label = NULL;
>> void *name = kstrdup(devname, GFP_KERNEL);
>> int error;
>>
>> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
>> index daca08c..ab08d0d 100644
>> --- a/fs/nfs/inode.c
>> +++ b/fs/nfs/inode.c
>> @@ -835,6 +835,15 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
>> goto out;
>>
>> nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
>> + label = nfs4_label_alloc(GFP_KERNEL);
>> + if (label == NULL) {
>> + status = -ENOMEM;
>> + goto out;
>> + }
>> + }
>> +#endif
>> status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
>> if (status != 0) {
>> dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
>> @@ -864,6 +873,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
>> (long long)NFS_FILEID(inode));
>>
>> out:
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
>> + nfs4_label_free(label);
>> +#endif
>> nfs_free_fattr(fattr);
>> return status;
>> }
>> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
>> index 8e0378c..4ab2738 100644
>> --- a/fs/nfs/nfs4proc.c
>> +++ b/fs/nfs/nfs4proc.c
>> @@ -865,9 +865,16 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
>> p = kzalloc(sizeof(*p), gfp_mask);
>> if (p == NULL)
>> goto err;
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL) {
>> + p->f_label = nfs4_label_alloc(gfp_mask);
>> + if (p->f_label == NULL)
>> + goto err_free_p;
>> + }
>> +#endif
>> p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
>> if (p->o_arg.seqid == NULL)
>> - goto err_free;
>> + goto err_free_label;
>> nfs_sb_active(dentry->d_sb);
>> p->dentry = dget(dentry);
>> p->dir = parent;
>> @@ -910,7 +917,13 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
>> nfs4_init_opendata_res(p);
>> kref_init(&p->kref);
>> return p;
>> -err_free:
>> +
>> +err_free_label:
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL)
>> + nfs4_label_free(p->f_label);
>> +#endif
>> +err_free_p:
>> kfree(p);
>> err:
>> dput(parent);
>> @@ -927,6 +940,10 @@ static void nfs4_opendata_free(struct kref *kref)
>> if (p->state != NULL)
>> nfs4_put_open_state(p->state);
>> nfs4_put_state_owner(p->owner);
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (p->o_arg.server->caps& NFS_CAP_SECURITY_LABEL)
>> + nfs4_label_free(p->f_label);
>> +#endif
>> dput(p->dir);
>> dput(p->dentry);
>> nfs_sb_deactive(sb);
>> @@ -1998,6 +2015,16 @@ static int _nfs4_do_open(struct inode *dir,
>> if (opendata == NULL)
>> goto err_put_state_owner;
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (label&& nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
>> + olabel = nfs4_label_alloc(GFP_KERNEL);
>> + if (olabel == NULL) {
>> + status = -ENOMEM;
>> + goto err_opendata_put;
>> + }
>> + }
>> +#endif
>> +
>> if (ctx_th&& server->attr_bitmask[2]& FATTR4_WORD2_MDSTHRESHOLD) {
>> opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
>> if (!opendata->f_attr.mdsthreshold)
>> @@ -2041,6 +2068,10 @@ static int _nfs4_do_open(struct inode *dir,
>> kfree(opendata->f_attr.mdsthreshold);
>> opendata->f_attr.mdsthreshold = NULL;
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
>> + nfs4_label_free(olabel);
>> +#endif
>> nfs4_opendata_put(opendata);
>> nfs4_put_state_owner(sp);
>> *res = state;
>> @@ -2607,6 +2638,12 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
>> return error;
>> }
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + label = nfs4_label_alloc(GFP_KERNEL);
>> + if (label == NULL)
>> + return -ENOMEM;
>> +#endif
>> +
>> error = nfs4_proc_getattr(server, mntfh, fattr, label);
>> if (error< 0) {
>> dprintk("nfs4_get_root: getattr error = %d\n", -error);
>> @@ -2617,6 +2654,11 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
>> !nfs_fsid_equal(&server->fsid,&fattr->fsid))
>> memcpy(&server->fsid,&fattr->fsid, sizeof(server->fsid));
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL)
>> + nfs4_label_free(label);
>> +#endif
>> +
>> return error;
>> }
>>
>> @@ -2728,6 +2770,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
>> if (pnfs_ld_layoutret_on_setattr(inode))
>> pnfs_return_layout(inode);
>>
>> + olabel = nfs4_label_alloc(GFP_KERNEL);
>> + if (olabel == NULL)
>> + return -ENOMEM;
>> +
>> nfs_fattr_init(fattr);
>>
>> /* Deal with open(O_TRUNC) */
>> @@ -2905,12 +2951,27 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
>> res.fattr = nfs_alloc_fattr();
>> if (res.fattr == NULL)
>> return -ENOMEM;
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL) {
>> + res.label = nfs4_label_alloc(GFP_KERNEL);
>> + if (res.label == NULL) {
>> + status = -ENOMEM;
>> + goto out;
>> + }
>> + }
>> +#endif
>>
>> status = nfs4_call_sync(server->client, server,&msg,&args.seq_args,&res.seq_res, 0);
>> if (!status) {
>> nfs_access_set_mask(entry, res.access);
>> nfs_refresh_inode(inode, res.fattr, res.label);
>> }
>> +
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL)
>> + nfs4_label_free(res.label);
>> +#endif
>> +out:
>> nfs_free_fattr(res.fattr);
>> return status;
>> }
>> @@ -3034,6 +3095,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
>> status = nfs4_call_sync(server->client, server,&msg,&args.seq_args,&res.seq_res, 1);
>> if (status == 0)
>> update_changeattr(dir,&res.cinfo);
>> +
>> return status;
>> }
>>
>> @@ -3079,6 +3141,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
>> if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
>> return 0;
>> update_changeattr(dir,&res->cinfo);
>> +
>> return 1;
>> }
>>
>> @@ -3139,12 +3202,33 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
>> .rpc_resp =&res,
>> };
>> int status = -ENOMEM;
>> +
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL) {
>> + res.old_label = nfs4_label_alloc(GFP_NOWAIT);
>> + if (res.old_label == NULL)
>> + goto out;
>> + res.new_label = nfs4_label_alloc(GFP_NOWAIT);
>> + if (res.new_label == NULL) {
>> + nfs4_label_free(res.old_label);
>> + goto out;
>> + }
>> + }
>> +#endif
>>
>> status = nfs4_call_sync(server->client, server,&msg,&arg.seq_args,&res.seq_res, 1);
>> if (!status) {
>> update_changeattr(old_dir,&res.old_cinfo);
>> update_changeattr(new_dir,&res.new_cinfo);
>> }
>> +
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL) {
>> + nfs4_label_free(res.old_label);
>> + nfs4_label_free(res.new_label);
>> + }
>> +#endif
>> +out:
>> return status;
>> }
>>
>> @@ -3186,11 +3270,25 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
>> if (res.fattr == NULL)
>> goto out;
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL) {
>> + res.label = nfs4_label_alloc(GFP_KERNEL);
>> + if (res.label == NULL)
>> + goto out;
>> + }
>> +#endif
>> +
>> status = nfs4_call_sync(server->client, server,&msg,&arg.seq_args,&res.seq_res, 1);
>> if (!status) {
>> update_changeattr(dir,&res.cinfo);
>> nfs_post_op_update_inode(inode, res.fattr, res.label);
>> }
>> +
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL)
>> + nfs4_label_free(res.label);
>> +#endif
>> +
>> out:
>> nfs_free_fattr(res.fattr);
>> return status;
>> @@ -3226,6 +3324,13 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
>> if (data != NULL) {
>> struct nfs_server *server = NFS_SERVER(dir);
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (server->caps& NFS_CAP_SECURITY_LABEL) {
>> + data->label = nfs4_label_alloc(GFP_KERNEL);
>> + if (data->label == NULL)
>> + goto out_free;
>> + }
>> +#endif
>> data->msg.rpc_proc =&nfs4_procedures[NFSPROC4_CLNT_CREATE];
>> data->msg.rpc_argp =&data->arg;
>> data->msg.rpc_resp =&data->res;
>> @@ -3242,6 +3347,9 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
>> nfs_fattr_init(data->res.fattr);
>> }
>> return data;
>> +out_free:
>> + kfree(data);
>> + return NULL;
>> }
>>
>> static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
>> @@ -3257,6 +3365,10 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
>>
>> static void nfs4_free_createdata(struct nfs4_createdata *data)
>> {
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> + if (data->arg.server->caps& NFS_CAP_SECURITY_LABEL)
>> + nfs4_label_free(data->label);
>> +#endif
>> kfree(data);
>> }
>>
>> --
>> 1.7.11.7
>>


2012-11-12 15:33:20

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 10/13] NFS: Add label lifecycle management

On Mon, Nov 12, 2012 at 01:15:44AM -0500, David Quigley wrote:
> >From David Quigley <[email protected]>
>
> This patch adds the lifecycle management for the security label structure
> introduced in an earlier patch. The label is not used yet but allocations and
> freeing of the structure is handled.
>
> Signed-off-by: Matthew N. Dodd <[email protected]>
> Signed-off-by: Miguel Rodel Felipe <[email protected]>
> Signed-off-by: Phua Eu Gene <[email protected]>
> Signed-off-by: Khin Mi Mi Aung <[email protected]>
> Signed-off-by: David Quigley <[email protected]>
> ---
> fs/nfs/dir.c | 30 +++++++++++++-
> fs/nfs/getroot.c | 1 -
> fs/nfs/inode.c | 13 ++++++
> fs/nfs/nfs4proc.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 4 files changed, 156 insertions(+), 4 deletions(-)
>
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 1339e44..561d2fb 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -581,7 +581,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
> entry.fh = nfs_alloc_fhandle();
> entry.fattr = nfs_alloc_fattr();
> entry.server = NFS_SERVER(inode);
> - if (entry.fh == NULL || entry.fattr == NULL)
> + entry.label = nfs4_label_alloc(GFP_NOWAIT);
> + if (entry.fh == NULL || entry.fattr == NULL || entry.label == NULL)
> goto out;
>
> array = nfs_readdir_get_array(page);
> @@ -616,6 +617,7 @@ out_release_array:
> out:
> nfs_free_fattr(entry.fattr);
> nfs_free_fhandle(entry.fh);
> + nfs4_label_free(entry.label);
> return status;
> }
>
> @@ -1077,6 +1079,14 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
> if (fhandle == NULL || fattr == NULL)
> goto out_error;
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
> + label = nfs4_label_alloc(GFP_NOWAIT);
> + if (label == NULL)
> + goto out_error;
> + }
> +#endif

We usually try to avoid sprinkling too many #ifdef's around the code.
Do we really need these? (E.g. can't we ensure that
nfs_server_capable() will return the right thing when labelled NFS is
compiled out?)

--b.

> +
> error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
> if (error)
> goto out_bad;
> @@ -1087,6 +1097,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
>
> nfs_free_fattr(fattr);
> nfs_free_fhandle(fhandle);
> +
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
> + nfs4_label_free(label);
> +#endif
> +
> out_set_verifier:
> nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
> out_valid:
> @@ -1123,6 +1139,7 @@ out_zap_parent:
> out_error:
> nfs_free_fattr(fattr);
> nfs_free_fhandle(fhandle);
> + nfs4_label_free(label);
> dput(parent);
> dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n",
> __func__, dentry->d_parent->d_name.name,
> @@ -1235,6 +1252,13 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
> if (fhandle == NULL || fattr == NULL)
> goto out;
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
> + label = nfs4_label_alloc(GFP_NOWAIT);
> + if (label == NULL)
> + goto out;
> + }
> +#endif
> parent = dentry->d_parent;
> /* Protect against concurrent sillydeletes */
> nfs_block_sillyrename(parent);
> @@ -1264,6 +1288,10 @@ no_entry:
> out_unblock_sillyrename:
> nfs_unblock_sillyrename(parent);
> out:
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
> + nfs4_label_free(label);
> +#endif
> nfs_free_fattr(fattr);
> nfs_free_fhandle(fhandle);
> return res;
> diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
> index 3b68bb6..14bd667 100644
> --- a/fs/nfs/getroot.c
> +++ b/fs/nfs/getroot.c
> @@ -75,7 +75,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
> struct nfs_fsinfo fsinfo;
> struct dentry *ret;
> struct inode *inode;
> - struct nfs4_label *label = NULL;
> void *name = kstrdup(devname, GFP_KERNEL);
> int error;
>
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index daca08c..ab08d0d 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -835,6 +835,15 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
> goto out;
>
> nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
> + label = nfs4_label_alloc(GFP_KERNEL);
> + if (label == NULL) {
> + status = -ENOMEM;
> + goto out;
> + }
> + }
> +#endif
> status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
> if (status != 0) {
> dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
> @@ -864,6 +873,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
> (long long)NFS_FILEID(inode));
>
> out:
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
> + nfs4_label_free(label);
> +#endif
> nfs_free_fattr(fattr);
> return status;
> }
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 8e0378c..4ab2738 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -865,9 +865,16 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
> p = kzalloc(sizeof(*p), gfp_mask);
> if (p == NULL)
> goto err;
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL) {
> + p->f_label = nfs4_label_alloc(gfp_mask);
> + if (p->f_label == NULL)
> + goto err_free_p;
> + }
> +#endif
> p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
> if (p->o_arg.seqid == NULL)
> - goto err_free;
> + goto err_free_label;
> nfs_sb_active(dentry->d_sb);
> p->dentry = dget(dentry);
> p->dir = parent;
> @@ -910,7 +917,13 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
> nfs4_init_opendata_res(p);
> kref_init(&p->kref);
> return p;
> -err_free:
> +
> +err_free_label:
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL)
> + nfs4_label_free(p->f_label);
> +#endif
> +err_free_p:
> kfree(p);
> err:
> dput(parent);
> @@ -927,6 +940,10 @@ static void nfs4_opendata_free(struct kref *kref)
> if (p->state != NULL)
> nfs4_put_open_state(p->state);
> nfs4_put_state_owner(p->owner);
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (p->o_arg.server->caps & NFS_CAP_SECURITY_LABEL)
> + nfs4_label_free(p->f_label);
> +#endif
> dput(p->dir);
> dput(p->dentry);
> nfs_sb_deactive(sb);
> @@ -1998,6 +2015,16 @@ static int _nfs4_do_open(struct inode *dir,
> if (opendata == NULL)
> goto err_put_state_owner;
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (label && nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
> + olabel = nfs4_label_alloc(GFP_KERNEL);
> + if (olabel == NULL) {
> + status = -ENOMEM;
> + goto err_opendata_put;
> + }
> + }
> +#endif
> +
> if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
> opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
> if (!opendata->f_attr.mdsthreshold)
> @@ -2041,6 +2068,10 @@ static int _nfs4_do_open(struct inode *dir,
> kfree(opendata->f_attr.mdsthreshold);
> opendata->f_attr.mdsthreshold = NULL;
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
> + nfs4_label_free(olabel);
> +#endif
> nfs4_opendata_put(opendata);
> nfs4_put_state_owner(sp);
> *res = state;
> @@ -2607,6 +2638,12 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
> return error;
> }
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + label = nfs4_label_alloc(GFP_KERNEL);
> + if (label == NULL)
> + return -ENOMEM;
> +#endif
> +
> error = nfs4_proc_getattr(server, mntfh, fattr, label);
> if (error < 0) {
> dprintk("nfs4_get_root: getattr error = %d\n", -error);
> @@ -2617,6 +2654,11 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
> !nfs_fsid_equal(&server->fsid, &fattr->fsid))
> memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL)
> + nfs4_label_free(label);
> +#endif
> +
> return error;
> }
>
> @@ -2728,6 +2770,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
> if (pnfs_ld_layoutret_on_setattr(inode))
> pnfs_return_layout(inode);
>
> + olabel = nfs4_label_alloc(GFP_KERNEL);
> + if (olabel == NULL)
> + return -ENOMEM;
> +
> nfs_fattr_init(fattr);
>
> /* Deal with open(O_TRUNC) */
> @@ -2905,12 +2951,27 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
> res.fattr = nfs_alloc_fattr();
> if (res.fattr == NULL)
> return -ENOMEM;
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL) {
> + res.label = nfs4_label_alloc(GFP_KERNEL);
> + if (res.label == NULL) {
> + status = -ENOMEM;
> + goto out;
> + }
> + }
> +#endif
>
> status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
> if (!status) {
> nfs_access_set_mask(entry, res.access);
> nfs_refresh_inode(inode, res.fattr, res.label);
> }
> +
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL)
> + nfs4_label_free(res.label);
> +#endif
> +out:
> nfs_free_fattr(res.fattr);
> return status;
> }
> @@ -3034,6 +3095,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
> status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
> if (status == 0)
> update_changeattr(dir, &res.cinfo);
> +
> return status;
> }
>
> @@ -3079,6 +3141,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
> if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
> return 0;
> update_changeattr(dir, &res->cinfo);
> +
> return 1;
> }
>
> @@ -3139,12 +3202,33 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
> .rpc_resp = &res,
> };
> int status = -ENOMEM;
> +
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL) {
> + res.old_label = nfs4_label_alloc(GFP_NOWAIT);
> + if (res.old_label == NULL)
> + goto out;
> + res.new_label = nfs4_label_alloc(GFP_NOWAIT);
> + if (res.new_label == NULL) {
> + nfs4_label_free(res.old_label);
> + goto out;
> + }
> + }
> +#endif
>
> status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
> if (!status) {
> update_changeattr(old_dir, &res.old_cinfo);
> update_changeattr(new_dir, &res.new_cinfo);
> }
> +
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL) {
> + nfs4_label_free(res.old_label);
> + nfs4_label_free(res.new_label);
> + }
> +#endif
> +out:
> return status;
> }
>
> @@ -3186,11 +3270,25 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
> if (res.fattr == NULL)
> goto out;
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL) {
> + res.label = nfs4_label_alloc(GFP_KERNEL);
> + if (res.label == NULL)
> + goto out;
> + }
> +#endif
> +
> status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
> if (!status) {
> update_changeattr(dir, &res.cinfo);
> nfs_post_op_update_inode(inode, res.fattr, res.label);
> }
> +
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL)
> + nfs4_label_free(res.label);
> +#endif
> +
> out:
> nfs_free_fattr(res.fattr);
> return status;
> @@ -3226,6 +3324,13 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
> if (data != NULL) {
> struct nfs_server *server = NFS_SERVER(dir);
>
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (server->caps & NFS_CAP_SECURITY_LABEL) {
> + data->label = nfs4_label_alloc(GFP_KERNEL);
> + if (data->label == NULL)
> + goto out_free;
> + }
> +#endif
> data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
> data->msg.rpc_argp = &data->arg;
> data->msg.rpc_resp = &data->res;
> @@ -3242,6 +3347,9 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
> nfs_fattr_init(data->res.fattr);
> }
> return data;
> +out_free:
> + kfree(data);
> + return NULL;
> }
>
> static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
> @@ -3257,6 +3365,10 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
>
> static void nfs4_free_createdata(struct nfs4_createdata *data)
> {
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (data->arg.server->caps & NFS_CAP_SECURITY_LABEL)
> + nfs4_label_free(data->label);
> +#endif
> kfree(data);
> }
>
> --
> 1.7.11.7
>

2012-11-12 16:53:16

by David Quigley

[permalink] [raw]
Subject: Re: [PATCH 07/13] NFSv4: Introduce new label structure

On 11/12/2012 11:05 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 10:32:56AM -0500, David P. Quigley wrote:
>> On 11/12/2012 10:13 AM, J. Bruce Fields wrote:
>>> On Mon, Nov 12, 2012 at 01:15:41AM -0500, David Quigley wrote:
>>>> From: David Quigley<[email protected]>
>>>>
>>>> In order to mimic the way that NFSv4 ACLs are implemented we have created a
>>>> structure to be used to pass label data up and down the call chain. This patch
>>>> adds the new structure and new members to the required NFSv4 call structures.
>>>>
>>>> Signed-off-by: Matthew N. Dodd<[email protected]>
>>>> Signed-off-by: Miguel Rodel Felipe<[email protected]>
>>>> Signed-off-by: Phua Eu Gene<[email protected]>
>>>> Signed-off-by: Khin Mi Mi Aung<[email protected]>
>>>> Signed-off-by: David Quigley<[email protected]>
>>>> ---
>>>> fs/nfs/inode.c | 40 ++++++++++++++++++++++++++++++++++++++++
>>>> fs/nfsd/xdr4.h | 3 +++
>>>> include/linux/nfs4.h | 8 ++++++++
>>>> include/linux/nfs_fs.h | 14 ++++++++++++++
>>>> include/linux/nfs_xdr.h | 20 ++++++++++++++++++++
>>>> 5 files changed, 85 insertions(+)
>>>>
>>>> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
>>>> index 5c7325c..0963ad9 100644
>>>> --- a/fs/nfs/inode.c
>>>> +++ b/fs/nfs/inode.c
>>>> @@ -246,6 +246,46 @@ nfs_init_locked(struct inode *inode, void *opaque)
>>>> return 0;
>>>> }
>>>>
>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>>>> +struct nfs4_label *nfs4_label_alloc(gfp_t flags)
>>>> +{
>>>> + struct nfs4_label *label = NULL;
>>>> +
>>>> + label = kzalloc(sizeof(struct nfs4_label) + NFS4_MAXLABELLEN, flags);
>>> NFS4_MAXLABELLEN is 4096, but we usually try to avoid allocating more
>>> than that in a single allocation.
>> Should we make this smaller? I figured a page would be a good upper bound.
> If we could make it small enough so that the above fits in 4096 bytes
> that would be easier.
>
> (What does the protocol say? On a quick glance it doesn't seem to
> impose a limit.)

The spec doesn't limit the size of a label but we thought that a page
would be good. We can make it 4095 to ensure that it will always be in a
page incase a null terminator is added. I believe someone mentioned this
in the past I'm not sure why it didn't make its way in. We initially had
something much larger but Trond chimed in and said that if its larger
than a page something is wrong so we lowered it.

>
>>>> + label->label = (void *)(label + 1);
>>>> + label->len = NFS4_MAXLABELLEN;
>>>> + /* 0 is the null format meaning that the data is not to be translated */
>>>> + label->lfs = 0;
>>>> + label->pi = 0;
>>> What's "pi"?
>>>
>>> --b.
>> In the LFS document we talk about how a policy identifier is a
>> recommended field. It isn't implemented yet as we're setting both
>> the LFS and the PI to 0 but I added it for when we put the LFS
>> mapping daemon in next. The idea is that even though we have a label
>> and we specify the format with the LFS we need to identify what
>> version of policy it is so we can ensure that the actual meaning of
>> a value is correct.
> And, my bad, this is in the spec--sorry, I need to go study it.
>
> --b.
>

Its ok. It's been in the works so long its hard to keep track of it all.

2012-11-14 13:45:40

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
> On 11/13/2012 7:55 AM, Steve Dickson wrote:
> >
> >
> >On 12/11/12 20:39, Dave Quigley wrote:
> >>If you're ok with non Fedora kernel images I can try to put up a tree either tonight or tomorrow with the patches that you just need to build and install. That plus the one patch for nfs-utils should make everything work.
> >I'm good with that....
> >
> >steved.
> >
>
> Ok so if you go to http://www.selinuxproject.org/git you will see a
> repo for lnfs and lnfs-patchset. The instructions at
> http://www.selinuxproject.org/page/Labeled_NFS give you a better
> indication on how to pull the trees. I've attached a patch for NFS
> utils which gives support for security_label/nosecurity_label in
> your /etc/exports file.

Do we need an export option? Is there any reason not to make the
feature available whenever there's support available for it?

--b.

> I've also attached a script called setup
> which should build a test directory called /export with a copy of
> /var/www under it which should be labeled properly. It does all the
> proper SELinux commands to make sure labeling is correct. Once you
> have that setup just mount -t nfs localhost:/ /mnt/lnfs (or wherever
> you want) and you should be good to go. Just ls -Z in /mnt/lnfs/var
> and check to make sure the labels are the same as /export/var. It
> should have the labels showing up in the network transfer. If you
> have any problems just let me know and I can try to help figure them
> out.
>
> Dave

> >From da84919c6957090cd961bb4ce40753820312a845 Mon Sep 17 00:00:00 2001
> From: Dave Quigley <[email protected]>
> Date: Fri, 18 Sep 2009 08:53:58 -0700
> Subject: [PATCH] Add support to specify which exports will provide Labeled NFS support.
>
> diff --git a/support/include/nfs/export.h b/support/include/nfs/export.h
> index 1547a87..b8e2fb0 100644
> --- a/support/include/nfs/export.h
> +++ b/support/include/nfs/export.h
> @@ -17,7 +17,8 @@
> #define NFSEXP_ALLSQUASH 0x0008
> #define NFSEXP_ASYNC 0x0010
> #define NFSEXP_GATHERED_WRITES 0x0020
> -/* 40, 80, 100 unused */
> +#define NFSEXP_SECURITY_LABEL 0x0040 /* Support MAC attribute */
> +/* 80, 100 unused */
> #define NFSEXP_NOHIDE 0x0200
> #define NFSEXP_NOSUBTREECHECK 0x0400
> #define NFSEXP_NOAUTHNLM 0x0800
> diff --git a/support/nfs/exports.c b/support/nfs/exports.c
> index a93941c..8965c8d 100644
> --- a/support/nfs/exports.c
> +++ b/support/nfs/exports.c
> @@ -239,6 +239,8 @@ putexportent(struct exportent *ep)
> fprintf(fp, "%ssync,", (ep->e_flags & NFSEXP_ASYNC)? "a" : "");
> fprintf(fp, "%swdelay,", (ep->e_flags & NFSEXP_GATHERED_WRITES)?
> "" : "no_");
> + fprintf(fp, "%ssecurity_label,", (ep->e_flags & NFSEXP_SECURITY_LABEL)?
> + "" : "no");
> fprintf(fp, "%shide,", (ep->e_flags & NFSEXP_NOHIDE)?
> "no" : "");
> fprintf(fp, "%scrossmnt,", (ep->e_flags & NFSEXP_CROSSMOUNT)?
> @@ -531,6 +533,10 @@ parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr)
> setflags(NFSEXP_GATHERED_WRITES, active, ep);
> else if (!strcmp(opt, "no_wdelay"))
> clearflags(NFSEXP_GATHERED_WRITES, active, ep);
> + else if (strcmp(opt, "security_label") == 0)
> + ep->e_flags |= NFSEXP_SECURITY_LABEL;
> + else if (strcmp(opt, "nosecurity_label") == 0)
> + ep->e_flags &= ~NFSEXP_SECURITY_LABEL;
> else if (strcmp(opt, "root_squash") == 0)
> setflags(NFSEXP_ROOTSQUASH, active, ep);
> else if (!strcmp(opt, "no_root_squash"))
> diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
> index b78957f..6434825 100644
> --- a/utils/exportfs/exportfs.c
> +++ b/utils/exportfs/exportfs.c
> @@ -531,6 +531,8 @@ dump(int verbose)
> c = dumpopt(c, "async");
> if (ep->e_flags & NFSEXP_GATHERED_WRITES)
> c = dumpopt(c, "wdelay");
> + if (ep->e_flags & NFSEXP_SECURITY_LABEL)
> + c = dumpopt(c, "security_label");
> if (ep->e_flags & NFSEXP_NOHIDE)
> c = dumpopt(c, "nohide");
> if (ep->e_flags & NFSEXP_CROSSMOUNT)

> #!/bin/bash
> mkdir /export
> semanage fcontext -a -t mnt_t /export
> mkdir /export/var
> cp -R /var/www /export/var
> semanage fcontext -ae /var /export/var
> restorecon -R /export
>
> echo "/export *(rw,fsid=0,sec=unix,security_label,insecure,no_subtree_check,sync, no_root_squash)" >> /etc/exports
> systemctl restart nfs-server.service


2012-11-14 13:50:18

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/14/2012 08:45, J. Bruce Fields wrote:
> On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>> On 11/13/2012 7:55 AM, Steve Dickson wrote:
>> >
>> >
>> >On 12/11/12 20:39, Dave Quigley wrote:
>> >>If you're ok with non Fedora kernel images I can try to put up a
>> tree either tonight or tomorrow with the patches that you just need to
>> build and install. That plus the one patch for nfs-utils should make
>> everything work.
>> >I'm good with that....
>> >
>> >steved.
>> >
>>
>> Ok so if you go to http://www.selinuxproject.org/git you will see a
>> repo for lnfs and lnfs-patchset. The instructions at
>> http://www.selinuxproject.org/page/Labeled_NFS give you a better
>> indication on how to pull the trees. I've attached a patch for NFS
>> utils which gives support for security_label/nosecurity_label in
>> your /etc/exports file.
>
> Do we need an export option? Is there any reason not to make the
> feature available whenever there's support available for it?
>
> --b.
>
>> I've also attached a script called setup
>> which should build a test directory called /export with a copy of
>> /var/www under it which should be labeled properly. It does all the
>> proper SELinux commands to make sure labeling is correct. Once you
>> have that setup just mount -t nfs localhost:/ /mnt/lnfs (or wherever
>> you want) and you should be good to go. Just ls -Z in /mnt/lnfs/var
>> and check to make sure the labels are the same as /export/var. It
>> should have the labels showing up in the network transfer. If you
>> have any problems just let me know and I can try to help figure them
>> out.
>>
>> Dave
>
>> >From da84919c6957090cd961bb4ce40753820312a845 Mon Sep 17 00:00:00
>> 2001
>> From: Dave Quigley <[email protected]>
>> Date: Fri, 18 Sep 2009 08:53:58 -0700
>> Subject: [PATCH] Add support to specify which exports will provide
>> Labeled NFS support.
>>
>> diff --git a/support/include/nfs/export.h
>> b/support/include/nfs/export.h
>> index 1547a87..b8e2fb0 100644
>> --- a/support/include/nfs/export.h
>> +++ b/support/include/nfs/export.h
>> @@ -17,7 +17,8 @@
>> #define NFSEXP_ALLSQUASH 0x0008
>> #define NFSEXP_ASYNC 0x0010
>> #define NFSEXP_GATHERED_WRITES 0x0020
>> -/* 40, 80, 100 unused */
>> +#define NFSEXP_SECURITY_LABEL 0x0040 /* Support MAC attribute */
>> +/* 80, 100 unused */
>> #define NFSEXP_NOHIDE 0x0200
>> #define NFSEXP_NOSUBTREECHECK 0x0400
>> #define NFSEXP_NOAUTHNLM 0x0800
>> diff --git a/support/nfs/exports.c b/support/nfs/exports.c
>> index a93941c..8965c8d 100644
>> --- a/support/nfs/exports.c
>> +++ b/support/nfs/exports.c
>> @@ -239,6 +239,8 @@ putexportent(struct exportent *ep)
>> fprintf(fp, "%ssync,", (ep->e_flags & NFSEXP_ASYNC)? "a" : "");
>> fprintf(fp, "%swdelay,", (ep->e_flags & NFSEXP_GATHERED_WRITES)?
>> "" : "no_");
>> + fprintf(fp, "%ssecurity_label,", (ep->e_flags &
>> NFSEXP_SECURITY_LABEL)?
>> + "" : "no");
>> fprintf(fp, "%shide,", (ep->e_flags & NFSEXP_NOHIDE)?
>> "no" : "");
>> fprintf(fp, "%scrossmnt,", (ep->e_flags & NFSEXP_CROSSMOUNT)?
>> @@ -531,6 +533,10 @@ parseopts(char *cp, struct exportent *ep, int
>> warn, int *had_subtree_opt_ptr)
>> setflags(NFSEXP_GATHERED_WRITES, active, ep);
>> else if (!strcmp(opt, "no_wdelay"))
>> clearflags(NFSEXP_GATHERED_WRITES, active, ep);
>> + else if (strcmp(opt, "security_label") == 0)
>> + ep->e_flags |= NFSEXP_SECURITY_LABEL;
>> + else if (strcmp(opt, "nosecurity_label") == 0)
>> + ep->e_flags &= ~NFSEXP_SECURITY_LABEL;
>> else if (strcmp(opt, "root_squash") == 0)
>> setflags(NFSEXP_ROOTSQUASH, active, ep);
>> else if (!strcmp(opt, "no_root_squash"))
>> diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
>> index b78957f..6434825 100644
>> --- a/utils/exportfs/exportfs.c
>> +++ b/utils/exportfs/exportfs.c
>> @@ -531,6 +531,8 @@ dump(int verbose)
>> c = dumpopt(c, "async");
>> if (ep->e_flags & NFSEXP_GATHERED_WRITES)
>> c = dumpopt(c, "wdelay");
>> + if (ep->e_flags & NFSEXP_SECURITY_LABEL)
>> + c = dumpopt(c, "security_label");
>> if (ep->e_flags & NFSEXP_NOHIDE)
>> c = dumpopt(c, "nohide");
>> if (ep->e_flags & NFSEXP_CROSSMOUNT)
>
>> #!/bin/bash
>> mkdir /export
>> semanage fcontext -a -t mnt_t /export
>> mkdir /export/var
>> cp -R /var/www /export/var
>> semanage fcontext -ae /var /export/var
>> restorecon -R /export
>>
>> echo "/export
>> *(rw,fsid=0,sec=unix,security_label,insecure,no_subtree_check,sync,
>> no_root_squash)" >> /etc/exports
>> systemctl restart nfs-server.service

I guess we could build it in but I figured an export option allowed
someone to turn off security labeling support if they didn't want it on
that export. What happens to clients when the server returns a cap that
they don't support? Do they mask the bits out?



2012-11-12 12:15:29

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 02/13] Security: Add Hook to test if the particular xattr is part of a MAC model.

On Mon, Nov 12, 2012 at 01:15:36AM -0500, David Quigley wrote:
> From: David Quigley <[email protected]>
>
> The interface to request security labels from user space is the xattr
> interface. When requesting the security label from an NFS server it is
> important to make sure the requested xattr

I'm confused--clients can't request xattrs from NFS servers. I must be
reading this wrong, but I'm not sure what you meant.

--b.

> actually is a MAC label. This allows
> us to make sure that we get the desired semantics from the attribute instead of
> something else such as capabilities or a time based LSM.
>
> Signed-off-by: Matthew N. Dodd <[email protected]>
> Signed-off-by: Miguel Rodel Felipe <[email protected]>
> Signed-off-by: Phua Eu Gene <[email protected]>
> Signed-off-by: Khin Mi Mi Aung <[email protected]>
> Signed-off-by: David Quigley <[email protected]>
> ---
> include/linux/security.h | 14 ++++++++++++++
> security/capability.c | 6 ++++++
> security/security.c | 6 ++++++
> security/selinux/hooks.c | 6 ++++++
> security/smack/smack_lsm.c | 11 +++++++++++
> 5 files changed, 43 insertions(+)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index c9f5eec..167bdd5 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1301,6 +1301,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> * @pages contains the number of pages.
> * Return 0 if permission is granted.
> *
> + * @ismaclabel:
> + * Check if the extended attribute specified by @name
> + * represents a MAC label. Returns 0 if name is a MAC
> + * attribute otherwise returns non-zero.
> + * @name full extended attribute name to check against
> + * LSM as a MAC label.
> + *
> * @secid_to_secctx:
> * Convert secid to security context. If secdata is NULL the length of
> * the result will be returned in seclen, but no secdata will be returned.
> @@ -1581,6 +1588,7 @@ struct security_operations {
>
> int (*getprocattr) (struct task_struct *p, char *name, char **value);
> int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
> + int (*ismaclabel) (const char *name);
> int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
> int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> void (*release_secctx) (char *secdata, u32 seclen);
> @@ -1829,6 +1837,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
> int security_getprocattr(struct task_struct *p, char *name, char **value);
> int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
> +int security_ismaclabel(const char *name);
> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> void security_release_secctx(char *secdata, u32 seclen);
> @@ -2512,6 +2521,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
> return cap_netlink_send(sk, skb);
> }
>
> +static inline int security_ismaclabel(const char *name)
> +{
> + return 0;
> +}
> +
> static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> {
> return -EOPNOTSUPP;
> diff --git a/security/capability.c b/security/capability.c
> index f1eb284..9071447 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -797,6 +797,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
> return -EINVAL;
> }
>
> +static int cap_ismaclabel(const char *name)
> +{
> + return 0;
> +}
> +
> static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> {
> return -EOPNOTSUPP;
> @@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
> set_to_cap_if_null(ops, d_instantiate);
> set_to_cap_if_null(ops, getprocattr);
> set_to_cap_if_null(ops, setprocattr);
> + set_to_cap_if_null(ops, ismaclabel);
> set_to_cap_if_null(ops, secid_to_secctx);
> set_to_cap_if_null(ops, secctx_to_secid);
> set_to_cap_if_null(ops, release_secctx);
> diff --git a/security/security.c b/security/security.c
> index b4b2017..a7bee7b 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1047,6 +1047,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
> return security_ops->netlink_send(sk, skb);
> }
>
> +int security_ismaclabel(const char *name)
> +{
> + return security_ops->ismaclabel(name);
> +}
> +EXPORT_SYMBOL(security_ismaclabel);
> +
> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> {
> return security_ops->secid_to_secctx(secid, secdata, seclen);
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 22d9adf..f7c4899 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5401,6 +5401,11 @@ abort_change:
> return error;
> }
>
> +static int selinux_ismaclabel(const char *name)
> +{
> + return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
> +}
> +
> static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> {
> return security_sid_to_context(secid, secdata, seclen);
> @@ -5639,6 +5644,7 @@ static struct security_operations selinux_ops = {
> .getprocattr = selinux_getprocattr,
> .setprocattr = selinux_setprocattr,
>
> + .ismaclabel = selinux_ismaclabel,
> .secid_to_secctx = selinux_secid_to_secctx,
> .secctx_to_secid = selinux_secctx_to_secid,
> .release_secctx = selinux_release_secctx,
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 38be92c..82c3c72 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void *vrule)
> #endif /* CONFIG_AUDIT */
>
> /**
> + * smack_ismaclabel - check if xattr @name references a smack MAC label
> + * @name: Full xattr name to check.
> + */
> +static int smack_ismaclabel(const char *name)
> +{
> + return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
> +}
> +
> +
> +/**
> * smack_secid_to_secctx - return the smack label for a secid
> * @secid: incoming integer
> * @secdata: destination
> @@ -3530,6 +3540,7 @@ struct security_operations smack_ops = {
> .audit_rule_free = smack_audit_rule_free,
> #endif /* CONFIG_AUDIT */
>
> + .ismaclabel = smack_ismaclabel,
> .secid_to_secctx = smack_secid_to_secctx,
> .secctx_to_secid = smack_secctx_to_secid,
> .release_secctx = smack_release_secctx,
> --
> 1.7.11.7
>

2012-11-29 22:28:19

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/28/2012 6:08 PM, Casey Schaufler wrote:
> On 11/28/2012 5:14 PM, Dave Quigley wrote:
>> On 11/28/2012 1:57 PM, Casey Schaufler wrote:
>>> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>>>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>>>> ...
>>>>>>
>>>>>>
>>>>>> Or I could just give you this link and you should be good to go ;)
>>>>>>
>>>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>>>
>>>>>> I haven't tried it but it should work. If it doesn't let me know and
>>>>>> i'll try to fix it on my end. I'd imagine you might need to yum
>>>>>> remove
>>>>>> nfs-utils first before adding this new one or you could also try an
>>>>>> rpm with the upgrade flag for this instead. Good luck.
>>> ...
>>>
>>>
>>> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
>>> attached stack trace on mount. After mounting I'm getting
>>> denials when I should, but also when I shouldn't.
>>>
>>> I've tried tracking down the issue, but there's a lot going on
>>> that I don't find obvious. I added a dentry_init hook just for
>>> grins, but it's not getting called.
>>>
>>> .
>>>
>>>
>> Any chance of you throwing a kickstart file my way that's configured
>> with SMACK so I can use it for a test box (both server and client)? I
>> can have the guys working with me test for SMACK as well if you
>> provide an appropriate test harness and image for testing.
> I've attached the .config from my Fedora17 machine. Who knows, maybe
> I got something wrong there. I get the error doing the test on the
> loopback interface (mount -t nfs4 localhist:/ /mnt).

I've done some instrumentation and security_ismaclabel() is getting
called with "selinux", but never "SMACK64". I would guess that somewhere
in the tools you're telling the kernel to expect "selinux". Where is
that, so that I can tell it to try "SMACK64" instead?



2012-11-30 14:02:01

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 08:50, Stephen Smalley wrote:
> On 11/30/2012 08:35 AM, David Quigley wrote:
>> On 11/30/2012 08:28, Stephen Smalley wrote:
>>> On 11/30/2012 08:17 AM, David Quigley wrote:
>>>> On 11/30/2012 07:57, David Quigley wrote:
>>>>> On 11/30/2012 07:14, J. Bruce Fields wrote:
>>>>>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>>>>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>>>>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>>>>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>>>>>> >>>I would think that were it not for the case that access is
>>>>>>> denied
>>>>>>> >>>and I get an audit record for nfsd that reports a subject
>>>>>>> >>>label of "_"
>>>>>>> >>>(which is correct for nfsd but not the process attempting
>>>>>>> >>>access) and
>>>>>>> >>>an object label of "WhooHoo", which is correct. The server
>>>>>>> side
>>>>>>> >>>looks like it might be working right, given the information
>>>>>>> that it
>>>>>>> >>>has.
>>>>>>> >>>
>>>>>>> >>
>>>>>>> >>Ok so this is the problem. nfsd is a kernel thread I believe.
>>>>>>> In
>>>>>>> >>SELinux land it has the type kernel_t which is all powerful.
>>>>>>> We
>>>>>>> >>don't
>>>>>>> >>have client label transport yet (That requires RPCSECGSSv3).
>>>>>>> Is
>>>>>>> >>there
>>>>>>> >>a way you can have that kernel thread running as a type that
>>>>>>> has
>>>>>>> >>access to everything?
>>>>>>> >
>>>>>>> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in
>>>>>>> Smackese.
>>>>>>> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of
>>>>>>> fff...fff
>>>>>>> >which
>>>>>>> >is to say, all capabilities.
>>>>>>> >
>>>>>>>
>>>>>>> Hmm thats interesting then. You could try using rpcdebug -m
>>>>>>> nfsd to
>>>>>>> turn on some of the debugging to look around the internals and
>>>>>>> figure out whats going on. If you pass -v it will give you all
>>>>>>> of
>>>>>>> the potential flags.
>>>>>>>
>>>>>>> >
>>>>>>> >>I think that is the current problem. Which makes perfect
>>>>>>> sense. If
>>>>>>> >>your kernel threads don't get started with max privilege then
>>>>>>> the
>>>>>>> >>server would be denied access on all of the file attributes
>>>>>>> and
>>>>>>> >>wouldn't be able to ship it over the wire properly.
>>>>>>> >
>>>>>>> >OK. I haven't had to do anything with kernel threads so far.
>>>>>>> >Where is NFS setting these up? Poking around fs/nfsd looks
>>>>>>> like
>>>>>>> >the place, but I haven't seen anything there that makes it
>>>>>>> look
>>>>>>> >like they would be running without capabilities. Clearly,
>>>>>>> that's
>>>>>>> >what I'm seeing. It looks as if the credential of nfsd does
>>>>>>> not
>>>>>>> >match what /proc reports. Bother.
>>>>>>> >
>>>>>>>
>>>>>>> I'm not entirely sure whats up either. If you want to look for
>>>>>>> the
>>>>>>> NFSd threads they are in fs/nfsd/nfssvc.c. The main function
>>>>>>> starts
>>>>>>> on line 487.
>>>>>>
>>>>>> I'm not following the discussion, but: maybe you want to look at
>>>>>> fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
>>>>>> cap_{drop/raise}_nfsd_set() calls at the end.
>>>>>>
>>>>>> --b.
>>>>>
>>>>>
>>>>> I'm not as familiar with the capabilities code as Casey is so
>>>>> I'll
>>>>> leave this ball in his court. I think you are correct though and
>>>>> the
>>>>> problem is that NFSd is dropping and raising caps and we need to
>>>>> make
>>>>> sure that MAC_ADMIN and MAC_OVERRIDE is in there in the SMACK
>>>>> case.
>>>>>
>>>>> --
>>>>> This message was distributed to subscribers of the selinux
>>>>> mailing
>>>>> list.
>>>>> If you no longer wish to subscribe, send mail to
>>>>> [email protected] with
>>>>> the words "unsubscribe selinux" without quotes as the message.
>>>>
>>>>
>>>> I think I found the offending code. I can't test it for a while so
>>>> hopefully Casey can.
>>>>
>>>> In include/linux/capability.h we have the following defines
>>>>
>>>>
>>>> # define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
>>>> | CAP_TO_MASK(CAP_MKNOD) \
>>>> | CAP_TO_MASK(CAP_DAC_OVERRIDE) \
>>>> | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
>>>> | CAP_TO_MASK(CAP_FOWNER) \
>>>> | CAP_TO_MASK(CAP_FSETID))
>>>>
>>>> # define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
>>>>
>>>> #if _KERNEL_CAPABILITY_U32S != 2
>>>> # error Fix up hand-coded capability macro initializers
>>>> #else /* HAND-CODED capability initializers */
>>>>
>>>> # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
>>>> # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
>>>> # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>>>> |
>>>> CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
>>>> CAP_FS_MASK_B1 } })
>>>> # define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>>>> |
>>>> CAP_TO_MASK(CAP_SYS_RESOURCE), \
>>>> CAP_FS_MASK_B1 } })
>>>>
>>>> So raise and drop nfsd caps uses CAP_NFSD_SET. In CAP_NFSD_SET we
>>>> have
>>>> CAP_MAC_OVERRIDE but we don't have CAP_MAC_ADMIN. I think maybe if
>>>> we
>>>> had both then Casey should be able to use the code with SMACK.
>>>> However
>>>> I'm not sure what implications this has for every other LSM.
>>>> Honestly
>>>> I'm not sure if we use either of those caps for SELinux at all (I
>>>> think
>>>> we ignore them completely).
>>>
>>> CAP_MAC_ADMIN is used by SELinux these days, but only to control
>>> the
>>> ability to get or set security contexts that are not yet defined in
>>> the policy (for package managers that lay down the security
>>> contexts
>>> before reloading policy and for installing a distro within a chroot
>>> on
>>> a build host running a different policy).
>>
>>
>> Do you think its reasonable to add that cap into the NFSd thread
>> then?
>> I'm not sure what other solution there would be. Casey needs it just
>> so
>> SMACK can work with it at all (assuming what I think is happening is
>> actually happening).
>
> Looks like Smack requires CAP_MAC_ADMIN in order to set Smack
> attributes on a file at all. So nfsd would require that capability
> for Smack. I think this means however that setting Smack labels on
> NFS files won't work in any case where root is squashed, which seems
> unfortunate.

I'll leave that problem to Casey to figure out. However it seems to me
that regardless of Labeled NFS Casey should have problems with the NFS
server not being able to serve up files that are dominated by floor. I
wonder if he has every tried NFSv4 on a SMACK enabled server before. It
may have just worked because all files implicitly get labeled floor.

>
> On the SELinux side, we don't require CAP_MAC_ADMIN to set the
> SELinux attribute on a file in the normal case, only when the SELinux
> attribute is not known to the security policy yet. So granting
> CAP_MAC_ADMIN there means that a client will be able to set security
> contexts on files that are unknown to the server. I guess that might
> even be desirable in some instances where client and server policy
> are
> different. We do have the option of denying mac_admin permission in
> policy for nfsd (kernel_t?), in which case we would block such
> attempts to set unknown contexts but would still support setting of
> known security contexts.
>
> So I think it is workable, albeit a bit confusing.

Yea it is unfortunate that we have to go mucking around in capability
land but it seems that adding CAP_MAC_ADMIN should be fine and we can
deal with it in policy if we like.


2012-11-14 14:04:20

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/14/2012 08:59, J. Bruce Fields wrote:
> On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
>> On 11/14/2012 08:45, J. Bruce Fields wrote:
>> >On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>> >>Ok so if you go to http://www.selinuxproject.org/git you will see
>> a
>> >>repo for lnfs and lnfs-patchset. The instructions at
>> >>http://www.selinuxproject.org/page/Labeled_NFS give you a better
>> >>indication on how to pull the trees. I've attached a patch for NFS
>> >>utils which gives support for security_label/nosecurity_label in
>> >>your /etc/exports file.
>> >
>> >Do we need an export option? Is there any reason not to make the
>> >feature available whenever there's support available for it?
>>
>> I guess we could build it in but I figured an export option allowed
>> someone to turn off security labeling support if they didn't want it
>> on that export. What happens to clients when the server returns a
>> cap that they don't support? Do they mask the bits out?
>
> Yeah, they should just ignore it.
>
> While this is still experimental it's still nice to have a way to
> turn
> this on and off at runtime so people can experiment without having to
> have it on for everyone all the time. But
> nfsd_supported_minorversion
> should be sufficient for that.
>
> (I don't think your patches actually dealt yet with the fact that
> this
> is part of minor version 2? Another for the todo list.)
>
> --b.

If we use nfsd_supported_minorversion which I'm guessing is an export
option what happens if someone wants to use other 4.2 features but not
labeling? I'll switch it over if you guys want it done that way, I think
though that this provides more flexibility. Although anything that makes
me carry around fewer patches is good in my book.

Dave

2012-11-21 00:39:05

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/20/2012 4:04 PM, Dave Quigley wrote:
> On 11/20/2012 4:09 PM, Casey Schaufler wrote:
>> On 11/11/2012 10:15 PM, David Quigley wrote:
>>> The NFSv4 working group has finally accepted Labeled NFS as part of
>>> the NFSv4.2
>>> specification and it has been decided that a reposting of the
>>> Labeled NFS code
>>> for inclusion into mainline was a good idea. The patches have been
>>> rebased onto
>>> v3.7-rc2 and have been tested against the SELinux testsuite with the
>>> only
>>> failures being for features not supported by NFS.
>>
>> I'm trying to get the user space tools built so that I can
>> do Smack testing. The instructions on selinuxproject.org
>> seen out of date with regard to the packages required to
>> build the NFS tools. I have failed to build on Fedora 17
>> and Ubuntu 12.04. Any pointers beyond what's on the wiki?
>>
>> Thank you.
>>
>>
>> --
>> This message was distributed to subscribers of the selinux mailing list.
>> If you no longer wish to subscribe, send mail to
>> [email protected] with
>> the words "unsubscribe selinux" without quotes as the message.
>>
>>
>
> There are a bunch of libs that need to be installed for it to compile
> properly.

Yes, indeed!

> Unfortunately there are new dependencies which have been added since I
> updated the wiki last.

I found that to be the case as well.

> unfortunately don't remember what they are.

And they're not obvious.

> What I did to build it last time though was to apply the one patch
> onto the latest tag from the nfs-utils tree.

Sound simple enough if you're building the nfs-util tree on a daily basis
I suppose. Not something that I do regularly, alas.


> Unfortunately I don't have a clean vm on hand at the moment so I can't
> manually go through and list all the packages for you. A heavy handed
> approach that should still work is that I can give you my rpm list
> from my VM and then you can just make sure you have all the devel
> packages installed.

I'd be up for that.


> Another option would be to grab the nfs-utils srpm for fedora 17 and
> just add the patch into the spec file.

Yeah. Or not.

> That would work too and tell you the build dependencies you need. I
> could also just try to make that for you and put the RPM up but that
> wouldn't be for a few days at the earliest.

That, or I could give you the instructions on how to enable and test
Smack.

Thank you.


>
> Dave
>


2012-11-12 17:51:02

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 07/13] NFSv4: Introduce new label structure

On Mon, Nov 12, 2012 at 11:53:13AM -0500, David P. Quigley wrote:
> On 11/12/2012 11:05 AM, J. Bruce Fields wrote:
> >On Mon, Nov 12, 2012 at 10:32:56AM -0500, David P. Quigley wrote:
> >>On 11/12/2012 10:13 AM, J. Bruce Fields wrote:
> >>>On Mon, Nov 12, 2012 at 01:15:41AM -0500, David Quigley wrote:
> >>>>From: David Quigley<[email protected]>
> >>>>
> >>>>In order to mimic the way that NFSv4 ACLs are implemented we have created a
> >>>>structure to be used to pass label data up and down the call chain. This patch
> >>>>adds the new structure and new members to the required NFSv4 call structures.
> >>>>
> >>>>Signed-off-by: Matthew N. Dodd<[email protected]>
> >>>>Signed-off-by: Miguel Rodel Felipe<[email protected]>
> >>>>Signed-off-by: Phua Eu Gene<[email protected]>
> >>>>Signed-off-by: Khin Mi Mi Aung<[email protected]>
> >>>>Signed-off-by: David Quigley<[email protected]>
> >>>>---
> >>>> fs/nfs/inode.c | 40 ++++++++++++++++++++++++++++++++++++++++
> >>>> fs/nfsd/xdr4.h | 3 +++
> >>>> include/linux/nfs4.h | 8 ++++++++
> >>>> include/linux/nfs_fs.h | 14 ++++++++++++++
> >>>> include/linux/nfs_xdr.h | 20 ++++++++++++++++++++
> >>>> 5 files changed, 85 insertions(+)
> >>>>
> >>>>diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> >>>>index 5c7325c..0963ad9 100644
> >>>>--- a/fs/nfs/inode.c
> >>>>+++ b/fs/nfs/inode.c
> >>>>@@ -246,6 +246,46 @@ nfs_init_locked(struct inode *inode, void *opaque)
> >>>> return 0;
> >>>> }
> >>>>
> >>>>+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >>>>+struct nfs4_label *nfs4_label_alloc(gfp_t flags)
> >>>>+{
> >>>>+ struct nfs4_label *label = NULL;
> >>>>+
> >>>>+ label = kzalloc(sizeof(struct nfs4_label) + NFS4_MAXLABELLEN, flags);
> >>>NFS4_MAXLABELLEN is 4096, but we usually try to avoid allocating more
> >>>than that in a single allocation.
> >>Should we make this smaller? I figured a page would be a good upper bound.
> >If we could make it small enough so that the above fits in 4096 bytes
> >that would be easier.
> >
> >(What does the protocol say? On a quick glance it doesn't seem to
> >impose a limit.)
>
> The spec doesn't limit the size of a label but we thought that a
> page would be good. We can make it 4095 to ensure that it will
> always be in a page incase a null terminator is added. I believe
> someone mentioned this in the past I'm not sure why it didn't make
> its way in. We initially had something much larger but Trond chimed
> in and said that if its larger than a page something is wrong so we
> lowered it.

Note that sizeof(struct nfs4_label) in there too. So maybe subtract the
maximum possible size of that thing, then round down to something nice?

--b.

2012-11-12 15:39:39

by David Quigley

[permalink] [raw]
Subject: Re: [PATCH 07/13] NFSv4: Introduce new label structure

On 11/12/2012 10:13 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 01:15:41AM -0500, David Quigley wrote:
>> From: David Quigley<[email protected]>
>>
>> In order to mimic the way that NFSv4 ACLs are implemented we have created a
>> structure to be used to pass label data up and down the call chain. This patch
>> adds the new structure and new members to the required NFSv4 call structures.
>>
>> Signed-off-by: Matthew N. Dodd<[email protected]>
>> Signed-off-by: Miguel Rodel Felipe<[email protected]>
>> Signed-off-by: Phua Eu Gene<[email protected]>
>> Signed-off-by: Khin Mi Mi Aung<[email protected]>
>> Signed-off-by: David Quigley<[email protected]>
>> ---
>> fs/nfs/inode.c | 40 ++++++++++++++++++++++++++++++++++++++++
>> fs/nfsd/xdr4.h | 3 +++
>> include/linux/nfs4.h | 8 ++++++++
>> include/linux/nfs_fs.h | 14 ++++++++++++++
>> include/linux/nfs_xdr.h | 20 ++++++++++++++++++++
>> 5 files changed, 85 insertions(+)
>>
>> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
>> index 5c7325c..0963ad9 100644
>> --- a/fs/nfs/inode.c
>> +++ b/fs/nfs/inode.c
>> @@ -246,6 +246,46 @@ nfs_init_locked(struct inode *inode, void *opaque)
>> return 0;
>> }
>>
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> +struct nfs4_label *nfs4_label_alloc(gfp_t flags)
>> +{
>> + struct nfs4_label *label = NULL;
>> +
>> + label = kzalloc(sizeof(struct nfs4_label) + NFS4_MAXLABELLEN, flags);
> NFS4_MAXLABELLEN is 4096, but we usually try to avoid allocating more
> than that in a single allocation.

Should we make this smaller? I figured a page would be a good upper bound.

>> + if (label == NULL)
>> + return NULL;
>> +
>> + label->label = (void *)(label + 1);
>> + label->len = NFS4_MAXLABELLEN;
>> + /* 0 is the null format meaning that the data is not to be translated */
>> + label->lfs = 0;
>> + label->pi = 0;
> What's "pi"?
>
> --b.

In the LFS document we talk about how a policy identifier is a
recommended field. It isn't implemented yet as we're setting both the
LFS and the PI to 0 but I added it for when we put the LFS mapping
daemon in next. The idea is that even though we have a label and we
specify the format with the LFS we need to identify what version of
policy it is so we can ensure that the actual meaning of a value is correct.

>
>> + return label;
>> +}
>> +EXPORT_SYMBOL_GPL(nfs4_label_alloc);
>> +
>> +void nfs4_label_init(struct nfs4_label *label)
>> +{
>> + if (label&& label->label) {
>> + *(unsigned char *)label->label = 0;
>> + label->len = NFS4_MAXLABELLEN;
>> + /* 0 is the null format meaning that the data is not
>> + to be translated */
>> + label->lfs = 0;
>> + label->pi = 0;
>> + }
>> + return;
>> +}
>> +EXPORT_SYMBOL_GPL(nfs4_label_init);
>> +
>> +void nfs4_label_free(struct nfs4_label *label)
>> +{
>> + kfree(label);
>> + return;
>> +}
>> +EXPORT_SYMBOL_GPL(nfs4_label_free);
>> +#endif
>> +
>> /*
>> * This is our front-end to iget that looks up inodes by file handle
>> * instead of inode number.
>> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
>> index acd127d..ca8f30b 100644
>> --- a/fs/nfsd/xdr4.h
>> +++ b/fs/nfsd/xdr4.h
>> @@ -118,6 +118,7 @@ struct nfsd4_create {
>> struct iattr cr_iattr; /* request */
>> struct nfsd4_change_info cr_cinfo; /* response */
>> struct nfs4_acl *cr_acl;
>> + struct nfs4_label *cr_label;
>> };
>> #define cr_linklen u.link.namelen
>> #define cr_linkname u.link.name
>> @@ -246,6 +247,7 @@ struct nfsd4_open {
>> struct nfs4_file *op_file; /* used during processing */
>> struct nfs4_ol_stateid *op_stp; /* used during processing */
>> struct nfs4_acl *op_acl;
>> + struct nfs4_label *op_label;
>> };
>> #define op_iattr iattr
>>
>> @@ -330,6 +332,7 @@ struct nfsd4_setattr {
>> u32 sa_bmval[3]; /* request */
>> struct iattr sa_iattr; /* request */
>> struct nfs4_acl *sa_acl;
>> + struct nfs4_label *sa_label;
>> };
>>
>> struct nfsd4_setclientid {
>> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
>> index f9235b4..862471f 100644
>> --- a/include/linux/nfs4.h
>> +++ b/include/linux/nfs4.h
>> @@ -28,6 +28,14 @@ struct nfs4_acl {
>> struct nfs4_ace aces[0];
>> };
>>
>> +struct nfs4_label {
>> + uint32_t lfs;
>> + uint32_t pi;
>> + u32 len;
>> + void *label;
>> +};
>> +
>> +
>> typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
>>
>> struct nfs_stateid4 {
>> diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
>> index 1cc2568..37a862c 100644
>> --- a/include/linux/nfs_fs.h
>> +++ b/include/linux/nfs_fs.h
>> @@ -489,6 +489,20 @@ extern int nfs_mountpoint_expiry_timeout;
>> extern void nfs_release_automount_timer(void);
>>
>> /*
>> + * linux/fs/nfs/nfs4proc.c
>> + */
>> +
>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> +extern struct nfs4_label *nfs4_label_alloc(gfp_t flags);
>> +extern void nfs4_label_init(struct nfs4_label *);
>> +extern void nfs4_label_free(struct nfs4_label *);
>> +#else
>> +static inline struct nfs4_label *nfs4_label_alloc(gfp_t flags) { return NULL; }
>> +static inline void nfs4_label_init(struct nfs4_label *) {}
>> +static inline void nfs4_label_free(struct nfs4_label *label) {}
>> +#endif
>> +
>> +/*
>> * linux/fs/nfs/unlink.c
>> */
>> extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
>> diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
>> index a0669d3..7e9347a 100644
>> --- a/include/linux/nfs_xdr.h
>> +++ b/include/linux/nfs_xdr.h
>> @@ -352,6 +352,7 @@ struct nfs_openargs {
>> const u32 * bitmask;
>> const u32 * open_bitmap;
>> __u32 claim;
>> + const struct nfs4_label *label;
>> struct nfs4_sequence_args seq_args;
>> };
>>
>> @@ -361,6 +362,7 @@ struct nfs_openres {
>> struct nfs4_change_info cinfo;
>> __u32 rflags;
>> struct nfs_fattr * f_attr;
>> + struct nfs4_label *f_label;
>> struct nfs_seqid * seqid;
>> const struct nfs_server *server;
>> fmode_t delegation_type;
>> @@ -405,6 +407,7 @@ struct nfs_closeargs {
>> struct nfs_closeres {
>> nfs4_stateid stateid;
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> struct nfs_seqid * seqid;
>> const struct nfs_server *server;
>> struct nfs4_sequence_res seq_res;
>> @@ -478,6 +481,7 @@ struct nfs4_delegreturnargs {
>>
>> struct nfs4_delegreturnres {
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> const struct nfs_server *server;
>> struct nfs4_sequence_res seq_res;
>> };
>> @@ -498,6 +502,7 @@ struct nfs_readargs {
>>
>> struct nfs_readres {
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> __u32 count;
>> int eof;
>> struct nfs4_sequence_res seq_res;
>> @@ -566,6 +571,7 @@ struct nfs_removeargs {
>> struct nfs_removeres {
>> const struct nfs_server *server;
>> struct nfs_fattr *dir_attr;
>> + struct nfs4_label *dir_label;
>> struct nfs4_change_info cinfo;
>> struct nfs4_sequence_res seq_res;
>> };
>> @@ -578,6 +584,8 @@ struct nfs_renameargs {
>> const struct nfs_fh *new_dir;
>> const struct qstr *old_name;
>> const struct qstr *new_name;
>> + const struct nfs4_label *old_label;
>> + const struct nfs4_label *new_label;
>> struct nfs4_sequence_args seq_args;
>> };
>>
>> @@ -585,8 +593,10 @@ struct nfs_renameres {
>> const struct nfs_server *server;
>> struct nfs4_change_info old_cinfo;
>> struct nfs_fattr *old_fattr;
>> + struct nfs4_label *old_label;
>> struct nfs4_change_info new_cinfo;
>> struct nfs_fattr *new_fattr;
>> + struct nfs4_label *new_label;
>> struct nfs4_sequence_res seq_res;
>> };
>>
>> @@ -634,6 +644,7 @@ struct nfs_setattrargs {
>> struct iattr * iap;
>> const struct nfs_server * server; /* Needed for name mapping */
>> const u32 * bitmask;
>> + const struct nfs4_label *label;
>> struct nfs4_sequence_args seq_args;
>> };
>>
>> @@ -669,6 +680,7 @@ struct nfs_getaclres {
>>
>> struct nfs_setattrres {
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> const struct nfs_server * server;
>> struct nfs4_sequence_res seq_res;
>> };
>> @@ -715,6 +727,7 @@ struct nfs3_setaclargs {
>> struct nfs_diropok {
>> struct nfs_fh * fh;
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> };
>>
>> struct nfs_readlinkargs {
>> @@ -844,6 +857,7 @@ struct nfs4_accessargs {
>> struct nfs4_accessres {
>> const struct nfs_server * server;
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> u32 supported;
>> u32 access;
>> struct nfs4_sequence_res seq_res;
>> @@ -866,6 +880,7 @@ struct nfs4_create_arg {
>> const struct iattr * attrs;
>> const struct nfs_fh * dir_fh;
>> const u32 * bitmask;
>> + const struct nfs4_label *label;
>> struct nfs4_sequence_args seq_args;
>> };
>>
>> @@ -873,6 +888,7 @@ struct nfs4_create_res {
>> const struct nfs_server * server;
>> struct nfs_fh * fh;
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> struct nfs4_change_info dir_cinfo;
>> struct nfs4_sequence_res seq_res;
>> };
>> @@ -898,6 +914,7 @@ struct nfs4_getattr_res {
>> const struct nfs_server * server;
>> struct nfs_fattr * fattr;
>> struct nfs4_sequence_res seq_res;
>> + struct nfs4_label *label;
>> };
>>
>> struct nfs4_link_arg {
>> @@ -911,8 +928,10 @@ struct nfs4_link_arg {
>> struct nfs4_link_res {
>> const struct nfs_server * server;
>> struct nfs_fattr * fattr;
>> + struct nfs4_label *label;
>> struct nfs4_change_info cinfo;
>> struct nfs_fattr * dir_attr;
>> + struct nfs4_label *dir_label;
>> struct nfs4_sequence_res seq_res;
>> };
>>
>> @@ -928,6 +947,7 @@ struct nfs4_lookup_res {
>> const struct nfs_server * server;
>> struct nfs_fattr * fattr;
>> struct nfs_fh * fh;
>> + struct nfs4_label *label;
>> struct nfs4_sequence_res seq_res;
>> };
>>
>> --
>> 1.7.11.7
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


2012-11-30 12:14:41

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
> On 11/29/2012 20:50, Casey Schaufler wrote:
> >On 11/29/2012 4:46 PM, David Quigley wrote:
> >>On 11/29/2012 19:34, Casey Schaufler wrote:
> >>>I would think that were it not for the case that access is denied
> >>>and I get an audit record for nfsd that reports a subject
> >>>label of "_"
> >>>(which is correct for nfsd but not the process attempting
> >>>access) and
> >>>an object label of "WhooHoo", which is correct. The server side
> >>>looks like it might be working right, given the information that it
> >>>has.
> >>>
> >>
> >>Ok so this is the problem. nfsd is a kernel thread I believe. In
> >>SELinux land it has the type kernel_t which is all powerful. We
> >>don't
> >>have client label transport yet (That requires RPCSECGSSv3). Is
> >>there
> >>a way you can have that kernel thread running as a type that has
> >>access to everything?
> >
> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in Smackese.
> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
> >which
> >is to say, all capabilities.
> >
>
> Hmm thats interesting then. You could try using rpcdebug -m nfsd to
> turn on some of the debugging to look around the internals and
> figure out whats going on. If you pass -v it will give you all of
> the potential flags.
>
> >
> >>I think that is the current problem. Which makes perfect sense. If
> >>your kernel threads don't get started with max privilege then the
> >>server would be denied access on all of the file attributes and
> >>wouldn't be able to ship it over the wire properly.
> >
> >OK. I haven't had to do anything with kernel threads so far.
> >Where is NFS setting these up? Poking around fs/nfsd looks like
> >the place, but I haven't seen anything there that makes it look
> >like they would be running without capabilities. Clearly, that's
> >what I'm seeing. It looks as if the credential of nfsd does not
> >match what /proc reports. Bother.
> >
>
> I'm not entirely sure whats up either. If you want to look for the
> NFSd threads they are in fs/nfsd/nfssvc.c. The main function starts
> on line 487.

I'm not following the discussion, but: maybe you want to look at
fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
cap_{drop/raise}_nfsd_set() calls at the end.

--b.

2012-11-15 20:28:07

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/15/2012 11:00, Casey Schaufler wrote:
> On 11/14/2012 6:30 AM, David Quigley wrote:
>> On 11/14/2012 09:24, J. Bruce Fields wrote:
>>> On Wed, Nov 14, 2012 at 09:04:18AM -0500, David Quigley wrote:
>>>> On 11/14/2012 08:59, J. Bruce Fields wrote:
>>>> >On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
>>>> >>On 11/14/2012 08:45, J. Bruce Fields wrote:
>>>> >>>On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>>>> >>>>Ok so if you go to http://www.selinuxproject.org/git you will
>>>> >>see a
>>>> >>>>repo for lnfs and lnfs-patchset. The instructions at
>>>> >>>>http://www.selinuxproject.org/page/Labeled_NFS give you a
>>>> better
>>>> >>>>indication on how to pull the trees. I've attached a patch for
>>>> NFS
>>>> >>>>utils which gives support for security_label/nosecurity_label
>>>> in
>>>> >>>>your /etc/exports file.
>>>> >>>
>>>> >>>Do we need an export option? Is there any reason not to make
>>>> the
>>>> >>>feature available whenever there's support available for it?
>>>> >>
>>>> >>I guess we could build it in but I figured an export option
>>>> allowed
>>>> >>someone to turn off security labeling support if they didn't
>>>> want it
>>>> >>on that export. What happens to clients when the server returns
>>>> a
>>>> >>cap that they don't support? Do they mask the bits out?
>>>> >
>>>> >Yeah, they should just ignore it.
>>>> >
>>>> >While this is still experimental it's still nice to have a way to
>>>> >turn
>>>> >this on and off at runtime so people can experiment without
>>>> having to
>>>> >have it on for everyone all the time. But
>>>> >nfsd_supported_minorversion
>>>> >should be sufficient for that.
>>>> >
>>>> >(I don't think your patches actually dealt yet with the fact that
>>>> >this
>>>> >is part of minor version 2? Another for the todo list.)
>>>> >
>>>> >--b.
>>>>
>>>> If we use nfsd_supported_minorversion which I'm guessing is an
>>>> export option
>>>
>>> That's just a variable in the code. It's controlled by
>>> /proc/fs/nfsd/versions.
>>>
>>>> what happens if someone wants to use other 4.2
>>>> features but not labeling?
>>>
>>> We'll cross that bridge when we come to it, maybe by adding some
>>> new
>>> global paramater.
>>>
>>> There's no reason this really needs to be per-export, is there?
>>>
>>> --b.
>>
>> At the moment I can't really think of a reason to have it be
>> per-export. I think we need a new LSM patch though to determine if
>> the
>> LSM supports labeling over NFS unless Steve can think of a better
>> way
>> to tell if the LSM supports labeling.
>
> If the LSM has a secid_to_secctx hook it supports labeling.
> Today that's SELinux and Smack. You already have support in
> for SELinux, and providing Smack's review and possibly updates
> is #2 on my gotta do list. On the whole, I think that, except
> for the fundamental philosophical difference between label
> support and xattr support, it should be a simple matter to
> get support in for any LSM that has secid_to_secctx.
>
> But I'm still working on the review.
>

I believe SMACK already works out of the box since we abstracted the
call to obtain labels and your implementation currently works. The call
that is needed is not secid_to_secctx but inode_getsecctx. You asked for
this because SMACK labels can span multiple xattrs. I don't think its
right to expect NFS to poke around the security structure to check if
there is a valid hook(and it isn't really possible either). Maybe we can
have an LSM hook where the LSM categorizes itself and returns a value
and if the value it returns is label based then NFS can use it.

>>
>>
>>>
>>>> I'll switch it over if you guys want it
>>>> done that way, I think though that this provides more flexibility.
>>>> Although anything that makes me carry around fewer patches is good
>>>> in my book.
>>>>
>>>> Dave
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>> linux-security-module" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> --
> This message was distributed to subscribers of the selinux mailing
> list.
> If you no longer wish to subscribe, send mail to
> [email protected] with
> the words "unsubscribe selinux" without quotes as the message.


2012-11-12 19:36:12

by David Quigley

[permalink] [raw]
Subject: Re: [PATCH 02/13] Security: Add Hook to test if the particular xattr is part of a MAC model.

On 11/12/2012 11:36 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 09:56:37AM -0500, Dave Quigley wrote:
>> On 11/12/2012 7:15 AM, J. Bruce Fields wrote:
>>> On Mon, Nov 12, 2012 at 01:15:36AM -0500, David Quigley wrote:
>>>> From: David Quigley<[email protected]>
>>>>
>>>> The interface to request security labels from user space is the xattr
>>>> interface. When requesting the security label from an NFS server it is
>>>> important to make sure the requested xattr
>>> I'm confused--clients can't request xattrs from NFS servers. I must be
>>> reading this wrong, but I'm not sure what you meant.
>>>
>>> --b.
>>>
>> Generically clients can't use xattrs from NFS servers but the LSM
>> method for getting labels is through the xattr interface. THe point
>> of this is if someone selects security.capability that we don't
>> translate that into a call in labeled nfs to get the security label.
>> We only want label based LSMs to cause a getfattr on the server to
>> grab the label and populate the inode with that information.
>> Currently if you use security.selinux or security.smack then labeled
>> nfs will handle the translation of that into a get/setfattr on the
>> security_label attribute in NFSv4.
> OK, I think I understand: so this is to help the NFS client implement
> the necessary xattr interface for userspace that get and sets security
> labels on NFS filesystems?
>
> --b.

Exactly. The problem is we don't want to have LSM specific logic in so
the best we can do is ask if the security.* xattr being accessed has the
proper semantics to be used with Labeled NFS.

>
>>
>>>> actually is a MAC label. This allows
>>>> us to make sure that we get the desired semantics from the attribute instead of
>>>> something else such as capabilities or a time based LSM.
>>>>
>>>> Signed-off-by: Matthew N. Dodd<[email protected]>
>>>> Signed-off-by: Miguel Rodel Felipe<[email protected]>
>>>> Signed-off-by: Phua Eu Gene<[email protected]>
>>>> Signed-off-by: Khin Mi Mi Aung<[email protected]>
>>>> Signed-off-by: David Quigley<[email protected]>
>>>> ---
>>>> include/linux/security.h | 14 ++++++++++++++
>>>> security/capability.c | 6 ++++++
>>>> security/security.c | 6 ++++++
>>>> security/selinux/hooks.c | 6 ++++++
>>>> security/smack/smack_lsm.c | 11 +++++++++++
>>>> 5 files changed, 43 insertions(+)
>>>>
>>>> diff --git a/include/linux/security.h b/include/linux/security.h
>>>> index c9f5eec..167bdd5 100644
>>>> --- a/include/linux/security.h
>>>> +++ b/include/linux/security.h
>>>> @@ -1301,6 +1301,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>>>> * @pages contains the number of pages.
>>>> * Return 0 if permission is granted.
>>>> *
>>>> + * @ismaclabel:
>>>> + * Check if the extended attribute specified by @name
>>>> + * represents a MAC label. Returns 0 if name is a MAC
>>>> + * attribute otherwise returns non-zero.
>>>> + * @name full extended attribute name to check against
>>>> + * LSM as a MAC label.
>>>> + *
>>>> * @secid_to_secctx:
>>>> * Convert secid to security context. If secdata is NULL the length of
>>>> * the result will be returned in seclen, but no secdata will be returned.
>>>> @@ -1581,6 +1588,7 @@ struct security_operations {
>>>>
>>>> int (*getprocattr) (struct task_struct *p, char *name, char **value);
>>>> int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
>>>> + int (*ismaclabel) (const char *name);
>>>> int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
>>>> int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
>>>> void (*release_secctx) (char *secdata, u32 seclen);
>>>> @@ -1829,6 +1837,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
>>>> int security_getprocattr(struct task_struct *p, char *name, char **value);
>>>> int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
>>>> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
>>>> +int security_ismaclabel(const char *name);
>>>> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
>>>> int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
>>>> void security_release_secctx(char *secdata, u32 seclen);
>>>> @@ -2512,6 +2521,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
>>>> return cap_netlink_send(sk, skb);
>>>> }
>>>>
>>>> +static inline int security_ismaclabel(const char *name)
>>>> +{
>>>> + return 0;
>>>> +}
>>>> +
>>>> static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>>>> {
>>>> return -EOPNOTSUPP;
>>>> diff --git a/security/capability.c b/security/capability.c
>>>> index f1eb284..9071447 100644
>>>> --- a/security/capability.c
>>>> +++ b/security/capability.c
>>>> @@ -797,6 +797,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
>>>> return -EINVAL;
>>>> }
>>>>
>>>> +static int cap_ismaclabel(const char *name)
>>>> +{
>>>> + return 0;
>>>> +}
>>>> +
>>>> static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>>>> {
>>>> return -EOPNOTSUPP;
>>>> @@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
>>>> set_to_cap_if_null(ops, d_instantiate);
>>>> set_to_cap_if_null(ops, getprocattr);
>>>> set_to_cap_if_null(ops, setprocattr);
>>>> + set_to_cap_if_null(ops, ismaclabel);
>>>> set_to_cap_if_null(ops, secid_to_secctx);
>>>> set_to_cap_if_null(ops, secctx_to_secid);
>>>> set_to_cap_if_null(ops, release_secctx);
>>>> diff --git a/security/security.c b/security/security.c
>>>> index b4b2017..a7bee7b 100644
>>>> --- a/security/security.c
>>>> +++ b/security/security.c
>>>> @@ -1047,6 +1047,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
>>>> return security_ops->netlink_send(sk, skb);
>>>> }
>>>>
>>>> +int security_ismaclabel(const char *name)
>>>> +{
>>>> + return security_ops->ismaclabel(name);
>>>> +}
>>>> +EXPORT_SYMBOL(security_ismaclabel);
>>>> +
>>>> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>>>> {
>>>> return security_ops->secid_to_secctx(secid, secdata, seclen);
>>>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>>>> index 22d9adf..f7c4899 100644
>>>> --- a/security/selinux/hooks.c
>>>> +++ b/security/selinux/hooks.c
>>>> @@ -5401,6 +5401,11 @@ abort_change:
>>>> return error;
>>>> }
>>>>
>>>> +static int selinux_ismaclabel(const char *name)
>>>> +{
>>>> + return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
>>>> +}
>>>> +
>>>> static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
>>>> {
>>>> return security_sid_to_context(secid, secdata, seclen);
>>>> @@ -5639,6 +5644,7 @@ static struct security_operations selinux_ops = {
>>>> .getprocattr = selinux_getprocattr,
>>>> .setprocattr = selinux_setprocattr,
>>>>
>>>> + .ismaclabel = selinux_ismaclabel,
>>>> .secid_to_secctx = selinux_secid_to_secctx,
>>>> .secctx_to_secid = selinux_secctx_to_secid,
>>>> .release_secctx = selinux_release_secctx,
>>>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>>>> index 38be92c..82c3c72 100644
>>>> --- a/security/smack/smack_lsm.c
>>>> +++ b/security/smack/smack_lsm.c
>>>> @@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void *vrule)
>>>> #endif /* CONFIG_AUDIT */
>>>>
>>>> /**
>>>> + * smack_ismaclabel - check if xattr @name references a smack MAC label
>>>> + * @name: Full xattr name to check.
>>>> + */
>>>> +static int smack_ismaclabel(const char *name)
>>>> +{
>>>> + return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
>>>> +}
>>>> +
>>>> +
>>>> +/**
>>>> * smack_secid_to_secctx - return the smack label for a secid
>>>> * @secid: incoming integer
>>>> * @secdata: destination
>>>> @@ -3530,6 +3540,7 @@ struct security_operations smack_ops = {
>>>> .audit_rule_free = smack_audit_rule_free,
>>>> #endif /* CONFIG_AUDIT */
>>>>
>>>> + .ismaclabel = smack_ismaclabel,
>>>> .secid_to_secctx = smack_secid_to_secctx,
>>>> .secctx_to_secid = smack_secctx_to_secid,
>>>> .release_secctx = smack_release_secctx,
>>>> --
>>>> 1.7.11.7
>>>>


2012-11-30 01:50:05

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/29/2012 4:46 PM, David Quigley wrote:
> On 11/29/2012 19:34, Casey Schaufler wrote:
>> On 11/29/2012 4:07 PM, David Quigley wrote:
>>> On 11/29/2012 17:28, Casey Schaufler wrote:
>>>> On 11/28/2012 6:08 PM, Casey Schaufler wrote:
>>>>> On 11/28/2012 5:14 PM, Dave Quigley wrote:
>>>>>> On 11/28/2012 1:57 PM, Casey Schaufler wrote:
>>>>>>> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>>>>>>>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>>>>>>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>>>>>>>> ...
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Or I could just give you this link and you should be good to
>>>>>>>>>> go ;)
>>>>>>>>>>
>>>>>>>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>>>>>>>
>>>>>>>>>> I haven't tried it but it should work. If it doesn't let me
>>>>>>>>>> know and
>>>>>>>>>> i'll try to fix it on my end. I'd imagine you might need to yum
>>>>>>>>>> remove
>>>>>>>>>> nfs-utils first before adding this new one or you could also
>>>>>>>>>> try an
>>>>>>>>>> rpm with the upgrade flag for this instead. Good luck.
>>>>>>> ...
>>>>>>>
>>>>>>>
>>>>>>> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
>>>>>>> attached stack trace on mount. After mounting I'm getting
>>>>>>> denials when I should, but also when I shouldn't.
>>>>>>>
>>>>>>> I've tried tracking down the issue, but there's a lot going on
>>>>>>> that I don't find obvious. I added a dentry_init hook just for
>>>>>>> grins, but it's not getting called.
>>>>>>>
>>>>>>> .
>>>>>>>
>>>>>>>
>>>>>> Any chance of you throwing a kickstart file my way that's configured
>>>>>> with SMACK so I can use it for a test box (both server and
>>>>>> client)? I
>>>>>> can have the guys working with me test for SMACK as well if you
>>>>>> provide an appropriate test harness and image for testing.
>>>>> I've attached the .config from my Fedora17 machine. Who knows, maybe
>>>>> I got something wrong there. I get the error doing the test on the
>>>>> loopback interface (mount -t nfs4 localhist:/ /mnt).
>>>>
>>>> I've done some instrumentation and security_ismaclabel() is getting
>>>> called with "selinux", but never "SMACK64". I would guess that
>>>> somewhere
>>>> in the tools you're telling the kernel to expect "selinux". Where is
>>>> that, so that I can tell it to try "SMACK64" instead?
>>>>
>>>>
>>>>
>>>> --
>>>> This message was distributed to subscribers of the selinux mailing
>>>> list.
>>>> If you no longer wish to subscribe, send mail to
>>>> [email protected] with
>>>> the words "unsubscribe selinux" without quotes as the message.
>>>
>>>
>>> What tools do you use in SMACK to see the labels?
>>
>> attr -S -g SMACK64 <path>
>
> ok so that seems to work for SELinux as well. Never knew about that.
> I'd always just rip the xattr out of the inode with getfattr.
>
>
>>
>>> Do you just use getxattr? If so can you try calling that and seeing
>>> what happens? I'm concerned that you aren't getting any attribute
>>> information on that file.
>>
>> I would think that were it not for the case that access is denied
>> and I get an audit record for nfsd that reports a subject label of "_"
>> (which is correct for nfsd but not the process attempting access) and
>> an object label of "WhooHoo", which is correct. The server side
>> looks like it might be working right, given the information that it
>> has.
>>
>
> Ok so this is the problem. nfsd is a kernel thread I believe. In
> SELinux land it has the type kernel_t which is all powerful. We don't
> have client label transport yet (That requires RPCSECGSSv3). Is there
> a way you can have that kernel thread running as a type that has
> access to everything?

That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in Smackese.
Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff which
is to say, all capabilities.


> I think that is the current problem. Which makes perfect sense. If
> your kernel threads don't get started with max privilege then the
> server would be denied access on all of the file attributes and
> wouldn't be able to ship it over the wire properly.

OK. I haven't had to do anything with kernel threads so far.
Where is NFS setting these up? Poking around fs/nfsd looks like
the place, but I haven't seen anything there that makes it look
like they would be running without capabilities. Clearly, that's
what I'm seeing. It looks as if the credential of nfsd does not
match what /proc reports. Bother.


> I'm not sure what you need to do but you'll probably have to work this
> out. We have a usage mode in the IETF spec which has a non-mac
> enforcing server which still support object labeling. In the SELinux
> case it works for us since kernel_t can access anything. Ideally when
> RPCSECGSSv3 is finished and merged we'll be able to choose whether to
> use the label of the process on the client side or kernel_t for the
> server if its not available.
>
>>> Do you have a disto that I can use that has full smack integration and
>>> is easy to setup?
>>
>> There's no full integration, but Ubuntu is easy to set up because they
>> compile in all the LSMs.
>> Set "security=smack" on the boot line in grub.cfg and reboot.
>>
>> All processes and files will get the floor ("_") label unless you change
>> one. You can change
>> a file label with:
>> # attr -S -s SMACK64 WhooHoo path
>> or execute at a different label with:
>> # (echo WhooHoo > /proc/self/attr/current ; command)
>>
>
> I'm not out of here until really late tonight so getting an Ubuntu VM
> setup probably won't happen until sometime next week when everything
> calms down. However I think we isolated the problem above. If I'm
> correct this is strictly a smack labeling problem. I don't know if you
> need to put some code into smack to init kernel threads with a more
> powerful label or not so I'll leave it up to you on how to address this.
>
>
> Dave
>


2012-11-12 16:05:28

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 07/13] NFSv4: Introduce new label structure

On Mon, Nov 12, 2012 at 10:32:56AM -0500, David P. Quigley wrote:
> On 11/12/2012 10:13 AM, J. Bruce Fields wrote:
> >On Mon, Nov 12, 2012 at 01:15:41AM -0500, David Quigley wrote:
> >>From: David Quigley<[email protected]>
> >>
> >>In order to mimic the way that NFSv4 ACLs are implemented we have created a
> >>structure to be used to pass label data up and down the call chain. This patch
> >>adds the new structure and new members to the required NFSv4 call structures.
> >>
> >>Signed-off-by: Matthew N. Dodd<[email protected]>
> >>Signed-off-by: Miguel Rodel Felipe<[email protected]>
> >>Signed-off-by: Phua Eu Gene<[email protected]>
> >>Signed-off-by: Khin Mi Mi Aung<[email protected]>
> >>Signed-off-by: David Quigley<[email protected]>
> >>---
> >> fs/nfs/inode.c | 40 ++++++++++++++++++++++++++++++++++++++++
> >> fs/nfsd/xdr4.h | 3 +++
> >> include/linux/nfs4.h | 8 ++++++++
> >> include/linux/nfs_fs.h | 14 ++++++++++++++
> >> include/linux/nfs_xdr.h | 20 ++++++++++++++++++++
> >> 5 files changed, 85 insertions(+)
> >>
> >>diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> >>index 5c7325c..0963ad9 100644
> >>--- a/fs/nfs/inode.c
> >>+++ b/fs/nfs/inode.c
> >>@@ -246,6 +246,46 @@ nfs_init_locked(struct inode *inode, void *opaque)
> >> return 0;
> >> }
> >>
> >>+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >>+struct nfs4_label *nfs4_label_alloc(gfp_t flags)
> >>+{
> >>+ struct nfs4_label *label = NULL;
> >>+
> >>+ label = kzalloc(sizeof(struct nfs4_label) + NFS4_MAXLABELLEN, flags);
> >NFS4_MAXLABELLEN is 4096, but we usually try to avoid allocating more
> >than that in a single allocation.
>
> Should we make this smaller? I figured a page would be a good upper bound.

If we could make it small enough so that the above fits in 4096 bytes
that would be easier.

(What does the protocol say? On a quick glance it doesn't seem to
impose a limit.)

> >>+ label->label = (void *)(label + 1);
> >>+ label->len = NFS4_MAXLABELLEN;
> >>+ /* 0 is the null format meaning that the data is not to be translated */
> >>+ label->lfs = 0;
> >>+ label->pi = 0;
> >What's "pi"?
> >
> >--b.
>
> In the LFS document we talk about how a policy identifier is a
> recommended field. It isn't implemented yet as we're setting both
> the LFS and the PI to 0 but I added it for when we put the LFS
> mapping daemon in next. The idea is that even though we have a label
> and we specify the format with the LFS we need to identify what
> version of policy it is so we can ensure that the actual meaning of
> a value is correct.

And, my bad, this is in the spec--sorry, I need to go study it.

--b.

2012-11-12 16:31:41

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 13/13] NFSD: Server implementation of MAC Labeling

On Mon, Nov 12, 2012 at 01:15:47AM -0500, David Quigley wrote:
> From: David Quigley <[email protected]>
>
> This patch adds the ability to encode and decode file labels on the server for
> the purpose of sending them to the client and also to process label change
> requests from the client.

I started to compose a response to this one and then lost it; apologies
if I repeat myself anywhere:

> Signed-off-by: Matthew N. Dodd <[email protected]>
> Signed-off-by: Miguel Rodel Felipe <[email protected]>
> Signed-off-by: Phua Eu Gene <[email protected]>
> Signed-off-by: Khin Mi Mi Aung <[email protected]>
> Signed-off-by: David Quigley <[email protected]>
> ---
> fs/nfsd/export.c | 3 ++
> fs/nfsd/nfs4proc.c | 33 +++++++++++++++
> fs/nfsd/nfs4xdr.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++---
> fs/nfsd/vfs.c | 31 ++++++++++++++
> fs/nfsd/vfs.h | 2 +
> 5 files changed, 184 insertions(+), 6 deletions(-)
>
> diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> index a3946cf..251eca7 100644
> --- a/fs/nfsd/export.c
> +++ b/fs/nfsd/export.c
> @@ -1112,6 +1112,9 @@ static struct flags {
> { NFSEXP_ASYNC, {"async", "sync"}},
> { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
> { NFSEXP_NOHIDE, {"nohide", ""}},
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> + { NFSEXP_SECURITY_LABEL, {"security_label", ""}},
> +#endif
> { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
> { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
> { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 6c9a4b2..8e9c17c 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -41,6 +41,10 @@
> #include "vfs.h"
> #include "current_stateid.h"
>
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> +#include <linux/security.h>
> +#endif
> +
> #define NFSDDBG_FACILITY NFSDDBG_PROC
>
> static u32 nfsd_attrmask[] = {
> @@ -228,6 +232,18 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
> (u32 *)open->op_verf.data,
> &open->op_truncate, &open->op_created);
>
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL

As before: could you grep for your new ifdef's and work out if they
could be removed or hidden away somehow?

> + if (!status && open->op_label != NULL) {
> + struct inode *inode = resfh->fh_dentry->d_inode;
> +
> + mutex_lock(&inode->i_mutex);
> + /* Is it appropriate to just kick back an error? */
> + status = security_inode_setsecctx(resfh->fh_dentry,
> + open->op_label->label, open->op_label->len);

Yes, it can cause problems if we fail the open *after* creating the
file. Is this avoidable? What would cause this call to fail?

> + mutex_unlock(&inode->i_mutex);
> + }
> +#endif
> +
> /*
> * Following rfc 3530 14.2.16, use the returned bitmask
> * to indicate which attributes we used to store the
> @@ -588,6 +604,18 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> status = nfserr_badtype;
> }
>
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> + if (!status && create->cr_label != NULL) {
> + struct inode *inode = resfh.fh_dentry->d_inode;
> +
> + mutex_lock(&inode->i_mutex);
> + /* Is it appropriate to just kick back an error? */
> + status = security_inode_setsecctx(resfh.fh_dentry,
> + create->cr_label->label, create->cr_label->len);
> + mutex_unlock(&inode->i_mutex);
> + }
> +#endif
> +
> if (status)
> goto out;
>
> @@ -869,6 +897,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> setattr->sa_acl);
> if (status)
> goto out;
> + if (setattr->sa_label != NULL)
> + status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
> + setattr->sa_label);
> + if (status)
> + goto out;
> status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
> 0, (time_t)0);
> out:
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index fd548d1..58e205c 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -54,6 +54,11 @@
> #include "state.h"
> #include "cache.h"
>
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> +#include <linux/security.h>
> +#endif
> +
> +
> #define NFSDDBG_FACILITY NFSDDBG_XDR
>
> /*
> @@ -241,7 +246,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
>
> static __be32
> nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
> - struct iattr *iattr, struct nfs4_acl **acl)
> + struct iattr *iattr, struct nfs4_acl **acl,
> + struct nfs4_label **label)
> {
> int expected_len, len = 0;
> u32 dummy32;
> @@ -385,6 +391,50 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
> goto xdr_error;
> }
> }
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> + if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
> + uint32_t pi;
> + uint32_t lfs;
> +
> + READ_BUF(4);
> + len += 4;
> + READ32(lfs);
> + READ_BUF(4);
> + len += 4;
> + READ32(pi);
> + READ_BUF(4);
> + len += 4;
> + READ32(dummy32);
> + READ_BUF(dummy32);
> + len += (XDR_QUADLEN(dummy32) << 2);
> + READMEM(buf, dummy32);
> +
> + if (dummy32 > NFS4_MAXLABELLEN)
> + return nfserr_resource;
> +
> + *label = kzalloc(sizeof(struct nfs4_label), GFP_KERNEL);
> + if (*label == NULL) {
> + host_err = -ENOMEM;
> + goto out_nfserr;
> + }
> +
> + (*label)->label = kmalloc(dummy32 + 1, GFP_KERNEL);
> + if ((*label)->label == NULL) {
> + host_err = -ENOMEM;
> + kfree(*label);
> + goto out_nfserr;
> + }
> +
> + (*label)->len = dummy32;
> + memcpy((*label)->label, buf, dummy32);
> + ((char *)(*label)->label)[dummy32] = '\0';
> + (*label)->pi = pi;
> + (*label)->lfs = lfs;
> +
> + defer_free(argp, kfree, (*label)->label);
> + defer_free(argp, kfree, *label);
> + }
> +#endif
> if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
> || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
> || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
> @@ -494,7 +544,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
> return status;
>
> status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
> - &create->cr_acl);
> + &create->cr_acl, &create->cr_label);
> if (status)
> goto out;
>
> @@ -744,7 +794,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
> case NFS4_CREATE_UNCHECKED:
> case NFS4_CREATE_GUARDED:
> status = nfsd4_decode_fattr(argp, open->op_bmval,
> - &open->op_iattr, &open->op_acl);
> + &open->op_iattr, &open->op_acl, &open->op_label);
> if (status)
> goto out;
> break;
> @@ -758,7 +808,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
> READ_BUF(NFS4_VERIFIER_SIZE);
> COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
> status = nfsd4_decode_fattr(argp, open->op_bmval,
> - &open->op_iattr, &open->op_acl);
> + &open->op_iattr, &open->op_acl, &open->op_label);
> if (status)
> goto out;
> break;
> @@ -981,7 +1031,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
> if (status)
> return status;
> return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
> - &setattr->sa_acl);
> + &setattr->sa_acl, &setattr->sa_label);
> }
>
> static __be32
> @@ -1045,7 +1095,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
> * nfsd4_proc_verify; however we still decode here just to return
> * correct error in case of bad xdr. */
> #if 0
> - status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl);
> + status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl, &ve_label);
> if (status == nfserr_inval) {
> status = nfserrno(status);
> goto out;
> @@ -1998,6 +2048,47 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
> FATTR4_WORD0_RDATTR_ERROR)
> #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
>
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> + static inline __be32
> +nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **pp, int *buflen)
> +{
> + void *context;
> + int err;
> + int len;
> + uint32_t pi = 0;
> + uint32_t lfs = 0;
> + __be32 *p = *pp;
> +
> + err = 0;
> + (void)security_inode_getsecctx(dentry->d_inode, &context, &len);
> + if (len < 0)
> + return nfserrno(len);
> +
> + if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) {
> + err = nfserr_resource;
> + goto out;
> + }
> +
> + /* XXX: A call to the translation code should be placed here
> + * for now send 0 until we have that to indicate the null
> + * translation */
> +
> + if ((*buflen -= 4) < 0)
> + return nfserr_resource;
> +
> + WRITE32(lfs);

Watch for odd whitespace.

> + WRITE32(pi);
> + p = xdr_encode_opaque(p, context, len);
> + *buflen -= (XDR_QUADLEN(len) << 2) + 4;
> + BUG_ON(*buflen < 0);

I'd rather lose the BUG_ON before we merge.

> +
> + *pp = p;
> +out:
> + security_release_secctx(context, len);
> + return err;
> +}
> +#endif
> +
> static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
> {
> /* As per referral draft: */
> @@ -2122,6 +2213,14 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
>
> if (!aclsupport)
> word0 &= ~FATTR4_WORD0_ACL;
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> + if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
> + word2 |= FATTR4_WORD2_SECURITY_LABEL;
> + else
> + word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
> +#else
> + word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
> +#endif
> if (!word2) {
> if ((buflen -= 12) < 0)
> goto out_resource;
> @@ -2444,6 +2543,16 @@ out_acl:
> }
> WRITE64(stat.ino);
> }
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> + if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
> + status = nfsd4_encode_security_label(rqstp, dentry,
> + &p, &buflen);
> + if (status == nfserr_resource)
> + goto out_resource;
> + if (status)
> + goto out;
> + }
> +#endif
> if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
> WRITE32(3);
> WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index c120b48..717fb60 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -28,6 +28,7 @@
> #include <asm/uaccess.h>
> #include <linux/exportfs.h>
> #include <linux/writeback.h>
> +#include <linux/security.h>
>
> #ifdef CONFIG_NFSD_V3
> #include "xdr3.h"
> @@ -621,6 +622,36 @@ int nfsd4_is_junction(struct dentry *dentry)
> return 0;
> return 1;
> }
> +
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> +__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
> + struct nfs4_label *label)
> +{
> + __be32 error;
> + int host_error;
> + struct dentry *dentry;
> +
> + /* Get inode */
> + /* XXX: should we have a MAY_SSECCTX? */

Should we?

> + error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
> + if (error)
> + return error;
> +
> + dentry = fhp->fh_dentry;
> +
> + mutex_lock(&dentry->d_inode->i_mutex);
> + host_error = security_inode_setsecctx(dentry, label->label, label->len);
> + mutex_unlock(&dentry->d_inode->i_mutex);
> + return nfserrno(host_error);
> +}
> +#else
> +__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
> + struct nfs4_label *label)
> +{
> + return -EOPNOTSUPP;
> +}
> +#endif
> +
> #endif /* defined(CONFIG_NFSD_V4) */
>
> #ifdef CONFIG_NFSD_V3
> diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
> index 359594c..49c6cc0 100644
> --- a/fs/nfsd/vfs.h
> +++ b/fs/nfsd/vfs.h
> @@ -55,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
> __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
> struct nfs4_acl *);
> int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
> +__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
> + struct nfs4_label *);
> #endif /* CONFIG_NFSD_V4 */
> __be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
> char *name, int len, struct iattr *attrs,
> --
> 1.7.11.7
>

2012-11-12 16:36:20

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 02/13] Security: Add Hook to test if the particular xattr is part of a MAC model.

On Mon, Nov 12, 2012 at 09:56:37AM -0500, Dave Quigley wrote:
> On 11/12/2012 7:15 AM, J. Bruce Fields wrote:
> >On Mon, Nov 12, 2012 at 01:15:36AM -0500, David Quigley wrote:
> >>From: David Quigley <[email protected]>
> >>
> >>The interface to request security labels from user space is the xattr
> >>interface. When requesting the security label from an NFS server it is
> >>important to make sure the requested xattr
> >
> >I'm confused--clients can't request xattrs from NFS servers. I must be
> >reading this wrong, but I'm not sure what you meant.
> >
> >--b.
> >
>
> Generically clients can't use xattrs from NFS servers but the LSM
> method for getting labels is through the xattr interface. THe point
> of this is if someone selects security.capability that we don't
> translate that into a call in labeled nfs to get the security label.
> We only want label based LSMs to cause a getfattr on the server to
> grab the label and populate the inode with that information.
> Currently if you use security.selinux or security.smack then labeled
> nfs will handle the translation of that into a get/setfattr on the
> security_label attribute in NFSv4.

OK, I think I understand: so this is to help the NFS client implement
the necessary xattr interface for userspace that get and sets security
labels on NFS filesystems?

--b.

>
>
> >>actually is a MAC label. This allows
> >>us to make sure that we get the desired semantics from the attribute instead of
> >>something else such as capabilities or a time based LSM.
> >>
> >>Signed-off-by: Matthew N. Dodd <[email protected]>
> >>Signed-off-by: Miguel Rodel Felipe <[email protected]>
> >>Signed-off-by: Phua Eu Gene <[email protected]>
> >>Signed-off-by: Khin Mi Mi Aung <[email protected]>
> >>Signed-off-by: David Quigley <[email protected]>
> >>---
> >> include/linux/security.h | 14 ++++++++++++++
> >> security/capability.c | 6 ++++++
> >> security/security.c | 6 ++++++
> >> security/selinux/hooks.c | 6 ++++++
> >> security/smack/smack_lsm.c | 11 +++++++++++
> >> 5 files changed, 43 insertions(+)
> >>
> >>diff --git a/include/linux/security.h b/include/linux/security.h
> >>index c9f5eec..167bdd5 100644
> >>--- a/include/linux/security.h
> >>+++ b/include/linux/security.h
> >>@@ -1301,6 +1301,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> >> * @pages contains the number of pages.
> >> * Return 0 if permission is granted.
> >> *
> >>+ * @ismaclabel:
> >>+ * Check if the extended attribute specified by @name
> >>+ * represents a MAC label. Returns 0 if name is a MAC
> >>+ * attribute otherwise returns non-zero.
> >>+ * @name full extended attribute name to check against
> >>+ * LSM as a MAC label.
> >>+ *
> >> * @secid_to_secctx:
> >> * Convert secid to security context. If secdata is NULL the length of
> >> * the result will be returned in seclen, but no secdata will be returned.
> >>@@ -1581,6 +1588,7 @@ struct security_operations {
> >>
> >> int (*getprocattr) (struct task_struct *p, char *name, char **value);
> >> int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
> >>+ int (*ismaclabel) (const char *name);
> >> int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
> >> int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> >> void (*release_secctx) (char *secdata, u32 seclen);
> >>@@ -1829,6 +1837,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
> >> int security_getprocattr(struct task_struct *p, char *name, char **value);
> >> int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
> >> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
> >>+int security_ismaclabel(const char *name);
> >> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> >> int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> >> void security_release_secctx(char *secdata, u32 seclen);
> >>@@ -2512,6 +2521,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
> >> return cap_netlink_send(sk, skb);
> >> }
> >>
> >>+static inline int security_ismaclabel(const char *name)
> >>+{
> >>+ return 0;
> >>+}
> >>+
> >> static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >> {
> >> return -EOPNOTSUPP;
> >>diff --git a/security/capability.c b/security/capability.c
> >>index f1eb284..9071447 100644
> >>--- a/security/capability.c
> >>+++ b/security/capability.c
> >>@@ -797,6 +797,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
> >> return -EINVAL;
> >> }
> >>
> >>+static int cap_ismaclabel(const char *name)
> >>+{
> >>+ return 0;
> >>+}
> >>+
> >> static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >> {
> >> return -EOPNOTSUPP;
> >>@@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
> >> set_to_cap_if_null(ops, d_instantiate);
> >> set_to_cap_if_null(ops, getprocattr);
> >> set_to_cap_if_null(ops, setprocattr);
> >>+ set_to_cap_if_null(ops, ismaclabel);
> >> set_to_cap_if_null(ops, secid_to_secctx);
> >> set_to_cap_if_null(ops, secctx_to_secid);
> >> set_to_cap_if_null(ops, release_secctx);
> >>diff --git a/security/security.c b/security/security.c
> >>index b4b2017..a7bee7b 100644
> >>--- a/security/security.c
> >>+++ b/security/security.c
> >>@@ -1047,6 +1047,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
> >> return security_ops->netlink_send(sk, skb);
> >> }
> >>
> >>+int security_ismaclabel(const char *name)
> >>+{
> >>+ return security_ops->ismaclabel(name);
> >>+}
> >>+EXPORT_SYMBOL(security_ismaclabel);
> >>+
> >> int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >> {
> >> return security_ops->secid_to_secctx(secid, secdata, seclen);
> >>diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> >>index 22d9adf..f7c4899 100644
> >>--- a/security/selinux/hooks.c
> >>+++ b/security/selinux/hooks.c
> >>@@ -5401,6 +5401,11 @@ abort_change:
> >> return error;
> >> }
> >>
> >>+static int selinux_ismaclabel(const char *name)
> >>+{
> >>+ return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
> >>+}
> >>+
> >> static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
> >> {
> >> return security_sid_to_context(secid, secdata, seclen);
> >>@@ -5639,6 +5644,7 @@ static struct security_operations selinux_ops = {
> >> .getprocattr = selinux_getprocattr,
> >> .setprocattr = selinux_setprocattr,
> >>
> >>+ .ismaclabel = selinux_ismaclabel,
> >> .secid_to_secctx = selinux_secid_to_secctx,
> >> .secctx_to_secid = selinux_secctx_to_secid,
> >> .release_secctx = selinux_release_secctx,
> >>diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> >>index 38be92c..82c3c72 100644
> >>--- a/security/smack/smack_lsm.c
> >>+++ b/security/smack/smack_lsm.c
> >>@@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void *vrule)
> >> #endif /* CONFIG_AUDIT */
> >>
> >> /**
> >>+ * smack_ismaclabel - check if xattr @name references a smack MAC label
> >>+ * @name: Full xattr name to check.
> >>+ */
> >>+static int smack_ismaclabel(const char *name)
> >>+{
> >>+ return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
> >>+}
> >>+
> >>+
> >>+/**
> >> * smack_secid_to_secctx - return the smack label for a secid
> >> * @secid: incoming integer
> >> * @secdata: destination
> >>@@ -3530,6 +3540,7 @@ struct security_operations smack_ops = {
> >> .audit_rule_free = smack_audit_rule_free,
> >> #endif /* CONFIG_AUDIT */
> >>
> >>+ .ismaclabel = smack_ismaclabel,
> >> .secid_to_secctx = smack_secid_to_secctx,
> >> .secctx_to_secid = smack_secctx_to_secid,
> >> .release_secctx = smack_release_secctx,
> >>--
> >>1.7.11.7
> >>
> >
>

2012-11-29 22:49:36

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

I have an idea of what it is then. I'm cloning the tree so I can take a
look really quick but I have a feeling that I didn't convey something
properly and it got messed up in the implementation. If that's the case
I'll make sure to be clearer next time to avoid confusion.

2012-11-14 14:25:01

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Wed, Nov 14, 2012 at 09:04:18AM -0500, David Quigley wrote:
> On 11/14/2012 08:59, J. Bruce Fields wrote:
> >On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
> >>On 11/14/2012 08:45, J. Bruce Fields wrote:
> >>>On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
> >>>>Ok so if you go to http://www.selinuxproject.org/git you will
> >>see a
> >>>>repo for lnfs and lnfs-patchset. The instructions at
> >>>>http://www.selinuxproject.org/page/Labeled_NFS give you a better
> >>>>indication on how to pull the trees. I've attached a patch for NFS
> >>>>utils which gives support for security_label/nosecurity_label in
> >>>>your /etc/exports file.
> >>>
> >>>Do we need an export option? Is there any reason not to make the
> >>>feature available whenever there's support available for it?
> >>
> >>I guess we could build it in but I figured an export option allowed
> >>someone to turn off security labeling support if they didn't want it
> >>on that export. What happens to clients when the server returns a
> >>cap that they don't support? Do they mask the bits out?
> >
> >Yeah, they should just ignore it.
> >
> >While this is still experimental it's still nice to have a way to
> >turn
> >this on and off at runtime so people can experiment without having to
> >have it on for everyone all the time. But
> >nfsd_supported_minorversion
> >should be sufficient for that.
> >
> >(I don't think your patches actually dealt yet with the fact that
> >this
> >is part of minor version 2? Another for the todo list.)
> >
> >--b.
>
> If we use nfsd_supported_minorversion which I'm guessing is an
> export option

That's just a variable in the code. It's controlled by
/proc/fs/nfsd/versions.

> what happens if someone wants to use other 4.2
> features but not labeling?

We'll cross that bridge when we come to it, maybe by adding some new
global paramater.

There's no reason this really needs to be per-export, is there?

--b.

> I'll switch it over if you guys want it
> done that way, I think though that this provides more flexibility.
> Although anything that makes me carry around fewer patches is good
> in my book.
>
> Dave

2012-11-30 16:55:49

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Fri, Nov 30, 2012 at 08:50:55AM -0500, Stephen Smalley wrote:
> On the SELinux side, we don't require CAP_MAC_ADMIN to set the
> SELinux attribute on a file in the normal case, only when the
> SELinux attribute is not known to the security policy yet. So
> granting CAP_MAC_ADMIN there means that a client will be able to set
> security contexts on files that are unknown to the server. I guess
> that might even be desirable in some instances where client and
> server policy are different.

Note (as you probably know) this first pass at labeled NFS only lets us
label files, not rpc calls--if we want the server to know who's doing
something (beyond the information the rpc headers already carry), we'll
need to implement rpcsec_gss v3, and that's a project for another day.

I've been assuming that makes server-side enforcement less useful for
now.

--b.

2012-11-12 20:56:16

by Steve Dickson

[permalink] [raw]
Subject: Re: Labeled NFS [v5]



On 12/11/12 11:09, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 10:34:08AM -0500, David P. Quigley wrote:
>> On 11/12/2012 10:23 AM, J. Bruce Fields wrote:
>>> On Mon, Nov 12, 2012 at 01:15:34AM -0500, David Quigley wrote:
>>>> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
>>>> specification and it has been decided that a reposting of the Labeled NFS code
>>>> for inclusion into mainline was a good idea. The patches have been rebased onto
>>>> v3.7-rc2 and have been tested against the SELinux testsuite with the only
>>>> failures being for features not supported by NFS.
>>> By the way, is there wireshark support anywhere for the labeled NFS
>>> protocol?
>>>
>>> --b.
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
>>> the body of a message to [email protected]
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>>
>>
>> Unfortunately I never got a chance to add it. You can see the label
>> pretty clearly in wireshark but it comes up as an unknown attribute
>> in the fattr decomposition. If someone knows how to do it I'd be
>> glad to help.
>
> It's usually not too hard: last time I needed something I did a
>
> git clone http://code.wireshark.org/git/wireshark
>
> then grepped through epan/dissectors/packet-nfs.c for something similar
> to imitate. It wa easy to build and run the result from the build
> directory. Then I submitted a patch following:
>
> http://www.wireshark.org/docs/wsdg_html_chunked/ChSrcContribute.html#ChSrcSend
>
> and the response was quick and helpful.
>
> (But yeah I don't have time to volunteer right now either.)
Maybe I could take a look into helping out... If you guys can point
me a some binary traces or a boot-able kernel I can take a crack
at coming up with some dissectors...

Connectathon is 3.5 months out so hopefully we can come up with
something by then....

steved.


2012-11-30 00:46:44

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/29/2012 19:34, Casey Schaufler wrote:
> On 11/29/2012 4:07 PM, David Quigley wrote:
>> On 11/29/2012 17:28, Casey Schaufler wrote:
>>> On 11/28/2012 6:08 PM, Casey Schaufler wrote:
>>>> On 11/28/2012 5:14 PM, Dave Quigley wrote:
>>>>> On 11/28/2012 1:57 PM, Casey Schaufler wrote:
>>>>>> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>>>>>>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>>>>>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>>>>>>> ...
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Or I could just give you this link and you should be good to
>>>>>>>>> go ;)
>>>>>>>>>
>>>>>>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>>>>>>
>>>>>>>>> I haven't tried it but it should work. If it doesn't let me
>>>>>>>>> know and
>>>>>>>>> i'll try to fix it on my end. I'd imagine you might need to
>>>>>>>>> yum
>>>>>>>>> remove
>>>>>>>>> nfs-utils first before adding this new one or you could also
>>>>>>>>> try an
>>>>>>>>> rpm with the upgrade flag for this instead. Good luck.
>>>>>> ...
>>>>>>
>>>>>>
>>>>>> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
>>>>>> attached stack trace on mount. After mounting I'm getting
>>>>>> denials when I should, but also when I shouldn't.
>>>>>>
>>>>>> I've tried tracking down the issue, but there's a lot going on
>>>>>> that I don't find obvious. I added a dentry_init hook just for
>>>>>> grins, but it's not getting called.
>>>>>>
>>>>>> .
>>>>>>
>>>>>>
>>>>> Any chance of you throwing a kickstart file my way that's
>>>>> configured
>>>>> with SMACK so I can use it for a test box (both server and
>>>>> client)? I
>>>>> can have the guys working with me test for SMACK as well if you
>>>>> provide an appropriate test harness and image for testing.
>>>> I've attached the .config from my Fedora17 machine. Who knows,
>>>> maybe
>>>> I got something wrong there. I get the error doing the test on the
>>>> loopback interface (mount -t nfs4 localhist:/ /mnt).
>>>
>>> I've done some instrumentation and security_ismaclabel() is getting
>>> called with "selinux", but never "SMACK64". I would guess that
>>> somewhere
>>> in the tools you're telling the kernel to expect "selinux". Where
>>> is
>>> that, so that I can tell it to try "SMACK64" instead?
>>>
>>>
>>>
>>> --
>>> This message was distributed to subscribers of the selinux mailing
>>> list.
>>> If you no longer wish to subscribe, send mail to
>>> [email protected] with
>>> the words "unsubscribe selinux" without quotes as the message.
>>
>>
>> What tools do you use in SMACK to see the labels?
>
> attr -S -g SMACK64 <path>

ok so that seems to work for SELinux as well. Never knew about that.
I'd always just rip the xattr out of the inode with getfattr.


>
>> Do you just use getxattr? If so can you try calling that and seeing
>> what happens? I'm concerned that you aren't getting any attribute
>> information on that file.
>
> I would think that were it not for the case that access is denied
> and I get an audit record for nfsd that reports a subject label of
> "_"
> (which is correct for nfsd but not the process attempting access) and
> an object label of "WhooHoo", which is correct. The server side
> looks like it might be working right, given the information that it
> has.
>

Ok so this is the problem. nfsd is a kernel thread I believe. In
SELinux land it has the type kernel_t which is all powerful. We don't
have client label transport yet (That requires RPCSECGSSv3). Is there a
way you can have that kernel thread running as a type that has access to
everything? I think that is the current problem. Which makes perfect
sense. If your kernel threads don't get started with max privilege then
the server would be denied access on all of the file attributes and
wouldn't be able to ship it over the wire properly. I'm not sure what
you need to do but you'll probably have to work this out. We have a
usage mode in the IETF spec which has a non-mac enforcing server which
still support object labeling. In the SELinux case it works for us since
kernel_t can access anything. Ideally when RPCSECGSSv3 is finished and
merged we'll be able to choose whether to use the label of the process
on the client side or kernel_t for the server if its not available.

>> Do you have a disto that I can use that has full smack integration
>> and
>> is easy to setup?
>
> There's no full integration, but Ubuntu is easy to set up because
> they
> compile in all the LSMs.
> Set "security=smack" on the boot line in grub.cfg and reboot.
>
> All processes and files will get the floor ("_") label unless you
> change
> one. You can change
> a file label with:
> # attr -S -s SMACK64 WhooHoo path
> or execute at a different label with:
> # (echo WhooHoo > /proc/self/attr/current ; command)
>

I'm not out of here until really late tonight so getting an Ubuntu VM
setup probably won't happen until sometime next week when everything
calms down. However I think we isolated the problem above. If I'm
correct this is strictly a smack labeling problem. I don't know if you
need to put some code into smack to init kernel threads with a more
powerful label or not so I'll leave it up to you on how to address this.


Dave

2012-11-21 00:04:09

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/20/2012 4:09 PM, Casey Schaufler wrote:
> On 11/11/2012 10:15 PM, David Quigley wrote:
>> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
>> specification and it has been decided that a reposting of the Labeled NFS code
>> for inclusion into mainline was a good idea. The patches have been rebased onto
>> v3.7-rc2 and have been tested against the SELinux testsuite with the only
>> failures being for features not supported by NFS.
>
> I'm trying to get the user space tools built so that I can
> do Smack testing. The instructions on selinuxproject.org
> seen out of date with regard to the packages required to
> build the NFS tools. I have failed to build on Fedora 17
> and Ubuntu 12.04. Any pointers beyond what's on the wiki?
>
> Thank you.
>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to [email protected] with
> the words "unsubscribe selinux" without quotes as the message.
>
>

There are a bunch of libs that need to be installed for it to compile
properly. Unfortunately there are new dependencies which have been added
since I updated the wiki last. I unfortunately don't remember what they
are. What I did to build it last time though was to apply the one patch
onto the latest tag from the nfs-utils tree. Unfortunately I don't have
a clean vm on hand at the moment so I can't manually go through and list
all the packages for you. A heavy handed approach that should still work
is that I can give you my rpm list from my VM and then you can just make
sure you have all the devel packages installed. Another option would be
to grab the nfs-utils srpm for fedora 17 and just add the patch into the
spec file. That would work too and tell you the build dependencies you
need. I could also just try to make that for you and put the RPM up but
that wouldn't be for a few days at the earliest.

Dave

2012-11-13 00:12:11

by Dave Quigley

[permalink] [raw]
Subject: Re: [PATCH 02/13] Security: Add Hook to test if the particular xattr is part of a MAC model.

On 11/12/2012 4:43 PM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 02:36:09PM -0500, David P. Quigley wrote:
>> On 11/12/2012 11:36 AM, J. Bruce Fields wrote:
>>> On Mon, Nov 12, 2012 at 09:56:37AM -0500, Dave Quigley wrote:
>>>> On 11/12/2012 7:15 AM, J. Bruce Fields wrote:
>>>>> On Mon, Nov 12, 2012 at 01:15:36AM -0500, David Quigley wrote:
>>>>>> From: David Quigley<[email protected]>
>>>>>>
>>>>>> The interface to request security labels from user space is the xattr
>>>>>> interface. When requesting the security label from an NFS server it is
>>>>>> important to make sure the requested xattr
>>>>> I'm confused--clients can't request xattrs from NFS servers. I must be
>>>>> reading this wrong, but I'm not sure what you meant.
>>>>>
>>>>> --b.
>>>>>
>>>> Generically clients can't use xattrs from NFS servers but the LSM
>>>> method for getting labels is through the xattr interface. THe point
>>>> of this is if someone selects security.capability that we don't
>>>> translate that into a call in labeled nfs to get the security label.
>>>> We only want label based LSMs to cause a getfattr on the server to
>>>> grab the label and populate the inode with that information.
>>>> Currently if you use security.selinux or security.smack then labeled
>>>> nfs will handle the translation of that into a get/setfattr on the
>>>> security_label attribute in NFSv4.
>>> OK, I think I understand: so this is to help the NFS client implement
>>> the necessary xattr interface for userspace that get and sets security
>>> labels on NFS filesystems?
>>>
>>> --b.
>>
>> Exactly. The problem is we don't want to have LSM specific logic in
>> so the best we can do is ask if the security.* xattr being accessed
>> has the proper semantics to be used with Labeled NFS.
>
> OK, thanks. The changelog could probably be clarified (at least make it
> clear that this is for the client side.)
>
> Delaying this patch till right before the patch that actually uses it
> might also help (and/or even combining those two patches).
>
> --b.
>

I should be able to rearrange them and change the patch text. Merging
probably isn't a good idea since all of this code is in LSMs so it seems
weird to put it in with the NFS code.


2012-11-15 16:06:54

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/14/2012 6:30 AM, David Quigley wrote:
> On 11/14/2012 09:24, J. Bruce Fields wrote:
>> On Wed, Nov 14, 2012 at 09:04:18AM -0500, David Quigley wrote:
>>> On 11/14/2012 08:59, J. Bruce Fields wrote:
>>> >On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
>>> >>On 11/14/2012 08:45, J. Bruce Fields wrote:
>>> >>>On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>>> >>>>Ok so if you go to http://www.selinuxproject.org/git you will
>>> >>see a
>>> >>>>repo for lnfs and lnfs-patchset. The instructions at
>>> >>>>http://www.selinuxproject.org/page/Labeled_NFS give you a better
>>> >>>>indication on how to pull the trees. I've attached a patch for NFS
>>> >>>>utils which gives support for security_label/nosecurity_label in
>>> >>>>your /etc/exports file.
>>> >>>
>>> >>>Do we need an export option? Is there any reason not to make the
>>> >>>feature available whenever there's support available for it?
>>> >>
>>> >>I guess we could build it in but I figured an export option allowed
>>> >>someone to turn off security labeling support if they didn't want it
>>> >>on that export. What happens to clients when the server returns a
>>> >>cap that they don't support? Do they mask the bits out?
>>> >
>>> >Yeah, they should just ignore it.
>>> >
>>> >While this is still experimental it's still nice to have a way to
>>> >turn
>>> >this on and off at runtime so people can experiment without having to
>>> >have it on for everyone all the time. But
>>> >nfsd_supported_minorversion
>>> >should be sufficient for that.
>>> >
>>> >(I don't think your patches actually dealt yet with the fact that
>>> >this
>>> >is part of minor version 2? Another for the todo list.)
>>> >
>>> >--b.
>>>
>>> If we use nfsd_supported_minorversion which I'm guessing is an
>>> export option
>>
>> That's just a variable in the code. It's controlled by
>> /proc/fs/nfsd/versions.
>>
>>> what happens if someone wants to use other 4.2
>>> features but not labeling?
>>
>> We'll cross that bridge when we come to it, maybe by adding some new
>> global paramater.
>>
>> There's no reason this really needs to be per-export, is there?
>>
>> --b.
>
> At the moment I can't really think of a reason to have it be
> per-export. I think we need a new LSM patch though to determine if the
> LSM supports labeling over NFS unless Steve can think of a better way
> to tell if the LSM supports labeling.

If the LSM has a secid_to_secctx hook it supports labeling.
Today that's SELinux and Smack. You already have support in
for SELinux, and providing Smack's review and possibly updates
is #2 on my gotta do list. On the whole, I think that, except
for the fundamental philosophical difference between label
support and xattr support, it should be a simple matter to
get support in for any LSM that has secid_to_secctx.

But I'm still working on the review.

>
>
>>
>>> I'll switch it over if you guys want it
>>> done that way, I think though that this provides more flexibility.
>>> Although anything that makes me carry around fewer patches is good
>>> in my book.
>>>
>>> Dave
>
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


2012-11-14 14:01:37

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/14/2012 08:59, J. Bruce Fields wrote:
> On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
>> On 11/14/2012 08:45, J. Bruce Fields wrote:
>> >On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>> >>Ok so if you go to http://www.selinuxproject.org/git you will see
>> a
>> >>repo for lnfs and lnfs-patchset. The instructions at
>> >>http://www.selinuxproject.org/page/Labeled_NFS give you a better
>> >>indication on how to pull the trees. I've attached a patch for NFS
>> >>utils which gives support for security_label/nosecurity_label in
>> >>your /etc/exports file.
>> >
>> >Do we need an export option? Is there any reason not to make the
>> >feature available whenever there's support available for it?
>>
>> I guess we could build it in but I figured an export option allowed
>> someone to turn off security labeling support if they didn't want it
>> on that export. What happens to clients when the server returns a
>> cap that they don't support? Do they mask the bits out?
>
> Yeah, they should just ignore it.
>
> While this is still experimental it's still nice to have a way to
> turn
> this on and off at runtime so people can experiment without having to
> have it on for everyone all the time. But
> nfsd_supported_minorversion
> should be sufficient for that.
>
> (I don't think your patches actually dealt yet with the fact that
> this
> is part of minor version 2? Another for the todo list.)
>
> --b.

Hmm... I'll have to look at the patches again to find out. Its been so
long since I worked on these full time that I have to go back and check
quite a bit. Luckily since i put the tree up for Trond last night I
should be able to look at them while at work.

2012-11-14 13:59:42

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
> On 11/14/2012 08:45, J. Bruce Fields wrote:
> >On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
> >>Ok so if you go to http://www.selinuxproject.org/git you will see a
> >>repo for lnfs and lnfs-patchset. The instructions at
> >>http://www.selinuxproject.org/page/Labeled_NFS give you a better
> >>indication on how to pull the trees. I've attached a patch for NFS
> >>utils which gives support for security_label/nosecurity_label in
> >>your /etc/exports file.
> >
> >Do we need an export option? Is there any reason not to make the
> >feature available whenever there's support available for it?
>
> I guess we could build it in but I figured an export option allowed
> someone to turn off security labeling support if they didn't want it
> on that export. What happens to clients when the server returns a
> cap that they don't support? Do they mask the bits out?

Yeah, they should just ignore it.

While this is still experimental it's still nice to have a way to turn
this on and off at runtime so people can experiment without having to
have it on for everyone all the time. But nfsd_supported_minorversion
should be sufficient for that.

(I don't think your patches actually dealt yet with the fact that this
is part of minor version 2? Another for the todo list.)

--b.

2012-11-30 16:28:36

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 11:21, Casey Schaufler wrote:
> On 11/30/2012 6:02 AM, David Quigley wrote:
>
> There are times when living by the correct ocean makes
> life so much easier. Thanks all for the early morning
> brain work.
>
>> On 11/30/2012 08:50, Stephen Smalley wrote:
>>> On 11/30/2012 08:35 AM, David Quigley wrote:
>>>> On 11/30/2012 08:28, Stephen Smalley wrote:
>>>>> On 11/30/2012 08:17 AM, David Quigley wrote:
>>>>>> On 11/30/2012 07:57, David Quigley wrote:
>>>>>>> On 11/30/2012 07:14, J. Bruce Fields wrote:
>>>>>>>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>>>>>>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>>>>>>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>>>>>>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>>>>>>>> >... Whole bunch snipped ...
>>>
>>> Looks like Smack requires CAP_MAC_ADMIN in order to set Smack
>>> attributes on a file at all. So nfsd would require that capability
>>> for Smack. I think this means however that setting Smack labels on
>>> NFS files won't work in any case where root is squashed, which
>>> seems
>>> unfortunate.
>
> I'm building a kernel with CAP_MAC_ADMIN set for nfsd.
> I am reasonably sure that this will get me past the current
> issue. As far as a squashed root goes, well, doing things
> that the security policy doesn't allow requires privilege.
>
>>
>> I'll leave that problem to Casey to figure out. However it seems to
>> me
>> that regardless of Labeled NFS Casey should have problems with the
>> NFS
>> server not being able to serve up files that are dominated by floor.
>> I
>> wonder if he has every tried NFSv4 on a SMACK enabled server before.
>> It may have just worked because all files implicitly get labeled
>> floor.
>
> CAP_MAC_OVERRIDE, which nfsd does have, is sufficient for
> reading and writing files. A Smack enabled server is able
> to serve to Smack and Smackless clients, but of course all
> label enforcement is lost. Thus it will "work", but it will
> be bad. I haven't used NFS much lately, in part because of
> the lack of labeling and the security issues inherent in
> serving labeled files to clueless clients.

Can we confirm that this problem doesn't manifest itself without a
Labeled NFS kernel? Set the labels on the exported files properly and
then just mount over NFSv4 and see what happens?


>
>
>>
>>>
>>> On the SELinux side, we don't require CAP_MAC_ADMIN to set the
>>> SELinux attribute on a file in the normal case, only when the
>>> SELinux
>>> attribute is not known to the security policy yet. So granting
>>> CAP_MAC_ADMIN there means that a client will be able to set
>>> security
>>> contexts on files that are unknown to the server. I guess that
>>> might
>>> even be desirable in some instances where client and server policy
>>> are
>>> different. We do have the option of denying mac_admin permission
>>> in
>>> policy for nfsd (kernel_t?), in which case we would block such
>>> attempts to set unknown contexts but would still support setting of
>>> known security contexts.
>>>
>>> So I think it is workable, albeit a bit confusing.
>>
>> Yea it is unfortunate that we have to go mucking around in
>> capability
>> land but it seems that adding CAP_MAC_ADMIN should be fine and we
>> can
>> deal with it in policy if we like.
>
> Worst case we could add a security_set_nfsd_capabilities hook.
> Maybe make the capability set an export option?
>
>>
>>
>> --
>> This message was distributed to subscribers of the selinux mailing
>> list.
>> If you no longer wish to subscribe, send mail to
>> [email protected] with
>> the words "unsubscribe selinux" without quotes as the message.
>>


2012-11-21 03:29:03

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/20/2012 9:52 PM, Casey Schaufler wrote:
> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>> ...
>>
>>
>> Or I could just give you this link and you should be good to go ;)
>>
>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>
>> I haven't tried it but it should work. If it doesn't let me know and
>> i'll try to fix it on my end. I'd imagine you might need to yum remove
>> nfs-utils first before adding this new one or you could also try an
>> rpm with the upgrade flag for this instead. Good luck.
>
> I don't care what Eric says, you're OK with me.
>
> The behavior is interesting with a Smack kernel:
>
> I create an export using the recommended options (sec=unix,security_label, ...)
> of /pub. Then , I create a directory sub with the floor ("_") label and a file
> named Pop labeled "Pop". I mount the filesystem at /mnt.
>
> # ls -l /mnt
> ls: cannot access /mnt/Pop: Permission Denied
> total 4
> ?????????? ? ? ? ? ? Pop
> drwxr-xr-x 2 root root 4096 Nov 20 17:57 sub
>
> which is exactly correct!
>
> Unfortunately, I get the exact same result if the process
> is run with the Pop label. A process run with the Pop label
> should be able to see the attributes of the file Pop.
>
> It looks as if the basic mechanism is working, but that there
> is some detail that is not working right. I will have to dig
> deeper to understand what's up. Let me know if you have ideas.
>
>
>>
>> Dave
>>
>> --
>> This message was distributed to subscribers of the selinux mailing list.
>> If you no longer wish to subscribe, send mail to
>> [email protected] with
>> the words "unsubscribe selinux" without quotes as the message.
>>
>

You might want to load up wireshark and see if the getfattr call is what
is failing. If it is then its an issue with the interaction between
smack and the server components. Otherwise I'm not sure you'll have to
look in the NFS debug info to find the call that is failing. ]

Dave

2012-11-12 16:33:17

by J. Bruce Fields

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On Mon, Nov 12, 2012 at 01:15:34AM -0500, David Quigley wrote:
> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
> specification and it has been decided that a reposting of the Labeled NFS code
> for inclusion into mainline was a good idea. The patches have been rebased onto
> v3.7-rc2 and have been tested against the SELinux testsuite with the only
> failures being for features not supported by NFS.

This will still need support for FATTR4_CHANGE_SEC_LABEL.

--b.

2012-11-21 00:37:37

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/20/2012 7:32 PM, Casey Schaufler wrote:
> On 11/20/2012 4:04 PM, Dave Quigley wrote:
>> On 11/20/2012 4:09 PM, Casey Schaufler wrote:
>>> On 11/11/2012 10:15 PM, David Quigley wrote:
>>>> The NFSv4 working group has finally accepted Labeled NFS as part of
>>>> the NFSv4.2
>>>> specification and it has been decided that a reposting of the
>>>> Labeled NFS code
>>>> for inclusion into mainline was a good idea. The patches have been
>>>> rebased onto
>>>> v3.7-rc2 and have been tested against the SELinux testsuite with the
>>>> only
>>>> failures being for features not supported by NFS.
>>>
>>> I'm trying to get the user space tools built so that I can
>>> do Smack testing. The instructions on selinuxproject.org
>>> seen out of date with regard to the packages required to
>>> build the NFS tools. I have failed to build on Fedora 17
>>> and Ubuntu 12.04. Any pointers beyond what's on the wiki?
>>>
>>> Thank you.
>>>
>>>
>>> --
>>> This message was distributed to subscribers of the selinux mailing list.
>>> If you no longer wish to subscribe, send mail to
>>> [email protected] with
>>> the words "unsubscribe selinux" without quotes as the message.
>>>
>>>
>>
>> There are a bunch of libs that need to be installed for it to compile
>> properly.
>
> Yes, indeed!
>
>> Unfortunately there are new dependencies which have been added since I
>> updated the wiki last.
>
> I found that to be the case as well.
>
>> unfortunately don't remember what they are.
>
> And they're not obvious.
>
>> What I did to build it last time though was to apply the one patch
>> onto the latest tag from the nfs-utils tree.
>
> Sound simple enough if you're building the nfs-util tree on a daily basis
> I suppose. Not something that I do regularly, alas.
>
>
>> Unfortunately I don't have a clean vm on hand at the moment so I can't
>> manually go through and list all the packages for you. A heavy handed
>> approach that should still work is that I can give you my rpm list
>> from my VM and then you can just make sure you have all the devel
>> packages installed.
>
> I'd be up for that.
>
>
>> Another option would be to grab the nfs-utils srpm for fedora 17 and
>> just add the patch into the spec file.
>
> Yeah. Or not.
>
>> That would work too and tell you the build dependencies you need. I
>> could also just try to make that for you and put the RPM up but that
>> wouldn't be for a few days at the earliest.
>
> That, or I could give you the instructions on how to enable and test
> Smack.
>
> Thank you.
>
>
>>
>> Dave
>>
>


Or I could just give you this link and you should be good to go ;)

http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/

I haven't tried it but it should work. If it doesn't let me know and
i'll try to fix it on my end. I'd imagine you might need to yum remove
nfs-utils first before adding this new one or you could also try an rpm
with the upgrade flag for this instead. Good luck.

Dave

2012-11-14 14:30:04

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/14/2012 09:24, J. Bruce Fields wrote:
> On Wed, Nov 14, 2012 at 09:04:18AM -0500, David Quigley wrote:
>> On 11/14/2012 08:59, J. Bruce Fields wrote:
>> >On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
>> >>On 11/14/2012 08:45, J. Bruce Fields wrote:
>> >>>On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>> >>>>Ok so if you go to http://www.selinuxproject.org/git you will
>> >>see a
>> >>>>repo for lnfs and lnfs-patchset. The instructions at
>> >>>>http://www.selinuxproject.org/page/Labeled_NFS give you a better
>> >>>>indication on how to pull the trees. I've attached a patch for
>> NFS
>> >>>>utils which gives support for security_label/nosecurity_label in
>> >>>>your /etc/exports file.
>> >>>
>> >>>Do we need an export option? Is there any reason not to make the
>> >>>feature available whenever there's support available for it?
>> >>
>> >>I guess we could build it in but I figured an export option
>> allowed
>> >>someone to turn off security labeling support if they didn't want
>> it
>> >>on that export. What happens to clients when the server returns a
>> >>cap that they don't support? Do they mask the bits out?
>> >
>> >Yeah, they should just ignore it.
>> >
>> >While this is still experimental it's still nice to have a way to
>> >turn
>> >this on and off at runtime so people can experiment without having
>> to
>> >have it on for everyone all the time. But
>> >nfsd_supported_minorversion
>> >should be sufficient for that.
>> >
>> >(I don't think your patches actually dealt yet with the fact that
>> >this
>> >is part of minor version 2? Another for the todo list.)
>> >
>> >--b.
>>
>> If we use nfsd_supported_minorversion which I'm guessing is an
>> export option
>
> That's just a variable in the code. It's controlled by
> /proc/fs/nfsd/versions.
>
>> what happens if someone wants to use other 4.2
>> features but not labeling?
>
> We'll cross that bridge when we come to it, maybe by adding some new
> global paramater.
>
> There's no reason this really needs to be per-export, is there?
>
> --b.

At the moment I can't really think of a reason to have it be
per-export. I think we need a new LSM patch though to determine if the
LSM supports labeling over NFS unless Steve can think of a better way to
tell if the LSM supports labeling.


>
>> I'll switch it over if you guys want it
>> done that way, I think though that this provides more flexibility.
>> Although anything that makes me carry around fewer patches is good
>> in my book.
>>
>> Dave


2012-11-12 15:04:00

by Dave Quigley

[permalink] [raw]
Subject: Re: [PATCH 05/13] KConfig: Add KConfig entries for Labeled NFS

On 11/12/2012 9:45 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 01:15:39AM -0500, David Quigley wrote:
>> From: David Quigley <[email protected]>
>>
>> This patch adds two entries into the fs/KConfig file. The first entry
>> NFS_V4_SECURITY_LABEL enables security label support for the NFSv4 client while
>> the second entry NFSD_V4_SECURITY_LABEL enables security labeling support on
>> the server side.
>>
>> Signed-off-by: Matthew N. Dodd <[email protected]>
>> Signed-off-by: Miguel Rodel Felipe <[email protected]>
>> Signed-off-by: Phua Eu Gene <[email protected]>
>> Signed-off-by: Khin Mi Mi Aung <[email protected]>
>> Signed-off-by: David Quigley <[email protected]>
>> ---
>> fs/nfs/Kconfig | 16 ++++++++++++++++
>> fs/nfsd/Kconfig | 13 +++++++++++++
>> 2 files changed, 29 insertions(+)
>>
>> diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
>> index 13ca196..0077197 100644
>> --- a/fs/nfs/Kconfig
>> +++ b/fs/nfs/Kconfig
>> @@ -131,6 +131,22 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
>> If the NFS client is unchanged from the upstream kernel, this
>> option should be set to the default "kernel.org".
>>
>> +config NFS_V4_SECURITY_LABEL
>> + bool "Provide Security Label support for NFSv4 client"
>> + depends on NFS_V4 && SECURITY
>> + help
>> +
>> + Say Y here if you want enable fine-grained security label attribute
>> + support for NFS version 4. Security labels allow security modules like
>> + SELinux and Smack to label files to facilitate enforcement of their policies.
>> + Without this an NFSv4 mount will have the same label on each file.
>> +
>> + If you do not wish to enable fine-grained security labels SELinux or
>> + Smack policies on NFSv4 files, say N.
>
> Here and below we also need some warning abouot the current state of
> this: we definitely want to warn any distro that might be tempted to
> turn this on by default that there's still a chance of
> backwards-incompatible protocol changes.
>
> --b.
>

Sounds good to me I'll make sure to include that.

>> +
>> +
>> + If unsure, say N.
>> +
>> config ROOT_NFS
>> bool "Root file system on NFS"
>> depends on NFS_FS=y && IP_PNP
>> diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
>> index 8df1ea4..75ba894 100644
>> --- a/fs/nfsd/Kconfig
>> +++ b/fs/nfsd/Kconfig
>> @@ -81,6 +81,19 @@ config NFSD_V4
>>
>> If unsure, say N.
>>
>> +config NFSD_V4_SECURITY_LABEL
>> + bool "Provide Security Label support for NFSv4 server"
>> + depends on NFSD_V4 && SECURITY
>> + help
>> +
>> + Say Y here if you want enable fine-grained security label attribute
>> + support for NFS version 4. Security labels allow security modules like
>> + SELinux and Smack to label files to facilitate enforcement of their policies.
>> + Without this an NFSv4 mount will have the same label on each file.
>> +
>> + If you do not wish to enable fine-grained security labels SELinux or
>> + Smack policies on NFSv4 files, say N.
>> +
>> config NFSD_FAULT_INJECTION
>> bool "NFS server manual fault injection"
>> depends on NFSD_V4 && DEBUG_KERNEL
>> --
>> 1.7.11.7
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


2012-11-12 20:44:25

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/12/2012 11:33 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 01:15:34AM -0500, David Quigley wrote:
>> The NFSv4 working group has finally accepted Labeled NFS as part of the NFSv4.2
>> specification and it has been decided that a reposting of the Labeled NFS code
>> for inclusion into mainline was a good idea. The patches have been rebased onto
>> v3.7-rc2 and have been tested against the SELinux testsuite with the only
>> failures being for features not supported by NFS.
>
> This will still need support for FATTR4_CHANGE_SEC_LABEL.
>
> --b.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

That's true. At the time we didn't have FATTR4_CHANGE_SEC_LABEL so it
wasn't implemented. This should be a good start at Labeled NFS support
but will take more work.

2012-11-12 12:14:04

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 01/13] Security: Add hook to calculate context based on a negative dentry.

On Mon, Nov 12, 2012 at 01:15:35AM -0500, David Quigley wrote:
> From: David Quigley <[email protected]>
>
> There is a time where we need to calculate a context without the
> inode having been created yet. To do this we take the negative dentry and
> calculate a context based on the process and the parent directory contexts.
>
> Signed-off-by: Matthew N. Dodd <[email protected]>
> Signed-off-by: Miguel Rodel Felipe <[email protected]>
> Signed-off-by: Phua Eu Gene <[email protected]>
> Signed-off-by: Khin Mi Mi Aung <[email protected]>
> Signed-off-by: David Quigley <[email protected]>
> ---
> include/linux/security.h | 27 +++++++++++++++++++++++++++
> security/capability.c | 8 ++++++++
> security/security.c | 10 ++++++++++
> security/selinux/hooks.c | 35 +++++++++++++++++++++++++++++++++++
> 4 files changed, 80 insertions(+)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 05e88bd..c9f5eec 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -26,6 +26,7 @@
> #include <linux/capability.h>
> #include <linux/slab.h>
> #include <linux/err.h>
> +#include <linux/string.h>
>
> struct linux_binprm;
> struct cred;
> @@ -306,6 +307,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> * Parse a string of security data filling in the opts structure
> * @options string containing all mount options known by the LSM
> * @opts binary data structure usable by the LSM
> + * @dentry_init_security:
> + * Compute a context for a dentry as the inode is not yet available
> + * since NFSv4 has no label backed by an EA anyway.

I don't understand this comment. Why exactly is NFSv4 the first user
that needs this?

--b.

> + * @dentry dentry to use in calculating the context.
> + * @mode mode used to determine resource type.
> + * @name name of the last path component used to create file
> + * @ctx pointer to place the pointer to the resulting context in.
> + * @ctxlen point to place the length of the resulting context.
> + *
> *
> * Security hooks for inode operations.
> *
> @@ -1421,6 +1431,10 @@ struct security_operations {
> void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
> struct super_block *newsb);
> int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
> + int (*dentry_init_security) (struct dentry *dentry, int mode,
> + struct qstr *name, void **ctx,
> + u32 *ctxlen);
> +
>
> #ifdef CONFIG_SECURITY_PATH
> int (*path_unlink) (struct path *dir, struct dentry *dentry);
> @@ -1702,6 +1716,9 @@ int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *o
> void security_sb_clone_mnt_opts(const struct super_block *oldsb,
> struct super_block *newsb);
> int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
> +int security_dentry_init_security(struct dentry *dentry, int mode,
> + struct qstr *name, void **ctx,
> + u32 *ctxlen);
>
> int security_inode_alloc(struct inode *inode);
> void security_inode_free(struct inode *inode);
> @@ -2005,6 +2022,16 @@ static inline int security_inode_alloc(struct inode *inode)
> static inline void security_inode_free(struct inode *inode)
> { }
>
> +static inline int security_dentry_init_security(struct dentry *dentry,
> + int mode,
> + struct qstr *name,
> + void **ctx,
> + u32 *ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +
> static inline int security_inode_init_security(struct inode *inode,
> struct inode *dir,
> const struct qstr *qstr,
> diff --git a/security/capability.c b/security/capability.c
> index b14a30c..f1eb284 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -108,6 +108,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
> return 0;
> }
>
> +static int cap_dentry_init_security(struct dentry *dentry, int mode,
> + struct qstr *name, void **ctx,
> + u32 *ctxlen)
> +{
> + return 0;
> +}
> +
> static int cap_inode_alloc_security(struct inode *inode)
> {
> return 0;
> @@ -905,6 +912,7 @@ void __init security_fixup_ops(struct security_operations *ops)
> set_to_cap_if_null(ops, sb_set_mnt_opts);
> set_to_cap_if_null(ops, sb_clone_mnt_opts);
> set_to_cap_if_null(ops, sb_parse_opts_str);
> + set_to_cap_if_null(ops, dentry_init_security);
> set_to_cap_if_null(ops, inode_alloc_security);
> set_to_cap_if_null(ops, inode_free_security);
> set_to_cap_if_null(ops, inode_init_security);
> diff --git a/security/security.c b/security/security.c
> index 8dcd4ae..b4b2017 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -12,6 +12,7 @@
> */
>
> #include <linux/capability.h>
> +#include <linux/dcache.h>
> #include <linux/module.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> @@ -324,6 +325,15 @@ void security_inode_free(struct inode *inode)
> security_ops->inode_free_security(inode);
> }
>
> +int security_dentry_init_security(struct dentry *dentry, int mode,
> + struct qstr *name, void **ctx,
> + u32 *ctxlen)
> +{
> + return security_ops->dentry_init_security(dentry, mode, name,
> + ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_dentry_init_security);
> +
> int security_inode_init_security(struct inode *inode, struct inode *dir,
> const struct qstr *qstr,
> const initxattrs initxattrs, void *fs_data)
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 61a5336..22d9adf 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2483,6 +2483,40 @@ static void selinux_inode_free_security(struct inode *inode)
> inode_free_security(inode);
> }
>
> +static int selinux_dentry_init_security(struct dentry *dentry, int mode,
> + struct qstr *name, void **ctx,
> + u32 *ctxlen)
> +{
> + struct cred *cred = current_cred();
> + struct task_security_struct *tsec;
> + struct inode_security_struct *dsec;
> + struct superblock_security_struct *sbsec;
> + struct inode *dir = dentry->d_parent->d_inode;
> + u32 newsid;
> + int rc;
> +
> + tsec = cred->security;
> + dsec = dir->i_security;
> + sbsec = dir->i_sb->s_security;
> +
> + if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
> + newsid = tsec->create_sid;
> + } else {
> + rc = security_transition_sid(tsec->sid, dsec->sid,
> + inode_mode_to_security_class(mode),
> + name,
> + &newsid);
> + if (rc) {
> + printk(KERN_WARNING
> + "%s: security_transition_sid failed, rc=%d\n",
> + __func__, -rc);
> + return rc;
> + }
> + }
> +
> + return security_sid_to_context(newsid, (char **)ctx, ctxlen);
> +}
> +
> static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
> const struct qstr *qstr, char **name,
> void **value, size_t *len)
> @@ -5509,6 +5543,7 @@ static struct security_operations selinux_ops = {
> .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
> .sb_parse_opts_str = selinux_parse_opts_str,
>
> + .dentry_init_security = selinux_dentry_init_security,
>
> .inode_alloc_security = selinux_inode_alloc_security,
> .inode_free_security = selinux_inode_free_security,
> --
> 1.7.11.7
>

2012-11-16 03:44:00

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/15/2012 22:34, Casey Schaufler wrote:
> On 11/15/2012 12:28 PM, David Quigley wrote:
>> On 11/15/2012 11:00, Casey Schaufler wrote:
>>> On 11/14/2012 6:30 AM, David Quigley wrote:
>>>> On 11/14/2012 09:24, J. Bruce Fields wrote:
>>>>> On Wed, Nov 14, 2012 at 09:04:18AM -0500, David Quigley wrote:
>>>>>> On 11/14/2012 08:59, J. Bruce Fields wrote:
>>>>>> >On Wed, Nov 14, 2012 at 08:50:17AM -0500, David Quigley wrote:
>>>>>> >>On 11/14/2012 08:45, J. Bruce Fields wrote:
>>>>>> >>>On Tue, Nov 13, 2012 at 11:32:53PM -0500, Dave Quigley wrote:
>>>>>> >>>>Ok so if you go to http://www.selinuxproject.org/git you
>>>>>> will
>>>>>> >>see a
>>>>>> >>>>repo for lnfs and lnfs-patchset. The instructions at
>>>>>> >>>>http://www.selinuxproject.org/page/Labeled_NFS give you a
>>>>>> better
>>>>>> >>>>indication on how to pull the trees. I've attached a patch
>>>>>> for
>>>>>> NFS
>>>>>> >>>>utils which gives support for
>>>>>> security_label/nosecurity_label in
>>>>>> >>>>your /etc/exports file.
>>>>>> >>>
>>>>>> >>>Do we need an export option? Is there any reason not to make
>>>>>> the
>>>>>> >>>feature available whenever there's support available for it?
>>>>>> >>
>>>>>> >>I guess we could build it in but I figured an export option
>>>>>> allowed
>>>>>> >>someone to turn off security labeling support if they didn't
>>>>>> want it
>>>>>> >>on that export. What happens to clients when the server
>>>>>> returns a
>>>>>> >>cap that they don't support? Do they mask the bits out?
>>>>>> >
>>>>>> >Yeah, they should just ignore it.
>>>>>> >
>>>>>> >While this is still experimental it's still nice to have a way
>>>>>> to
>>>>>> >turn
>>>>>> >this on and off at runtime so people can experiment without
>>>>>> having to
>>>>>> >have it on for everyone all the time. But
>>>>>> >nfsd_supported_minorversion
>>>>>> >should be sufficient for that.
>>>>>> >
>>>>>> >(I don't think your patches actually dealt yet with the fact
>>>>>> that
>>>>>> >this
>>>>>> >is part of minor version 2? Another for the todo list.)
>>>>>> >
>>>>>> >--b.
>>>>>>
>>>>>> If we use nfsd_supported_minorversion which I'm guessing is an
>>>>>> export option
>>>>>
>>>>> That's just a variable in the code. It's controlled by
>>>>> /proc/fs/nfsd/versions.
>>>>>
>>>>>> what happens if someone wants to use other 4.2
>>>>>> features but not labeling?
>>>>>
>>>>> We'll cross that bridge when we come to it, maybe by adding some
>>>>> new
>>>>> global paramater.
>>>>>
>>>>> There's no reason this really needs to be per-export, is there?
>>>>>
>>>>> --b.
>>>>
>>>> At the moment I can't really think of a reason to have it be
>>>> per-export. I think we need a new LSM patch though to determine if
>>>> the
>>>> LSM supports labeling over NFS unless Steve can think of a better
>>>> way
>>>> to tell if the LSM supports labeling.
>>>
>>> If the LSM has a secid_to_secctx hook it supports labeling.
>>> Today that's SELinux and Smack. You already have support in
>>> for SELinux, and providing Smack's review and possibly updates
>>> is #2 on my gotta do list. On the whole, I think that, except
>>> for the fundamental philosophical difference between label
>>> support and xattr support, it should be a simple matter to
>>> get support in for any LSM that has secid_to_secctx.
>>>
>>> But I'm still working on the review.
>>>
>>
>> I believe SMACK already works out of the box since we abstracted the
>> call to obtain labels and your implementation currently works.
>
> I'm looking to do a little verification. I hate assuming that
> something
> will work only to discover otherwise in the wild.
>
>> The call that is needed is not secid_to_secctx but inode_getsecctx.
>
> I was pointing out that secid_to_secctx pretty well defines that the
> LSM
> is using labels.
>
>> You asked for this because SMACK labels can span multiple xattrs. I
>> don't think its right to expect NFS to poke around the security
>> structure to check if there is a valid hook(and it isn't really
>> possible either).
>
> Yeah, I can see that.
>
>> Maybe we can have an LSM hook where the LSM categorizes itself and
>> returns a value and if the value it returns is label based then NFS
>> can use it.
>
> I'm not sure what the proposed hook would be for except to identify
> it
> as concerned with nfs. Perhaps the hook could return the names of
> attributes that it wants nfs to provide.
>

I'm not quite sure what you're proposing? I'm sure someone would find
another use for this hook though. The inode_getsecctx hook we made for
Labeled NFS was already merged because it was needed for providing
"persistent" label support for sysfs (meaning that it persisted inode
eviction from memory). The problem is that we have no real way to ask in
the NFS code if this is an LSM that can be used with Labeled NFS. In the
xattr code we have the new ismaclabel hook we add which allows us to
verify the xattr used as belonging to a label based LSM however we need
an xattr from userspace for that. The reason this is required is that
the server will need to fill out its capability mask to indicate it
supports security labeling. In addition the client also needs to know if
its running a security label based LSM because it will need to mask out
the label fattr bit from its getattr calls if it doesn't support it. We
can override this in SELinux by giving it a context mount but if we
don't then it will need to know whether or not to be pulling security
labels back.


2012-11-30 12:57:21

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 07:14, J. Bruce Fields wrote:
> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>> On 11/29/2012 20:50, Casey Schaufler wrote:
>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>> >>>I would think that were it not for the case that access is denied
>> >>>and I get an audit record for nfsd that reports a subject
>> >>>label of "_"
>> >>>(which is correct for nfsd but not the process attempting
>> >>>access) and
>> >>>an object label of "WhooHoo", which is correct. The server side
>> >>>looks like it might be working right, given the information that
>> it
>> >>>has.
>> >>>
>> >>
>> >>Ok so this is the problem. nfsd is a kernel thread I believe. In
>> >>SELinux land it has the type kernel_t which is all powerful. We
>> >>don't
>> >>have client label transport yet (That requires RPCSECGSSv3). Is
>> >>there
>> >>a way you can have that kernel thread running as a type that has
>> >>access to everything?
>> >
>> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in
>> Smackese.
>> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
>> >which
>> >is to say, all capabilities.
>> >
>>
>> Hmm thats interesting then. You could try using rpcdebug -m nfsd to
>> turn on some of the debugging to look around the internals and
>> figure out whats going on. If you pass -v it will give you all of
>> the potential flags.
>>
>> >
>> >>I think that is the current problem. Which makes perfect sense. If
>> >>your kernel threads don't get started with max privilege then the
>> >>server would be denied access on all of the file attributes and
>> >>wouldn't be able to ship it over the wire properly.
>> >
>> >OK. I haven't had to do anything with kernel threads so far.
>> >Where is NFS setting these up? Poking around fs/nfsd looks like
>> >the place, but I haven't seen anything there that makes it look
>> >like they would be running without capabilities. Clearly, that's
>> >what I'm seeing. It looks as if the credential of nfsd does not
>> >match what /proc reports. Bother.
>> >
>>
>> I'm not entirely sure whats up either. If you want to look for the
>> NFSd threads they are in fs/nfsd/nfssvc.c. The main function starts
>> on line 487.
>
> I'm not following the discussion, but: maybe you want to look at
> fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
> cap_{drop/raise}_nfsd_set() calls at the end.
>
> --b.


I'm not as familiar with the capabilities code as Casey is so I'll
leave this ball in his court. I think you are correct though and the
problem is that NFSd is dropping and raising caps and we need to make
sure that MAC_ADMIN and MAC_OVERRIDE is in there in the SMACK case.

2012-11-12 14:59:35

by Dave Quigley

[permalink] [raw]
Subject: Re: [PATCH 01/13] Security: Add hook to calculate context based on a negative dentry.

On 11/12/2012 7:13 AM, J. Bruce Fields wrote:
> On Mon, Nov 12, 2012 at 01:15:35AM -0500, David Quigley wrote:
>> From: David Quigley <[email protected]>
>>
>> There is a time where we need to calculate a context without the
>> inode having been created yet. To do this we take the negative dentry and
>> calculate a context based on the process and the parent directory contexts.
>>
>> Signed-off-by: Matthew N. Dodd <[email protected]>
>> Signed-off-by: Miguel Rodel Felipe <[email protected]>
>> Signed-off-by: Phua Eu Gene <[email protected]>
>> Signed-off-by: Khin Mi Mi Aung <[email protected]>
>> Signed-off-by: David Quigley <[email protected]>
>> ---
>> include/linux/security.h | 27 +++++++++++++++++++++++++++
>> security/capability.c | 8 ++++++++
>> security/security.c | 10 ++++++++++
>> security/selinux/hooks.c | 35 +++++++++++++++++++++++++++++++++++
>> 4 files changed, 80 insertions(+)
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 05e88bd..c9f5eec 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -26,6 +26,7 @@
>> #include <linux/capability.h>
>> #include <linux/slab.h>
>> #include <linux/err.h>
>> +#include <linux/string.h>
>>
>> struct linux_binprm;
>> struct cred;
>> @@ -306,6 +307,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>> * Parse a string of security data filling in the opts structure
>> * @options string containing all mount options known by the LSM
>> * @opts binary data structure usable by the LSM
>> + * @dentry_init_security:
>> + * Compute a context for a dentry as the inode is not yet available
>> + * since NFSv4 has no label backed by an EA anyway.
>
> I don't understand this comment. Why exactly is NFSv4 the first user
> that needs this?
>
> --b.
>

Normally the calculation of a label for an inode is based on the inode
and the parent directory. We unfortunately don't have all of that
information available in NFSv4 where we need it so instead we base the
calculation off of the dentry instead. That is the best I can remember
for why we do it. Unfortunately that decision was made so long ago its
hard to remember the fine details.

>> + * @dentry dentry to use in calculating the context.
>> + * @mode mode used to determine resource type.
>> + * @name name of the last path component used to create file
>> + * @ctx pointer to place the pointer to the resulting context in.
>> + * @ctxlen point to place the length of the resulting context.
>> + *
>> *
>> * Security hooks for inode operations.
>> *
>> @@ -1421,6 +1431,10 @@ struct security_operations {
>> void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
>> struct super_block *newsb);
>> int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
>> + int (*dentry_init_security) (struct dentry *dentry, int mode,
>> + struct qstr *name, void **ctx,
>> + u32 *ctxlen);
>> +
>>
>> #ifdef CONFIG_SECURITY_PATH
>> int (*path_unlink) (struct path *dir, struct dentry *dentry);
>> @@ -1702,6 +1716,9 @@ int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *o
>> void security_sb_clone_mnt_opts(const struct super_block *oldsb,
>> struct super_block *newsb);
>> int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
>> +int security_dentry_init_security(struct dentry *dentry, int mode,
>> + struct qstr *name, void **ctx,
>> + u32 *ctxlen);
>>
>> int security_inode_alloc(struct inode *inode);
>> void security_inode_free(struct inode *inode);
>> @@ -2005,6 +2022,16 @@ static inline int security_inode_alloc(struct inode *inode)
>> static inline void security_inode_free(struct inode *inode)
>> { }
>>
>> +static inline int security_dentry_init_security(struct dentry *dentry,
>> + int mode,
>> + struct qstr *name,
>> + void **ctx,
>> + u32 *ctxlen)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> +
>> +
>> static inline int security_inode_init_security(struct inode *inode,
>> struct inode *dir,
>> const struct qstr *qstr,
>> diff --git a/security/capability.c b/security/capability.c
>> index b14a30c..f1eb284 100644
>> --- a/security/capability.c
>> +++ b/security/capability.c
>> @@ -108,6 +108,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
>> return 0;
>> }
>>
>> +static int cap_dentry_init_security(struct dentry *dentry, int mode,
>> + struct qstr *name, void **ctx,
>> + u32 *ctxlen)
>> +{
>> + return 0;
>> +}
>> +
>> static int cap_inode_alloc_security(struct inode *inode)
>> {
>> return 0;
>> @@ -905,6 +912,7 @@ void __init security_fixup_ops(struct security_operations *ops)
>> set_to_cap_if_null(ops, sb_set_mnt_opts);
>> set_to_cap_if_null(ops, sb_clone_mnt_opts);
>> set_to_cap_if_null(ops, sb_parse_opts_str);
>> + set_to_cap_if_null(ops, dentry_init_security);
>> set_to_cap_if_null(ops, inode_alloc_security);
>> set_to_cap_if_null(ops, inode_free_security);
>> set_to_cap_if_null(ops, inode_init_security);
>> diff --git a/security/security.c b/security/security.c
>> index 8dcd4ae..b4b2017 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -12,6 +12,7 @@
>> */
>>
>> #include <linux/capability.h>
>> +#include <linux/dcache.h>
>> #include <linux/module.h>
>> #include <linux/init.h>
>> #include <linux/kernel.h>
>> @@ -324,6 +325,15 @@ void security_inode_free(struct inode *inode)
>> security_ops->inode_free_security(inode);
>> }
>>
>> +int security_dentry_init_security(struct dentry *dentry, int mode,
>> + struct qstr *name, void **ctx,
>> + u32 *ctxlen)
>> +{
>> + return security_ops->dentry_init_security(dentry, mode, name,
>> + ctx, ctxlen);
>> +}
>> +EXPORT_SYMBOL(security_dentry_init_security);
>> +
>> int security_inode_init_security(struct inode *inode, struct inode *dir,
>> const struct qstr *qstr,
>> const initxattrs initxattrs, void *fs_data)
>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> index 61a5336..22d9adf 100644
>> --- a/security/selinux/hooks.c
>> +++ b/security/selinux/hooks.c
>> @@ -2483,6 +2483,40 @@ static void selinux_inode_free_security(struct inode *inode)
>> inode_free_security(inode);
>> }
>>
>> +static int selinux_dentry_init_security(struct dentry *dentry, int mode,
>> + struct qstr *name, void **ctx,
>> + u32 *ctxlen)
>> +{
>> + struct cred *cred = current_cred();
>> + struct task_security_struct *tsec;
>> + struct inode_security_struct *dsec;
>> + struct superblock_security_struct *sbsec;
>> + struct inode *dir = dentry->d_parent->d_inode;
>> + u32 newsid;
>> + int rc;
>> +
>> + tsec = cred->security;
>> + dsec = dir->i_security;
>> + sbsec = dir->i_sb->s_security;
>> +
>> + if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
>> + newsid = tsec->create_sid;
>> + } else {
>> + rc = security_transition_sid(tsec->sid, dsec->sid,
>> + inode_mode_to_security_class(mode),
>> + name,
>> + &newsid);
>> + if (rc) {
>> + printk(KERN_WARNING
>> + "%s: security_transition_sid failed, rc=%d\n",
>> + __func__, -rc);
>> + return rc;
>> + }
>> + }
>> +
>> + return security_sid_to_context(newsid, (char **)ctx, ctxlen);
>> +}
>> +
>> static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
>> const struct qstr *qstr, char **name,
>> void **value, size_t *len)
>> @@ -5509,6 +5543,7 @@ static struct security_operations selinux_ops = {
>> .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
>> .sb_parse_opts_str = selinux_parse_opts_str,
>>
>> + .dentry_init_security = selinux_dentry_init_security,
>>
>> .inode_alloc_security = selinux_inode_alloc_security,
>> .inode_free_security = selinux_inode_free_security,
>> --
>> 1.7.11.7
>>
>


2012-11-30 02:02:52

by Dave Quigley

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/29/2012 20:50, Casey Schaufler wrote:
> On 11/29/2012 4:46 PM, David Quigley wrote:
>> On 11/29/2012 19:34, Casey Schaufler wrote:
>>> On 11/29/2012 4:07 PM, David Quigley wrote:
>>>> On 11/29/2012 17:28, Casey Schaufler wrote:
>>>>> On 11/28/2012 6:08 PM, Casey Schaufler wrote:
>>>>>> On 11/28/2012 5:14 PM, Dave Quigley wrote:
>>>>>>> On 11/28/2012 1:57 PM, Casey Schaufler wrote:
>>>>>>>> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>>>>>>>>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>>>>>>>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>>>>>>>>> ...
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Or I could just give you this link and you should be good
>>>>>>>>>>> to
>>>>>>>>>>> go ;)
>>>>>>>>>>>
>>>>>>>>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>>>>>>>>
>>>>>>>>>>> I haven't tried it but it should work. If it doesn't let me
>>>>>>>>>>> know and
>>>>>>>>>>> i'll try to fix it on my end. I'd imagine you might need to
>>>>>>>>>>> yum
>>>>>>>>>>> remove
>>>>>>>>>>> nfs-utils first before adding this new one or you could
>>>>>>>>>>> also
>>>>>>>>>>> try an
>>>>>>>>>>> rpm with the upgrade flag for this instead. Good luck.
>>>>>>>> ...
>>>>>>>>
>>>>>>>>
>>>>>>>> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
>>>>>>>> attached stack trace on mount. After mounting I'm getting
>>>>>>>> denials when I should, but also when I shouldn't.
>>>>>>>>
>>>>>>>> I've tried tracking down the issue, but there's a lot going on
>>>>>>>> that I don't find obvious. I added a dentry_init hook just for
>>>>>>>> grins, but it's not getting called.
>>>>>>>>
>>>>>>>> .
>>>>>>>>
>>>>>>>>
>>>>>>> Any chance of you throwing a kickstart file my way that's
>>>>>>> configured
>>>>>>> with SMACK so I can use it for a test box (both server and
>>>>>>> client)? I
>>>>>>> can have the guys working with me test for SMACK as well if you
>>>>>>> provide an appropriate test harness and image for testing.
>>>>>> I've attached the .config from my Fedora17 machine. Who knows,
>>>>>> maybe
>>>>>> I got something wrong there. I get the error doing the test on
>>>>>> the
>>>>>> loopback interface (mount -t nfs4 localhist:/ /mnt).
>>>>>
>>>>> I've done some instrumentation and security_ismaclabel() is
>>>>> getting
>>>>> called with "selinux", but never "SMACK64". I would guess that
>>>>> somewhere
>>>>> in the tools you're telling the kernel to expect "selinux". Where
>>>>> is
>>>>> that, so that I can tell it to try "SMACK64" instead?
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> This message was distributed to subscribers of the selinux
>>>>> mailing
>>>>> list.
>>>>> If you no longer wish to subscribe, send mail to
>>>>> [email protected] with
>>>>> the words "unsubscribe selinux" without quotes as the message.
>>>>
>>>>
>>>> What tools do you use in SMACK to see the labels?
>>>
>>> attr -S -g SMACK64 <path>
>>
>> ok so that seems to work for SELinux as well. Never knew about that.
>> I'd always just rip the xattr out of the inode with getfattr.
>>
>>
>>>
>>>> Do you just use getxattr? If so can you try calling that and
>>>> seeing
>>>> what happens? I'm concerned that you aren't getting any attribute
>>>> information on that file.
>>>
>>> I would think that were it not for the case that access is denied
>>> and I get an audit record for nfsd that reports a subject label of
>>> "_"
>>> (which is correct for nfsd but not the process attempting access)
>>> and
>>> an object label of "WhooHoo", which is correct. The server side
>>> looks like it might be working right, given the information that it
>>> has.
>>>
>>
>> Ok so this is the problem. nfsd is a kernel thread I believe. In
>> SELinux land it has the type kernel_t which is all powerful. We
>> don't
>> have client label transport yet (That requires RPCSECGSSv3). Is
>> there
>> a way you can have that kernel thread running as a type that has
>> access to everything?
>
> That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in Smackese.
> Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
> which
> is to say, all capabilities.
>

Hmm thats interesting then. You could try using rpcdebug -m nfsd to
turn on some of the debugging to look around the internals and figure
out whats going on. If you pass -v it will give you all of the potential
flags.

>
>> I think that is the current problem. Which makes perfect sense. If
>> your kernel threads don't get started with max privilege then the
>> server would be denied access on all of the file attributes and
>> wouldn't be able to ship it over the wire properly.
>
> OK. I haven't had to do anything with kernel threads so far.
> Where is NFS setting these up? Poking around fs/nfsd looks like
> the place, but I haven't seen anything there that makes it look
> like they would be running without capabilities. Clearly, that's
> what I'm seeing. It looks as if the credential of nfsd does not
> match what /proc reports. Bother.
>

I'm not entirely sure whats up either. If you want to look for the NFSd
threads they are in fs/nfsd/nfssvc.c. The main function starts on line
487.

>
>> I'm not sure what you need to do but you'll probably have to work
>> this
>> out. We have a usage mode in the IETF spec which has a non-mac
>> enforcing server which still support object labeling. In the SELinux
>> case it works for us since kernel_t can access anything. Ideally
>> when
>> RPCSECGSSv3 is finished and merged we'll be able to choose whether
>> to
>> use the label of the process on the client side or kernel_t for the
>> server if its not available.
>>
>>>> Do you have a disto that I can use that has full smack integration
>>>> and
>>>> is easy to setup?
>>>
>>> There's no full integration, but Ubuntu is easy to set up because
>>> they
>>> compile in all the LSMs.
>>> Set "security=smack" on the boot line in grub.cfg and reboot.
>>>
>>> All processes and files will get the floor ("_") label unless you
>>> change
>>> one. You can change
>>> a file label with:
>>> # attr -S -s SMACK64 WhooHoo path
>>> or execute at a different label with:
>>> # (echo WhooHoo > /proc/self/attr/current ; command)
>>>
>>
>> I'm not out of here until really late tonight so getting an Ubuntu
>> VM
>> setup probably won't happen until sometime next week when everything
>> calms down. However I think we isolated the problem above. If I'm
>> correct this is strictly a smack labeling problem. I don't know if
>> you
>> need to put some code into smack to init kernel threads with a more
>> powerful label or not so I'll leave it up to you on how to address
>> this.
>>
>>
>> Dave
>>


2012-11-29 02:08:24

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/28/2012 5:14 PM, Dave Quigley wrote:
> On 11/28/2012 1:57 PM, Casey Schaufler wrote:
>> On 11/20/2012 7:28 PM, Dave Quigley wrote:
>>> On 11/20/2012 9:52 PM, Casey Schaufler wrote:
>>>> On 11/20/2012 4:37 PM, Dave Quigley wrote:
>>>>> ...
>>>>>
>>>>>
>>>>> Or I could just give you this link and you should be good to go ;)
>>>>>
>>>>> http://www.selinuxproject.org/~dpquigl/nfs-utils-rpms/
>>>>>
>>>>> I haven't tried it but it should work. If it doesn't let me know and
>>>>> i'll try to fix it on my end. I'd imagine you might need to yum
>>>>> remove
>>>>> nfs-utils first before adding this new one or you could also try an
>>>>> rpm with the upgrade flag for this instead. Good luck.
>>>>
>> ...
>>
>>
>> I've tried on Fedora17 and Ubuntu12.04, and I'm getting the
>> attached stack trace on mount. After mounting I'm getting
>> denials when I should, but also when I shouldn't.
>>
>> I've tried tracking down the issue, but there's a lot going on
>> that I don't find obvious. I added a dentry_init hook just for
>> grins, but it's not getting called.
>>
>> .
>>
>>
>
> Any chance of you throwing a kickstart file my way that's configured
> with SMACK so I can use it for a test box (both server and client)? I
> can have the guys working with me test for SMACK as well if you
> provide an appropriate test harness and image for testing.

I've attached the .config from my Fedora17 machine. Who knows, maybe
I got something wrong there. I get the error doing the test on the
loopback interface (mount -t nfs4 localhist:/ /mnt).

>
> Dave
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>


Attachments:
f17smack.config (111.48 kB)

2012-11-12 06:15:46

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 12/13] NFS: Extend NFS xattr handlers to accept the security namespace

From: David Quigley <[email protected]>

The existing NFSv4 xattr handlers do not accept xattr calls to the security
namespace. This patch extends these handlers to accept xattrs from the security
namespace in addition to the default NFSv4 ACL namespace.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/nfs4proc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
security/security.c | 1 +
2 files changed, 51 insertions(+)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 77d1a29..2c8dd55 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5632,6 +5632,53 @@ static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
return len;
}

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+static inline int nfs4_server_supports_labels(struct nfs_server *server)
+{
+ return server->caps & NFS_CAP_SECURITY_LABEL;
+}
+
+static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key,
+ const void *buf, size_t buflen,
+ int flags, int type)
+{
+ if (security_ismaclabel(key))
+ return nfs4_set_security_label(dentry, buf, buflen);
+
+ return -EOPNOTSUPP;
+}
+
+static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key,
+ void *buf, size_t buflen, int type)
+{
+ if (security_ismaclabel(key))
+ return nfs4_get_security_label(dentry->d_inode, buf, buflen);
+ return -EOPNOTSUPP;
+}
+
+static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list,
+ size_t list_len, const char *name,
+ size_t name_len, int type)
+{
+ size_t len = 0;
+
+ if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL)) {
+ len = security_inode_listsecurity(dentry->d_inode, NULL, 0);
+ if (list && len <= list_len)
+ security_inode_listsecurity(dentry->d_inode, list, len);
+ }
+ return len;
+}
+
+static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .list = nfs4_xattr_list_nfs4_label,
+ .get = nfs4_xattr_get_nfs4_label,
+ .set = nfs4_xattr_set_nfs4_label,
+};
+#endif
+
+
/*
* nfs_fhget will use either the mounted_on_fileid or the fileid
*/
@@ -7590,6 +7637,9 @@ static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {

const struct xattr_handler *nfs4_xattr_handlers[] = {
&nfs4_xattr_nfs4_acl_handler,
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ &nfs4_xattr_nfs4_label_handler,
+#endif
NULL
};

diff --git a/security/security.c b/security/security.c
index 60a6017..310362b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -660,6 +660,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
return 0;
return security_ops->inode_listsecurity(inode, buffer, buffer_size);
}
+EXPORT_SYMBOL(security_inode_listsecurity);

void security_inode_getsecid(const struct inode *inode, u32 *secid)
{
--
1.7.11.7

2012-11-12 06:15:36

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 02/13] Security: Add Hook to test if the particular xattr is part of a MAC model.

From: David Quigley <[email protected]>

The interface to request security labels from user space is the xattr
interface. When requesting the security label from an NFS server it is
important to make sure the requested xattr actually is a MAC label. This allows
us to make sure that we get the desired semantics from the attribute instead of
something else such as capabilities or a time based LSM.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
include/linux/security.h | 14 ++++++++++++++
security/capability.c | 6 ++++++
security/security.c | 6 ++++++
security/selinux/hooks.c | 6 ++++++
security/smack/smack_lsm.c | 11 +++++++++++
5 files changed, 43 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index c9f5eec..167bdd5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1301,6 +1301,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @pages contains the number of pages.
* Return 0 if permission is granted.
*
+ * @ismaclabel:
+ * Check if the extended attribute specified by @name
+ * represents a MAC label. Returns 0 if name is a MAC
+ * attribute otherwise returns non-zero.
+ * @name full extended attribute name to check against
+ * LSM as a MAC label.
+ *
* @secid_to_secctx:
* Convert secid to security context. If secdata is NULL the length of
* the result will be returned in seclen, but no secdata will be returned.
@@ -1581,6 +1588,7 @@ struct security_operations {

int (*getprocattr) (struct task_struct *p, char *name, char **value);
int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
+ int (*ismaclabel) (const char *name);
int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx) (char *secdata, u32 seclen);
@@ -1829,6 +1837,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
int security_getprocattr(struct task_struct *p, char *name, char **value);
int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
+int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
@@ -2512,6 +2521,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
return cap_netlink_send(sk, skb);
}

+static inline int security_ismaclabel(const char *name)
+{
+ return 0;
+}
+
static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return -EOPNOTSUPP;
diff --git a/security/capability.c b/security/capability.c
index f1eb284..9071447 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -797,6 +797,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
return -EINVAL;
}

+static int cap_ismaclabel(const char *name)
+{
+ return 0;
+}
+
static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return -EOPNOTSUPP;
@@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, d_instantiate);
set_to_cap_if_null(ops, getprocattr);
set_to_cap_if_null(ops, setprocattr);
+ set_to_cap_if_null(ops, ismaclabel);
set_to_cap_if_null(ops, secid_to_secctx);
set_to_cap_if_null(ops, secctx_to_secid);
set_to_cap_if_null(ops, release_secctx);
diff --git a/security/security.c b/security/security.c
index b4b2017..a7bee7b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1047,6 +1047,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
return security_ops->netlink_send(sk, skb);
}

+int security_ismaclabel(const char *name)
+{
+ return security_ops->ismaclabel(name);
+}
+EXPORT_SYMBOL(security_ismaclabel);
+
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return security_ops->secid_to_secctx(secid, secdata, seclen);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 22d9adf..f7c4899 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5401,6 +5401,11 @@ abort_change:
return error;
}

+static int selinux_ismaclabel(const char *name)
+{
+ return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
+}
+
static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return security_sid_to_context(secid, secdata, seclen);
@@ -5639,6 +5644,7 @@ static struct security_operations selinux_ops = {
.getprocattr = selinux_getprocattr,
.setprocattr = selinux_setprocattr,

+ .ismaclabel = selinux_ismaclabel,
.secid_to_secctx = selinux_secid_to_secctx,
.secctx_to_secid = selinux_secctx_to_secid,
.release_secctx = selinux_release_secctx,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 38be92c..82c3c72 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void *vrule)
#endif /* CONFIG_AUDIT */

/**
+ * smack_ismaclabel - check if xattr @name references a smack MAC label
+ * @name: Full xattr name to check.
+ */
+static int smack_ismaclabel(const char *name)
+{
+ return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
+}
+
+
+/**
* smack_secid_to_secctx - return the smack label for a secid
* @secid: incoming integer
* @secdata: destination
@@ -3530,6 +3540,7 @@ struct security_operations smack_ops = {
.audit_rule_free = smack_audit_rule_free,
#endif /* CONFIG_AUDIT */

+ .ismaclabel = smack_ismaclabel,
.secid_to_secctx = smack_secid_to_secctx,
.secctx_to_secid = smack_secctx_to_secid,
.release_secctx = smack_release_secctx,
--
1.7.11.7

2012-11-12 06:15:44

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 10/13] NFS: Add label lifecycle management

>From David Quigley <[email protected]>

This patch adds the lifecycle management for the security label structure
introduced in an earlier patch. The label is not used yet but allocations and
freeing of the structure is handled.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/dir.c | 30 +++++++++++++-
fs/nfs/getroot.c | 1 -
fs/nfs/inode.c | 13 ++++++
fs/nfs/nfs4proc.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 156 insertions(+), 4 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 1339e44..561d2fb 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -581,7 +581,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
entry.fh = nfs_alloc_fhandle();
entry.fattr = nfs_alloc_fattr();
entry.server = NFS_SERVER(inode);
- if (entry.fh == NULL || entry.fattr == NULL)
+ entry.label = nfs4_label_alloc(GFP_NOWAIT);
+ if (entry.fh == NULL || entry.fattr == NULL || entry.label == NULL)
goto out;

array = nfs_readdir_get_array(page);
@@ -616,6 +617,7 @@ out_release_array:
out:
nfs_free_fattr(entry.fattr);
nfs_free_fhandle(entry.fh);
+ nfs4_label_free(entry.label);
return status;
}

@@ -1077,6 +1079,14 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if (fhandle == NULL || fattr == NULL)
goto out_error;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ label = nfs4_label_alloc(GFP_NOWAIT);
+ if (label == NULL)
+ goto out_error;
+ }
+#endif
+
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
if (error)
goto out_bad;
@@ -1087,6 +1097,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)

nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle);
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+ nfs4_label_free(label);
+#endif
+
out_set_verifier:
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid:
@@ -1123,6 +1139,7 @@ out_zap_parent:
out_error:
nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle);
+ nfs4_label_free(label);
dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n",
__func__, dentry->d_parent->d_name.name,
@@ -1235,6 +1252,13 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
if (fhandle == NULL || fattr == NULL)
goto out;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ label = nfs4_label_alloc(GFP_NOWAIT);
+ if (label == NULL)
+ goto out;
+ }
+#endif
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
@@ -1264,6 +1288,10 @@ no_entry:
out_unblock_sillyrename:
nfs_unblock_sillyrename(parent);
out:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+ nfs4_label_free(label);
+#endif
nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle);
return res;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 3b68bb6..14bd667 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -75,7 +75,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
struct nfs_fsinfo fsinfo;
struct dentry *ret;
struct inode *inode;
- struct nfs4_label *label = NULL;
void *name = kstrdup(devname, GFP_KERNEL);
int error;

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index daca08c..ab08d0d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -835,6 +835,15 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
goto out;

nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
+ label = nfs4_label_alloc(GFP_KERNEL);
+ if (label == NULL) {
+ status = -ENOMEM;
+ goto out;
+ }
+ }
+#endif
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
if (status != 0) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
@@ -864,6 +873,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
(long long)NFS_FILEID(inode));

out:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+ nfs4_label_free(label);
+#endif
nfs_free_fattr(fattr);
return status;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 8e0378c..4ab2738 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -865,9 +865,16 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p = kzalloc(sizeof(*p), gfp_mask);
if (p == NULL)
goto err;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ p->f_label = nfs4_label_alloc(gfp_mask);
+ if (p->f_label == NULL)
+ goto err_free_p;
+ }
+#endif
p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
if (p->o_arg.seqid == NULL)
- goto err_free;
+ goto err_free_label;
nfs_sb_active(dentry->d_sb);
p->dentry = dget(dentry);
p->dir = parent;
@@ -910,7 +917,13 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
nfs4_init_opendata_res(p);
kref_init(&p->kref);
return p;
-err_free:
+
+err_free_label:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs4_label_free(p->f_label);
+#endif
+err_free_p:
kfree(p);
err:
dput(parent);
@@ -927,6 +940,10 @@ static void nfs4_opendata_free(struct kref *kref)
if (p->state != NULL)
nfs4_put_open_state(p->state);
nfs4_put_state_owner(p->owner);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (p->o_arg.server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs4_label_free(p->f_label);
+#endif
dput(p->dir);
dput(p->dentry);
nfs_sb_deactive(sb);
@@ -1998,6 +2015,16 @@ static int _nfs4_do_open(struct inode *dir,
if (opendata == NULL)
goto err_put_state_owner;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label && nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ olabel = nfs4_label_alloc(GFP_KERNEL);
+ if (olabel == NULL) {
+ status = -ENOMEM;
+ goto err_opendata_put;
+ }
+ }
+#endif
+
if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
if (!opendata->f_attr.mdsthreshold)
@@ -2041,6 +2068,10 @@ static int _nfs4_do_open(struct inode *dir,
kfree(opendata->f_attr.mdsthreshold);
opendata->f_attr.mdsthreshold = NULL;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+ nfs4_label_free(olabel);
+#endif
nfs4_opendata_put(opendata);
nfs4_put_state_owner(sp);
*res = state;
@@ -2607,6 +2638,12 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
return error;
}

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ label = nfs4_label_alloc(GFP_KERNEL);
+ if (label == NULL)
+ return -ENOMEM;
+#endif
+
error = nfs4_proc_getattr(server, mntfh, fattr, label);
if (error < 0) {
dprintk("nfs4_get_root: getattr error = %d\n", -error);
@@ -2617,6 +2654,11 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
!nfs_fsid_equal(&server->fsid, &fattr->fsid))
memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs4_label_free(label);
+#endif
+
return error;
}

@@ -2728,6 +2770,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
if (pnfs_ld_layoutret_on_setattr(inode))
pnfs_return_layout(inode);

+ olabel = nfs4_label_alloc(GFP_KERNEL);
+ if (olabel == NULL)
+ return -ENOMEM;
+
nfs_fattr_init(fattr);

/* Deal with open(O_TRUNC) */
@@ -2905,12 +2951,27 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
res.fattr = nfs_alloc_fattr();
if (res.fattr == NULL)
return -ENOMEM;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ res.label = nfs4_label_alloc(GFP_KERNEL);
+ if (res.label == NULL) {
+ status = -ENOMEM;
+ goto out;
+ }
+ }
+#endif

status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
if (!status) {
nfs_access_set_mask(entry, res.access);
nfs_refresh_inode(inode, res.fattr, res.label);
}
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs4_label_free(res.label);
+#endif
+out:
nfs_free_fattr(res.fattr);
return status;
}
@@ -3034,6 +3095,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
if (status == 0)
update_changeattr(dir, &res.cinfo);
+
return status;
}

@@ -3079,6 +3141,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
return 0;
update_changeattr(dir, &res->cinfo);
+
return 1;
}

@@ -3139,12 +3202,33 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
.rpc_resp = &res,
};
int status = -ENOMEM;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ res.old_label = nfs4_label_alloc(GFP_NOWAIT);
+ if (res.old_label == NULL)
+ goto out;
+ res.new_label = nfs4_label_alloc(GFP_NOWAIT);
+ if (res.new_label == NULL) {
+ nfs4_label_free(res.old_label);
+ goto out;
+ }
+ }
+#endif

status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
if (!status) {
update_changeattr(old_dir, &res.old_cinfo);
update_changeattr(new_dir, &res.new_cinfo);
}
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs4_label_free(res.old_label);
+ nfs4_label_free(res.new_label);
+ }
+#endif
+out:
return status;
}

@@ -3186,11 +3270,25 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
if (res.fattr == NULL)
goto out;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ res.label = nfs4_label_alloc(GFP_KERNEL);
+ if (res.label == NULL)
+ goto out;
+ }
+#endif
+
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
if (!status) {
update_changeattr(dir, &res.cinfo);
nfs_post_op_update_inode(inode, res.fattr, res.label);
}
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs4_label_free(res.label);
+#endif
+
out:
nfs_free_fattr(res.fattr);
return status;
@@ -3226,6 +3324,13 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
if (data != NULL) {
struct nfs_server *server = NFS_SERVER(dir);

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ data->label = nfs4_label_alloc(GFP_KERNEL);
+ if (data->label == NULL)
+ goto out_free;
+ }
+#endif
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
data->msg.rpc_argp = &data->arg;
data->msg.rpc_resp = &data->res;
@@ -3242,6 +3347,9 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
nfs_fattr_init(data->res.fattr);
}
return data;
+out_free:
+ kfree(data);
+ return NULL;
}

static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
@@ -3257,6 +3365,10 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_

static void nfs4_free_createdata(struct nfs4_createdata *data)
{
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (data->arg.server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs4_label_free(data->label);
+#endif
kfree(data);
}

--
1.7.11.7

2012-11-12 06:15:41

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 07/13] NFSv4: Introduce new label structure

From: David Quigley <[email protected]>

In order to mimic the way that NFSv4 ACLs are implemented we have created a
structure to be used to pass label data up and down the call chain. This patch
adds the new structure and new members to the required NFSv4 call structures.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/inode.c | 40 ++++++++++++++++++++++++++++++++++++++++
fs/nfsd/xdr4.h | 3 +++
include/linux/nfs4.h | 8 ++++++++
include/linux/nfs_fs.h | 14 ++++++++++++++
include/linux/nfs_xdr.h | 20 ++++++++++++++++++++
5 files changed, 85 insertions(+)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5c7325c..0963ad9 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -246,6 +246,46 @@ nfs_init_locked(struct inode *inode, void *opaque)
return 0;
}

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+struct nfs4_label *nfs4_label_alloc(gfp_t flags)
+{
+ struct nfs4_label *label = NULL;
+
+ label = kzalloc(sizeof(struct nfs4_label) + NFS4_MAXLABELLEN, flags);
+ if (label == NULL)
+ return NULL;
+
+ label->label = (void *)(label + 1);
+ label->len = NFS4_MAXLABELLEN;
+ /* 0 is the null format meaning that the data is not to be translated */
+ label->lfs = 0;
+ label->pi = 0;
+ return label;
+}
+EXPORT_SYMBOL_GPL(nfs4_label_alloc);
+
+void nfs4_label_init(struct nfs4_label *label)
+{
+ if (label && label->label) {
+ *(unsigned char *)label->label = 0;
+ label->len = NFS4_MAXLABELLEN;
+ /* 0 is the null format meaning that the data is not
+ to be translated */
+ label->lfs = 0;
+ label->pi = 0;
+ }
+ return;
+}
+EXPORT_SYMBOL_GPL(nfs4_label_init);
+
+void nfs4_label_free(struct nfs4_label *label)
+{
+ kfree(label);
+ return;
+}
+EXPORT_SYMBOL_GPL(nfs4_label_free);
+#endif
+
/*
* This is our front-end to iget that looks up inodes by file handle
* instead of inode number.
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index acd127d..ca8f30b 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -118,6 +118,7 @@ struct nfsd4_create {
struct iattr cr_iattr; /* request */
struct nfsd4_change_info cr_cinfo; /* response */
struct nfs4_acl *cr_acl;
+ struct nfs4_label *cr_label;
};
#define cr_linklen u.link.namelen
#define cr_linkname u.link.name
@@ -246,6 +247,7 @@ struct nfsd4_open {
struct nfs4_file *op_file; /* used during processing */
struct nfs4_ol_stateid *op_stp; /* used during processing */
struct nfs4_acl *op_acl;
+ struct nfs4_label *op_label;
};
#define op_iattr iattr

@@ -330,6 +332,7 @@ struct nfsd4_setattr {
u32 sa_bmval[3]; /* request */
struct iattr sa_iattr; /* request */
struct nfs4_acl *sa_acl;
+ struct nfs4_label *sa_label;
};

struct nfsd4_setclientid {
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index f9235b4..862471f 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -28,6 +28,14 @@ struct nfs4_acl {
struct nfs4_ace aces[0];
};

+struct nfs4_label {
+ uint32_t lfs;
+ uint32_t pi;
+ u32 len;
+ void *label;
+};
+
+
typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;

struct nfs_stateid4 {
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1cc2568..37a862c 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -489,6 +489,20 @@ extern int nfs_mountpoint_expiry_timeout;
extern void nfs_release_automount_timer(void);

/*
+ * linux/fs/nfs/nfs4proc.c
+ */
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+extern struct nfs4_label *nfs4_label_alloc(gfp_t flags);
+extern void nfs4_label_init(struct nfs4_label *);
+extern void nfs4_label_free(struct nfs4_label *);
+#else
+static inline struct nfs4_label *nfs4_label_alloc(gfp_t flags) { return NULL; }
+static inline void nfs4_label_init(struct nfs4_label *) {}
+static inline void nfs4_label_free(struct nfs4_label *label) {}
+#endif
+
+/*
* linux/fs/nfs/unlink.c
*/
extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index a0669d3..7e9347a 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -352,6 +352,7 @@ struct nfs_openargs {
const u32 * bitmask;
const u32 * open_bitmap;
__u32 claim;
+ const struct nfs4_label *label;
struct nfs4_sequence_args seq_args;
};

@@ -361,6 +362,7 @@ struct nfs_openres {
struct nfs4_change_info cinfo;
__u32 rflags;
struct nfs_fattr * f_attr;
+ struct nfs4_label *f_label;
struct nfs_seqid * seqid;
const struct nfs_server *server;
fmode_t delegation_type;
@@ -405,6 +407,7 @@ struct nfs_closeargs {
struct nfs_closeres {
nfs4_stateid stateid;
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
struct nfs_seqid * seqid;
const struct nfs_server *server;
struct nfs4_sequence_res seq_res;
@@ -478,6 +481,7 @@ struct nfs4_delegreturnargs {

struct nfs4_delegreturnres {
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
const struct nfs_server *server;
struct nfs4_sequence_res seq_res;
};
@@ -498,6 +502,7 @@ struct nfs_readargs {

struct nfs_readres {
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
__u32 count;
int eof;
struct nfs4_sequence_res seq_res;
@@ -566,6 +571,7 @@ struct nfs_removeargs {
struct nfs_removeres {
const struct nfs_server *server;
struct nfs_fattr *dir_attr;
+ struct nfs4_label *dir_label;
struct nfs4_change_info cinfo;
struct nfs4_sequence_res seq_res;
};
@@ -578,6 +584,8 @@ struct nfs_renameargs {
const struct nfs_fh *new_dir;
const struct qstr *old_name;
const struct qstr *new_name;
+ const struct nfs4_label *old_label;
+ const struct nfs4_label *new_label;
struct nfs4_sequence_args seq_args;
};

@@ -585,8 +593,10 @@ struct nfs_renameres {
const struct nfs_server *server;
struct nfs4_change_info old_cinfo;
struct nfs_fattr *old_fattr;
+ struct nfs4_label *old_label;
struct nfs4_change_info new_cinfo;
struct nfs_fattr *new_fattr;
+ struct nfs4_label *new_label;
struct nfs4_sequence_res seq_res;
};

@@ -634,6 +644,7 @@ struct nfs_setattrargs {
struct iattr * iap;
const struct nfs_server * server; /* Needed for name mapping */
const u32 * bitmask;
+ const struct nfs4_label *label;
struct nfs4_sequence_args seq_args;
};

@@ -669,6 +680,7 @@ struct nfs_getaclres {

struct nfs_setattrres {
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
const struct nfs_server * server;
struct nfs4_sequence_res seq_res;
};
@@ -715,6 +727,7 @@ struct nfs3_setaclargs {
struct nfs_diropok {
struct nfs_fh * fh;
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
};

struct nfs_readlinkargs {
@@ -844,6 +857,7 @@ struct nfs4_accessargs {
struct nfs4_accessres {
const struct nfs_server * server;
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
u32 supported;
u32 access;
struct nfs4_sequence_res seq_res;
@@ -866,6 +880,7 @@ struct nfs4_create_arg {
const struct iattr * attrs;
const struct nfs_fh * dir_fh;
const u32 * bitmask;
+ const struct nfs4_label *label;
struct nfs4_sequence_args seq_args;
};

@@ -873,6 +888,7 @@ struct nfs4_create_res {
const struct nfs_server * server;
struct nfs_fh * fh;
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
struct nfs4_change_info dir_cinfo;
struct nfs4_sequence_res seq_res;
};
@@ -898,6 +914,7 @@ struct nfs4_getattr_res {
const struct nfs_server * server;
struct nfs_fattr * fattr;
struct nfs4_sequence_res seq_res;
+ struct nfs4_label *label;
};

struct nfs4_link_arg {
@@ -911,8 +928,10 @@ struct nfs4_link_arg {
struct nfs4_link_res {
const struct nfs_server * server;
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
struct nfs4_change_info cinfo;
struct nfs_fattr * dir_attr;
+ struct nfs4_label *dir_label;
struct nfs4_sequence_res seq_res;
};

@@ -928,6 +947,7 @@ struct nfs4_lookup_res {
const struct nfs_server * server;
struct nfs_fattr * fattr;
struct nfs_fh * fh;
+ struct nfs4_label *label;
struct nfs4_sequence_res seq_res;
};

--
1.7.11.7

2012-11-12 06:15:39

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 05/13] KConfig: Add KConfig entries for Labeled NFS

From: David Quigley <[email protected]>

This patch adds two entries into the fs/KConfig file. The first entry
NFS_V4_SECURITY_LABEL enables security label support for the NFSv4 client while
the second entry NFSD_V4_SECURITY_LABEL enables security labeling support on
the server side.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/Kconfig | 16 ++++++++++++++++
fs/nfsd/Kconfig | 13 +++++++++++++
2 files changed, 29 insertions(+)

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 13ca196..0077197 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -131,6 +131,22 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
If the NFS client is unchanged from the upstream kernel, this
option should be set to the default "kernel.org".

+config NFS_V4_SECURITY_LABEL
+ bool "Provide Security Label support for NFSv4 client"
+ depends on NFS_V4 && SECURITY
+ help
+
+ Say Y here if you want enable fine-grained security label attribute
+ support for NFS version 4. Security labels allow security modules like
+ SELinux and Smack to label files to facilitate enforcement of their policies.
+ Without this an NFSv4 mount will have the same label on each file.
+
+ If you do not wish to enable fine-grained security labels SELinux or
+ Smack policies on NFSv4 files, say N.
+
+
+ If unsure, say N.
+
config ROOT_NFS
bool "Root file system on NFS"
depends on NFS_FS=y && IP_PNP
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 8df1ea4..75ba894 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -81,6 +81,19 @@ config NFSD_V4

If unsure, say N.

+config NFSD_V4_SECURITY_LABEL
+ bool "Provide Security Label support for NFSv4 server"
+ depends on NFSD_V4 && SECURITY
+ help
+
+ Say Y here if you want enable fine-grained security label attribute
+ support for NFS version 4. Security labels allow security modules like
+ SELinux and Smack to label files to facilitate enforcement of their policies.
+ Without this an NFSv4 mount will have the same label on each file.
+
+ If you do not wish to enable fine-grained security labels SELinux or
+ Smack policies on NFSv4 files, say N.
+
config NFSD_FAULT_INJECTION
bool "NFS server manual fault injection"
depends on NFSD_V4 && DEBUG_KERNEL
--
1.7.11.7

2012-11-12 06:15:35

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 01/13] Security: Add hook to calculate context based on a negative dentry.

From: David Quigley <[email protected]>

There is a time where we need to calculate a context without the
inode having been created yet. To do this we take the negative dentry and
calculate a context based on the process and the parent directory contexts.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
include/linux/security.h | 27 +++++++++++++++++++++++++++
security/capability.c | 8 ++++++++
security/security.c | 10 ++++++++++
security/selinux/hooks.c | 35 +++++++++++++++++++++++++++++++++++
4 files changed, 80 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index 05e88bd..c9f5eec 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -26,6 +26,7 @@
#include <linux/capability.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/string.h>

struct linux_binprm;
struct cred;
@@ -306,6 +307,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Parse a string of security data filling in the opts structure
* @options string containing all mount options known by the LSM
* @opts binary data structure usable by the LSM
+ * @dentry_init_security:
+ * Compute a context for a dentry as the inode is not yet available
+ * since NFSv4 has no label backed by an EA anyway.
+ * @dentry dentry to use in calculating the context.
+ * @mode mode used to determine resource type.
+ * @name name of the last path component used to create file
+ * @ctx pointer to place the pointer to the resulting context in.
+ * @ctxlen point to place the length of the resulting context.
+ *
*
* Security hooks for inode operations.
*
@@ -1421,6 +1431,10 @@ struct security_operations {
void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
+ int (*dentry_init_security) (struct dentry *dentry, int mode,
+ struct qstr *name, void **ctx,
+ u32 *ctxlen);
+

#ifdef CONFIG_SECURITY_PATH
int (*path_unlink) (struct path *dir, struct dentry *dentry);
@@ -1702,6 +1716,9 @@ int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *o
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
+int security_dentry_init_security(struct dentry *dentry, int mode,
+ struct qstr *name, void **ctx,
+ u32 *ctxlen);

int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode);
@@ -2005,6 +2022,16 @@ static inline int security_inode_alloc(struct inode *inode)
static inline void security_inode_free(struct inode *inode)
{ }

+static inline int security_dentry_init_security(struct dentry *dentry,
+ int mode,
+ struct qstr *name,
+ void **ctx,
+ u32 *ctxlen)
+{
+ return -EOPNOTSUPP;
+}
+
+
static inline int security_inode_init_security(struct inode *inode,
struct inode *dir,
const struct qstr *qstr,
diff --git a/security/capability.c b/security/capability.c
index b14a30c..f1eb284 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -108,6 +108,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
return 0;
}

+static int cap_dentry_init_security(struct dentry *dentry, int mode,
+ struct qstr *name, void **ctx,
+ u32 *ctxlen)
+{
+ return 0;
+}
+
static int cap_inode_alloc_security(struct inode *inode)
{
return 0;
@@ -905,6 +912,7 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, sb_set_mnt_opts);
set_to_cap_if_null(ops, sb_clone_mnt_opts);
set_to_cap_if_null(ops, sb_parse_opts_str);
+ set_to_cap_if_null(ops, dentry_init_security);
set_to_cap_if_null(ops, inode_alloc_security);
set_to_cap_if_null(ops, inode_free_security);
set_to_cap_if_null(ops, inode_init_security);
diff --git a/security/security.c b/security/security.c
index 8dcd4ae..b4b2017 100644
--- a/security/security.c
+++ b/security/security.c
@@ -12,6 +12,7 @@
*/

#include <linux/capability.h>
+#include <linux/dcache.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -324,6 +325,15 @@ void security_inode_free(struct inode *inode)
security_ops->inode_free_security(inode);
}

+int security_dentry_init_security(struct dentry *dentry, int mode,
+ struct qstr *name, void **ctx,
+ u32 *ctxlen)
+{
+ return security_ops->dentry_init_security(dentry, mode, name,
+ ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_dentry_init_security);
+
int security_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
const initxattrs initxattrs, void *fs_data)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 61a5336..22d9adf 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2483,6 +2483,40 @@ static void selinux_inode_free_security(struct inode *inode)
inode_free_security(inode);
}

+static int selinux_dentry_init_security(struct dentry *dentry, int mode,
+ struct qstr *name, void **ctx,
+ u32 *ctxlen)
+{
+ struct cred *cred = current_cred();
+ struct task_security_struct *tsec;
+ struct inode_security_struct *dsec;
+ struct superblock_security_struct *sbsec;
+ struct inode *dir = dentry->d_parent->d_inode;
+ u32 newsid;
+ int rc;
+
+ tsec = cred->security;
+ dsec = dir->i_security;
+ sbsec = dir->i_sb->s_security;
+
+ if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
+ newsid = tsec->create_sid;
+ } else {
+ rc = security_transition_sid(tsec->sid, dsec->sid,
+ inode_mode_to_security_class(mode),
+ name,
+ &newsid);
+ if (rc) {
+ printk(KERN_WARNING
+ "%s: security_transition_sid failed, rc=%d\n",
+ __func__, -rc);
+ return rc;
+ }
+ }
+
+ return security_sid_to_context(newsid, (char **)ctx, ctxlen);
+}
+
static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, char **name,
void **value, size_t *len)
@@ -5509,6 +5543,7 @@ static struct security_operations selinux_ops = {
.sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
.sb_parse_opts_str = selinux_parse_opts_str,

+ .dentry_init_security = selinux_dentry_init_security,

.inode_alloc_security = selinux_inode_alloc_security,
.inode_free_security = selinux_inode_free_security,
--
1.7.11.7

2012-11-12 06:15:47

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 13/13] NFSD: Server implementation of MAC Labeling

From: David Quigley <[email protected]>

This patch adds the ability to encode and decode file labels on the server for
the purpose of sending them to the client and also to process label change
requests from the client.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfsd/export.c | 3 ++
fs/nfsd/nfs4proc.c | 33 +++++++++++++++
fs/nfsd/nfs4xdr.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++---
fs/nfsd/vfs.c | 31 ++++++++++++++
fs/nfsd/vfs.h | 2 +
5 files changed, 184 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index a3946cf..251eca7 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1112,6 +1112,9 @@ static struct flags {
{ NFSEXP_ASYNC, {"async", "sync"}},
{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
{ NFSEXP_NOHIDE, {"nohide", ""}},
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ { NFSEXP_SECURITY_LABEL, {"security_label", ""}},
+#endif
{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 6c9a4b2..8e9c17c 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -41,6 +41,10 @@
#include "vfs.h"
#include "current_stateid.h"

+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
#define NFSDDBG_FACILITY NFSDDBG_PROC

static u32 nfsd_attrmask[] = {
@@ -228,6 +232,18 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
(u32 *)open->op_verf.data,
&open->op_truncate, &open->op_created);

+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (!status && open->op_label != NULL) {
+ struct inode *inode = resfh->fh_dentry->d_inode;
+
+ mutex_lock(&inode->i_mutex);
+ /* Is it appropriate to just kick back an error? */
+ status = security_inode_setsecctx(resfh->fh_dentry,
+ open->op_label->label, open->op_label->len);
+ mutex_unlock(&inode->i_mutex);
+ }
+#endif
+
/*
* Following rfc 3530 14.2.16, use the returned bitmask
* to indicate which attributes we used to store the
@@ -588,6 +604,18 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_badtype;
}

+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (!status && create->cr_label != NULL) {
+ struct inode *inode = resfh.fh_dentry->d_inode;
+
+ mutex_lock(&inode->i_mutex);
+ /* Is it appropriate to just kick back an error? */
+ status = security_inode_setsecctx(resfh.fh_dentry,
+ create->cr_label->label, create->cr_label->len);
+ mutex_unlock(&inode->i_mutex);
+ }
+#endif
+
if (status)
goto out;

@@ -869,6 +897,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
setattr->sa_acl);
if (status)
goto out;
+ if (setattr->sa_label != NULL)
+ status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
+ setattr->sa_label);
+ if (status)
+ goto out;
status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
0, (time_t)0);
out:
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index fd548d1..58e205c 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -54,6 +54,11 @@
#include "state.h"
#include "cache.h"

+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
+
#define NFSDDBG_FACILITY NFSDDBG_XDR

/*
@@ -241,7 +246,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)

static __be32
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
- struct iattr *iattr, struct nfs4_acl **acl)
+ struct iattr *iattr, struct nfs4_acl **acl,
+ struct nfs4_label **label)
{
int expected_len, len = 0;
u32 dummy32;
@@ -385,6 +391,50 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
goto xdr_error;
}
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
+ uint32_t pi;
+ uint32_t lfs;
+
+ READ_BUF(4);
+ len += 4;
+ READ32(lfs);
+ READ_BUF(4);
+ len += 4;
+ READ32(pi);
+ READ_BUF(4);
+ len += 4;
+ READ32(dummy32);
+ READ_BUF(dummy32);
+ len += (XDR_QUADLEN(dummy32) << 2);
+ READMEM(buf, dummy32);
+
+ if (dummy32 > NFS4_MAXLABELLEN)
+ return nfserr_resource;
+
+ *label = kzalloc(sizeof(struct nfs4_label), GFP_KERNEL);
+ if (*label == NULL) {
+ host_err = -ENOMEM;
+ goto out_nfserr;
+ }
+
+ (*label)->label = kmalloc(dummy32 + 1, GFP_KERNEL);
+ if ((*label)->label == NULL) {
+ host_err = -ENOMEM;
+ kfree(*label);
+ goto out_nfserr;
+ }
+
+ (*label)->len = dummy32;
+ memcpy((*label)->label, buf, dummy32);
+ ((char *)(*label)->label)[dummy32] = '\0';
+ (*label)->pi = pi;
+ (*label)->lfs = lfs;
+
+ defer_free(argp, kfree, (*label)->label);
+ defer_free(argp, kfree, *label);
+ }
+#endif
if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
|| bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
|| bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
@@ -494,7 +544,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
return status;

status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
- &create->cr_acl);
+ &create->cr_acl, &create->cr_label);
if (status)
goto out;

@@ -744,7 +794,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
case NFS4_CREATE_UNCHECKED:
case NFS4_CREATE_GUARDED:
status = nfsd4_decode_fattr(argp, open->op_bmval,
- &open->op_iattr, &open->op_acl);
+ &open->op_iattr, &open->op_acl, &open->op_label);
if (status)
goto out;
break;
@@ -758,7 +808,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
READ_BUF(NFS4_VERIFIER_SIZE);
COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
status = nfsd4_decode_fattr(argp, open->op_bmval,
- &open->op_iattr, &open->op_acl);
+ &open->op_iattr, &open->op_acl, &open->op_label);
if (status)
goto out;
break;
@@ -981,7 +1031,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
if (status)
return status;
return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
- &setattr->sa_acl);
+ &setattr->sa_acl, &setattr->sa_label);
}

static __be32
@@ -1045,7 +1095,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
* nfsd4_proc_verify; however we still decode here just to return
* correct error in case of bad xdr. */
#if 0
- status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl);
+ status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl, &ve_label);
if (status == nfserr_inval) {
status = nfserrno(status);
goto out;
@@ -1998,6 +2048,47 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
FATTR4_WORD0_RDATTR_ERROR)
#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID

+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ static inline __be32
+nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **pp, int *buflen)
+{
+ void *context;
+ int err;
+ int len;
+ uint32_t pi = 0;
+ uint32_t lfs = 0;
+ __be32 *p = *pp;
+
+ err = 0;
+ (void)security_inode_getsecctx(dentry->d_inode, &context, &len);
+ if (len < 0)
+ return nfserrno(len);
+
+ if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) {
+ err = nfserr_resource;
+ goto out;
+ }
+
+ /* XXX: A call to the translation code should be placed here
+ * for now send 0 until we have that to indicate the null
+ * translation */
+
+ if ((*buflen -= 4) < 0)
+ return nfserr_resource;
+
+ WRITE32(lfs);
+ WRITE32(pi);
+ p = xdr_encode_opaque(p, context, len);
+ *buflen -= (XDR_QUADLEN(len) << 2) + 4;
+ BUG_ON(*buflen < 0);
+
+ *pp = p;
+out:
+ security_release_secctx(context, len);
+ return err;
+}
+#endif
+
static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
{
/* As per referral draft: */
@@ -2122,6 +2213,14 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,

if (!aclsupport)
word0 &= ~FATTR4_WORD0_ACL;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
+ word2 |= FATTR4_WORD2_SECURITY_LABEL;
+ else
+ word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
+#else
+ word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
+#endif
if (!word2) {
if ((buflen -= 12) < 0)
goto out_resource;
@@ -2444,6 +2543,16 @@ out_acl:
}
WRITE64(stat.ino);
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
+ status = nfsd4_encode_security_label(rqstp, dentry,
+ &p, &buflen);
+ if (status == nfserr_resource)
+ goto out_resource;
+ if (status)
+ goto out;
+ }
+#endif
if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
WRITE32(3);
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index c120b48..717fb60 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -28,6 +28,7 @@
#include <asm/uaccess.h>
#include <linux/exportfs.h>
#include <linux/writeback.h>
+#include <linux/security.h>

#ifdef CONFIG_NFSD_V3
#include "xdr3.h"
@@ -621,6 +622,36 @@ int nfsd4_is_junction(struct dentry *dentry)
return 0;
return 1;
}
+
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfs4_label *label)
+{
+ __be32 error;
+ int host_error;
+ struct dentry *dentry;
+
+ /* Get inode */
+ /* XXX: should we have a MAY_SSECCTX? */
+ error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
+ if (error)
+ return error;
+
+ dentry = fhp->fh_dentry;
+
+ mutex_lock(&dentry->d_inode->i_mutex);
+ host_error = security_inode_setsecctx(dentry, label->label, label->len);
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ return nfserrno(host_error);
+}
+#else
+__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfs4_label *label)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
#endif /* defined(CONFIG_NFSD_V4) */

#ifdef CONFIG_NFSD_V3
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 359594c..49c6cc0 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -55,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
struct nfs4_acl *);
int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
+__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
+ struct nfs4_label *);
#endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
--
1.7.11.7

2012-11-12 06:15:45

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 11/13] NFS: Client implementation of Labeled-NFS

From: David Quigley <[email protected]>

This patch implements the client transport and handling support for labeled
NFS. The patch adds two functions to encode and decode the security label
recommended attribute which makes use of the LSM hooks added earlier. It also
adds code to grab the label from the file attribute structures and encode the
label to be sent back to the server.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/inode.c | 52 +++++++-
fs/nfs/nfs4proc.c | 310 ++++++++++++++++++++++++++++++++++++++++++++--
fs/nfs/nfs4xdr.c | 182 ++++++++++++++++++++++-----
fs/nfs/super.c | 19 ++-
include/linux/nfs_fs.h | 3 +
include/linux/nfs_fs_sb.h | 7 ++
security/selinux/hooks.c | 4 +
7 files changed, 531 insertions(+), 46 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index ab08d0d..ac29093 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -156,9 +156,18 @@ static void nfs_zap_caches_locked(struct inode *inode)

memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
+ | NFS_INO_INVALID_LABEL
+ | NFS_INO_INVALID_DATA
+ | NFS_INO_INVALID_ACCESS
+ | NFS_INO_INVALID_ACL
+ | NFS_INO_REVAL_PAGECACHE;
else
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR
+ | NFS_INO_INVALID_LABEL
+ | NFS_INO_INVALID_ACCESS
+ | NFS_INO_INVALID_ACL
+ | NFS_INO_REVAL_PAGECACHE;
}

void nfs_zap_caches(struct inode *inode)
@@ -247,6 +256,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
}

#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
+ struct nfs4_label *label)
+{
+ int error;
+
+ if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) &&
+ label && inode->i_security) {
+ error = security_inode_notifysecctx(inode, label->label,
+ label->len);
+ if (error)
+ printk(KERN_ERR "%s() %s %d "
+ "security_inode_notifysecctx() %d\n",
+ __func__,
+ (char *)label->label,
+ label->len, error);
+ }
+}
+
struct nfs4_label *nfs4_label_alloc(gfp_t flags)
{
struct nfs4_label *label = NULL;
@@ -284,7 +311,14 @@ void nfs4_label_free(struct nfs4_label *label)
return;
}
EXPORT_SYMBOL_GPL(nfs4_label_free);
+
+#else
+void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
+ struct nfs4_label *label)
+{
+}
#endif
+EXPORT_SYMBOL_GPL(nfs_setsecurity);

/*
* This is our front-end to iget that looks up inodes by file handle
@@ -413,6 +447,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
*/
inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ nfs_setsecurity(inode, fattr, label);
+#endif
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now;
nfsi->access_cache = RB_ROOT;
@@ -772,6 +809,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c
spin_unlock(&inode->i_lock);
return ctx;
}
+EXPORT_SYMBOL_GPL(nfs_find_open_context);

static void nfs_file_clear_open_context(struct file *filp)
{
@@ -904,7 +942,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
*/
int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
- if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR)
+ if (!(NFS_I(inode)->cache_validity &
+ (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
&& !nfs_attribute_cache_expired(inode))
return NFS_STALE(inode) ? -ESTALE : 0;
return __nfs_revalidate_inode(server, inode);
@@ -1497,6 +1536,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
| NFS_INO_INVALID_ACL
| NFS_INO_REVAL_FORCED);

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label)
+ nfs_setsecurity(inode, fattr, label);
+#endif
if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
if (inode->i_nlink != fattr->nlink) {
invalid |= NFS_INO_INVALID_ATTR;
@@ -1518,7 +1561,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
inode->i_blocks = fattr->du.nfs2.blocks;

/* Update attrtimeo value if we're out of the unstable period */
- if (invalid & NFS_INO_INVALID_ATTR) {
+ if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) {
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now;
@@ -1531,6 +1574,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
}
}
invalid &= ~NFS_INO_INVALID_ATTR;
+ invalid &= ~NFS_INO_INVALID_LABEL;
/* Don't invalidate the data if we were to blame */
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode)))
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4ab2738..77d1a29 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -133,7 +133,11 @@ const u32 nfs4_fattr_bitmap[3] = {
| FATTR4_WORD1_TIME_ACCESS
| FATTR4_WORD1_TIME_METADATA
| FATTR4_WORD1_TIME_MODIFY,
- 0
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ FATTR4_WORD2_SECURITY_LABEL
+#else
+ 0
+#endif
};

static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -2059,6 +2063,7 @@ static int _nfs4_do_open(struct inode *dir,
if (status == 0) {
nfs_setattr_update_inode(state->inode, sattr);
nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
+ nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
}
}

@@ -2172,6 +2177,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
unsigned long timestamp = jiffies;
int status;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (ilabel == NULL || olabel == NULL)
+ arg.bitmask = server->attr_bitmask_nl;
+#endif
nfs_fattr_init(fattr);

if (state != NULL) {
@@ -2399,7 +2408,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
if (calldata->arg.seqid == NULL)
goto out_free_calldata;
calldata->arg.fmode = 0;
- calldata->arg.bitmask = server->cache_consistency_bitmask;
+ calldata->arg.bitmask = server->cache_consistency_bitmask_nl;
calldata->res.fattr = &calldata->fattr;
calldata->res.seqid = calldata->arg.seqid;
calldata->res.server = server;
@@ -2431,9 +2440,24 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags
struct nfs4_state *state;
struct nfs4_label l, *label = NULL;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ struct dentry *dentry = ctx->dentry;
+ int error;
+ error = security_dentry_init_security(dentry, attr->ia_mode,
+ &dentry->d_name, &l.label, &l.len);
+ if (error == 0)
+ label = &l;
+ }
+#endif
+
/* Protect against concurrent sillydeletes */
state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, label,
ctx->cred, &ctx->mdsthreshold);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label)
+ security_release_secctx(l.label, l.len);
+#endif
if (IS_ERR(state))
return ERR_CAST(state);
ctx->state = state;
@@ -2493,10 +2517,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
server->caps |= NFS_CAP_CTIME;
if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)
server->caps |= NFS_CAP_MTIME;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
+ server->caps |= NFS_CAP_SECURITY_LABEL;
+ } else
+#endif
+ server->attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ memcpy(server->attr_bitmask_nl, res.attr_bitmask, sizeof(server->attr_bitmask));
+ server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+#endif

memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
- server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
+ server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA |
+ FATTR4_WORD1_TIME_MODIFY;
+ server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
+ memcpy(server->cache_consistency_bitmask_nl, server->cache_consistency_bitmask,
+ sizeof(server->cache_consistency_bitmask_nl));
+ server->cache_consistency_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
server->acl_bitmask = res.acl_bitmask;
server->fh_expire_type = res.fh_expire_type;
}
@@ -2519,8 +2559,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
+ u32 bitmask[3];
struct nfs4_lookup_root_arg args = {
- .bitmask = nfs4_fattr_bitmap,
+ .bitmask = bitmask,
};
struct nfs4_lookup_res res = {
.server = server,
@@ -2533,6 +2574,10 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_resp = &res,
};

+ bitmask[0] = nfs4_fattr_bitmap[0];
+ bitmask[1] = nfs4_fattr_bitmap[1];
+ bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
+
nfs_fattr_init(info->fattr);
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
}
@@ -2722,7 +2767,12 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_argp = &args,
.rpc_resp = &res,
};
-
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (!label)
+ args.bitmask = server->attr_bitmask_nl;
+#endif
+
nfs_fattr_init(fattr);
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
}
@@ -2815,6 +2865,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
struct nfs4_lookup_res res = {
.server = server,
.fattr = fattr,
+ .label = label,
.fh = fhandle,
};
struct rpc_message msg = {
@@ -2823,6 +2874,11 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
.rpc_resp = &res,
};

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label == NULL)
+ args.bitmask = server->attr_bitmask_nl;
+#endif
+
nfs_fattr_init(fattr);

dprintk("NFS call lookup %s\n", name->name);
@@ -2929,7 +2985,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
.rpc_cred = entry->cred,
};
int mode = entry->mask;
- int status;
+ int status = 0;

/*
* Determine which access bits we want to ask for...
@@ -3058,6 +3114,15 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
if (IS_ERR(ctx))
return PTR_ERR(ctx);

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ status = security_dentry_init_security(dentry, sattr->ia_mode,
+ &dentry->d_name, &l.label, &l.len);
+ if (status == 0)
+ ilabel = &l;
+ }
+#endif
+
sattr->ia_mode &= ~current_umask();
state = nfs4_do_open(dir, dentry, ctx->mode,
flags, sattr, ilabel, ctx->cred,
@@ -3071,6 +3136,10 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
ctx->state = state;
out:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (ilabel)
+ security_release_secctx(ilabel->label, ilabel->len);
+#endif
put_nfs_open_context(ctx);
return status;
}
@@ -3120,6 +3189,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
res->server = server;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
+
+ nfs_fattr_init(res->dir_attr);
}

static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
@@ -3405,12 +3476,27 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct nfs4_exception exception = { };
struct nfs4_label l, *label = NULL;
int err;
+
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ err = security_dentry_init_security(dentry, sattr->ia_mode,
+ &dentry->d_name, &l.label, &l.len);
+ if (err == 0)
+ label = &l;
+ }
+#endif
+
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_symlink(dir, dentry, page,
len, sattr, label),
&exception);
} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label)
+ security_release_secctx(l.label, l.len);
+#endif
return err;
}

@@ -3439,6 +3525,15 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct nfs4_label l, *label = NULL;
int err;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ err = security_dentry_init_security(dentry, sattr->ia_mode,
+ &dentry->d_name, &l.label, &l.len);
+ if (err == 0)
+ label = &l;
+ }
+#endif
+
sattr->ia_mode &= ~current_umask();
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
@@ -3446,6 +3541,10 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
&exception);
} while (exception.retry);
return err;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label)
+ security_release_secctx(l.label, l.len);
+#endif
}

static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
@@ -3460,7 +3559,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
.bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
.plus = plus,
};
- struct nfs4_readdir_res res;
+ struct nfs4_readdir_res res = {
+ .pgbase = 0,
+ };
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
.rpc_argp = &args,
@@ -3543,12 +3644,25 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct nfs4_label l, *label = NULL;
int err;

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ err = security_dentry_init_security(dentry, sattr->ia_mode,
+ &dentry->d_name, &l.label, &l.len);
+ if (err == 0)
+ label = &l;
+ }
+#endif
+
sattr->ia_mode &= ~current_umask();
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
&exception);
} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label)
+ security_release_secctx(l.label, l.len);
+#endif
return err;
}

@@ -3766,7 +3880,11 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
data->args.bitmask = NULL;
data->res.fattr = NULL;
} else
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ data->args.bitmask = server->cache_consistency_bitmask_nl;
+#else
data->args.bitmask = server->cache_consistency_bitmask;
+#endif

if (!data->write_done_cb)
data->write_done_cb = nfs4_write_done_cb;
@@ -4190,6 +4308,182 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
return err;
}

+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+static int _nfs4_get_security_label(struct inode *inode, void *buf,
+ size_t buflen)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_fattr fattr;
+ struct nfs4_label label;
+ u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
+ struct nfs4_getattr_arg args = {
+ .fh = NFS_FH(inode),
+ .bitmask = bitmask,
+ };
+ struct nfs4_getattr_res res = {
+ .fattr = &fattr,
+ .label = &label,
+ .server = server,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+ int ret;
+
+ label.label = buf;
+ label.len = buflen;
+ nfs_fattr_init(&fattr);
+
+ ret = rpc_call_sync(server->client, &msg, 0);
+ if (ret)
+ return ret;
+ if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
+ return -ENOENT;
+ if (buflen < label.len)
+ return -ERANGE;
+ return 0;
+}
+
+static int nfs4_get_security_label(struct inode *inode, void *buf,
+ size_t buflen)
+{
+ struct nfs4_exception exception = { };
+ int err;
+
+ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+ return -EOPNOTSUPP;
+
+ do {
+ err = nfs4_handle_exception(NFS_SERVER(inode),
+ _nfs4_get_security_label(inode, buf, buflen),
+ &exception);
+ } while (exception.retry);
+ return err;
+}
+
+static int _nfs4_do_set_security_label(struct inode *inode,
+ struct nfs4_label *ilabel,
+ struct nfs_fattr *fattr,
+ struct nfs4_label *olabel,
+ struct nfs4_state *state)
+{
+
+ struct iattr sattr;
+ struct nfs_server *server = NFS_SERVER(inode);
+ const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
+ struct nfs_setattrargs args = {
+ .fh = NFS_FH(inode),
+ .iap = &sattr,
+ .server = server,
+ .bitmask = bitmask,
+ .label = ilabel,
+ };
+ struct nfs_setattrres res = {
+ .fattr = fattr,
+ .label = olabel,
+ .server = server,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+ unsigned long timestamp = jiffies;
+ int status;
+
+ memset(&sattr, 0, sizeof(struct iattr));
+
+ if (state != NULL) {
+ struct nfs_lockowner lockowner = {
+ .l_owner = current->files,
+ .l_pid = current->tgid,
+ };
+
+ msg.rpc_cred = state->owner->so_cred;
+ nfs4_select_rw_stateid(&args.stateid, state, FMODE_WRITE,
+ &lockowner);
+ } else if (nfs4_copy_delegation_stateid(&args.stateid, inode,
+ FMODE_WRITE)) {
+ /* Use that stateid */
+ } else
+ nfs4_stateid_copy(&args.stateid, &zero_stateid);
+
+ status = rpc_call_sync(server->client, &msg, 0);
+ if (status == 0 && state != NULL)
+ renew_lease(server, timestamp);
+ return status;
+}
+
+static int nfs4_do_set_security_label(struct inode *inode,
+ struct nfs4_label *ilabel,
+ struct nfs_fattr *fattr,
+ struct nfs4_label *olabel,
+ struct nfs4_state *state)
+{
+ struct nfs4_exception exception = { };
+ int err;
+
+ do {
+ err = nfs4_handle_exception(NFS_SERVER(inode),
+ _nfs4_do_set_security_label(inode, ilabel,
+ fattr, olabel, state),
+ &exception);
+ } while (exception.retry);
+ return err;
+}
+
+ static int
+nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
+{
+ struct nfs4_label ilabel, *olabel = NULL;
+ struct nfs_fattr fattr;
+ struct rpc_cred *cred;
+ struct nfs_open_context *ctx;
+ struct nfs4_state *state = NULL;
+ struct inode *inode = dentry->d_inode;
+ int status;
+
+ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+ return -EOPNOTSUPP;
+
+ nfs_fattr_init(&fattr);
+
+ ilabel.pi = 0;
+ ilabel.lfs = 0;
+ ilabel.label = (char *)buf;
+ ilabel.len = buflen;
+
+ cred = rpc_lookup_cred();
+ if (IS_ERR(cred))
+ return PTR_ERR(cred);
+
+ olabel = nfs4_label_alloc(GFP_KERNEL);
+ if (olabel == NULL) {
+ status = -ENOMEM;
+ goto out;
+ }
+
+ /* Search for an existing open(O_WRITE) file */
+ ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
+ if (ctx != NULL)
+ state = ctx->state;
+
+ status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel,
+ state);
+ if (status == 0)
+ nfs_setsecurity(inode, &fattr, olabel);
+ if (ctx != NULL)
+ put_nfs_open_context(ctx);
+ nfs4_label_free(olabel);
+out:
+ put_rpccred(cred);
+ return status;
+}
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
+
+
static int
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
{
@@ -4480,7 +4774,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
data->args.fhandle = &data->fh;
data->args.stateid = &data->stateid;
- data->args.bitmask = server->cache_consistency_bitmask;
+ data->args.bitmask = server->cache_consistency_bitmask_nl;
nfs_copy_fh(&data->fh, NFS_FH(inode));
nfs4_stateid_copy(&data->stateid, stateid);
data->res.fattr = &data->fattr;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 146d4d3..db57d72 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -101,12 +101,19 @@ static int nfs4_stat_to_errno(int);
#define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
#define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+/* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */
+#define nfs4_label_maxsz (4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN))
+#else
+#define nfs4_label_maxsz 0
+#endif
/* We support only one layout type per file system */
#define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8)
/* This is based on getfattr, which uses the most attributes: */
#define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
3 + 3 + 3 + nfs4_owner_maxsz + \
- nfs4_group_maxsz + decode_mdsthreshold_maxsz))
+ nfs4_group_maxsz + nfs4_label_maxsz + \
+ decode_mdsthreshold_maxsz))
#define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
nfs4_fattr_value_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
@@ -114,6 +121,7 @@ static int nfs4_stat_to_errno(int);
1 + 2 + 1 + \
nfs4_owner_maxsz + \
nfs4_group_maxsz + \
+ nfs4_label_maxsz + \
4 + 4)
#define encode_savefh_maxsz (op_encode_hdr_maxsz)
#define decode_savefh_maxsz (op_decode_hdr_maxsz)
@@ -191,9 +199,11 @@ static int nfs4_stat_to_errno(int);
encode_stateid_maxsz + 3)
#define decode_read_maxsz (op_decode_hdr_maxsz + 2)
#define encode_readdir_maxsz (op_encode_hdr_maxsz + \
- 2 + encode_verifier_maxsz + 5)
+ 2 + encode_verifier_maxsz + 5 + \
+ nfs4_label_maxsz)
#define decode_readdir_maxsz (op_decode_hdr_maxsz + \
- decode_verifier_maxsz)
+ decode_verifier_maxsz + \
+ nfs4_label_maxsz + nfs4_fattr_maxsz)
#define encode_readlink_maxsz (op_encode_hdr_maxsz)
#define decode_readlink_maxsz (op_decode_hdr_maxsz + 1)
#define encode_write_maxsz (op_encode_hdr_maxsz + \
@@ -969,7 +979,9 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE);
}

-static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
+static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
+ const struct nfs4_label *label,
+ const struct nfs_server *server)
{
char owner_name[IDMAP_NAMESZ];
char owner_group[IDMAP_NAMESZ];
@@ -1019,6 +1031,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
}
len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label)
+ len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
+#endif
if (iap->ia_valid & ATTR_ATIME_SET)
len += 16;
else if (iap->ia_valid & ATTR_ATIME)
@@ -1075,6 +1091,15 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label) {
+ bmval2 |= FATTR4_WORD2_SECURITY_LABEL;
+ *p++ = cpu_to_be32(label->lfs);
+ *p++ = cpu_to_be32(label->pi);
+ *p++ = cpu_to_be32(label->len);
+ p = xdr_encode_opaque_fixed(p, label->label, label->len);
+ }
+#endif

/*
* Now we backfill the bitmap and the attribute buffer length.
@@ -1141,7 +1166,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
}

encode_string(xdr, create->name->len, create->name->name);
- encode_attrs(xdr, create->attrs, create->server);
+ encode_attrs(xdr, create->attrs, create->label, create->server);
}

static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
@@ -1374,21 +1399,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
switch(arg->open_flags & O_EXCL) {
case 0:
*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
- encode_attrs(xdr, arg->u.attrs, arg->server);
+ encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
break;
default:
clp = arg->server->nfs_client;
if (clp->cl_mvops->minor_version > 0) {
if (nfs4_has_persistent_session(clp)) {
*p = cpu_to_be32(NFS4_CREATE_GUARDED);
- encode_attrs(xdr, arg->u.attrs, arg->server);
+ encode_attrs(xdr, arg->u.attrs, arg->label,
+ arg->server);
} else {
struct iattr dummy;

*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
encode_nfs4_verifier(xdr, &arg->u.verifier);
dummy.ia_valid = 0;
- encode_attrs(xdr, &dummy, arg->server);
+ encode_attrs(xdr, &dummy, arg->label,
+ arg->server);
}
} else {
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
@@ -1568,20 +1595,43 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
encode_uint64(xdr, readdir->cookie);
encode_nfs4_verifier(xdr, &readdir->verifier);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ p = reserve_space(xdr, 24);
+#else
p = reserve_space(xdr, 20);
+#endif
*p++ = cpu_to_be32(dircount);
*p++ = cpu_to_be32(readdir->count);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ *p++ = cpu_to_be32(3);
+#else
*p++ = cpu_to_be32(2);
-
+#endif
*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ *p++ = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
+ *p = cpu_to_be32(readdir->bitmask[2]);
+#else
*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
+#endif
memcpy(verf, readdir->verifier.data, sizeof(verf));
- dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n",
+ __func__,
+ (unsigned long long)readdir->cookie,
+ verf[0], verf[1],
+ attrs[0] & readdir->bitmask[0],
+ attrs[1] & readdir->bitmask[1],
+ readdir->bitmask[2]);
+#else
+ dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
__func__,
(unsigned long long)readdir->cookie,
verf[0], verf[1],
attrs[0] & readdir->bitmask[0],
attrs[1] & readdir->bitmask[1]);
+#endif
+
}

static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1641,7 +1691,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
{
encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
encode_nfs4_stateid(xdr, &arg->stateid);
- encode_attrs(xdr, arg->iap, server);
+ encode_attrs(xdr, arg->iap, arg->label, server);
}

static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
@@ -4060,6 +4110,67 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
return status;
}

+static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
+ struct nfs4_label *label)
+{
+ uint32_t pi = 0;
+ uint32_t lfs = 0;
+ __u32 len;
+ __be32 *p;
+ int status = 0;
+
+ if (unlikely(bitmap[2] & (FATTR4_WORD2_SECURITY_LABEL - 1U)))
+ return -EIO;
+ if (likely(bitmap[2] & FATTR4_WORD2_SECURITY_LABEL)) {
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ lfs = be32_to_cpup(p++);
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ pi = be32_to_cpup(p++);
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+ len = be32_to_cpup(p++);
+ p = xdr_inline_decode(xdr, len);
+ if (unlikely(!p))
+ goto out_overflow;
+ if (len < XDR_MAX_NETOBJ) {
+ if (label) {
+ nfs4_label_init(label);
+ if (label->len < len) {
+ printk(KERN_ERR
+ "%s(): label->len %d < len %d\n",
+ __func__, label->len, len);
+ } else {
+ memcpy(label->label, p, len);
+ label->len = len;
+ label->pi = pi;
+ label->lfs = lfs;
+ status = NFS_ATTR_FATTR_V4_SECURITY_LABEL;
+ }
+ } else {
+ printk("%s(): NULL label.\n", __func__);
+ dump_stack();
+ goto out_overflow;
+ }
+ bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+ } else
+ printk(KERN_WARNING "%s: label too long (%u)!\n",
+ __func__, len);
+ }
+ if (label && label->label)
+ dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__,
+ label->label, label->len, label->pi, label->lfs);
+ return status;
+
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+
static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
int status = 0;
@@ -4402,7 +4513,7 @@ out_overflow:

static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
struct nfs_fattr *fattr, struct nfs_fh *fh,
- struct nfs4_fs_locations *fs_loc,
+ struct nfs4_fs_locations *fs_loc, struct nfs4_label *label,
const struct nfs_server *server)
{
int status;
@@ -4510,6 +4621,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
if (status < 0)
goto xdr_error;

+ status = decode_attr_security_label(xdr, bitmap, label);
+ if (status < 0)
+ goto xdr_error;
+ fattr->valid |= status;
+
xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status);
return status;
@@ -4517,7 +4633,7 @@ xdr_error:

static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
- const struct nfs_server *server)
+ struct nfs4_label *label, const struct nfs_server *server)
{
unsigned int savep;
uint32_t attrlen,
@@ -4536,7 +4652,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
if (status < 0)
goto xdr_error;

- status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server);
+ status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc,
+ label, server);
if (status < 0)
goto xdr_error;

@@ -4547,9 +4664,9 @@ xdr_error:
}

static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
- const struct nfs_server *server)
+ struct nfs4_label *label, const struct nfs_server *server)
{
- return decode_getfattr_generic(xdr, fattr, NULL, NULL, server);
+ return decode_getfattr_generic(xdr, fattr, NULL, NULL, label, server);
}

/*
@@ -5881,7 +5998,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
status = decode_open_downgrade(xdr, res);
if (status != 0)
goto out;
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -5907,7 +6024,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_access(xdr, &res->supported, &res->access);
if (status != 0)
goto out;
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -5936,7 +6053,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_getfh(xdr, res->fh);
if (status)
goto out;
- status = decode_getfattr(xdr, res->fattr, res->server);
+ status = decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -5962,7 +6079,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
goto out;
status = decode_getfh(xdr, res->fh);
if (status == 0)
- status = decode_getfattr(xdr, res->fattr, res->server);
+ status = decode_getfattr(xdr, res->fattr,
+ res->label, res->server);
out:
return status;
}
@@ -6053,7 +6171,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_restorefh(xdr);
if (status)
goto out;
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -6082,7 +6200,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_getfh(xdr, res->fh);
if (status)
goto out;
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -6114,7 +6232,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_putfh(xdr);
if (status)
goto out;
- status = decode_getfattr(xdr, res->fattr, res->server);
+ status = decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -6216,7 +6334,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
* an ESTALE error. Shouldn't be a problem,
* though, since fattr->valid will remain unset.
*/
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -6247,7 +6365,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
goto out;
if (res->access_request)
decode_access(xdr, &res->access_supported, &res->access_result);
- decode_getfattr(xdr, res->f_attr, res->server);
+ decode_getfattr(xdr, res->f_attr, res->f_label, res->server);
out:
return status;
}
@@ -6297,7 +6415,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
goto out;
if (res->access_request)
decode_access(xdr, &res->access_supported, &res->access_result);
- decode_getfattr(xdr, res->f_attr, res->server);
+ decode_getfattr(xdr, res->f_attr, NULL, res->server);
out:
return status;
}
@@ -6324,7 +6442,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
status = decode_setattr(xdr);
if (status)
goto out;
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, res->label, res->server);
out:
return status;
}
@@ -6504,7 +6622,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
if (status)
goto out;
if (res->fattr)
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, NULL, res->server);
if (!status)
status = res->count;
out:
@@ -6685,7 +6803,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
status = decode_putfh(xdr);
if (status != 0)
goto out;
- status = decode_getfattr(xdr, res->fattr, res->server);
+ status = decode_getfattr(xdr, res->fattr, res->label, res->server);
if (status != 0)
goto out;
status = decode_delegreturn(xdr);
@@ -6718,7 +6836,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
xdr_enter_page(xdr, PAGE_SIZE);
status = decode_getfattr_generic(xdr, &res->fs_locations->fattr,
NULL, res->fs_locations,
- res->fs_locations->server);
+ NULL, res->fs_locations->server);
out:
return status;
}
@@ -6999,7 +7117,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
status = decode_layoutcommit(xdr, rqstp, res);
if (status)
goto out;
- decode_getfattr(xdr, res->fattr, res->server);
+ decode_getfattr(xdr, res->fattr, NULL, res->server);
out:
return status;
}
@@ -7131,7 +7249,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
goto out_overflow;

if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
- NULL, entry->server) < 0)
+ NULL, entry->label, entry->server) < 0)
goto out_overflow;
if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
entry->ino = entry->fattr->mounted_on_fileid;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f4e13c3..3828ba6 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2357,8 +2357,23 @@ static int nfs_bdi_register(struct nfs_server *server)
int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
struct nfs_mount_info *mount_info)
{
- return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
- 0, NULL);
+ int error;
+ unsigned long kflags = 0, kflags_out = 0;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
+ kflags |= SECURITY_LSM_NATIVE_LABELS;
+#endif
+ error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
+ kflags, &kflags_out);
+ if (error)
+ goto err;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
+ !(kflags_out & SECURITY_LSM_NATIVE_LABELS))
+ NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
+#endif
+err:
+ return error;
}
EXPORT_SYMBOL_GPL(nfs_set_sb_security);

diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index c8ace0d..2ef01f8 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -199,6 +199,7 @@ struct nfs_inode {
#define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */
#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */
#define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */
+#define NFS_INO_INVALID_LABEL 0x0080 /* cached label is invalid */

/*
* Bit offsets in flags field
@@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
+extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
+ struct nfs4_label *label);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 383fe9c..ac07d98 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -145,11 +145,18 @@ struct nfs_server {
u32 attr_bitmask[3];/* V4 bitmask representing the set
of attributes supported on this
filesystem */
+ u32 attr_bitmask_nl[3];
+ /* V4 bitmask representing the
+ set of attributes supported
+ on this filesystem excluding
+ the label support bit. */
u32 cache_consistency_bitmask[3];
/* V4 bitmask representing the subset
of change attribute, size, ctime
and mtime attributes supported by
the server */
+ u32 cache_consistency_bitmask_nl[3];
+ /* As above, excluding label. */
u32 acl_bitmask; /* V4 bitmask representing the ACEs
that are supported on this
filesystem */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8f233ff..3e1b84d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2876,7 +2876,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}

+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
+ isec->initialized = 1;
+
return;
}

@@ -2964,6 +2967,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (rc)
return rc;

+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
isec->initialized = 1;
return 0;
--
1.7.11.7

2012-11-12 06:15:37

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 03/13] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data.

From: David Quigley <[email protected]>

There is no way to differentiate if a text mount option is passed from user
space or the kernel. A flags field is being added to the
security_sb_set_mnt_opts hook to allow for in kernel security flags to be sent
to the LSM for processing in addition to the text options received from mount.
This patch also updated existing code to fix compilation errors.

Signed-off-by: David P. Quigley <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/super.c | 3 ++-
include/linux/security.h | 13 ++++++++++---
security/capability.c | 5 ++++-
security/security.c | 7 +++++--
security/selinux/hooks.c | 12 ++++++++++--
5 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index e831bce..ee07a08 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2356,7 +2356,8 @@ static int nfs_bdi_register(struct nfs_server *server)
int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
struct nfs_mount_info *mount_info)
{
- return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts);
+ return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
+ 0, NULL);
}
EXPORT_SYMBOL_GPL(nfs_set_sb_security);

diff --git a/include/linux/security.h b/include/linux/security.h
index 167bdd5..c94bcf5 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1434,7 +1434,9 @@ struct security_operations {
int (*sb_pivotroot) (struct path *old_path,
struct path *new_path);
int (*sb_set_mnt_opts) (struct super_block *sb,
- struct security_mnt_opts *opts);
+ struct security_mnt_opts *opts,
+ unsigned long kern_flags,
+ unsigned long *set_kern_flags);
void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
@@ -1720,7 +1722,10 @@ int security_sb_mount(const char *dev_name, struct path *path,
const char *type, unsigned long flags, void *data);
int security_sb_umount(struct vfsmount *mnt, int flags);
int security_sb_pivotroot(struct path *old_path, struct path *new_path);
-int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
+int security_sb_set_mnt_opts(struct super_block *sb,
+ struct security_mnt_opts *opts,
+ unsigned long kern_flags,
+ unsigned long *set_kern_flags);
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
@@ -2009,7 +2014,9 @@ static inline int security_sb_pivotroot(struct path *old_path,
}

static inline int security_sb_set_mnt_opts(struct super_block *sb,
- struct security_mnt_opts *opts)
+ struct security_mnt_opts *opts,
+ unsigned long kern_flags,
+ unsigned long *set_kern_flags)
{
return 0;
}
diff --git a/security/capability.c b/security/capability.c
index 9071447..cf9f511 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -91,7 +91,10 @@ static int cap_sb_pivotroot(struct path *old_path, struct path *new_path)
}

static int cap_sb_set_mnt_opts(struct super_block *sb,
- struct security_mnt_opts *opts)
+ struct security_mnt_opts *opts,
+ unsigned long kern_flags,
+ unsigned long *set_kern_flags)
+
{
if (unlikely(opts->num_mnt_opts))
return -EOPNOTSUPP;
diff --git a/security/security.c b/security/security.c
index a7bee7b..60a6017 100644
--- a/security/security.c
+++ b/security/security.c
@@ -294,9 +294,12 @@ int security_sb_pivotroot(struct path *old_path, struct path *new_path)
}

int security_sb_set_mnt_opts(struct super_block *sb,
- struct security_mnt_opts *opts)
+ struct security_mnt_opts *opts,
+ unsigned long kern_flags,
+ unsigned long *set_kern_flags)
{
- return security_ops->sb_set_mnt_opts(sb, opts);
+ return security_ops->sb_set_mnt_opts(sb, opts, kern_flags,
+ set_kern_flags);
}
EXPORT_SYMBOL(security_sb_set_mnt_opts);

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f7c4899..4e7e7c2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -551,7 +551,9 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
* labeling information.
*/
static int selinux_set_mnt_opts(struct super_block *sb,
- struct security_mnt_opts *opts)
+ struct security_mnt_opts *opts,
+ unsigned long kern_flags,
+ unsigned long *set_kern_flags)
{
const struct cred *cred = current_cred();
int rc = 0, i;
@@ -579,6 +581,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
"before the security server is initialized\n");
goto out;
}
+ if (kern_flags && !set_kern_flags) {
+ /* Specifying internal flags without providing a place to
+ * place the results is not allowed */
+ rc = -EINVAL;
+ goto out;
+ }

/*
* Binary mount data FS will come through this function twice. Once
@@ -948,7 +956,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
goto out_err;

out:
- rc = selinux_set_mnt_opts(sb, &opts);
+ rc = selinux_set_mnt_opts(sb, &opts, 0, NULL);

out_err:
security_free_mnt_opts(&opts);
--
1.7.11.7

2012-11-12 06:15:43

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 09/13] NFS:Add labels to client function prototypes

>From David Quigley <[email protected]>

After looking at all of the nfsv4 operations the label structure has been added
to the prototypes of the functions which can transmit label data.


Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/client.c | 2 +-
fs/nfs/dir.c | 23 ++++++----
fs/nfs/getroot.c | 3 +-
fs/nfs/inode.c | 33 +++++++-------
fs/nfs/namespace.c | 2 +-
fs/nfs/nfs3acl.c | 4 +-
fs/nfs/nfs3proc.c | 41 +++++++++--------
fs/nfs/nfs4_fs.h | 2 +-
fs/nfs/nfs4namespace.c | 2 +-
fs/nfs/nfs4proc.c | 118 +++++++++++++++++++++++++++++++-----------------
fs/nfs/proc.c | 15 +++---
include/linux/nfs_fs.h | 9 ++--
include/linux/nfs_xdr.h | 5 +-
13 files changed, 151 insertions(+), 108 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 8b39a42..ecc7419 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1080,7 +1080,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
}

if (!(fattr->valid & NFS_ATTR_FATTR)) {
- error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr);
+ error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL);
if (error < 0) {
dprintk("nfs_create_server: getattr error = %d\n", -error);
goto error;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index ce8cb92..1339e44 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -447,7 +447,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
dentry = d_lookup(parent, &filename);
if (dentry != NULL) {
if (nfs_same_file(dentry, entry)) {
- nfs_refresh_inode(dentry->d_inode, entry->fattr);
+ nfs_refresh_inode(dentry->d_inode, entry->fattr, entry->label);
goto out;
} else {
d_drop(dentry);
@@ -459,7 +459,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
if (dentry == NULL)
return;

- inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
+ inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label);
if (IS_ERR(inode))
goto out;

@@ -1034,6 +1034,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
struct dentry *parent;
struct nfs_fh *fhandle = NULL;
struct nfs_fattr *fattr = NULL;
+ struct nfs4_label *label = NULL;
int error;

if (flags & LOOKUP_RCU)
@@ -1076,12 +1077,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if (fhandle == NULL || fattr == NULL)
goto out_error;

- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
if (error)
goto out_bad;
if (nfs_compare_fh(NFS_FH(inode), fhandle))
goto out_bad;
- if ((error = nfs_refresh_inode(inode, fattr)) != 0)
+ if ((error = nfs_refresh_inode(inode, fattr, label)) != 0)
goto out_bad;

nfs_free_fattr(fattr);
@@ -1207,6 +1208,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
struct inode *inode = NULL;
struct nfs_fh *fhandle = NULL;
struct nfs_fattr *fattr = NULL;
+ struct nfs4_label *label = NULL;
int error;

dfprintk(VFS, "NFS: lookup(%s/%s)\n",
@@ -1236,14 +1238,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
if (error == -ENOENT)
goto no_entry;
if (error < 0) {
res = ERR_PTR(error);
goto out_unblock_sillyrename;
}
- inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
+ inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
res = ERR_CAST(inode);
if (IS_ERR(res))
goto out_unblock_sillyrename;
@@ -1477,7 +1479,8 @@ no_open:
* Code common to create, mkdir, and mknod.
*/
int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+ struct nfs_fattr *fattr,
+ struct nfs4_label *label)
{
struct dentry *parent = dget_parent(dentry);
struct inode *dir = parent->d_inode;
@@ -1490,18 +1493,18 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
if (dentry->d_inode)
goto out;
if (fhandle->size == 0) {
- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL);
if (error)
goto out_error;
}
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (!(fattr->valid & NFS_ATTR_FATTR)) {
struct nfs_server *server = NFS_SB(dentry->d_sb);
- error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
+ error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr, NULL);
if (error < 0)
goto out_error;
}
- inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
+ inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
error = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_error;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 033803c..3b68bb6 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -75,6 +75,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
struct nfs_fsinfo fsinfo;
struct dentry *ret;
struct inode *inode;
+ struct nfs4_label *label = NULL;
void *name = kstrdup(devname, GFP_KERNEL);
int error;

@@ -95,7 +96,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
goto out;
}

- inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
+ inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
ret = ERR_CAST(inode);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 0963ad9..daca08c 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -61,7 +61,7 @@
static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;

static void nfs_invalidate_inode(struct inode *);
-static int nfs_update_inode(struct inode *, struct nfs_fattr *);
+static int nfs_update_inode(struct inode *, struct nfs_fattr *, struct nfs4_label *);

static struct kmem_cache * nfs_inode_cachep;

@@ -291,7 +291,7 @@ EXPORT_SYMBOL_GPL(nfs4_label_free);
* instead of inode number.
*/
struct inode *
-nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
+nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs_find_desc desc = {
.fh = fh,
@@ -421,7 +421,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)

unlock_new_inode(inode);
} else
- nfs_refresh_inode(inode, fattr);
+ nfs_refresh_inode(inode, fattr, label);
dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
inode->i_sb->s_id,
(long long)NFS_FILEID(inode),
@@ -478,7 +478,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
NFS_PROTO(inode)->return_delegation(inode);
error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
if (error == 0)
- nfs_refresh_inode(inode, fattr);
+ nfs_refresh_inode(inode, fattr, NULL);
nfs_free_fattr(fattr);
out:
return error;
@@ -817,6 +817,7 @@ int
__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
int status = -ESTALE;
+ struct nfs4_label *label = NULL;
struct nfs_fattr *fattr = NULL;
struct nfs_inode *nfsi = NFS_I(inode);

@@ -834,7 +835,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
goto out;

nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
- status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr);
+ status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
if (status != 0) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
inode->i_sb->s_id,
@@ -847,7 +848,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
goto out;
}

- status = nfs_refresh_inode(inode, fattr);
+ status = nfs_refresh_inode(inode, fattr, label);
if (status) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
inode->i_sb->s_id,
@@ -1200,10 +1201,10 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
}

-static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
{
if (nfs_inode_attrs_need_update(inode, fattr))
- return nfs_update_inode(inode, fattr);
+ return nfs_update_inode(inode, fattr, label);
return nfs_check_inode_attributes(inode, fattr);
}

@@ -1217,21 +1218,21 @@ static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr
* safe to do a full update of the inode attributes, or whether just to
* call nfs_check_inode_attributes.
*/
-int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
{
int status;

if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0;
spin_lock(&inode->i_lock);
- status = nfs_refresh_inode_locked(inode, fattr);
+ status = nfs_refresh_inode_locked(inode, fattr, label);
spin_unlock(&inode->i_lock);

return status;
}
EXPORT_SYMBOL_GPL(nfs_refresh_inode);

-static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs_inode *nfsi = NFS_I(inode);

@@ -1240,7 +1241,7 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0;
- return nfs_refresh_inode_locked(inode, fattr);
+ return nfs_refresh_inode_locked(inode, fattr, label);
}

/**
@@ -1257,12 +1258,12 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
* are expected to change one or more attributes, to avoid
* unnecessary NFS requests and trips through nfs_update_inode().
*/
-int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
{
int status;

spin_lock(&inode->i_lock);
- status = nfs_post_op_update_inode_locked(inode, fattr);
+ status = nfs_post_op_update_inode_locked(inode, fattr, label);
spin_unlock(&inode->i_lock);
return status;
}
@@ -1314,7 +1315,7 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
}
out_noforce:
- status = nfs_post_op_update_inode_locked(inode, fattr);
+ status = nfs_post_op_update_inode_locked(inode, fattr, NULL);
spin_unlock(&inode->i_lock);
return status;
}
@@ -1332,7 +1333,7 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);
*
* A very similar scenario holds for the dir cache.
*/
-static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs_server *server;
struct nfs_inode *nfsi = NFS_I(inode);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 6559253..25747d2 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -251,7 +251,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
struct dentry *parent = dget_parent(dentry);

/* Look it up again to get its attributes */
- err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr);
+ err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL);
dput(parent);
if (err != 0)
return ERR_PTR(err);
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 4a1aafb..1a2f11b 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -240,7 +240,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)

switch (status) {
case 0:
- status = nfs_refresh_inode(inode, res.fattr);
+ status = nfs_refresh_inode(inode, res.fattr, NULL);
break;
case -EPFNOSUPPORT:
case -EPROTONOSUPPORT:
@@ -352,7 +352,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,

switch (status) {
case 0:
- status = nfs_refresh_inode(inode, fattr);
+ status = nfs_refresh_inode(inode, fattr, NULL);
nfs3_cache_acls(inode, acl, dfacl);
break;
case -EPFNOSUPPORT:
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 6932209..c2aaca7 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
*/
static int
nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+ struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR],
@@ -143,7 +143,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,

static int
nfs3_proc_lookup(struct inode *dir, struct qstr *name,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+ struct nfs4_label *label)
{
struct nfs3_diropargs arg = {
.fh = NFS_FH(dir),
@@ -168,7 +169,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,

nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_refresh_inode(dir, res.dir_attr);
+ nfs_refresh_inode(dir, res.dir_attr, NULL);
if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) {
msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
msg.rpc_argp = fhandle;
@@ -216,7 +217,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
goto out;

status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
- nfs_refresh_inode(inode, res.fattr);
+ nfs_refresh_inode(inode, res.fattr, NULL);
if (status == 0) {
entry->mask = 0;
if (res.access & NFS3_ACCESS_READ)
@@ -255,7 +256,7 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page,
msg.rpc_resp = fattr;

status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
- nfs_refresh_inode(inode, fattr);
+ nfs_refresh_inode(inode, fattr, NULL);
nfs_free_fattr(fattr);
out:
dprintk("NFS reply readlink: %d\n", status);
@@ -298,9 +299,9 @@ static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_
int status;

status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
- nfs_post_op_update_inode(dir, data->res.dir_attr);
+ nfs_post_op_update_inode(dir, data->res.dir_attr, NULL);
if (status == 0)
- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
return status;
}

@@ -381,7 +382,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
* not sure this buys us anything (and I'd have
* to revamp the NFSv3 XDR code) */
status = nfs3_proc_setattr(dentry, data->res.fattr, sattr);
- nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
+ nfs_post_op_update_inode(dentry->d_inode, data->res.fattr, NULL);
dprintk("NFS reply setattr (post-create): %d\n", status);
if (status != 0)
goto out;
@@ -414,7 +415,7 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name)
goto out;

status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_post_op_update_inode(dir, res.dir_attr);
+ nfs_post_op_update_inode(dir, res.dir_attr, NULL);
nfs_free_fattr(res.dir_attr);
out:
dprintk("NFS reply remove: %d\n", status);
@@ -439,7 +440,7 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
if (nfs3_async_handle_jukebox(task, dir))
return 0;
res = task->tk_msg.rpc_resp;
- nfs_post_op_update_inode(dir, res->dir_attr);
+ nfs_post_op_update_inode(dir, res->dir_attr, NULL);
return 1;
}

@@ -464,8 +465,8 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
return 0;
res = task->tk_msg.rpc_resp;

- nfs_post_op_update_inode(old_dir, res->old_fattr);
- nfs_post_op_update_inode(new_dir, res->new_fattr);
+ nfs_post_op_update_inode(old_dir, res->old_fattr, NULL);
+ nfs_post_op_update_inode(new_dir, res->new_fattr, NULL);
return 1;
}

@@ -495,8 +496,8 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
goto out;

status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
- nfs_post_op_update_inode(old_dir, res.old_fattr);
- nfs_post_op_update_inode(new_dir, res.new_fattr);
+ nfs_post_op_update_inode(old_dir, res.old_fattr, NULL);
+ nfs_post_op_update_inode(new_dir, res.new_fattr, NULL);
out:
nfs_free_fattr(res.old_fattr);
nfs_free_fattr(res.new_fattr);
@@ -528,8 +529,8 @@ nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
goto out;

status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
- nfs_post_op_update_inode(dir, res.dir_attr);
- nfs_post_op_update_inode(inode, res.fattr);
+ nfs_post_op_update_inode(dir, res.dir_attr, NULL);
+ nfs_post_op_update_inode(inode, res.fattr, NULL);
out:
nfs_free_fattr(res.dir_attr);
nfs_free_fattr(res.fattr);
@@ -622,7 +623,7 @@ nfs3_proc_rmdir(struct inode *dir, struct qstr *name)

msg.rpc_resp = dir_attr;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_post_op_update_inode(dir, dir_attr);
+ nfs_post_op_update_inode(dir, dir_attr, NULL);
nfs_free_fattr(dir_attr);
out:
dprintk("NFS reply rmdir: %d\n", status);
@@ -677,7 +678,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);

nfs_invalidate_atime(dir);
- nfs_refresh_inode(dir, res.dir_attr);
+ nfs_refresh_inode(dir, res.dir_attr, NULL);

nfs_free_fattr(res.dir_attr);
out:
@@ -816,7 +817,7 @@ static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
return -EAGAIN;

nfs_invalidate_atime(inode);
- nfs_refresh_inode(inode, &data->fattr);
+ nfs_refresh_inode(inode, &data->fattr, NULL);
return 0;
}

@@ -860,7 +861,7 @@ static int nfs3_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
{
if (nfs3_async_handle_jukebox(task, data->inode))
return -EAGAIN;
- nfs_refresh_inode(data->inode, data->res.fattr);
+ nfs_refresh_inode(data->inode, data->res.fattr, NULL);
return 0;
}

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index f15015a..c97c6837 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -230,7 +230,7 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *,
struct nfs4_fs_locations *, struct page *);
extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *,
- struct nfs_fh *, struct nfs_fattr *);
+ struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *);
extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
extern int nfs4_release_lockowner(struct nfs4_lock_state *);
extern const struct xattr_handler *nfs4_xattr_handlers[];
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 79fbb61..f40cf63 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -367,7 +367,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
struct vfsmount *mnt;

/* Look it up again to get its attributes and sec flavor */
- client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr);
+ client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr, NULL);
dput(parent);
if (IS_ERR(client))
return ERR_CAST(client);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 3c49f3e..8e0378c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -78,11 +78,12 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
-static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *);
-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
+static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
- struct nfs4_state *state);
+ struct nfs4_state *state, struct nfs4_label *ilabel,
+ struct nfs4_label *olabel);
#ifdef CONFIG_NFS_V4_1
static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *);
static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);
@@ -826,6 +827,7 @@ struct nfs4_opendata {
struct nfs4_string owner_name;
struct nfs4_string group_name;
struct nfs_fattr f_attr;
+ struct nfs4_label *f_label;
struct dentry *dir;
struct dentry *dentry;
struct nfs4_state_owner *owner;
@@ -841,6 +843,7 @@ struct nfs4_opendata {
static void nfs4_init_opendata_res(struct nfs4_opendata *p)
{
p->o_res.f_attr = &p->f_attr;
+ p->o_res.f_label = p->f_label;
p->o_res.seqid = p->o_arg.seqid;
p->c_res.seqid = p->c_arg.seqid;
p->o_res.server = p->o_arg.server;
@@ -851,7 +854,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)

static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
struct nfs4_state_owner *sp, fmode_t fmode, int flags,
- const struct iattr *attrs,
+ const struct iattr *attrs, struct nfs4_label *label,
gfp_t gfp_mask)
{
struct dentry *parent = dget_parent(dentry);
@@ -889,6 +892,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.bitmask = server->attr_bitmask;
p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
+ p->o_arg.label = label;
if (attrs != NULL && attrs->ia_valid != 0) {
__be32 verf[2];

@@ -1190,7 +1194,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
if (state == NULL)
goto err;

- ret = nfs_refresh_inode(inode, &data->f_attr);
+ ret = nfs_refresh_inode(inode, &data->f_attr, data->f_label);
if (ret)
goto err;

@@ -1220,7 +1224,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
ret = -EAGAIN;
if (!(data->f_attr.valid & NFS_ATTR_FATTR))
goto err;
- inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
+ inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr, data->f_label);
ret = PTR_ERR(inode);
if (IS_ERR(inode))
goto err;
@@ -1270,7 +1274,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
{
struct nfs4_opendata *opendata;

- opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS);
+ opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, NULL, GFP_NOFS);
if (opendata == NULL)
return ERR_PTR(-ENOMEM);
opendata->state = state;
@@ -1788,7 +1792,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
return status;
}
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
- _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);
+ _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label);
return 0;
}

@@ -1965,6 +1969,7 @@ static int _nfs4_do_open(struct inode *dir,
fmode_t fmode,
int flags,
struct iattr *sattr,
+ struct nfs4_label *label,
struct rpc_cred *cred,
struct nfs4_state **res,
struct nfs4_threshold **ctx_th)
@@ -1973,6 +1978,7 @@ static int _nfs4_do_open(struct inode *dir,
struct nfs4_state *state = NULL;
struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_opendata *opendata;
+ struct nfs4_label *olabel = NULL;
int status;

/* Protect against reboot recovery conflicts */
@@ -1988,7 +1994,7 @@ static int _nfs4_do_open(struct inode *dir,
if (dentry->d_inode != NULL)
nfs4_return_incompatible_delegation(dentry->d_inode, fmode);
status = -ENOMEM;
- opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL);
+ opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, label, GFP_KERNEL);
if (opendata == NULL)
goto err_put_state_owner;

@@ -2022,10 +2028,11 @@ static int _nfs4_do_open(struct inode *dir,
nfs_fattr_init(opendata->o_res.f_attr);
status = nfs4_do_setattr(state->inode, cred,
opendata->o_res.f_attr, sattr,
- state);
- if (status == 0)
+ state, label, olabel);
+ if (status == 0) {
nfs_setattr_update_inode(state->inode, sattr);
- nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
+ nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
+ }
}

if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
@@ -2054,6 +2061,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
fmode_t fmode,
int flags,
struct iattr *sattr,
+ struct nfs4_label *label,
struct rpc_cred *cred,
struct nfs4_threshold **ctx_th)
{
@@ -2063,7 +2071,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,

fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC;
do {
- status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred,
+ status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, label, cred,
&res, ctx_th);
if (status == 0)
break;
@@ -2108,7 +2116,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,

static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
- struct nfs4_state *state)
+ struct nfs4_state *state, struct nfs4_label *ilabel,
+ struct nfs4_label *olabel)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_setattrargs arg = {
@@ -2116,9 +2125,11 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
.iap = sattr,
.server = server,
.bitmask = server->attr_bitmask,
+ .label = ilabel,
};
struct nfs_setattrres res = {
.fattr = fattr,
+ .label = olabel,
.server = server,
};
struct rpc_message msg = {
@@ -2153,7 +2164,8 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,

static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
- struct nfs4_state *state)
+ struct nfs4_state *state, struct nfs4_label *ilabel,
+ struct nfs4_label *olabel)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_exception exception = {
@@ -2162,7 +2174,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
};
int err;
do {
- err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
+ err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
switch (err) {
case -NFS4ERR_OPENMODE:
if (state && !(state->state & FMODE_WRITE)) {
@@ -2249,7 +2261,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
rpc_restart_call_prepare(task);
}
nfs_release_seqid(calldata->arg.seqid);
- nfs_refresh_inode(calldata->inode, calldata->res.fattr);
+ nfs_refresh_inode(calldata->inode, calldata->res.fattr, NULL);
dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
}

@@ -2386,9 +2398,10 @@ static struct inode *
nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
{
struct nfs4_state *state;
+ struct nfs4_label l, *label = NULL;

/* Protect against concurrent sillydeletes */
- state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr,
+ state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, label,
ctx->cred, &ctx->mdsthreshold);
if (IS_ERR(state))
return ERR_CAST(state);
@@ -2586,6 +2599,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
{
int error;
struct nfs_fattr *fattr = info->fattr;
+ struct nfs4_label *label = NULL;

error = nfs4_server_capabilities(server, mntfh);
if (error < 0) {
@@ -2593,7 +2607,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
return error;
}

- error = nfs4_proc_getattr(server, mntfh, fattr);
+ error = nfs4_proc_getattr(server, mntfh, fattr, label);
if (error < 0) {
dprintk("nfs4_get_root: getattr error = %d\n", -error);
return error;
@@ -2649,7 +2663,8 @@ out:
return status;
}

-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs4_getattr_arg args = {
.fh = fhandle,
@@ -2657,6 +2672,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
};
struct nfs4_getattr_res res = {
.fattr = fattr,
+ .label = label,
.server = server,
};
struct rpc_message msg = {
@@ -2669,13 +2685,14 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
}

-static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
- _nfs4_proc_getattr(server, fhandle, fattr),
+ _nfs4_proc_getattr(server, fhandle, fattr, label),
&exception);
} while (exception.retry);
return err;
@@ -2705,6 +2722,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
struct inode *inode = dentry->d_inode;
struct rpc_cred *cred = NULL;
struct nfs4_state *state = NULL;
+ struct nfs4_label *olabel = NULL;
int status;

if (pnfs_ld_layoutret_on_setattr(inode))
@@ -2731,7 +2749,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
}
}

- status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
+ status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, NULL);
if (status == 0)
nfs_setattr_update_inode(inode, sattr);
return status;
@@ -2739,7 +2757,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,

static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
const struct qstr *name, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+ struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs_server *server = NFS_SERVER(dir);
int status;
@@ -2777,13 +2795,13 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)

static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
struct qstr *name, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+ struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs4_exception exception = { };
struct rpc_clnt *client = *clnt;
int err;
do {
- err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr);
+ err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
switch (err) {
case -NFS4ERR_BADNAME:
err = -ENOENT;
@@ -2817,12 +2835,13 @@ out:
}

static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+ struct nfs4_label *label)
{
int status;
struct rpc_clnt *client = NFS_CLIENT(dir);

- status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
+ status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
if (client != NFS_CLIENT(dir)) {
rpc_shutdown_client(client);
nfs_fixup_secinfo_attributes(fattr);
@@ -2832,12 +2851,13 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,

struct rpc_clnt *
nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+ struct nfs4_label *label)
{
int status;
struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));

- status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
+ status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
if (status < 0) {
rpc_shutdown_client(client);
return ERR_PTR(status);
@@ -2854,6 +2874,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
};
struct nfs4_accessres res = {
.server = server,
+ .label = NULL,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
@@ -2888,7 +2909,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
if (!status) {
nfs_access_set_mask(entry, res.access);
- nfs_refresh_inode(inode, res.fattr);
+ nfs_refresh_inode(inode, res.fattr, res.label);
}
nfs_free_fattr(res.fattr);
return status;
@@ -2967,6 +2988,7 @@ static int
nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
int flags)
{
+ struct nfs4_label l, *ilabel = NULL;
struct nfs_open_context *ctx;
struct nfs4_state *state;
int status = 0;
@@ -2977,7 +2999,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,

sattr->ia_mode &= ~current_umask();
state = nfs4_do_open(dir, dentry, ctx->mode,
- flags, sattr, ctx->cred,
+ flags, sattr, ilabel, ctx->cred,
&ctx->mdsthreshold);
d_drop(dentry);
if (IS_ERR(state)) {
@@ -3105,6 +3127,8 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
.new_dir = NFS_FH(new_dir),
.old_name = old_name,
.new_name = new_name,
+ .old_label = NULL,
+ .new_label = NULL,
};
struct nfs_renameres res = {
.server = server,
@@ -3149,6 +3173,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
};
struct nfs4_link_res res = {
.server = server,
+ .label = NULL,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
@@ -3164,7 +3189,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
if (!status) {
update_changeattr(dir, &res.cinfo);
- nfs_post_op_update_inode(inode, res.fattr);
+ nfs_post_op_update_inode(inode, res.fattr, res.label);
}
out:
nfs_free_fattr(res.fattr);
@@ -3189,6 +3214,7 @@ struct nfs4_createdata {
struct nfs4_create_res res;
struct nfs_fh fh;
struct nfs_fattr fattr;
+ struct nfs4_label *label;
};

static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
@@ -3212,6 +3238,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
data->res.server = server;
data->res.fh = &data->fh;
data->res.fattr = &data->fattr;
+ data->res.label = data->label;
nfs_fattr_init(data->res.fattr);
}
return data;
@@ -3223,7 +3250,7 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
&data->arg.seq_args, &data->res.seq_res, 1);
if (status == 0) {
update_changeattr(dir, &data->res.dir_cinfo);
- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
}
return status;
}
@@ -3234,7 +3261,8 @@ static void nfs4_free_createdata(struct nfs4_createdata *data)
}

static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
- struct page *page, unsigned int len, struct iattr *sattr)
+ struct page *page, unsigned int len, struct iattr *sattr,
+ struct nfs4_label *label)
{
struct nfs4_createdata *data;
int status = -ENAMETOOLONG;
@@ -3250,6 +3278,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
data->arg.u.symlink.pages = &page;
data->arg.u.symlink.len = len;
+ data->arg.label = label;

status = nfs4_do_create(dir, dentry, data);

@@ -3262,18 +3291,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct page *page, unsigned int len, struct iattr *sattr)
{
struct nfs4_exception exception = { };
+ struct nfs4_label l, *label = NULL;
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_symlink(dir, dentry, page,
- len, sattr),
+ len, sattr, label),
&exception);
} while (exception.retry);
return err;
}

static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
- struct iattr *sattr)
+ struct iattr *sattr, struct nfs4_label *label)
{
struct nfs4_createdata *data;
int status = -ENOMEM;
@@ -3282,6 +3312,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
if (data == NULL)
goto out;

+ data->arg.label = label;
status = nfs4_do_create(dir, dentry, data);

nfs4_free_createdata(data);
@@ -3293,12 +3324,13 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct iattr *sattr)
{
struct nfs4_exception exception = { };
+ struct nfs4_label l, *label = NULL;
int err;

sattr->ia_mode &= ~current_umask();
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
- _nfs4_proc_mkdir(dir, dentry, sattr),
+ _nfs4_proc_mkdir(dir, dentry, sattr, label),
&exception);
} while (exception.retry);
return err;
@@ -3358,7 +3390,7 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
}

static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
- struct iattr *sattr, dev_t rdev)
+ struct iattr *sattr, struct nfs4_label *label, dev_t rdev)
{
struct nfs4_createdata *data;
int mode = sattr->ia_mode;
@@ -3383,7 +3415,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
data->arg.u.device.specdata1 = MAJOR(rdev);
data->arg.u.device.specdata2 = MINOR(rdev);
}
-
+
+ data->arg.label = label;
status = nfs4_do_create(dir, dentry, data);

nfs4_free_createdata(data);
@@ -3395,12 +3428,13 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, dev_t rdev)
{
struct nfs4_exception exception = { };
+ struct nfs4_label l, *label = NULL;
int err;

sattr->ia_mode &= ~current_umask();
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
- _nfs4_proc_mknod(dir, dentry, sattr, rdev),
+ _nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
&exception);
} while (exception.retry);
return err;
@@ -4358,7 +4392,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
if (status == 0)
nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
else
- nfs_refresh_inode(inode, &data->fattr);
+ nfs_refresh_inode(inode, &data->fattr, NULL);
out:
rpc_put_task(task);
return status;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 50a88c3..b4ae668 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -131,7 +131,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
*/
static int
nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+ struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct rpc_message msg = {
.rpc_proc = &nfs_procedures[NFSPROC_GETATTR],
@@ -179,7 +179,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,

static int
nfs_proc_lookup(struct inode *dir, struct qstr *name,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr,
+ struct nfs4_label *label)
{
struct nfs_diropargs arg = {
.fh = NFS_FH(dir),
@@ -276,7 +277,7 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir);
if (status == 0)
- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
nfs_free_createdata(data);
out:
dprintk("NFS reply create: %d\n", status);
@@ -323,7 +324,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
}
if (status == 0)
- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
nfs_free_createdata(data);
out:
dprintk("NFS reply mknod: %d\n", status);
@@ -479,7 +480,7 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
* should fill in the data with a LOOKUP call on the wire.
*/
if (status == 0)
- status = nfs_instantiate(dentry, fh, fattr);
+ status = nfs_instantiate(dentry, fh, fattr, NULL);

out_free:
nfs_free_fattr(fattr);
@@ -508,7 +509,7 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir);
if (status == 0)
- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
nfs_free_createdata(data);
out:
dprintk("NFS reply mkdir: %d\n", status);
@@ -647,7 +648,7 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)

nfs_invalidate_atime(inode);
if (task->tk_status >= 0) {
- nfs_refresh_inode(inode, data->res.fattr);
+ nfs_refresh_inode(inode, data->res.fattr, data->res.label);
/* Emulate the eof flag, which isn't normally needed in NFSv2
* as it is guaranteed to always return the file attributes
*/
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 37a862c..c8ace0d 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -328,9 +328,9 @@ extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
extern void nfs_zap_caches(struct inode *);
extern void nfs_invalidate_atime(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
- struct nfs_fattr *);
-extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
-extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
+ struct nfs_fattr *, struct nfs4_label *);
+extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *, struct nfs4_label *);
+extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *);
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
@@ -460,7 +460,8 @@ extern const struct file_operations nfs_dir_operations;
extern const struct dentry_operations nfs_dentry_operations;

extern void nfs_force_lookup_revalidate(struct inode *dir);
-extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
+extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
+ struct nfs_fattr *fattr, struct nfs4_label *label);
extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
extern void nfs_access_zap_cache(struct inode *inode);

diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 7e9347a..31268c0 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1402,11 +1402,12 @@ struct nfs_rpc_ops {
struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *,
struct nfs_subversion *);
int (*getattr) (struct nfs_server *, struct nfs_fh *,
- struct nfs_fattr *);
+ struct nfs_fattr *, struct nfs4_label *);
int (*setattr) (struct dentry *, struct nfs_fattr *,
struct iattr *);
int (*lookup) (struct inode *, struct qstr *,
- struct nfs_fh *, struct nfs_fattr *);
+ struct nfs_fh *, struct nfs_fattr *,
+ struct nfs4_label *);
int (*access) (struct inode *, struct nfs_access_entry *);
int (*readlink)(struct inode *, struct page *, unsigned int,
unsigned int);
--
1.7.11.7

2012-11-12 06:15:38

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 04/13] SELinux: Add new labeling type native labels

From: David Quigley <[email protected]>

There currently doesn't exist a labeling type that is adequate for use with
labeled NFS. Since NFS doesn't really support xattrs we can't use the use xattr
labeling behavior. For this we developed a new labeling type. The native
labeling type is used solely by NFS to ensure NFS inodes are labeled at runtime
by the NFS code instead of relying on the SELinux security server on the client
end.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
include/linux/security.h | 3 +++
security/selinux/hooks.c | 35 ++++++++++++++++++++++++++---------
security/selinux/include/security.h | 2 ++
security/selinux/ss/policydb.c | 5 ++++-
4 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index c94bcf5..afddfec 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -61,6 +61,9 @@ struct mm_struct;
#define SECURITY_CAP_NOAUDIT 0
#define SECURITY_CAP_AUDIT 1

+/* LSM Agnostic defines for sb_set_mnt_opts */
+#define SECURITY_LSM_NATIVE_LABELS 1
+
struct ctl_table;
struct audit_krule;
struct user_namespace;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4e7e7c2..8f233ff 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -80,6 +80,7 @@
#include <linux/syslog.h>
#include <linux/user_namespace.h>
#include <linux/export.h>
+#include <linux/security.h>
#include <linux/msg.h>
#include <linux/shm.h>

@@ -283,13 +284,14 @@ static void superblock_free_security(struct super_block *sb)

/* The file system's label must be initialized prior to use. */

-static const char *labeling_behaviors[6] = {
+static const char *labeling_behaviors[7] = {
"uses xattr",
"uses transition SIDs",
"uses task SIDs",
"uses genfs_contexts",
"not configured for labeling",
"uses mountpoint labeling",
+ "uses native labeling",
};

static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
@@ -677,14 +679,21 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (strcmp(sb->s_type->name, "proc") == 0)
sbsec->flags |= SE_SBPROC;

- /* Determine the labeling behavior to use for this filesystem type. */
- rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
- if (rc) {
- printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
- __func__, sb->s_type->name, rc);
- goto out;
+ if (!sbsec->behavior) {
+ /*
+ * Determine the labeling behavior to use for this
+ * filesystem type.
+ */
+ rc = security_fs_use((sbsec->flags & SE_SBPROC) ?
+ "proc" : sb->s_type->name,
+ &sbsec->behavior, &sbsec->sid);
+ if (rc) {
+ printk(KERN_WARNING
+ "%s: security_fs_use(%s) returned %d\n",
+ __func__, sb->s_type->name, rc);
+ goto out;
+ }
}
-
/* sets the context of the superblock for the fs being mounted. */
if (fscontext_sid) {
rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
@@ -699,6 +708,11 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* sets the label used on all file below the mountpoint, and will set
* the superblock context if not already set.
*/
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
+ sbsec->behavior = SECURITY_FS_USE_NATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ }
+
if (context_sid) {
if (!fscontext_sid) {
rc = may_context_mount_sb_relabel(context_sid, sbsec,
@@ -730,7 +744,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}

if (defcontext_sid) {
- if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
+ if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
+ sbsec->behavior != SECURITY_FS_USE_NATIVE) {
rc = -EINVAL;
printk(KERN_WARNING "SELinux: defcontext option is "
"invalid for this filesystem type\n");
@@ -1198,6 +1213,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
}

switch (sbsec->behavior) {
+ case SECURITY_FS_USE_NATIVE:
+ break;
case SECURITY_FS_USE_XATTR:
if (!inode->i_op->getxattr) {
isec->sid = sbsec->def_sid;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 6d38851..8fd8e18 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -169,6 +169,8 @@ int security_get_allow_unknown(void);
#define SECURITY_FS_USE_GENFS 4 /* use the genfs support */
#define SECURITY_FS_USE_NONE 5 /* no labeling support */
#define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */
+#define SECURITY_FS_USE_NATIVE 7 /* use native label support */
+#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */

int security_fs_use(const char *fstype, unsigned int *behavior,
u32 *sid);
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 9cd9b7c..c8adde3 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,

rc = -EINVAL;
c->v.behavior = le32_to_cpu(buf[0]);
- if (c->v.behavior > SECURITY_FS_USE_NONE)
+ /* Determined at runtime, not in policy DB. */
+ if (c->v.behavior == SECURITY_FS_USE_MNTPOINT)
+ goto out;
+ if (c->v.behavior > SECURITY_FS_USE_MAX)
goto out;

rc = -ENOMEM;
--
1.7.11.7

2012-11-12 06:15:40

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 06/13] NFSv4: Add label recommended attribute and NFSv4 flags

From: David Quigley <[email protected]>

This patch adds several new flags to allow the NFS client and server to
determine if this attribute is supported and if it is being sent over the wire.

Signed-off-by: Matthew N. Dodd <[email protected]>
Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfsd/nfsd.h | 8 ++++----
include/linux/nfs4.h | 1 +
include/linux/nfs_fs_sb.h | 1 +
include/linux/nfs_xdr.h | 5 ++++-
include/uapi/linux/nfs4.h | 1 +
include/uapi/linux/nfsd/export.h | 5 +++--
6 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 80d5ce4..3a87cbb 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -322,10 +322,10 @@ extern time_t nfsd4_grace;
| FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \
| FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \
| FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \
- | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \
- | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
+ | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY \
+ | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)

-#define NFSD4_SUPPORTED_ATTRS_WORD2 0
+#define NFSD4_SUPPORTED_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL

#define NFSD4_1_SUPPORTED_ATTRS_WORD0 \
NFSD4_SUPPORTED_ATTRS_WORD0
@@ -364,7 +364,7 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
#define NFSD_WRITEABLE_ATTRS_WORD1 \
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
-#define NFSD_WRITEABLE_ATTRS_WORD2 0
+#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL

#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
NFSD_WRITEABLE_ATTRS_WORD0
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index e111fa4..f9235b4 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -373,6 +373,7 @@ enum lock_type4 {
#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
+#define FATTR4_WORD2_SECURITY_LABEL (1UL << 17)
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)

/* MDS threshold bitmap bits */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index a9e76ee..a794715 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -197,6 +197,7 @@ struct nfs_server {
#define NFS_CAP_MTIME (1U << 13)
#define NFS_CAP_POSIX_LOCK (1U << 14)
#define NFS_CAP_UIDGID_NOMAP (1U << 15)
+#define NFS_CAP_SECURITY_LABEL (1U << 16)


/* maximum number of slots to use */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index a73ea89..a0669d3 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -104,6 +104,7 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
#define NFS_ATTR_FATTR_OWNER_NAME (1U << 23)
#define NFS_ATTR_FATTR_GROUP_NAME (1U << 24)
+#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25)

#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
| NFS_ATTR_FATTR_MODE \
@@ -123,7 +124,8 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
| NFS_ATTR_FATTR_SPACE_USED)
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
- | NFS_ATTR_FATTR_SPACE_USED)
+ | NFS_ATTR_FATTR_SPACE_USED \
+ | NFS_ATTR_FATTR_V4_SECURITY_LABEL)

/*
* Info on the file system
@@ -600,6 +602,7 @@ struct nfs_entry {
int eof;
struct nfs_fh * fh;
struct nfs_fattr * fattr;
+ struct nfs4_label *label;
unsigned char d_type;
struct nfs_server * server;
};
diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h
index 788128e..dcc8582 100644
--- a/include/uapi/linux/nfs4.h
+++ b/include/uapi/linux/nfs4.h
@@ -25,6 +25,7 @@
#define NFS4_MAXNAMLEN NAME_MAX
#define NFS4_OPAQUE_LIMIT 1024
#define NFS4_MAX_SESSIONID_LEN 16
+#define NFS4_MAXLABELLEN 4096

#define NFS4_ACCESS_READ 0x0001
#define NFS4_ACCESS_LOOKUP 0x0002
diff --git a/include/uapi/linux/nfsd/export.h b/include/uapi/linux/nfsd/export.h
index cf47c31..e6c76d9 100644
--- a/include/uapi/linux/nfsd/export.h
+++ b/include/uapi/linux/nfsd/export.h
@@ -28,7 +28,8 @@
#define NFSEXP_ALLSQUASH 0x0008
#define NFSEXP_ASYNC 0x0010
#define NFSEXP_GATHERED_WRITES 0x0020
-/* 40 80 100 currently unused */
+#define NFSEXP_SECURITY_LABEL 0x0040 /* Support security label fattr4 */
+/* 80 100 currently unused */
#define NFSEXP_NOHIDE 0x0200
#define NFSEXP_NOSUBTREECHECK 0x0400
#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */
@@ -47,7 +48,7 @@
*/
#define NFSEXP_V4ROOT 0x10000
/* All flags that we claim to support. (Note we don't support NOACL.) */
-#define NFSEXP_ALLFLAGS 0x17E3F
+#define NFSEXP_ALLFLAGS 0x17E7F

/* The flags that may vary depending on security flavor: */
#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
--
1.7.11.7

2012-11-12 06:15:42

by Dave Quigley

[permalink] [raw]
Subject: [PATCH 08/13] NFSv4: Extend fattr bitmaps to support all 3 words

From: David Quigley <[email protected]>

The fattr handling bitmap code only uses the first two fattr words sofar. This
patch adds the 3rd word to being sent but doesn't populate it yet.

Signed-off-by: Miguel Rodel Felipe <[email protected]>
Signed-off-by: Phua Eu Gene <[email protected]>
Signed-off-by: Khin Mi Mi Aung <[email protected]>
Signed-off-by: David Quigley <[email protected]>
---
fs/nfs/nfs4_fs.h | 6 +++---
fs/nfs/nfs4proc.c | 20 +++++++++++++-------
fs/nfs/nfs4xdr.c | 20 ++++++++++++--------
fs/nfs/super.c | 1 +
include/linux/nfs_fs_sb.h | 2 +-
5 files changed, 30 insertions(+), 19 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index a525fde..f15015a 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -304,10 +304,10 @@ is_ds_client(struct nfs_client *clp)
extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];

extern const u32 nfs4_fattr_bitmap[3];
-extern const u32 nfs4_statfs_bitmap[2];
-extern const u32 nfs4_pathconf_bitmap[2];
+extern const u32 nfs4_statfs_bitmap[3];
+extern const u32 nfs4_pathconf_bitmap[3];
extern const u32 nfs4_fsinfo_bitmap[3];
-extern const u32 nfs4_fs_locations_bitmap[2];
+extern const u32 nfs4_fs_locations_bitmap[3];

void nfs4_free_client(struct nfs_client *);

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 68b21d8..3c49f3e 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -131,7 +131,8 @@ const u32 nfs4_fattr_bitmap[3] = {
| FATTR4_WORD1_SPACE_USED
| FATTR4_WORD1_TIME_ACCESS
| FATTR4_WORD1_TIME_METADATA
- | FATTR4_WORD1_TIME_MODIFY
+ | FATTR4_WORD1_TIME_MODIFY,
+ 0
};

static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -158,18 +159,20 @@ static const u32 nfs4_open_noattr_bitmap[3] = {
| FATTR4_WORD0_FILEID,
};

-const u32 nfs4_statfs_bitmap[2] = {
+const u32 nfs4_statfs_bitmap[3] = {
FATTR4_WORD0_FILES_AVAIL
| FATTR4_WORD0_FILES_FREE
| FATTR4_WORD0_FILES_TOTAL,
FATTR4_WORD1_SPACE_AVAIL
| FATTR4_WORD1_SPACE_FREE
- | FATTR4_WORD1_SPACE_TOTAL
+ | FATTR4_WORD1_SPACE_TOTAL,
+ 0
};

-const u32 nfs4_pathconf_bitmap[2] = {
+const u32 nfs4_pathconf_bitmap[3] = {
FATTR4_WORD0_MAXLINK
| FATTR4_WORD0_MAXNAME,
+ 0,
0
};

@@ -182,7 +185,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
FATTR4_WORD2_LAYOUT_BLKSIZE
};

-const u32 nfs4_fs_locations_bitmap[2] = {
+const u32 nfs4_fs_locations_bitmap[3] = {
FATTR4_WORD0_TYPE
| FATTR4_WORD0_CHANGE
| FATTR4_WORD0_SIZE
@@ -198,7 +201,8 @@ const u32 nfs4_fs_locations_bitmap[2] = {
| FATTR4_WORD1_TIME_ACCESS
| FATTR4_WORD1_TIME_METADATA
| FATTR4_WORD1_TIME_MODIFY
- | FATTR4_WORD1_MOUNTED_ON_FILEID
+ | FATTR4_WORD1_MOUNTED_ON_FILEID,
+ 0
};

static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
@@ -5211,8 +5215,10 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
struct page *page)
{
struct nfs_server *server = NFS_SERVER(dir);
- u32 bitmask[2] = {
+ u32 bitmask[3] = {
[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
+ [1] = 0,
+ [2] = 0
};
struct nfs4_fs_locations_arg args = {
.dir_fh = NFS_FH(dir),
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 40836ee..146d4d3 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -980,15 +980,16 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
int len;
uint32_t bmval0 = 0;
uint32_t bmval1 = 0;
+ uint32_t bmval2 = 0;

/*
* We reserve enough space to write the entire attribute buffer at once.
* In the worst-case, this would be
- * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
- * = 36 bytes, plus any contribution from variable-length fields
+ * 16(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
+ * = 40 bytes, plus any contribution from variable-length fields
* such as owner/group.
*/
- len = 16;
+ len = 20;

/* Sigh */
if (iap->ia_valid & ATTR_SIZE)
@@ -1032,9 +1033,9 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
* We write the bitmap length now, but leave the bitmap and the attribute
* buffer length to be backfilled at the end of this routine.
*/
- *p++ = cpu_to_be32(2);
+ *p++ = cpu_to_be32(3);
q = p;
- p += 3;
+ p += 4;

if (iap->ia_valid & ATTR_SIZE) {
bmval0 |= FATTR4_WORD0_SIZE;
@@ -1083,9 +1084,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
len, ((char *)p - (char *)q) + 4);
BUG();
}
- len = (char *)p - (char *)q - 12;
+ len = (char *)p - (char *)q - 16;
*q++ = htonl(bmval0);
*q++ = htonl(bmval1);
+ *q++ = htonl(bmval2);
*q = htonl(len);

/* out: */
@@ -1191,8 +1193,10 @@ encode_getattr_three(struct xdr_stream *xdr,

static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
{
- encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
- bitmask[1] & nfs4_fattr_bitmap[1], hdr);
+ encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
+ bitmask[1] & nfs4_fattr_bitmap[1],
+ bitmask[2] & nfs4_fattr_bitmap[2],
+ hdr);
}

static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ee07a08..f4e13c3 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -826,6 +826,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
seq_printf(m, "\n\tnfsv4:\t");
seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
+ seq_printf(m, ",bm2=0x%x", nfss->attr_bitmask[2]);
seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
show_sessions(m, nfss);
show_pnfs(m, nfss);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index a794715..383fe9c 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -145,7 +145,7 @@ struct nfs_server {
u32 attr_bitmask[3];/* V4 bitmask representing the set
of attributes supported on this
filesystem */
- u32 cache_consistency_bitmask[2];
+ u32 cache_consistency_bitmask[3];
/* V4 bitmask representing the subset
of change attribute, size, ctime
and mtime attributes supported by
--
1.7.11.7

2012-12-03 18:27:30

by Casey Schaufler

[permalink] [raw]
Subject: Re: Labeled NFS [v5]

On 11/30/2012 6:02 AM, David Quigley wrote:
> On 11/30/2012 08:50, Stephen Smalley wrote:
>> On 11/30/2012 08:35 AM, David Quigley wrote:
>>> On 11/30/2012 08:28, Stephen Smalley wrote:
>>>> On 11/30/2012 08:17 AM, David Quigley wrote:
>>>>> On 11/30/2012 07:57, David Quigley wrote:
>>>>>> On 11/30/2012 07:14, J. Bruce Fields wrote:
>>>>>>> On Thu, Nov 29, 2012 at 09:02:49PM -0500, David Quigley wrote:
>>>>>>>> On 11/29/2012 20:50, Casey Schaufler wrote:
>>>>>>>> >On 11/29/2012 4:46 PM, David Quigley wrote:
>>>>>>>> >>On 11/29/2012 19:34, Casey Schaufler wrote:
>>>>>>>> >>>I would think that were it not for the case that access is
>>>>>>>> denied
>>>>>>>> >>>and I get an audit record for nfsd that reports a subject
>>>>>>>> >>>label of "_"
>>>>>>>> >>>(which is correct for nfsd but not the process attempting
>>>>>>>> >>>access) and
>>>>>>>> >>>an object label of "WhooHoo", which is correct. The server side
>>>>>>>> >>>looks like it might be working right, given the information
>>>>>>>> that it
>>>>>>>> >>>has.
>>>>>>>> >>>
>>>>>>>> >>
>>>>>>>> >>Ok so this is the problem. nfsd is a kernel thread I believe. In
>>>>>>>> >>SELinux land it has the type kernel_t which is all powerful. We
>>>>>>>> >>don't
>>>>>>>> >>have client label transport yet (That requires RPCSECGSSv3). Is
>>>>>>>> >>there
>>>>>>>> >>a way you can have that kernel thread running as a type that has
>>>>>>>> >>access to everything?
>>>>>>>> >
>>>>>>>> >That would be having CAP_MAC_ADMIN and CAP_MAC_OVERRIDE in
>>>>>>>> Smackese.
>>>>>>>> >Looking at /proc/<pid-of-nfsd>/status we see CapEff of fff...fff
>>>>>>>> >which
>>>>>>>> >is to say, all capabilities.
>>>>>>>> >
>>>>>>>>
>>>>>>>> Hmm thats interesting then. You could try using rpcdebug -m
>>>>>>>> nfsd to
>>>>>>>> turn on some of the debugging to look around the internals and
>>>>>>>> figure out whats going on. If you pass -v it will give you all of
>>>>>>>> the potential flags.
>>>>>>>>
>>>>>>>> >
>>>>>>>> >>I think that is the current problem. Which makes perfect
>>>>>>>> sense. If
>>>>>>>> >>your kernel threads don't get started with max privilege then
>>>>>>>> the
>>>>>>>> >>server would be denied access on all of the file attributes and
>>>>>>>> >>wouldn't be able to ship it over the wire properly.
>>>>>>>> >
>>>>>>>> >OK. I haven't had to do anything with kernel threads so far.
>>>>>>>> >Where is NFS setting these up? Poking around fs/nfsd looks like
>>>>>>>> >the place, but I haven't seen anything there that makes it look
>>>>>>>> >like they would be running without capabilities. Clearly, that's
>>>>>>>> >what I'm seeing. It looks as if the credential of nfsd does not
>>>>>>>> >match what /proc reports. Bother.
>>>>>>>> >
>>>>>>>>
>>>>>>>> I'm not entirely sure whats up either. If you want to look for the
>>>>>>>> NFSd threads they are in fs/nfsd/nfssvc.c. The main function
>>>>>>>> starts
>>>>>>>> on line 487.
>>>>>>>
>>>>>>> I'm not following the discussion, but: maybe you want to look at
>>>>>>> fs/nfsd/auth.c:nfsd_setuser() ? In particular, the
>>>>>>> cap_{drop/raise}_nfsd_set() calls at the end.
>>>>>>>
>>>>>>> --b.
>>>>>>
>>>>>>
>>>>>> I'm not as familiar with the capabilities code as Casey is so I'll
>>>>>> leave this ball in his court. I think you are correct though and the
>>>>>> problem is that NFSd is dropping and raising caps and we need to
>>>>>> make
>>>>>> sure that MAC_ADMIN and MAC_OVERRIDE is in there in the SMACK case.
>>>>>>
>>>>>> --
>>>>>> This message was distributed to subscribers of the selinux mailing
>>>>>> list.
>>>>>> If you no longer wish to subscribe, send mail to
>>>>>> [email protected] with
>>>>>> the words "unsubscribe selinux" without quotes as the message.
>>>>>
>>>>>
>>>>> I think I found the offending code. I can't test it for a while so
>>>>> hopefully Casey can.
>>>>>
>>>>> In include/linux/capability.h we have the following defines
>>>>>
>>>>>
>>>>> # define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \
>>>>> | CAP_TO_MASK(CAP_MKNOD) \
>>>>> | CAP_TO_MASK(CAP_DAC_OVERRIDE) \
>>>>> | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \
>>>>> | CAP_TO_MASK(CAP_FOWNER) \
>>>>> | CAP_TO_MASK(CAP_FSETID))
>>>>>
>>>>> # define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE))
>>>>>
>>>>> #if _KERNEL_CAPABILITY_U32S != 2
>>>>> # error Fix up hand-coded capability macro initializers
>>>>> #else /* HAND-CODED capability initializers */
>>>>>
>>>>> # define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
>>>>> # define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
>>>>> # define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>>>>> |
>>>>> CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
>>>>> CAP_FS_MASK_B1 } })
>>>>> # define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \
>>>>> |
>>>>> CAP_TO_MASK(CAP_SYS_RESOURCE), \
>>>>> CAP_FS_MASK_B1 } })
>>>>>
>>>>> So raise and drop nfsd caps uses CAP_NFSD_SET. In CAP_NFSD_SET we
>>>>> have
>>>>> CAP_MAC_OVERRIDE but we don't have CAP_MAC_ADMIN. I think maybe if we
>>>>> had both then Casey should be able to use the code with SMACK.
>>>>> However
>>>>> I'm not sure what implications this has for every other LSM. Honestly
>>>>> I'm not sure if we use either of those caps for SELinux at all (I
>>>>> think
>>>>> we ignore them completely).
>>>>
>>>> CAP_MAC_ADMIN is used by SELinux these days, but only to control the
>>>> ability to get or set security contexts that are not yet defined in
>>>> the policy (for package managers that lay down the security contexts
>>>> before reloading policy and for installing a distro within a chroot on
>>>> a build host running a different policy).
>>>
>>>
>>> Do you think its reasonable to add that cap into the NFSd thread then?
>>> I'm not sure what other solution there would be. Casey needs it just so
>>> SMACK can work with it at all (assuming what I think is happening is
>>> actually happening).
>>
>> Looks like Smack requires CAP_MAC_ADMIN in order to set Smack
>> attributes on a file at all. So nfsd would require that capability
>> for Smack. I think this means however that setting Smack labels on
>> NFS files won't work in any case where root is squashed, which seems
>> unfortunate.

Adding CAP_MAC_ADMIN has no effect whatsoever. Further,
the audit record from the nfsd access failure is in
smack_get_inode, which would require CAP_MAC_OVERRIDE.
That capability is already supposed to be in the NFSD set.
Humbum and bother. I am doing additional instrumentation
to see if I can track down where it's going awry.


>
> I'll leave that problem to Casey to figure out. However it seems to me
> that regardless of Labeled NFS Casey should have problems with the NFS
> server not being able to serve up files that are dominated by floor. I
> wonder if he has every tried NFSv4 on a SMACK enabled server before.
> It may have just worked because all files implicitly get labeled floor.
>
>>
>> On the SELinux side, we don't require CAP_MAC_ADMIN to set the
>> SELinux attribute on a file in the normal case, only when the SELinux
>> attribute is not known to the security policy yet. So granting
>> CAP_MAC_ADMIN there means that a client will be able to set security
>> contexts on files that are unknown to the server. I guess that might
>> even be desirable in some instances where client and server policy are
>> different. We do have the option of denying mac_admin permission in
>> policy for nfsd (kernel_t?), in which case we would block such
>> attempts to set unknown contexts but would still support setting of
>> known security contexts.
>>
>> So I think it is workable, albeit a bit confusing.
>
> Yea it is unfortunate that we have to go mucking around in capability
> land but it seems that adding CAP_MAC_ADMIN should be fine and we can
> deal with it in policy if we like.
>
>