diff options
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 169 |
1 files changed, 149 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 6cd86e0fe450..0c0f3ea90de5 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 | /* |
@@ -134,6 +139,19 @@ xdr_error: \ | |||
134 | } \ | 139 | } \ |
135 | } while (0) | 140 | } while (0) |
136 | 141 | ||
142 | static void next_decode_page(struct nfsd4_compoundargs *argp) | ||
143 | { | ||
144 | argp->pagelist++; | ||
145 | argp->p = page_address(argp->pagelist[0]); | ||
146 | if (argp->pagelen < PAGE_SIZE) { | ||
147 | argp->end = argp->p + (argp->pagelen>>2); | ||
148 | argp->pagelen = 0; | ||
149 | } else { | ||
150 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
151 | argp->pagelen -= PAGE_SIZE; | ||
152 | } | ||
153 | } | ||
154 | |||
137 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) | 155 | static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) |
138 | { | 156 | { |
139 | /* We want more bytes than seem to be available. | 157 | /* We want more bytes than seem to be available. |
@@ -161,16 +179,7 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) | |||
161 | * guarantee p points to at least nbytes bytes. | 179 | * guarantee p points to at least nbytes bytes. |
162 | */ | 180 | */ |
163 | memcpy(p, argp->p, avail); | 181 | memcpy(p, argp->p, avail); |
164 | /* step to next page */ | 182 | next_decode_page(argp); |
165 | argp->p = page_address(argp->pagelist[0]); | ||
166 | argp->pagelist++; | ||
167 | if (argp->pagelen < PAGE_SIZE) { | ||
168 | argp->end = argp->p + (argp->pagelen>>2); | ||
169 | argp->pagelen = 0; | ||
170 | } else { | ||
171 | argp->end = argp->p + (PAGE_SIZE>>2); | ||
172 | argp->pagelen -= PAGE_SIZE; | ||
173 | } | ||
174 | memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); | 183 | memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); |
175 | argp->p += XDR_QUADLEN(nbytes - avail); | 184 | argp->p += XDR_QUADLEN(nbytes - avail); |
176 | return p; | 185 | return p; |
@@ -242,7 +251,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
242 | 251 | ||
243 | static __be32 | 252 | static __be32 |
244 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | 253 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
245 | struct iattr *iattr, struct nfs4_acl **acl) | 254 | struct iattr *iattr, struct nfs4_acl **acl, |
255 | struct xdr_netobj *label) | ||
246 | { | 256 | { |
247 | int expected_len, len = 0; | 257 | int expected_len, len = 0; |
248 | u32 dummy32; | 258 | u32 dummy32; |
@@ -380,6 +390,32 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
380 | goto xdr_error; | 390 | goto xdr_error; |
381 | } | 391 | } |
382 | } | 392 | } |
393 | |||
394 | label->len = 0; | ||
395 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
396 | if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { | ||
397 | READ_BUF(4); | ||
398 | len += 4; | ||
399 | READ32(dummy32); /* lfs: we don't use it */ | ||
400 | READ_BUF(4); | ||
401 | len += 4; | ||
402 | READ32(dummy32); /* pi: we don't use it either */ | ||
403 | READ_BUF(4); | ||
404 | len += 4; | ||
405 | READ32(dummy32); | ||
406 | READ_BUF(dummy32); | ||
407 | if (dummy32 > NFSD4_MAX_SEC_LABEL_LEN) | ||
408 | return nfserr_badlabel; | ||
409 | len += (XDR_QUADLEN(dummy32) << 2); | ||
410 | READMEM(buf, dummy32); | ||
411 | label->data = kzalloc(dummy32 + 1, GFP_KERNEL); | ||
412 | if (!label->data) | ||
413 | return nfserr_jukebox; | ||
414 | defer_free(argp, kfree, label->data); | ||
415 | memcpy(label->data, buf, dummy32); | ||
416 | } | ||
417 | #endif | ||
418 | |||
383 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 | 419 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
384 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 | 420 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
385 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | 421 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) |
@@ -428,7 +464,11 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_ | |||
428 | /* callback_sec_params4 */ | 464 | /* callback_sec_params4 */ |
429 | READ_BUF(4); | 465 | READ_BUF(4); |
430 | READ32(nr_secflavs); | 466 | READ32(nr_secflavs); |
431 | cbs->flavor = (u32)(-1); | 467 | if (nr_secflavs) |
468 | cbs->flavor = (u32)(-1); | ||
469 | else | ||
470 | /* Is this legal? Be generous, take it to mean AUTH_NONE: */ | ||
471 | cbs->flavor = 0; | ||
432 | for (i = 0; i < nr_secflavs; ++i) { | 472 | for (i = 0; i < nr_secflavs; ++i) { |
433 | READ_BUF(4); | 473 | READ_BUF(4); |
434 | READ32(dummy); | 474 | READ32(dummy); |
@@ -576,7 +616,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
576 | return status; | 616 | return status; |
577 | 617 | ||
578 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, | 618 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
579 | &create->cr_acl); | 619 | &create->cr_acl, &create->cr_label); |
580 | if (status) | 620 | if (status) |
581 | goto out; | 621 | goto out; |
582 | 622 | ||
@@ -827,7 +867,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
827 | case NFS4_CREATE_UNCHECKED: | 867 | case NFS4_CREATE_UNCHECKED: |
828 | case NFS4_CREATE_GUARDED: | 868 | case NFS4_CREATE_GUARDED: |
829 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 869 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
830 | &open->op_iattr, &open->op_acl); | 870 | &open->op_iattr, &open->op_acl, &open->op_label); |
831 | if (status) | 871 | if (status) |
832 | goto out; | 872 | goto out; |
833 | break; | 873 | break; |
@@ -841,7 +881,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
841 | READ_BUF(NFS4_VERIFIER_SIZE); | 881 | READ_BUF(NFS4_VERIFIER_SIZE); |
842 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); | 882 | COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); |
843 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 883 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
844 | &open->op_iattr, &open->op_acl); | 884 | &open->op_iattr, &open->op_acl, &open->op_label); |
845 | if (status) | 885 | if (status) |
846 | goto out; | 886 | goto out; |
847 | break; | 887 | break; |
@@ -1063,7 +1103,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
1063 | if (status) | 1103 | if (status) |
1064 | return status; | 1104 | return status; |
1065 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, | 1105 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
1066 | &setattr->sa_acl); | 1106 | &setattr->sa_acl, &setattr->sa_label); |
1067 | } | 1107 | } |
1068 | 1108 | ||
1069 | static __be32 | 1109 | static __be32 |
@@ -1567,6 +1607,7 @@ struct nfsd4_minorversion_ops { | |||
1567 | static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { | 1607 | static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { |
1568 | [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, | 1608 | [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, |
1569 | [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | 1609 | [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, |
1610 | [2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, | ||
1570 | }; | 1611 | }; |
1571 | 1612 | ||
1572 | static __be32 | 1613 | static __be32 |
@@ -1953,6 +1994,36 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace, | |||
1953 | FATTR4_WORD0_RDATTR_ERROR) | 1994 | FATTR4_WORD0_RDATTR_ERROR) |
1954 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID | 1995 | #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID |
1955 | 1996 | ||
1997 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
1998 | static inline __be32 | ||
1999 | nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen) | ||
2000 | { | ||
2001 | __be32 *p = *pp; | ||
2002 | |||
2003 | if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) | ||
2004 | return nfserr_resource; | ||
2005 | |||
2006 | /* | ||
2007 | * For now we use a 0 here to indicate the null translation; in | ||
2008 | * the future we may place a call to translation code here. | ||
2009 | */ | ||
2010 | if ((*buflen -= 8) < 0) | ||
2011 | return nfserr_resource; | ||
2012 | |||
2013 | WRITE32(0); /* lfs */ | ||
2014 | WRITE32(0); /* pi */ | ||
2015 | p = xdr_encode_opaque(p, context, len); | ||
2016 | *buflen -= (XDR_QUADLEN(len) << 2) + 4; | ||
2017 | |||
2018 | *pp = p; | ||
2019 | return 0; | ||
2020 | } | ||
2021 | #else | ||
2022 | static inline __be32 | ||
2023 | nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen) | ||
2024 | { return 0; } | ||
2025 | #endif | ||
2026 | |||
1956 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) | 2027 | static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) |
1957 | { | 2028 | { |
1958 | /* As per referral draft: */ | 2029 | /* As per referral draft: */ |
@@ -2012,6 +2083,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2012 | int err; | 2083 | int err; |
2013 | int aclsupport = 0; | 2084 | int aclsupport = 0; |
2014 | struct nfs4_acl *acl = NULL; | 2085 | struct nfs4_acl *acl = NULL; |
2086 | void *context = NULL; | ||
2087 | int contextlen; | ||
2088 | bool contextsupport = false; | ||
2015 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 2089 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
2016 | u32 minorversion = resp->cstate.minorversion; | 2090 | u32 minorversion = resp->cstate.minorversion; |
2017 | struct path path = { | 2091 | struct path path = { |
@@ -2065,6 +2139,21 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2065 | } | 2139 | } |
2066 | } | 2140 | } |
2067 | 2141 | ||
2142 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
2143 | if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) || | ||
2144 | bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) { | ||
2145 | err = security_inode_getsecctx(dentry->d_inode, | ||
2146 | &context, &contextlen); | ||
2147 | contextsupport = (err == 0); | ||
2148 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2149 | if (err == -EOPNOTSUPP) | ||
2150 | bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2151 | else if (err) | ||
2152 | goto out_nfserr; | ||
2153 | } | ||
2154 | } | ||
2155 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | ||
2156 | |||
2068 | if (bmval2) { | 2157 | if (bmval2) { |
2069 | if ((buflen -= 16) < 0) | 2158 | if ((buflen -= 16) < 0) |
2070 | goto out_resource; | 2159 | goto out_resource; |
@@ -2093,6 +2182,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
2093 | 2182 | ||
2094 | if (!aclsupport) | 2183 | if (!aclsupport) |
2095 | word0 &= ~FATTR4_WORD0_ACL; | 2184 | word0 &= ~FATTR4_WORD0_ACL; |
2185 | if (!contextsupport) | ||
2186 | word2 &= ~FATTR4_WORD2_SECURITY_LABEL; | ||
2096 | if (!word2) { | 2187 | if (!word2) { |
2097 | if ((buflen -= 12) < 0) | 2188 | if ((buflen -= 12) < 0) |
2098 | goto out_resource; | 2189 | goto out_resource; |
@@ -2400,6 +2491,12 @@ out_acl: | |||
2400 | get_parent_attributes(exp, &stat); | 2491 | get_parent_attributes(exp, &stat); |
2401 | WRITE64(stat.ino); | 2492 | WRITE64(stat.ino); |
2402 | } | 2493 | } |
2494 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | ||
2495 | status = nfsd4_encode_security_label(rqstp, context, | ||
2496 | contextlen, &p, &buflen); | ||
2497 | if (status) | ||
2498 | goto out; | ||
2499 | } | ||
2403 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { | 2500 | if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { |
2404 | WRITE32(3); | 2501 | WRITE32(3); |
2405 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); | 2502 | WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); |
@@ -2412,6 +2509,10 @@ out_acl: | |||
2412 | status = nfs_ok; | 2509 | status = nfs_ok; |
2413 | 2510 | ||
2414 | out: | 2511 | out: |
2512 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | ||
2513 | if (context) | ||
2514 | security_release_secctx(context, contextlen); | ||
2515 | #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ | ||
2415 | kfree(acl); | 2516 | kfree(acl); |
2416 | if (fhp == &tempfh) | 2517 | if (fhp == &tempfh) |
2417 | fh_put(&tempfh); | 2518 | fh_put(&tempfh); |
@@ -3176,16 +3277,18 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
3176 | { | 3277 | { |
3177 | __be32 *p; | 3278 | __be32 *p; |
3178 | 3279 | ||
3179 | RESERVE_SPACE(12); | 3280 | RESERVE_SPACE(16); |
3180 | if (nfserr) { | 3281 | if (nfserr) { |
3181 | WRITE32(2); | 3282 | WRITE32(3); |
3283 | WRITE32(0); | ||
3182 | WRITE32(0); | 3284 | WRITE32(0); |
3183 | WRITE32(0); | 3285 | WRITE32(0); |
3184 | } | 3286 | } |
3185 | else { | 3287 | else { |
3186 | WRITE32(2); | 3288 | WRITE32(3); |
3187 | WRITE32(setattr->sa_bmval[0]); | 3289 | WRITE32(setattr->sa_bmval[0]); |
3188 | WRITE32(setattr->sa_bmval[1]); | 3290 | WRITE32(setattr->sa_bmval[1]); |
3291 | WRITE32(setattr->sa_bmval[2]); | ||
3189 | } | 3292 | } |
3190 | ADJUST_ARGS(); | 3293 | ADJUST_ARGS(); |
3191 | return nfserr; | 3294 | return nfserr; |
@@ -3226,6 +3329,14 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w | |||
3226 | return nfserr; | 3329 | return nfserr; |
3227 | } | 3330 | } |
3228 | 3331 | ||
3332 | static const u32 nfs4_minimal_spo_must_enforce[2] = { | ||
3333 | [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) | | ||
3334 | 1 << (OP_EXCHANGE_ID - 32) | | ||
3335 | 1 << (OP_CREATE_SESSION - 32) | | ||
3336 | 1 << (OP_DESTROY_SESSION - 32) | | ||
3337 | 1 << (OP_DESTROY_CLIENTID - 32) | ||
3338 | }; | ||
3339 | |||
3229 | static __be32 | 3340 | static __be32 |
3230 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | 3341 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, |
3231 | struct nfsd4_exchange_id *exid) | 3342 | struct nfsd4_exchange_id *exid) |
@@ -3264,6 +3375,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
3264 | /* state_protect4_r. Currently only support SP4_NONE */ | 3375 | /* state_protect4_r. Currently only support SP4_NONE */ |
3265 | BUG_ON(exid->spa_how != SP4_NONE); | 3376 | BUG_ON(exid->spa_how != SP4_NONE); |
3266 | WRITE32(exid->spa_how); | 3377 | WRITE32(exid->spa_how); |
3378 | switch (exid->spa_how) { | ||
3379 | case SP4_NONE: | ||
3380 | break; | ||
3381 | case SP4_MACH_CRED: | ||
3382 | /* spo_must_enforce bitmap: */ | ||
3383 | WRITE32(2); | ||
3384 | WRITE32(nfs4_minimal_spo_must_enforce[0]); | ||
3385 | WRITE32(nfs4_minimal_spo_must_enforce[1]); | ||
3386 | /* empty spo_must_allow bitmap: */ | ||
3387 | WRITE32(0); | ||
3388 | break; | ||
3389 | default: | ||
3390 | WARN_ON_ONCE(1); | ||
3391 | } | ||
3267 | 3392 | ||
3268 | /* The server_owner struct */ | 3393 | /* The server_owner struct */ |
3269 | WRITE64(minor_id); /* Minor id */ | 3394 | WRITE64(minor_id); /* Minor id */ |
@@ -3635,13 +3760,17 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3635 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; | 3760 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; |
3636 | BUG_ON(iov->iov_len > PAGE_SIZE); | 3761 | BUG_ON(iov->iov_len > PAGE_SIZE); |
3637 | if (nfsd4_has_session(cs)) { | 3762 | if (nfsd4_has_session(cs)) { |
3763 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3764 | struct nfs4_client *clp = cs->session->se_client; | ||
3638 | if (cs->status != nfserr_replay_cache) { | 3765 | if (cs->status != nfserr_replay_cache) { |
3639 | nfsd4_store_cache_entry(resp); | 3766 | nfsd4_store_cache_entry(resp); |
3640 | cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; | 3767 | cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; |
3641 | } | 3768 | } |
3642 | /* Renew the clientid on success and on replay */ | 3769 | /* Renew the clientid on success and on replay */ |
3643 | put_client_renew(cs->session->se_client); | 3770 | spin_lock(&nn->client_lock); |
3644 | nfsd4_put_session(cs->session); | 3771 | nfsd4_put_session(cs->session); |
3772 | spin_unlock(&nn->client_lock); | ||
3773 | put_client_renew(clp); | ||
3645 | } | 3774 | } |
3646 | return 1; | 3775 | return 1; |
3647 | } | 3776 | } |