diff options
| -rw-r--r-- | fs/nfsd/Kconfig | 16 | ||||
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 44 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 225 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 169 | ||||
| -rw-r--r-- | fs/nfsd/nfsd.h | 20 | ||||
| -rw-r--r-- | fs/nfsd/nfssvc.c | 2 | ||||
| -rw-r--r-- | fs/nfsd/state.h | 1 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 28 | ||||
| -rw-r--r-- | fs/nfsd/vfs.h | 7 | ||||
| -rw-r--r-- | fs/nfsd/xdr4.h | 4 | ||||
| -rw-r--r-- | include/linux/sunrpc/cache.h | 49 | ||||
| -rw-r--r-- | include/linux/sunrpc/gss_api.h | 2 | ||||
| -rw-r--r-- | include/linux/sunrpc/svcauth.h | 11 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/gss_mech_switch.c | 5 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 10 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 83 | ||||
| -rw-r--r-- | net/sunrpc/svcauth_unix.c | 6 | ||||
| -rw-r--r-- | net/sunrpc/svcsock.c | 9 | ||||
| -rw-r--r-- | net/sunrpc/xprtsock.c | 1 | ||||
| -rw-r--r-- | security/capability.c | 2 |
20 files changed, 512 insertions, 182 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..a7cee864e7b2 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 |
| @@ -263,7 +296,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru | |||
| 263 | 296 | ||
| 264 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); | 297 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); |
| 265 | accmode = NFSD_MAY_NOP; | 298 | accmode = NFSD_MAY_NOP; |
| 266 | if (open->op_created) | 299 | if (open->op_created || |
| 300 | open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
| 267 | accmode |= NFSD_MAY_OWNER_OVERRIDE; | 301 | accmode |= NFSD_MAY_OWNER_OVERRIDE; |
| 268 | status = do_open_permission(rqstp, resfh, open, accmode); | 302 | status = do_open_permission(rqstp, resfh, open, accmode); |
| 269 | set_change_info(&open->op_cinfo, current_fh); | 303 | set_change_info(&open->op_cinfo, current_fh); |
| @@ -637,6 +671,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 637 | if (status) | 671 | if (status) |
| 638 | goto out; | 672 | goto out; |
| 639 | 673 | ||
| 674 | if (create->cr_label.len) | ||
| 675 | nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); | ||
| 676 | |||
| 640 | if (create->cr_acl != NULL) | 677 | if (create->cr_acl != NULL) |
| 641 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, | 678 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, |
| 642 | create->cr_bmval); | 679 | create->cr_bmval); |
| @@ -916,6 +953,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 916 | setattr->sa_acl); | 953 | setattr->sa_acl); |
| 917 | if (status) | 954 | if (status) |
| 918 | goto out; | 955 | goto out; |
| 956 | if (setattr->sa_label.len) | ||
| 957 | status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, | ||
| 958 | &setattr->sa_label); | ||
| 959 | if (status) | ||
| 960 | goto out; | ||
| 919 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, | 961 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, |
| 920 | 0, (time_t)0); | 962 | 0, (time_t)0); |
| 921 | out: | 963 | out: |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f17051838b41..280acef6f0dc 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -97,19 +97,20 @@ nfs4_lock_state(void) | |||
| 97 | 97 | ||
| 98 | static void free_session(struct nfsd4_session *); | 98 | static void free_session(struct nfsd4_session *); |
| 99 | 99 | ||
| 100 | void nfsd4_put_session(struct nfsd4_session *ses) | 100 | static bool is_session_dead(struct nfsd4_session *ses) |
| 101 | { | 101 | { |
| 102 | atomic_dec(&ses->se_ref); | 102 | return ses->se_flags & NFS4_SESSION_DEAD; |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static bool is_session_dead(struct nfsd4_session *ses) | 105 | void nfsd4_put_session(struct nfsd4_session *ses) |
| 106 | { | 106 | { |
| 107 | return ses->se_flags & NFS4_SESSION_DEAD; | 107 | if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) |
| 108 | free_session(ses); | ||
| 108 | } | 109 | } |
| 109 | 110 | ||
| 110 | static __be32 mark_session_dead_locked(struct nfsd4_session *ses) | 111 | static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) |
| 111 | { | 112 | { |
| 112 | if (atomic_read(&ses->se_ref)) | 113 | if (atomic_read(&ses->se_ref) > ref_held_by_me) |
| 113 | return nfserr_jukebox; | 114 | return nfserr_jukebox; |
| 114 | ses->se_flags |= NFS4_SESSION_DEAD; | 115 | ses->se_flags |= NFS4_SESSION_DEAD; |
| 115 | return nfs_ok; | 116 | return nfs_ok; |
| @@ -364,19 +365,12 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) | |||
| 364 | } | 365 | } |
| 365 | 366 | ||
| 366 | static struct nfs4_delegation * | 367 | static struct nfs4_delegation * |
| 367 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type) | 368 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) |
| 368 | { | 369 | { |
| 369 | struct nfs4_delegation *dp; | 370 | struct nfs4_delegation *dp; |
| 370 | struct nfs4_file *fp = stp->st_file; | 371 | struct nfs4_file *fp = stp->st_file; |
| 371 | 372 | ||
| 372 | dprintk("NFSD alloc_init_deleg\n"); | 373 | dprintk("NFSD alloc_init_deleg\n"); |
| 373 | /* | ||
| 374 | * Major work on the lease subsystem (for example, to support | ||
| 375 | * calbacks on stat) will be required before we can support | ||
| 376 | * write delegations properly. | ||
| 377 | */ | ||
| 378 | if (type != NFS4_OPEN_DELEGATE_READ) | ||
