227 lines
8.1 KiB
Diff
227 lines
8.1 KiB
Diff
|
diff -up linux-2.6.32.i686/fs/nfsd/export.c.save linux-2.6.32.i686/fs/nfsd/export.c
|
||
|
--- linux-2.6.32.i686/fs/nfsd/export.c.save 2009-12-04 10:24:17.000000000 -0500
|
||
|
+++ linux-2.6.32.i686/fs/nfsd/export.c 2009-12-04 10:40:52.000000000 -0500
|
||
|
@@ -372,10 +372,12 @@ static struct svc_export *svc_export_loo
|
||
|
static int check_export(struct inode *inode, int flags, unsigned char *uuid)
|
||
|
{
|
||
|
|
||
|
- /* We currently export only dirs and regular files.
|
||
|
- * This is what umountd does.
|
||
|
+ /*
|
||
|
+ * We currently export only dirs, regular files, and (for v4
|
||
|
+ * pseudoroot) symlinks.
|
||
|
*/
|
||
|
if (!S_ISDIR(inode->i_mode) &&
|
||
|
+ !S_ISLNK(inode->i_mode) &&
|
||
|
!S_ISREG(inode->i_mode))
|
||
|
return -ENOTDIR;
|
||
|
|
||
|
@@ -1425,6 +1427,7 @@ static struct flags {
|
||
|
{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
|
||
|
{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
|
||
|
{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
|
||
|
+ { NFSEXP_V4ROOT, {"v4root", ""}},
|
||
|
#ifdef MSNFS
|
||
|
{ NFSEXP_MSNFS, {"msnfs", ""}},
|
||
|
#endif
|
||
|
@@ -1505,7 +1508,7 @@ static int e_show(struct seq_file *m, vo
|
||
|
struct svc_export *exp = container_of(cp, struct svc_export, h);
|
||
|
|
||
|
if (p == SEQ_START_TOKEN) {
|
||
|
- seq_puts(m, "# Version 1.1\n");
|
||
|
+ seq_puts(m, "# Version 1.2\n");
|
||
|
seq_puts(m, "# Path Client(Flags) # IPs\n");
|
||
|
return 0;
|
||
|
}
|
||
|
diff -up linux-2.6.32.i686/fs/nfsd/nfs4xdr.c.save linux-2.6.32.i686/fs/nfsd/nfs4xdr.c
|
||
|
--- linux-2.6.32.i686/fs/nfsd/nfs4xdr.c.save 2009-12-04 10:24:17.000000000 -0500
|
||
|
+++ linux-2.6.32.i686/fs/nfsd/nfs4xdr.c 2009-12-04 10:26:49.000000000 -0500
|
||
|
@@ -2204,11 +2204,14 @@ nfsd4_encode_dirent_fattr(struct nfsd4_r
|
||
|
* we will not follow the cross mount and will fill the attribtutes
|
||
|
* directly from the mountpoint dentry.
|
||
|
*/
|
||
|
- if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
|
||
|
- ignore_crossmnt = 1;
|
||
|
- else if (d_mountpoint(dentry)) {
|
||
|
+ if (nfsd_mountpoint(dentry, exp)) {
|
||
|
int err;
|
||
|
|
||
|
+ if (!(exp->ex_flags & NFSEXP_V4ROOT)
|
||
|
+ && !attributes_need_mount(cd->rd_bmval)) {
|
||
|
+ ignore_crossmnt = 1;
|
||
|
+ goto out_encode;
|
||
|
+ }
|
||
|
/*
|
||
|
* Why the heck aren't we just using nfsd_lookup??
|
||
|
* Different "."/".." handling? Something else?
|
||
|
@@ -2224,6 +2227,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_r
|
||
|
goto out_put;
|
||
|
|
||
|
}
|
||
|
+out_encode:
|
||
|
nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
|
||
|
cd->rd_rqstp, ignore_crossmnt);
|
||
|
out_put:
|
||
|
diff -up linux-2.6.32.i686/fs/nfsd/nfsfh.c.save linux-2.6.32.i686/fs/nfsd/nfsfh.c
|
||
|
--- linux-2.6.32.i686/fs/nfsd/nfsfh.c.save 2009-12-04 10:24:17.000000000 -0500
|
||
|
+++ linux-2.6.32.i686/fs/nfsd/nfsfh.c 2009-12-04 10:38:26.000000000 -0500
|
||
|
@@ -109,6 +109,36 @@ static __be32 nfsd_setuser_and_check_por
|
||
|
return nfserrno(nfsd_setuser(rqstp, exp));
|
||
|
}
|
||
|
|
||
|
+static inline __be32 check_pseudo_root(struct svc_rqst *rqstp,
|
||
|
+ struct dentry *dentry, struct svc_export *exp)
|
||
|
+{
|
||
|
+ if (!(exp->ex_flags & NFSEXP_V4ROOT))
|
||
|
+ return nfs_ok;
|
||
|
+ /*
|
||
|
+ * v2/v3 clients have no need for the V4ROOT export--they use
|
||
|
+ * the mount protocl instead; also, further V4ROOT checks may be
|
||
|
+ * in v4-specific code, in which case v2/v3 clients could bypass
|
||
|
+ * them.
|
||
|
+ */
|
||
|
+ if (!nfsd_v4client(rqstp))
|
||
|
+ return nfserr_stale;
|
||
|
+ /*
|
||
|
+ * We're exposing only the directories and symlinks that have to be
|
||
|
+ * traversed on the way to real exports:
|
||
|
+ */
|
||
|
+ if (unlikely(!S_ISDIR(dentry->d_inode->i_mode) &&
|
||
|
+ !S_ISLNK(dentry->d_inode->i_mode)))
|
||
|
+ return nfserr_stale;
|
||
|
+ /*
|
||
|
+ * A pseudoroot export gives permission to access only one
|
||
|
+ * single directory; the kernel has to make another upcall
|
||
|
+ * before granting access to anything else under it:
|
||
|
+ */
|
||
|
+ if (unlikely(dentry != exp->ex_path.dentry))
|
||
|
+ return nfserr_stale;
|
||
|
+ return nfs_ok;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* Use the given filehandle to look up the corresponding export and
|
||
|
* dentry. On success, the results are used to set fh_export and
|
||
|
@@ -317,6 +347,13 @@ fh_verify(struct svc_rqst *rqstp, struct
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
+ /*
|
||
|
+ * Do some spoof checking if we are on the pseudo root
|
||
|
+ */
|
||
|
+ error = check_pseudo_root(rqstp, dentry, exp);
|
||
|
+ if (error)
|
||
|
+ goto out;
|
||
|
+
|
||
|
error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type);
|
||
|
if (error)
|
||
|
goto out;
|
||
|
diff -up linux-2.6.32.i686/fs/nfsd/vfs.c.save linux-2.6.32.i686/fs/nfsd/vfs.c
|
||
|
--- linux-2.6.32.i686/fs/nfsd/vfs.c.save 2009-12-04 10:24:18.000000000 -0500
|
||
|
+++ linux-2.6.32.i686/fs/nfsd/vfs.c 2009-12-04 10:35:04.000000000 -0500
|
||
|
@@ -89,12 +89,6 @@ struct raparm_hbucket {
|
||
|
#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
|
||
|
static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
|
||
|
|
||
|
-static inline int
|
||
|
-nfsd_v4client(struct svc_rqst *rq)
|
||
|
-{
|
||
|
- return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
|
||
|
-}
|
||
|
-
|
||
|
/*
|
||
|
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
|
||
|
* a mount point.
|
||
|
@@ -116,8 +110,16 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, s
|
||
|
|
||
|
exp2 = rqst_exp_get_by_name(rqstp, &path);
|
||
|
if (IS_ERR(exp2)) {
|
||
|
- if (PTR_ERR(exp2) != -ENOENT)
|
||
|
- err = PTR_ERR(exp2);
|
||
|
+ err = PTR_ERR(exp2);
|
||
|
+ /*
|
||
|
+ * We normally allow NFS clients to continue
|
||
|
+ * "underneath" a mountpoint that is not exported.
|
||
|
+ * The exception is V4ROOT, where no traversal is ever
|
||
|
+ * allowed without an explicit export of the new
|
||
|
+ * directory.
|
||
|
+ */
|
||
|
+ if (err == -ENOENT && !(exp->ex_flags & NFSEXP_V4ROOT))
|
||
|
+ err = 0;
|
||
|
path_put(&path);
|
||
|
goto out;
|
||
|
}
|
||
|
@@ -141,6 +143,19 @@ out:
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * For nfsd purposes, we treat V4ROOT exports as though there was an
|
||
|
+ * export at *every* directory.
|
||
|
+ */
|
||
|
+int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp)
|
||
|
+{
|
||
|
+ if (d_mountpoint(dentry))
|
||
|
+ return 1;
|
||
|
+ if (!(exp->ex_flags & NFSEXP_V4ROOT))
|
||
|
+ return 0;
|
||
|
+ return dentry->d_inode != NULL;
|
||
|
+}
|
||
|
+
|
||
|
__be32
|
||
|
nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||
|
const char *name, unsigned int len,
|
||
|
@@ -208,7 +223,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqst
|
||
|
/*
|
||
|
* check if we have crossed a mount point ...
|
||
|
*/
|
||
|
- if (d_mountpoint(dentry)) {
|
||
|
+ if (nfsd_mountpoint(dentry, exp)) {
|
||
|
if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
|
||
|
dput(dentry);
|
||
|
goto out_nfserr;
|
||
|
diff -up linux-2.6.32.i686/include/linux/nfsd/export.h.save linux-2.6.32.i686/include/linux/nfsd/export.h
|
||
|
--- linux-2.6.32.i686/include/linux/nfsd/export.h.save 2009-12-04 10:24:18.000000000 -0500
|
||
|
+++ linux-2.6.32.i686/include/linux/nfsd/export.h 2009-12-04 10:25:08.000000000 -0500
|
||
|
@@ -39,7 +39,17 @@
|
||
|
#define NFSEXP_FSID 0x2000
|
||
|
#define NFSEXP_CROSSMOUNT 0x4000
|
||
|
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
|
||
|
-#define NFSEXP_ALLFLAGS 0xFE3F
|
||
|
+/*
|
||
|
+ * The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4
|
||
|
+ * clients, and only to the single directory that is the root of the
|
||
|
+ * export; further lookup and readdir operations are treated as if every
|
||
|
+ * subdirectory was a mountpoint, and ignored if they are not themselves
|
||
|
+ * exported. This is used by nfsd and mountd to construct the NFSv4
|
||
|
+ * pseudofilesystem, which provides access only to paths leading to each
|
||
|
+ * exported filesystem.
|
||
|
+ */
|
||
|
+#define NFSEXP_V4ROOT 0x10000
|
||
|
+#define NFSEXP_ALLFLAGS 0x1FE3F
|
||
|
|
||
|
/* The flags that may vary depending on security flavor: */
|
||
|
#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
|
||
|
diff -up linux-2.6.32.i686/include/linux/nfsd/nfsd.h.save linux-2.6.32.i686/include/linux/nfsd/nfsd.h
|
||
|
--- linux-2.6.32.i686/include/linux/nfsd/nfsd.h.save 2009-12-04 10:24:18.000000000 -0500
|
||
|
+++ linux-2.6.32.i686/include/linux/nfsd/nfsd.h 2009-12-04 10:39:18.000000000 -0500
|
||
|
@@ -86,6 +86,7 @@ __be32 nfsd_lookup_dentry(struct svc_r
|
||
|
struct svc_export **, struct dentry **);
|
||
|
__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
|
||
|
struct iattr *, int, time_t);
|
||
|
+int nfsd_mountpoint(struct dentry *, struct svc_export *);
|
||
|
#ifdef CONFIG_NFSD_V4
|
||
|
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
|
||
|
struct nfs4_acl *);
|
||
|
@@ -394,6 +395,10 @@ static inline u32 nfsd_suppattrs2(u32 mi
|
||
|
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
|
||
|
: NFSD4_SUPPORTED_ATTRS_WORD2;
|
||
|
}
|
||
|
+static inline int nfsd_v4client(struct svc_rqst *rq)
|
||
|
+{
|
||
|
+ return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
|
||
|
+}
|
||
|
|
||
|
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
|
||
|
#define NFSD_WRITEONLY_ATTRS_WORD1 \
|