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