diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-11 13:17:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-11 13:17:13 -0400 |
commit | 0ff08ba5d066619f9973bfcdb5a21320d54219d0 (patch) | |
tree | 526e4a5799eb3023e9d5d81e81c0964b1d928a3e /fs/nfsd | |
parent | c72bb316916b1a6cf35e1d5238566ef27b0b7f80 (diff) | |
parent | d109148111cdfcdae94f797dc142468bd0ff7557 (diff) |
Merge branch 'for-3.11' of git://linux-nfs.org/~bfields/linux
Pull nfsd changes from Bruce Fields:
"Changes this time include:
- 4.1 enabled on the server by default: the last 4.1-specific issues
I know of are fixed, so we're not going to find the rest of the
bugs without more exposure.
- Experimental support for NFSv4.2 MAC Labeling (to allow running
selinux over NFS), from Dave Quigley.
- Fixes for some delicate cache/upcall races that could cause rare
server hangs; thanks to Neil Brown and Bodo Stroesser for extreme
debugging persistence.
- Fixes for some bugs found at the recent NFS bakeathon, mostly v4
and v4.1-specific, but also a generic bug handling fragmented rpc
calls"
* 'for-3.11' of git://linux-nfs.org/~bfields/linux: (31 commits)
nfsd4: support minorversion 1 by default
nfsd4: allow destroy_session over destroyed session
svcrpc: fix failures to handle -1 uid's
sunrpc: Don't schedule an upcall on a replaced cache entry.
net/sunrpc: xpt_auth_cache should be ignored when expired.
sunrpc/cache: ensure items removed from cache do not have pending upcalls.
sunrpc/cache: use cache_fresh_unlocked consistently and correctly.
sunrpc/cache: remove races with queuing an upcall.
nfsd4: return delegation immediately if lease fails
nfsd4: do not throw away 4.1 lock state on last unlock
nfsd4: delegation-based open reclaims should bypass permissions
svcrpc: don't error out on small tcp fragment
svcrpc: fix handling of too-short rpc's
nfsd4: minor read_buf cleanup
nfsd4: fix decoding of compounds across page boundaries
nfsd4: clean up nfs4_open_delegation
NFSD: Don't give out read delegations on creates
nfsd4: allow client to send no cb_sec flavors
nfsd4: fail attempts to request gss on the backchannel
nfsd4: implement minimal SP4_MACH_CRED
...
Diffstat (limited to 'fs/nfsd')
-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 |
10 files changed, 413 insertions, 103 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) | ||
379 | return NULL; | ||
380 | if (fp->fi_had_conflict) | 374 | if (fp->fi_had_conflict) |
381 | return NULL; | 375 | return NULL; |
382 | if (num_delegations > max_delegations) | 376 | if (num_delegations > max_delegations) |
@@ -397,7 +391,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv | |||
397 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 391 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
398 | get_nfs4_file(fp); | 392 | get_nfs4_file(fp); |
399 | dp->dl_file = fp; | 393 | dp->dl_file = fp; |
400 | dp->dl_type = type; | 394 | dp->dl_type = NFS4_OPEN_DELEGATE_READ; |
401 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 395 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
402 | dp->dl_time = 0; | 396 | dp->dl_time = 0; |
403 | atomic_set(&dp->dl_count, 1); | 397 | atomic_set(&dp->dl_count, 1); |
@@ -1188,6 +1182,9 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source) | |||
1188 | target->cr_gid = source->cr_gid; | 1182 | target->cr_gid = source->cr_gid; |
1189 | target->cr_group_info = source->cr_group_info; | 1183 | target->cr_group_info = source->cr_group_info; |
1190 | get_group_info(target->cr_group_info); | 1184 | get_group_info(target->cr_group_info); |
1185 | target->cr_gss_mech = source->cr_gss_mech; | ||
1186 | if (source->cr_gss_mech) | ||
1187 | gss_mech_get(source->cr_gss_mech); | ||
1191 | return 0; | 1188 | return 0; |
1192 | } | 1189 | } |
1193 | 1190 | ||
@@ -1262,6 +1259,31 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | |||
1262 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); | 1259 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); |
1263 | } | 1260 | } |
1264 | 1261 | ||
1262 | static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) | ||
1263 | { | ||
1264 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1265 | u32 service; | ||
1266 | |||
1267 | service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); | ||
1268 | return service == RPC_GSS_SVC_INTEGRITY || | ||
1269 | service == RPC_GSS_SVC_PRIVACY; | ||
1270 | } | ||
1271 | |||
1272 | static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) | ||
1273 | { | ||
1274 | struct svc_cred *cr = &rqstp->rq_cred; | ||
1275 | |||
1276 | if (!cl->cl_mach_cred) | ||
1277 | return true; | ||
1278 | if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) | ||
1279 | return false; | ||
1280 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1281 | return false; | ||
1282 | if (!cr->cr_principal) | ||
1283 | return false; | ||
1284 | return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); | ||
1285 | } | ||
1286 | |||
1265 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) | 1287 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) |
1266 | { | 1288 | { |
1267 | static u32 current_clientid = 1; | 1289 | static u32 current_clientid = 1; |
@@ -1639,16 +1661,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1639 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) | 1661 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) |
1640 | return nfserr_inval; | 1662 | return nfserr_inval; |
1641 | 1663 | ||
1642 | /* Currently only support SP4_NONE */ | ||
1643 | switch (exid->spa_how) { | 1664 | switch (exid->spa_how) { |
1665 | case SP4_MACH_CRED: | ||
1666 | if (!svc_rqst_integrity_protected(rqstp)) | ||
1667 | return nfserr_inval; | ||
1644 | case SP4_NONE: | 1668 | case SP4_NONE: |
1645 | break; | 1669 | break; |
1646 | default: /* checked by xdr code */ | 1670 | default: /* checked by xdr code */ |
1647 | WARN_ON_ONCE(1); | 1671 | WARN_ON_ONCE(1); |
1648 | case SP4_SSV: | 1672 | case SP4_SSV: |
1649 | return nfserr_encr_alg_unsupp; | 1673 | return nfserr_encr_alg_unsupp; |
1650 | case SP4_MACH_CRED: | ||
1651 | return nfserr_serverfault; /* no excuse :-/ */ | ||
1652 | } | 1674 | } |
1653 | 1675 | ||
1654 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 1676 | /* Cases below refer to rfc 5661 section 18.35.4: */ |
@@ -1663,6 +1685,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1663 | status = nfserr_inval; | 1685 | status = nfserr_inval; |
1664 | goto out; | 1686 | goto out; |
1665 | } | 1687 | } |
1688 | if (!mach_creds_match(conf, rqstp)) { | ||
1689 | status = nfserr_wrong_cred; | ||
1690 | goto out; | ||
1691 | } | ||
1666 | if (!creds_match) { /* case 9 */ | 1692 | if (!creds_match) { /* case 9 */ |
1667 | status = nfserr_perm; | 1693 | status = nfserr_perm; |
1668 | goto out; | 1694 | goto out; |
@@ -1709,7 +1735,8 @@ out_new: | |||
1709 | status = nfserr_jukebox; | 1735 | status = nfserr_jukebox; |
1710 | goto out; | 1736 | goto out; |
1711 | } | 1737 | } |
1712 | new->cl_minorversion = 1; | 1738 | new->cl_minorversion = cstate->minorversion; |
1739 | new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED); | ||
1713 | 1740 | ||
1714 | gen_clid(new, nn); | 1741 | gen_clid(new, nn); |
1715 | add_to_unconfirmed(new); | 1742 | add_to_unconfirmed(new); |
@@ -1839,6 +1866,24 @@ static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) | |||
1839 | return nfs_ok; | 1866 | return nfs_ok; |
1840 | } | 1867 | } |
1841 | 1868 | ||
1869 | static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) | ||
1870 | { | ||
1871 | switch (cbs->flavor) { | ||
1872 | case RPC_AUTH_NULL: | ||
1873 | case RPC_AUTH_UNIX: | ||
1874 | return nfs_ok; | ||
1875 | default: | ||
1876 | /* | ||
1877 | * GSS case: the spec doesn't allow us to return this | ||
1878 | * error. But it also doesn't allow us not to support | ||
1879 | * GSS. | ||
1880 | * I'd rather this fail hard than return some error the | ||
1881 | * client might think it can already handle: | ||
1882 | */ | ||
1883 | return nfserr_encr_alg_unsupp; | ||
1884 | } | ||
1885 | } | ||
1886 | |||
1842 | __be32 | 1887 | __be32 |
1843 | nfsd4_create_session(struct svc_rqst *rqstp, | 1888 | nfsd4_create_session(struct svc_rqst *rqstp, |
1844 | struct nfsd4_compound_state *cstate, | 1889 | struct nfsd4_compound_state *cstate, |
@@ -1854,6 +1899,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1854 | 1899 | ||
1855 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1900 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1856 | return nfserr_inval; | 1901 | return nfserr_inval; |
1902 | status = nfsd4_check_cb_sec(&cr_ses->cb_sec); | ||
1903 | if (status) | ||
1904 | return status; | ||
1857 | status = check_forechannel_attrs(&cr_ses->fore_channel, nn); | 1905 | status = check_forechannel_attrs(&cr_ses->fore_channel, nn); |
1858 | if (status) | 1906 | if (status) |
1859 | return status; | 1907 | return status; |
@@ -1874,6 +1922,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1874 | WARN_ON_ONCE(conf && unconf); | 1922 | WARN_ON_ONCE(conf && unconf); |
1875 | 1923 | ||
1876 | if (conf) { | 1924 | if (conf) { |
1925 | status = nfserr_wrong_cred; | ||
1926 | if (!mach_creds_match(conf, rqstp)) | ||
1927 | goto out_free_conn; | ||
1877 | cs_slot = &conf->cl_cs_slot; | 1928 | cs_slot = &conf->cl_cs_slot; |
1878 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1929 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1879 | if (status == nfserr_replay_cache) { | 1930 | if (status == nfserr_replay_cache) { |
@@ -1890,6 +1941,9 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1890 | status = nfserr_clid_inuse; | 1941 | status = nfserr_clid_inuse; |
1891 | goto out_free_conn; | 1942 | goto out_free_conn; |
1892 | } | 1943 | } |
1944 | status = nfserr_wrong_cred; | ||
1945 | if (!mach_creds_match(unconf, rqstp)) | ||
1946 | goto out_free_conn; | ||
1893 | cs_slot = &unconf->cl_cs_slot; | 1947 | cs_slot = &unconf->cl_cs_slot; |
1894 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1948 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1895 | if (status) { | 1949 | if (status) { |
@@ -1957,7 +2011,11 @@ __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state | |||
1957 | { | 2011 | { |
1958 | struct nfsd4_session *session = cstate->session; | 2012 | struct nfsd4_session *session = cstate->session; |
1959 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 2013 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
2014 | __be32 status; | ||
1960 | 2015 | ||
2016 | status = nfsd4_check_cb_sec(&bc->bc_cb_sec); | ||
2017 | if (status) | ||
2018 | return status; | ||
1961 | spin_lock(&nn->client_lock); | 2019 | spin_lock(&nn->client_lock); |
1962 | session->se_cb_prog = bc->bc_cb_program; | 2020 | session->se_cb_prog = bc->bc_cb_program; |
1963 | session->se_cb_sec = bc->bc_cb_sec; | 2021 | session->se_cb_sec = bc->bc_cb_sec; |
@@ -1986,6 +2044,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | |||
1986 | status = nfserr_badsession; | 2044 | status = nfserr_badsession; |
1987 | if (!session) | 2045 | if (!session) |
1988 | goto out; | 2046 | goto out; |
2047 | status = nfserr_wrong_cred; | ||
2048 | if (!mach_creds_match(session->se_client, rqstp)) | ||
2049 | goto out; | ||
1989 | status = nfsd4_map_bcts_dir(&bcts->dir); | 2050 | status = nfsd4_map_bcts_dir(&bcts->dir); |
1990 | if (status) | 2051 | if (status) |
1991 | goto out; | 2052 | goto out; |
@@ -2014,6 +2075,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2014 | { | 2075 | { |
2015 | struct nfsd4_session *ses; | 2076 | struct nfsd4_session *ses; |
2016 | __be32 status; | 2077 | __be32 status; |
2078 | int ref_held_by_me = 0; | ||
2017 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); | 2079 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); |
2018 | 2080 | ||
2019 | nfs4_lock_state(); | 2081 | nfs4_lock_state(); |
@@ -2021,6 +2083,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2021 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { | 2083 | if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) { |
2022 | if (!nfsd4_last_compound_op(r)) | 2084 | if (!nfsd4_last_compound_op(r)) |
2023 | goto out; | 2085 | goto out; |
2086 | ref_held_by_me++; | ||
2024 | } | 2087 | } |
2025 | dump_sessionid(__func__, &sessionid->sessionid); | 2088 | dump_sessionid(__func__, &sessionid->sessionid); |
2026 | spin_lock(&nn->client_lock); | 2089 | spin_lock(&nn->client_lock); |
@@ -2028,17 +2091,22 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
2028 | status = nfserr_badsession; | 2091 | status = nfserr_badsession; |
2029 | if (!ses) | 2092 | if (!ses) |
2030 | goto out_client_lock; | 2093 | goto out_client_lock; |
2031 | status = mark_session_dead_locked(ses); | 2094 | status = nfserr_wrong_cred; |
2032 | if (status) | 2095 | if (!mach_creds_match(ses->se_client, r)) |
2033 | goto out_client_lock; | 2096 | goto out_client_lock; |
2097 | nfsd4_get_session_locked(ses); | ||
2098 | status = mark_session_dead_locked(ses, 1 + ref_held_by_me); | ||
2099 | if (status) | ||
2100 | goto out_put_session; | ||
2034 | unhash_session(ses); | 2101 | unhash_session(ses); |
2035 | spin_unlock(&nn->client_lock); | 2102 | spin_unlock(&nn->client_lock); |
2036 | 2103 | ||
2037 | nfsd4_probe_callback_sync(ses->se_client); | 2104 | nfsd4_probe_callback_sync(ses->se_client); |
2038 | 2105 | ||
2039 | spin_lock(&nn->client_lock); | 2106 | spin_lock(&nn->client_lock); |
2040 | free_session(ses); | ||
2041 | status = nfs_ok; | 2107 | status = nfs_ok; |
2108 | out_put_session: | ||
2109 | nfsd4_put_session(ses); | ||
2042 | out_client_lock: | 2110 | out_client_lock: |
2043 | spin_unlock(&nn->client_lock); | 2111 | spin_unlock(&nn->client_lock); |
2044 | out: | 2112 | out: |
@@ -2058,26 +2126,31 @@ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_s | |||
2058 | return NULL; | 2126 | return NULL; |
2059 | } | 2127 | } |
2060 | 2128 | ||
2061 | static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) | 2129 | static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) |
2062 | { | 2130 | { |
2063 | struct nfs4_client *clp = ses->se_client; | 2131 | struct nfs4_client *clp = ses->se_client; |
2064 | struct nfsd4_conn *c; | 2132 | struct nfsd4_conn *c; |
2133 | __be32 status = nfs_ok; | ||
2065 | int ret; | 2134 | int ret; |
2066 | 2135 | ||
2067 | spin_lock(&clp->cl_lock); | 2136 | spin_lock(&clp->cl_lock); |
2068 | c = __nfsd4_find_conn(new->cn_xprt, ses); | 2137 | c = __nfsd4_find_conn(new->cn_xprt, ses); |
2069 | if (c) { | 2138 | if (c) |
2070 | spin_unlock(&clp->cl_lock); | 2139 | goto out_free; |
2071 | free_conn(new); | 2140 | status = nfserr_conn_not_bound_to_session; |
2072 | return; | 2141 | if (clp->cl_mach_cred) |
2073 | } | 2142 | goto out_free; |
2074 | __nfsd4_hash_conn(new, ses); | 2143 | __nfsd4_hash_conn(new, ses); |
2075 | spin_unlock(&clp->cl_lock); | 2144 | spin_unlock(&clp->cl_lock); |
2076 | ret = nfsd4_register_conn(new); | 2145 | ret = nfsd4_register_conn(new); |
2077 | if (ret) | 2146 | if (ret) |
2078 | /* oops; xprt is already down: */ | 2147 | /* oops; xprt is already down: */ |
2079 | nfsd4_conn_lost(&new->cn_xpt_user); | 2148 | nfsd4_conn_lost(&new->cn_xpt_user); |
2080 | return; | 2149 | return nfs_ok; |
2150 | out_free: | ||
2151 | spin_unlock(&clp->cl_lock); | ||
2152 | free_conn(new); | ||
2153 | return status; | ||
2081 | } | 2154 | } |
2082 | 2155 | ||
2083 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) | 2156 | static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) |
@@ -2169,8 +2242,10 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2169 | if (status) | 2242 | if (status) |
2170 | goto out_put_session; | 2243 | goto out_put_session; |
2171 | 2244 | ||
2172 | nfsd4_sequence_check_conn(conn, session); | 2245 | status = nfsd4_sequence_check_conn(conn, session); |
2173 | conn = NULL; | 2246 | conn = NULL; |
2247 | if (status) | ||
2248 | goto out_put_session; | ||
2174 | 2249 | ||
2175 | /* Success! bump slot seqid */ | 2250 | /* Success! bump slot seqid */ |
2176 | slot->sl_seqid = seq->seqid; | 2251 | slot->sl_seqid = seq->seqid; |
@@ -2232,7 +2307,10 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2232 | status = nfserr_stale_clientid; | 2307 | status = nfserr_stale_clientid; |
2233 | goto out; | 2308 | goto out; |
2234 | } | 2309 | } |
2235 | 2310 | if (!mach_creds_match(clp, rqstp)) { | |
2311 | status = nfserr_wrong_cred; | ||
2312 | goto out; | ||
2313 | } | ||
2236 | expire_client(clp); | 2314 | expire_client(clp); |
2237 | out: | 2315 | out: |
2238 | nfs4_unlock_state(); | 2316 | nfs4_unlock_state(); |
@@ -2940,13 +3018,13 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f | |||
2940 | return fl; | 3018 | return fl; |
2941 | } | 3019 | } |
2942 | 3020 | ||
2943 | static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | 3021 | static int nfs4_setlease(struct nfs4_delegation *dp) |
2944 | { | 3022 | { |
2945 | struct nfs4_file *fp = dp->dl_file; | 3023 | struct nfs4_file *fp = dp->dl_file; |
2946 | struct file_lock *fl; | 3024 | struct file_lock *fl; |
2947 | int status; | 3025 | int status; |
2948 | 3026 | ||
2949 | fl = nfs4_alloc_init_lease(dp, flag); | 3027 | fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); |
2950 | if (!fl) | 3028 | if (!fl) |
2951 | return -ENOMEM; | 3029 | return -ENOMEM; |
2952 | fl->fl_file = find_readable_file(fp); | 3030 | fl->fl_file = find_readable_file(fp); |
@@ -2964,12 +3042,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | |||
2964 | return 0; | 3042 | return 0; |
2965 | } | 3043 | } |
2966 | 3044 | ||
2967 | static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | 3045 | static int nfs4_set_delegation(struct nfs4_delegation *dp) |
2968 | { | 3046 | { |
2969 | struct nfs4_file *fp = dp->dl_file; | 3047 | struct nfs4_file *fp = dp->dl_file; |
2970 | 3048 | ||
2971 | if (!fp->fi_lease) | 3049 | if (!fp->fi_lease) |
2972 | return nfs4_setlease(dp, flag); | 3050 | return nfs4_setlease(dp); |
2973 | spin_lock(&recall_lock); | 3051 | spin_lock(&recall_lock); |
2974 | if (fp->fi_had_conflict) { | 3052 | if (fp->fi_had_conflict) { |
2975 | spin_unlock(&recall_lock); | 3053 | spin_unlock(&recall_lock); |
@@ -3005,6 +3083,9 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | |||
3005 | 3083 | ||
3006 | /* | 3084 | /* |
3007 | * Attempt to hand out a delegation. | 3085 | * Attempt to hand out a delegation. |
3086 | * | ||
3087 | * Note we don't support write delegations, and won't until the vfs has | ||
3088 | * proper support for them. | ||
3008 | */ | 3089 | */ |
3009 | static void | 3090 | static void |
3010 | nfs4_open_delegation(struct net *net, struct svc_fh *fh, | 3091 | nfs4_open_delegation(struct net *net, struct svc_fh *fh, |
@@ -3013,39 +3094,45 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3013 | struct nfs4_delegation *dp; | 3094 | struct nfs4_delegation *dp; |
3014 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); | 3095 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); |
3015 | int cb_up; | 3096 | int cb_up; |
3016 | int status = 0, flag = 0; | 3097 | int status = 0; |
3017 | 3098 | ||
3018 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); | 3099 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); |
3019 | flag = NFS4_OPEN_DELEGATE_NONE; | ||
3020 | open->op_recall = 0; | 3100 | open->op_recall = 0; |
3021 | switch (open->op_claim_type) { | 3101 | switch (open->op_claim_type) { |
3022 | case NFS4_OPEN_CLAIM_PREVIOUS: | 3102 | case NFS4_OPEN_CLAIM_PREVIOUS: |
3023 | if (!cb_up) | 3103 | if (!cb_up) |
3024 | open->op_recall = 1; | 3104 | open->op_recall = 1; |
3025 | flag = open->op_delegate_type; | 3105 | if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) |
3026 | if (flag == NFS4_OPEN_DELEGATE_NONE) | 3106 | goto out_no_deleg; |
3027 | goto out; | ||
3028 | break; | 3107 | break; |
3029 | case NFS4_OPEN_CLAIM_NULL: | 3108 | case NFS4_OPEN_CLAIM_NULL: |
3030 | /* Let's not give out any delegations till everyone's | 3109 | /* |
3031 | * had the chance to reclaim theirs.... */ | 3110 | * Let's not give out any delegations till everyone's |
3111 | * had the chance to reclaim theirs.... | ||
3112 | */ | ||
3032 | if (locks_in_grace(net)) | 3113 | if (locks_in_grace(net)) |
3033 | goto out; | 3114 | goto out_no_deleg; |
3034 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) | 3115 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) |
3035 | goto out; | 3116 | goto out_no_deleg; |
3117 | /* | ||
3118 | * Also, if the file was opened for write or | ||
3119 | * create, there's a good chance the client's | ||
3120 | * about to write to it, resulting in an | ||
3121 | * immediate recall (since we don't support | ||
3122 | * write delegations): | ||
3123 | */ | ||
3036 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 3124 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
3037 | flag = NFS4_OPEN_DELEGATE_WRITE; | 3125 | goto out_no_deleg; |
3038 | else | 3126 | if (open->op_create == NFS4_OPEN_CREATE) |
3039 | flag = NFS4_OPEN_DELEGATE_READ; | 3127 | goto out_no_deleg; |
3040 | break; | 3128 | break; |
3041 | default: | 3129 | default: |
3042 | goto out; | 3130 | goto out_no_deleg; |
3043 | } | 3131 | } |
3044 | 3132 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh); | |
3045 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag); | ||
3046 | if (dp == NULL) | 3133 | if (dp == NULL) |
3047 | goto out_no_deleg; | 3134 | goto out_no_deleg; |
3048 | status = nfs4_set_delegation(dp, flag); | 3135 | status = nfs4_set_delegation(dp); |
3049 | if (status) | 3136 | if (status) |
3050 | goto out_free; | 3137 | goto out_free; |
3051 | 3138 | ||
@@ -3053,24 +3140,23 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
3053 | 3140 | ||
3054 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", | 3141 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", |
3055 | STATEID_VAL(&dp->dl_stid.sc_stateid)); | 3142 | STATEID_VAL(&dp->dl_stid.sc_stateid)); |
3056 | out: | 3143 | open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; |
3057 | open->op_delegate_type = flag; | ||
3058 | if (flag == NFS4_OPEN_DELEGATE_NONE) { | ||
3059 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && | ||
3060 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
3061 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
3062 | |||
3063 | /* 4.1 client asking for a delegation? */ | ||
3064 | if (open->op_deleg_want) | ||
3065 | nfsd4_open_deleg_none_ext(open, status); | ||
3066 | } | ||
3067 | return; | 3144 | return; |
3068 | out_free: | 3145 | out_free: |
3069 | unhash_stid(&dp->dl_stid); | 3146 | unhash_stid(&dp->dl_stid); |
3070 | nfs4_put_delegation(dp); | 3147 | nfs4_put_delegation(dp); |
3071 | out_no_deleg: | 3148 | out_no_deleg: |
3072 | flag = NFS4_OPEN_DELEGATE_NONE; | 3149 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; |
3073 | goto out; | 3150 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && |
3151 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { | ||
3152 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
3153 | open->op_recall = 1; | ||
3154 | } | ||
3155 | |||
3156 | /* 4.1 client asking for a delegation? */ | ||
3157 | if (open->op_deleg_want) | ||
3158 | nfsd4_open_deleg_none_ext(open, status); | ||
3159 | return; | ||
3074 | } | 3160 | } |
3075 | 3161 | ||
3076 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, | 3162 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, |
@@ -3427,7 +3513,7 @@ grace_disallows_io(struct net *net, struct inode *inode) | |||
3427 | /* Returns true iff a is later than b: */ | 3513 | /* Returns true iff a is later than b: */ |
3428 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) | 3514 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) |
3429 | { | 3515 | { |
3430 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3516 | return (s32)(a->si_generation - b->si_generation) > 0; |
3431 | } | 3517 | } |
3432 | 3518 | ||
3433 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3519 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) |
@@ -4435,7 +4521,6 @@ __be32 | |||
4435 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 4521 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
4436 | struct nfsd4_locku *locku) | 4522 | struct nfsd4_locku *locku) |
4437 | { | 4523 | { |
4438 | struct nfs4_lockowner *lo; | ||
4439 | struct nfs4_ol_stateid *stp; | 4524 | struct nfs4_ol_stateid *stp; |
4440 | struct file *filp = NULL; | 4525 | struct file *filp = NULL; |
4441 | struct file_lock *file_lock = NULL; | 4526 | struct file_lock *file_lock = NULL; |
@@ -4468,10 +4553,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4468 | status = nfserr_jukebox; | 4553 | status = nfserr_jukebox; |
4469 | goto out; | 4554 | goto out; |
4470 | } | 4555 | } |
4471 | lo = lockowner(stp->st_stateowner); | ||
4472 | locks_init_lock(file_lock); | 4556 | locks_init_lock(file_lock); |
4473 | file_lock->fl_type = F_UNLCK; | 4557 | file_lock->fl_type = F_UNLCK; |
4474 | file_lock->fl_owner = (fl_owner_t)lo; | 4558 | file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); |
4475 | file_lock->fl_pid = current->tgid; | 4559 | file_lock->fl_pid = current->tgid; |
4476 | file_lock->fl_file = filp; | 4560 | file_lock->fl_file = filp; |
4477 | file_lock->fl_flags = FL_POSIX; | 4561 | file_lock->fl_flags = FL_POSIX; |
@@ -4490,11 +4574,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4490 | update_stateid(&stp->st_stid.sc_stateid); | 4574 | update_stateid(&stp->st_stid.sc_stateid); |
4491 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 4575 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
4492 | 4576 | ||
4493 | if (nfsd4_has_session(cstate) && !check_for_locks(stp->st_file, lo)) { | ||
4494 | WARN_ON_ONCE(cstate->replay_owner); | ||
4495 | release_lockowner(lo); | ||
4496 | } | ||
4497 | |||
4498 | out: | 4577 | out: |
4499 | nfsd4_bump_seqid(cstate, status); | 4578 | nfsd4_bump_seqid(cstate, status); |
4500 | if (!cstate->replay_owner) | 4579 | if (!cstate->replay_owner) |
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 | } |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index c0d93170585d..2bbd94e51efc 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -24,7 +24,7 @@ | |||
24 | /* | 24 | /* |
25 | * nfsd version | 25 | * nfsd version |
26 | */ | 26 | */ |
27 | #define NFSD_SUPPORTED_MINOR_VERSION 1 | 27 | #define NFSD_SUPPORTED_MINOR_VERSION 2 |
28 | /* | 28 | /* |
29 | * Maximum blocksizes supported by daemon under various circumstances. | 29 | * Maximum blocksizes supported by daemon under various circumstances. |
30 | */ | 30 | */ |
@@ -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/nfssvc.c b/fs/nfsd/nfssvc.c index 262df5ccbf59..6b9f48ca4c25 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -116,7 +116,7 @@ struct svc_program nfsd_program = { | |||
116 | 116 | ||
117 | }; | 117 | }; |
118 | 118 | ||
119 | u32 nfsd_supported_minorversion; | 119 | u32 nfsd_supported_minorversion = 1; |
120 | 120 | ||
121 | int nfsd_vers(int vers, enum vers_op change) | 121 | int nfsd_vers(int vers, enum vers_op change) |
122 | { | 122 | { |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 274e2a114e05..424d8f5f2317 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -246,6 +246,7 @@ struct nfs4_client { | |||
246 | nfs4_verifier cl_verifier; /* generated by client */ | 246 | nfs4_verifier cl_verifier; /* generated by client */ |
247 | time_t cl_time; /* time of last lease renewal */ | 247 | time_t cl_time; /* time of last lease renewal */ |
248 | struct sockaddr_storage cl_addr; /* client ipaddress */ | 248 | struct sockaddr_storage cl_addr; /* client ipaddress */ |
249 | bool cl_mach_cred; /* SP4_MACH_CRED in force */ | ||
249 | struct svc_cred cl_cred; /* setclientid principal */ | 250 | struct svc_cred cl_cred; /* setclientid principal */ |
250 | clientid_t cl_clientid; /* generated by server */ | 251 | clientid_t cl_clientid; /* generated by server */ |
251 | nfs4_verifier cl_confirm; /* generated by server */ | 252 | nfs4_verifier cl_confirm; /* generated by server */ |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a6bc8a7423db..8ff6a0019b0b 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 5b5894159f22..a4be2e389670 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -39,7 +39,6 @@ | |||
39 | typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); | 39 | typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); |
40 | 40 | ||
41 | /* nfsd/vfs.c */ | 41 | /* nfsd/vfs.c */ |
42 | int fh_lock_parent(struct svc_fh *, struct dentry *); | ||
43 | int nfsd_racache_init(int); | 42 | int nfsd_racache_init(int); |
44 | void nfsd_racache_shutdown(void); | 43 | void nfsd_racache_shutdown(void); |
45 | int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | 44 | int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, |
@@ -56,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *); | |||
56 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, | 55 | __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, |
57 | struct nfs4_acl *); | 56 | struct nfs4_acl *); |
58 | 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 *); | ||
59 | #endif /* CONFIG_NFSD_V4 */ | 60 | #endif /* CONFIG_NFSD_V4 */ |
60 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, | 61 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, |
61 | char *name, int len, struct iattr *attrs, | 62 | char *name, int len, struct iattr *attrs, |
@@ -92,17 +93,13 @@ __be32 nfsd_remove(struct svc_rqst *, | |||
92 | struct svc_fh *, char *, int); | 93 | struct svc_fh *, char *, int); |
93 | __be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, | 94 | __be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type, |
94 | char *name, int len); | 95 | char *name, int len); |
95 | int nfsd_truncate(struct svc_rqst *, struct svc_fh *, | ||
96 | unsigned long size); | ||
97 | __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, | 96 | __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, |
98 | loff_t *, struct readdir_cd *, filldir_t); | 97 | loff_t *, struct readdir_cd *, filldir_t); |
99 | __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, | 98 | __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, |
100 | struct kstatfs *, int access); | 99 | struct kstatfs *, int access); |
101 | 100 | ||
102 | int nfsd_notify_change(struct inode *, struct iattr *); | ||
103 | __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, | 101 | __be32 nfsd_permission(struct svc_rqst *, struct svc_export *, |
104 | struct dentry *, int); | 102 | struct dentry *, int); |
105 | int nfsd_sync_dir(struct dentry *dp); | ||
106 | 103 | ||
107 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 104 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
108 | struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); | 105 | struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); |
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 { |