diff options
author | David Quigley <dpquigl@davequigley.com> | 2013-05-02 13:19:10 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2013-05-15 09:27:02 -0400 |
commit | 18032ca062e621e15683cb61c066ef3dc5414a7b (patch) | |
tree | 18b061105452a5d47a85c0f693a151227ff3c02c /fs/nfsd | |
parent | 4bdc33ed5bd9fbaa243bda6fdccb22674aed6305 (diff) |
NFSD: Server implementation of MAC Labeling
Implement labeled NFS on the server: encoding and decoding, and writing
and reading, of file labels.
Enabled with CONFIG_NFSD_V4_SECURITY_LABEL.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/Kconfig | 16 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 41 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 108 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 18 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 28 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 2 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 4 |
7 files changed, 207 insertions, 10 deletions
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 430b6872806f..dc8f1ef665ce 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig | |||
@@ -81,6 +81,22 @@ config NFSD_V4 | |||
81 | 81 | ||
82 | If unsure, say N. | 82 | If unsure, say N. |
83 | 83 | ||
84 | config NFSD_V4_SECURITY_LABEL | ||
85 | bool "Provide Security Label support for NFSv4 server" | ||
86 | depends on NFSD_V4 && SECURITY | ||
87 | help | ||
88 | |||
89 | Say Y here if you want enable fine-grained security label attribute | ||
90 | support for NFS version 4. Security labels allow security modules like | ||
91 | SELinux and Smack to label files to facilitate enforcement of their policies. | ||
92 | Without this an NFSv4 mount will have the same label on each file. | ||
93 | |||
94 | If you do not wish to enable fine-grained security labels SELinux or | ||
95 | Smack policies on NFSv4 files, say N. | ||
96 | |||
97 | WARNING: there is still a chance of backwards-incompatible protocol changes. | ||
98 | For now we recommend "Y" only for developers and testers." | ||
99 | |||
84 | config NFSD_FAULT_INJECTION | 100 | config NFSD_FAULT_INJECTION |
85 | bool "NFS server manual fault injection" | 101 | bool "NFS server manual fault injection" |
86 | depends on NFSD_V4 && DEBUG_KERNEL | 102 | depends on NFSD_V4 && DEBUG_KERNEL |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 27d74a294515..1a1ff247bc59 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -42,6 +42,36 @@ | |||
42 | #include "current_stateid.h" | 42 | #include "current_stateid.h" |
43 | #include "netns.h" | 43 | #include "netns.h" |
44 | 44 | ||
45 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
46 | #include <linux/security.h> | ||
47 | |||
48 | static inline void | ||
49 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | ||
50 | { | ||
51 | struct inode *inode = resfh->fh_dentry->d_inode; | ||
52 | int status; | ||
53 | |||
54 | mutex_lock(&inode->i_mutex); | ||
55 | status = security_inode_setsecctx(resfh->fh_dentry, | ||
56 | label->data, label->len); | ||
57 | mutex_unlock(&inode->i_mutex); | ||
58 | |||
59 | if (status) | ||
60 | /* | ||
61 | * XXX: We should really fail the whole open, but we may | ||
62 | * already have created a new file, so it may be too | ||
63 | * late. For now this seems the least of evils: | ||
64 | */ | ||
65 | bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
66 | |||
67 | return; | ||
68 | } | ||
69 | #else | ||
70 | static inline void | ||
71 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | ||
72 | { } | ||
73 | #endif | ||
74 | |||
45 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 75 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
46 | 76 | ||
47 | static u32 nfsd_attrmask[] = { | 77 | static u32 nfsd_attrmask[] = { |
@@ -239,6 +269,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru | |||
239 | (u32 *)open->op_verf.data, | 269 | (u32 *)open->op_verf.data, |
240 | &open->op_truncate, &open->op_created); | 270 | &open->op_truncate, &open->op_created); |
241 | 271 | ||
272 | if (!status && open->op_label.len) | ||
273 | nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval); | ||
274 | |||
242 | /* | 275 | /* |
243 | * Following rfc 3530 14.2.16, use the returned bitmask | 276 | * Following rfc 3530 14.2.16, use the returned bitmask |
244 | * to indicate which attributes we used to store the | 277 | * to indicate which attributes we used to store the |
@@ -637,6 +670,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
637 | if (status) | 670 | if (status) |
638 | goto out; | 671 | goto out; |
639 | 672 | ||
673 | if (create->cr_label.len) | ||
674 | nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); | ||
675 | |||
640 | if (create->cr_acl != NULL) | 676 | if (create->cr_acl != NULL) |
641 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, | 677 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, |
642 | create->cr_bmval); | 678 | create->cr_bmval); |
@@ -916,6 +952,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
916 | setattr->sa_acl); | 952 | setattr->sa_acl); |
917 | if (status) | 953 | if (status) |
918 | goto out; | 954 | goto out; |
955 | if (setattr->sa_label.len) | ||
956 | status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, | ||
957 | &setattr->sa_label); | ||
958 | if (status) | ||
959 | goto out; | ||
919 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, | 960 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, |
920 | 0, (time_t)0); | 961 | 0, (time_t)0); |
921 | out: | 962 | out: |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 9aeacddafa3f..dfca5121de53 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -55,6 +55,11 @@ | |||
55 | #include "cache.h" | 55 | #include "cache.h" |
56 | #include "netns.h" | 56 | #include "netns.h" |
57 | 57 | ||
58 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
59 | #include <linux/security.h> | ||
60 | #endif | ||
61 | |||
62 | |||
58 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 63 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
59 | 64 | ||
60 | /* | 65 | /* |
@@ -242,7 +247,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
242 | 247 | ||
243 | static __be32 | 248 | static __be32 |
244 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | 249 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
245 | struct iattr *iattr, struct nfs4_acl **acl) | 250 | struct iattr *iattr, struct nfs4_acl **acl, |
251 | struct xdr_netobj *label) | ||
246 | { | 252 | { |
247 | int expected_len, len = 0; | 253 | int expected_len, len = 0; |
248 | u32 dummy32; | 254 | u32 dummy32; |
@@ -380,6 +386,32 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
380 | goto xdr_error; | 386 | goto xdr_error; |
381 | } | 387 | } |
382 | } | 388 | } |
389 | |||
390 | label->len = 0; | ||
391 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
392 | if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { | ||
393 | READ_BUF(4); | ||
394 | len += 4; | ||
395 | READ32(dummy32); /* lfs: we don't use it */ | ||
396 | READ_BUF(4); | ||
397 | len += 4; | ||
398 | READ32(dummy32); /* pi: we don't use it either */ | ||
399 | READ_BUF(4); | ||
400 | len += 4; | ||
401 | READ32(dummy32); | ||
402 | READ_BUF(dummy32); | ||
403 | if (dummy32 > NFSD4_MAX_SEC_LABEL_LEN) | ||
404 | return nfserr_badlabel; | ||
405 | len += (XDR_QUADLEN(dummy32) << 2); | ||
406 | READMEM(buf, dummy32); | ||
407 | label->data = kzalloc(dummy32 + 1, GFP_KERNEL); | ||
408 | if (!label->data) | ||
409 | return nfserr_jukebox; | ||
410 | defer_free(argp, kfree, label->data); | ||
411 | memcpy(label->data, buf, dummy32); | ||
412 | } | ||
413 | #endif | ||
414 | |||
383 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 | 415 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
384 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 | 416 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
385 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | 417 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) |
@@ -576,7 +608,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
576 | return status; | 608 | return status; |
577 | 609 | ||
578 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, | 610 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
579 | &create->cr_acl); | 611 | &create->cr_acl, &create->cr_label); |
580 | if (status) | 612 | if (status) |
581 | goto out; | 613 | goto out; |
582 | 614 | ||
@@ -827,7 +859,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
827 | case NFS4_CREATE_UNCHECKED: | 859 | case NFS4_CREATE_UNCHECKED: |
828 | case NFS4_CREATE_GUARDED: | 860 | case NFS4_CREATE_GUARDED: |
829 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 861 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
830 | &open->op_iattr, &open->op_acl); | 862 | &open->op_iattr, &open->op_acl, &open->op_label); |
831 | if (status) | 863 | if (status) |
832 | goto out; | 864 | goto out; |
833 | break; | 865 | break; |
@@ -841,7 +873,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
841 | READ_BUF(NFS4_VERIFIER_SIZE); | 873 | READ_BUF(NFS4_VERIFIER_SIZE); |
842 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); | 874 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); |
843 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 875 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
844 | &open->op_iattr, &open->op_acl); | 876 | &open->op_iattr, &open->op_acl, &open->op_label); |
845 | if (status) | 877 | if (status) |
846 | goto out; | 878 | goto out; |
847 | break; | 879 | break; |
@@ -1063,7 +1095,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
1063 | if (status) | 1095 | if (status) |
1064 | return status; | 1096 | return status; |
1065 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, | 1097 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
1066 | &setattr->sa_acl); | 1098 | &setattr->sa_acl, &setattr->sa_label); |
1067 | } | 1099 | } |
1068 | 1100 | ||
1069 | static __be32 | 1101 | static __be32 |
@@ -1954,6 +1986,36 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace, | |||
1954 | FATTR4_WORD0_RDATTR_ERROR) | 1986 | FATTR4_WORD0_RDATTR_ERROR) |
1955 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID | 1987 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID |
1956 | 1988 | ||
1989 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
1990 | static inline __be32 | ||
1991 | nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen) | ||
1992 | { | ||
1993 | __be32 *p = *pp; | ||
1994 | |||
1995 | if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) | ||
1996 | return nfserr_resource; | ||
1997 | |||
1998 | /* | ||
1999 | * For now we use a 0 here to indicate the null translation; in | ||
2000 | * the future we may place a call to translation code here. | ||
2001 | */ | ||
2002 | if ((*buflen -= 8) < 0) | ||
2003 | return nfserr_resource; | ||
2004 | |||
2005 | WRITE32(0); /* lfs */ | ||
2006 | WRITE32(0); /* pi */ | ||
2007 | p = xdr_encode_opaque(p, context, len); | ||
2008 | *buflen -= (XDR_QUADLEN(len) << 2) + 4; | ||
2009 | |||
2010 | *pp = p; | ||
2011 | return 0; | ||
2012 | } | ||
2013 | #else | ||
2014 | static inline __be32 | ||
2015 | nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **pp, int *buflen) | ||
2016 | { return 0; } | ||
2017 | #endif | ||
2018 | |||
1957 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) | 2019 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) |
1958 | { | 2020 | { |
1959 | /* As per referral draft: */ | 2021 | /* As per referral draft: */ |
@@ -2013,6 +2075,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2013 | int err; | 2075 | int err; |
2014 | int aclsupport = 0; | 2076 | int aclsupport = 0; |
2015 | struct nfs4_acl *acl = NULL; | 2077 | struct nfs4_acl *acl = NULL; |
2078 | void *context = NULL; | ||
2079 | int contextlen; | ||
2080 | bool contextsupport = false; | ||
2016 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 2081 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
2017 | u32 minorversion = resp->cstate.minorversion; | 2082 | u32 minorversion = resp->cstate.minorversion; |
2018 | struct path path = { | 2083 | struct path path = { |
@@ -2066,6 +2131,21 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2066 | } | 2131 | } |
2067 | } | 2132 | } |
2068 | 2133 | ||
2134 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
2135 | if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) || | ||
2136 | bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { | ||
2137 | err = security_inode_getsecctx(dentry->d_inode, | ||
2138 | &context, &contextlen); | ||
2139 | contextsupport = (err == 0); | ||
2140 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2141 | if (err == -EOPNOTSUPP) | ||
2142 | bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2143 | else if (err) | ||
2144 | goto out_nfserr; | ||
2145 | } | ||
2146 | } | ||
2147 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | ||
2148 | |||
2069 | if (bmval2) { | 2149 | if (bmval2) { |
2070 | if ((buflen -= 16) < 0) | 2150 | if ((buflen -= 16) < 0) |
2071 | goto out_resource; | 2151 | goto out_resource; |
@@ -2094,6 +2174,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2094 | 2174 | ||
2095 | if (!aclsupport) | 2175 | if (!aclsupport) |
2096 | word0 &= ~FATTR4_WORD0_ACL; | 2176 | word0 &= ~FATTR4_WORD0_ACL; |
2177 | if (!contextsupport) | ||
2178 | word2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2097 | if (!word2) { | 2179 | if (!word2) { |
2098 | if ((buflen -= 12) < 0) | 2180 | if ((buflen -= 12) < 0) |
2099 | goto out_resource; | 2181 | goto out_resource; |
@@ -2401,6 +2483,12 @@ out_acl: | |||
2401 | get_parent_attributes(exp, &stat); | 2483 | get_parent_attributes(exp, &stat); |
2402 | WRITE64(stat.ino); | 2484 | WRITE64(stat.ino); |
2403 | } | 2485 | } |
2486 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2487 | status = nfsd4_encode_security_label(rqstp, context, | ||
2488 | contextlen, &p, &buflen); | ||
2489 | if (status) | ||
2490 | goto out; | ||
2491 | } | ||
2404 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { | 2492 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { |
2405 | WRITE32(3); | 2493 | WRITE32(3); |
2406 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); | 2494 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); |
@@ -2413,6 +2501,8 @@ out_acl: | |||
2413 | status = nfs_ok; | 2501 | status = nfs_ok; |
2414 | 2502 | ||
2415 | out: | 2503 | out: |
2504 | if (context) | ||
2505 | security_release_secctx(context, contextlen); | ||
2416 | kfree(acl); | 2506 | kfree(acl); |
2417 | if (fhp == &tempfh) | 2507 | if (fhp == &tempfh) |
2418 | fh_put(&tempfh); | 2508 | fh_put(&tempfh); |
@@ -3177,16 +3267,18 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3177 | { | 3267 | { |
3178 | __be32 *p; | 3268 | __be32 *p; |
3179 | 3269 | ||
3180 | RESERVE_SPACE(12); | 3270 | RESERVE_SPACE(16); |
3181 | if (nfserr) { | 3271 | if (nfserr) { |
3182 | WRITE32(2); | 3272 | WRITE32(3); |
3273 | WRITE32(0); | ||
3183 | WRITE32(0); | 3274 | WRITE32(0); |
3184 | WRITE32(0); | 3275 | WRITE32(0); |
3185 | } | 3276 | } |
3186 | else { | 3277 | else { |
3187 | WRITE32(2); | 3278 | WRITE32(3); |
3188 | WRITE32(setattr->sa_bmval[0]); | 3279 | WRITE32(setattr->sa_bmval[0]); |
3189 | WRITE32(setattr->sa_bmval[1]); | 3280 | WRITE32(setattr->sa_bmval[1]); |
3281 | WRITE32(setattr->sa_bmval[2]); | ||
3190 | } | 3282 | } |
3191 | ADJUST_ARGS(); | 3283 | ADJUST_ARGS(); |
3192 | return nfserr; | 3284 | return nfserr; |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 15e7e1d531f0..2bbd94e51efc 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -328,6 +328,13 @@ void nfsd_lockd_shutdown(void); | |||
328 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ | 328 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ |
329 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) | 329 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) |
330 | 330 | ||
331 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
332 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ | ||
333 | (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL) | ||
334 | #else | ||
335 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0 | ||
336 | #endif | ||
337 | |||
331 | static inline u32 nfsd_suppattrs0(u32 minorversion) | 338 | static inline u32 nfsd_suppattrs0(u32 minorversion) |
332 | { | 339 | { |
333 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 | 340 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 |
@@ -342,8 +349,11 @@ static inline u32 nfsd_suppattrs1(u32 minorversion) | |||
342 | 349 | ||
343 | static inline u32 nfsd_suppattrs2(u32 minorversion) | 350 | static inline u32 nfsd_suppattrs2(u32 minorversion) |
344 | { | 351 | { |
345 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2 | 352 | switch (minorversion) { |
346 | : NFSD4_SUPPORTED_ATTRS_WORD2; | 353 | default: return NFSD4_2_SUPPORTED_ATTRS_WORD2; |
354 | case 1: return NFSD4_1_SUPPORTED_ATTRS_WORD2; | ||
355 | case 0: return NFSD4_SUPPORTED_ATTRS_WORD2; | ||
356 | } | ||
347 | } | 357 | } |
348 | 358 | ||
349 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ | 359 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ |
@@ -356,7 +366,11 @@ static inline u32 nfsd_suppattrs2(u32 minorversion) | |||
356 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ | 366 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ |
357 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ | 367 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ |
358 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) | 368 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
369 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
370 | #define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL | ||
371 | #else | ||
359 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 | 372 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 |
373 | #endif | ||
360 | 374 | ||
361 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ | 375 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ |
362 | NFSD_WRITEABLE_ATTRS_WORD0 | 376 | NFSD_WRITEABLE_ATTRS_WORD0 |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 84ce601d8063..1e757fa45c40 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
29 | #include <linux/exportfs.h> | 29 | #include <linux/exportfs.h> |
30 | #include <linux/writeback.h> | 30 | #include <linux/writeback.h> |
31 | #include <linux/security.h> | ||
31 | 32 | ||
32 | #ifdef CONFIG_NFSD_V3 | 33 | #ifdef CONFIG_NFSD_V3 |
33 | #include "xdr3.h" | 34 | #include "xdr3.h" |
@@ -621,6 +622,33 @@ int nfsd4_is_junction(struct dentry *dentry) | |||
621 | return 0; | 622 | return 0; |
622 | return 1; | 623 | return 1; |
623 | } | 624 | } |
625 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
626 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
627 | struct xdr_netobj *label) | ||
628 | { | ||
629 | __be32 error; | ||
630 | int host_error; | ||
631 | struct dentry *dentry; | ||
632 | |||
633 | error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); | ||
634 | if (error) | ||
635 | return error; | ||
636 | |||
637 | dentry = fhp->fh_dentry; | ||
638 | |||
639 | mutex_lock(&dentry->d_inode->i_mutex); | ||
640 | host_error = security_inode_setsecctx(dentry, label->data, label->len); | ||
641 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
642 | return nfserrno(host_error); | ||
643 | } | ||
644 | #else | ||
645 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
646 | struct xdr_netobj *label) | ||
647 | { | ||
648 | return nfserr_notsupp; | ||
649 | } | ||
650 | #endif | ||
651 | |||
624 | #endif /* defined(CONFIG_NFSD_V4) */ | 652 | #endif /* defined(CONFIG_NFSD_V4) */ |
625 | 653 | ||
626 | #ifdef CONFIG_NFSD_V3 | 654 | #ifdef CONFIG_NFSD_V3 |
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 8d2b40d71669..a4be2e389670 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -55,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *); | |||
55 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, | 55 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, |
56 | struct nfs4_acl *); | 56 | struct nfs4_acl *); |
57 | int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); | 57 | int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); |
58 | __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, | ||
59 | struct xdr_netobj *); | ||
58 | #endif /* CONFIG_NFSD_V4 */ | 60 | #endif /* CONFIG_NFSD_V4 */ |
59 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, | 61 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, |
60 | char *name, int len, struct iattr *attrs, | 62 | char *name, int len, struct iattr *attrs, |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 3b271d2092b6..b3ed6446ed8e 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "state.h" | 40 | #include "state.h" |
41 | #include "nfsd.h" | 41 | #include "nfsd.h" |
42 | 42 | ||
43 | #define NFSD4_MAX_SEC_LABEL_LEN 2048 | ||
43 | #define NFSD4_MAX_TAGLEN 128 | 44 | #define NFSD4_MAX_TAGLEN 128 |
44 | #define XDR_LEN(n) (((n) + 3) & ~3) | 45 | #define XDR_LEN(n) (((n) + 3) & ~3) |
45 | 46 | ||
@@ -118,6 +119,7 @@ struct nfsd4_create { | |||
118 | struct iattr cr_iattr; /* request */ | 119 | struct iattr cr_iattr; /* request */ |
119 | struct nfsd4_change_info cr_cinfo; /* response */ | 120 | struct nfsd4_change_info cr_cinfo; /* response */ |
120 | struct nfs4_acl *cr_acl; | 121 | struct nfs4_acl *cr_acl; |
122 | struct xdr_netobj cr_label; | ||
121 | }; | 123 | }; |
122 | #define cr_linklen u.link.namelen | 124 | #define cr_linklen u.link.namelen |
123 | #define cr_linkname u.link.name | 125 | #define cr_linkname u.link.name |
@@ -246,6 +248,7 @@ struct nfsd4_open { | |||
246 | struct nfs4_file *op_file; /* used during processing */ | 248 | struct nfs4_file *op_file; /* used during processing */ |
247 | struct nfs4_ol_stateid *op_stp; /* used during processing */ | 249 | struct nfs4_ol_stateid *op_stp; /* used during processing */ |
248 | struct nfs4_acl *op_acl; | 250 | struct nfs4_acl *op_acl; |
251 | struct xdr_netobj op_label; | ||
249 | }; | 252 | }; |
250 | #define op_iattr iattr | 253 | #define op_iattr iattr |
251 | 254 | ||
@@ -330,6 +333,7 @@ struct nfsd4_setattr { | |||
330 | u32 sa_bmval[3]; /* request */ | 333 | u32 sa_bmval[3]; /* request */ |
331 | struct iattr sa_iattr; /* request */ | 334 | struct iattr sa_iattr; /* request */ |
332 | struct nfs4_acl *sa_acl; | 335 | struct nfs4_acl *sa_acl; |
336 | struct xdr_netobj sa_label; | ||
333 | }; | 337 | }; |
334 | 338 | ||
335 | struct nfsd4_setclientid { | 339 | struct nfsd4_setclientid { |