aboutsummaryrefslogtreecommitdiff
path: root/fs/nfsd/export.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/export.c')
-rw-r--r--fs/nfsd/export.c57
1 files changed, 49 insertions, 8 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c82d8e3e0d4f..eacafe46e3b6 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -40,15 +40,24 @@
#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
-static void expkey_put(struct kref *ref)
+static void expkey_put_work(struct work_struct *work)
{
- struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
+ struct svc_expkey *key =
+ container_of(to_rcu_work(work), struct svc_expkey, ek_rcu_work);
if (test_bit(CACHE_VALID, &key->h.flags) &&
!test_bit(CACHE_NEGATIVE, &key->h.flags))
path_put(&key->ek_path);
auth_domain_put(key->ek_client);
- kfree_rcu(key, ek_rcu);
+ kfree(key);
+}
+
+static void expkey_put(struct kref *ref)
+{
+ struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
+
+ INIT_RCU_WORK(&key->ek_rcu_work, expkey_put_work);
+ queue_rcu_work(system_wq, &key->ek_rcu_work);
}
static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
@@ -355,16 +364,26 @@ static void export_stats_destroy(struct export_stats *stats)
EXP_STATS_COUNTERS_NUM);
}
-static void svc_export_put(struct kref *ref)
+static void svc_export_put_work(struct work_struct *work)
{
- struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
+ struct svc_export *exp =
+ container_of(to_rcu_work(work), struct svc_export, ex_rcu_work);
+
path_put(&exp->ex_path);
auth_domain_put(exp->ex_client);
nfsd4_fslocs_free(&exp->ex_fslocs);
export_stats_destroy(exp->ex_stats);
kfree(exp->ex_stats);
kfree(exp->ex_uuid);
- kfree_rcu(exp, ex_rcu);
+ kfree(exp);
+}
+
+static void svc_export_put(struct kref *ref)
+{
+ struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
+
+ INIT_RCU_WORK(&exp->ex_rcu_work, svc_export_put_work);
+ queue_rcu_work(system_wq, &exp->ex_rcu_work);
}
static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
@@ -1078,12 +1097,14 @@ static struct svc_export *exp_find(struct cache_detail *cd,
* check_nfsd_access - check if access to export is allowed.
* @exp: svc_export that is being accessed.
* @rqstp: svc_rqst attempting to access @exp (will be NULL for LOCALIO).
+ * @may_bypass_gss: reduce strictness of authorization check
*
* Return values:
* %nfs_ok if access is granted, or
* %nfserr_wrongsec if access is denied
*/
-__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
+__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
+ bool may_bypass_gss)
{
struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
struct svc_xprt *xprt;
@@ -1140,6 +1161,23 @@ ok:
if (nfsd4_spo_must_allow(rqstp))
return nfs_ok;
+ /* Some calls may be processed without authentication
+ * on GSS exports. For example NFS2/3 calls on root
+ * directory, see section 2.3.2 of rfc 2623.
+ * For "may_bypass_gss" check that export has really
+ * enabled some flavor with authentication (GSS or any
+ * other) and also check that the used auth flavor is
+ * without authentication (none or sys).
+ */
+ if (may_bypass_gss && (
+ rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
+ rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
+ for (f = exp->ex_flavors; f < end; f++) {
+ if (f->pseudoflavor >= RPC_AUTH_DES)
+ return 0;
+ }
+ }
+
denied:
return nfserr_wrongsec;
}
@@ -1406,9 +1444,12 @@ static int e_show(struct seq_file *m, void *p)
return 0;
}
- exp_get(exp);
+ if (!cache_get_rcu(&exp->h))
+ return 0;
+
if (cache_check(cd, &exp->h, NULL))
return 0;
+
exp_put(exp);
return svc_export_show(m, cd, cp);
}