diff options
Diffstat (limited to 'linux-2.6-nfsd4-proots.patch')
-rw-r--r-- | linux-2.6-nfsd4-proots.patch | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/linux-2.6-nfsd4-proots.patch b/linux-2.6-nfsd4-proots.patch new file mode 100644 index 0000000..84d5894 --- /dev/null +++ b/linux-2.6-nfsd4-proots.patch @@ -0,0 +1,226 @@ +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 \ |