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/nfs4xdr.c | |
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/nfs4xdr.c')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 108 |
1 files changed, 100 insertions, 8 deletions
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; |