diff options
Diffstat (limited to 'fs/nfs/nfs4namespace.c')
-rw-r--r-- | fs/nfs/nfs4namespace.c | 110 |
1 files changed, 85 insertions, 25 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index faed9bcba50f..24e47f3bbd17 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * linux/fs/nfs/nfs4namespace.c | 2 | * linux/fs/nfs/nfs4namespace.c |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> | 4 | * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> |
5 | * - Modified by David Howells <dhowells@redhat.com> | ||
5 | * | 6 | * |
6 | * NFSv4 namespace | 7 | * NFSv4 namespace |
7 | */ | 8 | */ |
@@ -47,6 +48,68 @@ Elong: | |||
47 | return ERR_PTR(-ENAMETOOLONG); | 48 | return ERR_PTR(-ENAMETOOLONG); |
48 | } | 49 | } |
49 | 50 | ||
51 | /* | ||
52 | * Determine the mount path as a string | ||
53 | */ | ||
54 | static char *nfs4_path(const struct vfsmount *mnt_parent, | ||
55 | const struct dentry *dentry, | ||
56 | char *buffer, ssize_t buflen) | ||
57 | { | ||
58 | const char *srvpath; | ||
59 | |||
60 | srvpath = strchr(mnt_parent->mnt_devname, ':'); | ||
61 | if (srvpath) | ||
62 | srvpath++; | ||
63 | else | ||
64 | srvpath = mnt_parent->mnt_devname; | ||
65 | |||
66 | return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we | ||
71 | * believe to be the server path to this dentry | ||
72 | */ | ||
73 | static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | ||
74 | const struct dentry *dentry, | ||
75 | const struct nfs4_fs_locations *locations, | ||
76 | char *page, char *page2) | ||
77 | { | ||
78 | const char *path, *fs_path; | ||
79 | |||
80 | path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE); | ||
81 | if (IS_ERR(path)) | ||
82 | return PTR_ERR(path); | ||
83 | |||
84 | fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | ||
85 | if (IS_ERR(fs_path)) | ||
86 | return PTR_ERR(fs_path); | ||
87 | |||
88 | if (strncmp(path, fs_path, strlen(fs_path)) != 0) { | ||
89 | dprintk("%s: path %s does not begin with fsroot %s\n", | ||
90 | __FUNCTION__, path, fs_path); | ||
91 | return -ENOENT; | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Check if the string represents a "valid" IPv4 address | ||
99 | */ | ||
100 | static inline int valid_ipaddr4(const char *buf) | ||
101 | { | ||
102 | int rc, count, in[4]; | ||
103 | |||
104 | rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); | ||
105 | if (rc != 4) | ||
106 | return -EINVAL; | ||
107 | for (count = 0; count < 4; count++) { | ||
108 | if (in[count] > 255) | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
50 | 113 | ||
51 | /** | 114 | /** |
52 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error | 115 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
@@ -68,10 +131,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
68 | .dentry = dentry, | 131 | .dentry = dentry, |
69 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 132 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, |
70 | }; | 133 | }; |
71 | char *page, *page2; | 134 | char *page = NULL, *page2 = NULL; |
72 | char *path, *fs_path; | ||
73 | char *devname; | 135 | char *devname; |
74 | int loc, s; | 136 | int loc, s, error; |
75 | 137 | ||
76 | if (locations == NULL || locations->nlocations <= 0) | 138 | if (locations == NULL || locations->nlocations <= 0) |
77 | goto out; | 139 | goto out; |
@@ -79,31 +141,25 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
79 | dprintk("%s: referral at %s/%s\n", __FUNCTION__, | 141 | dprintk("%s: referral at %s/%s\n", __FUNCTION__, |
80 | dentry->d_parent->d_name.name, dentry->d_name.name); | 142 | dentry->d_parent->d_name.name, dentry->d_name.name); |
81 | 143 | ||
82 | /* Ensure fs path is a prefix of current dentry path */ | ||
83 | page = (char *) __get_free_page(GFP_USER); | 144 | page = (char *) __get_free_page(GFP_USER); |
84 | if (page == NULL) | 145 | if (!page) |
85 | goto out; | 146 | goto out; |
147 | |||
86 | page2 = (char *) __get_free_page(GFP_USER); | 148 | page2 = (char *) __get_free_page(GFP_USER); |
87 | if (page2 == NULL) | 149 | if (!page2) |
88 | goto out; | 150 | goto out; |
89 | 151 | ||
90 | path = nfs4_path(dentry, page, PAGE_SIZE); | 152 | /* Ensure fs path is a prefix of current dentry path */ |
91 | if (IS_ERR(path)) | 153 | error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2); |
92 | goto out_free; | 154 | if (error < 0) { |
93 | 155 | mnt = ERR_PTR(error); | |
94 | fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | 156 | goto out; |
95 | if (IS_ERR(fs_path)) | ||
96 | goto out_free; | ||
97 | |||
98 | if (strncmp(path, fs_path, strlen(fs_path)) != 0) { | ||
99 | dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path); | ||
100 | goto out_free; | ||
101 | } | 157 | } |
102 | 158 | ||
103 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); | 159 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); |
104 | if (IS_ERR(devname)) { | 160 | if (IS_ERR(devname)) { |
105 | mnt = (struct vfsmount *)devname; | 161 | mnt = (struct vfsmount *)devname; |
106 | goto out_free; | 162 | goto out; |
107 | } | 163 | } |
108 | 164 | ||
109 | loc = 0; | 165 | loc = 0; |
@@ -140,7 +196,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
140 | addr.sin_port = htons(NFS_PORT); | 196 | addr.sin_port = htons(NFS_PORT); |
141 | mountdata.addr = &addr; | 197 | mountdata.addr = &addr; |
142 | 198 | ||
143 | mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata); | 199 | mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata); |
144 | if (!IS_ERR(mnt)) { | 200 | if (!IS_ERR(mnt)) { |
145 | break; | 201 | break; |
146 | } | 202 | } |
@@ -149,10 +205,9 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
149 | loc++; | 205 | loc++; |
150 | } | 206 | } |
151 | 207 | ||
152 | out_free: | ||
153 | free_page((unsigned long)page); | ||
154 | free_page((unsigned long)page2); | ||
155 | out: | 208 | out: |
209 | free_page((unsigned long) page); | ||
210 | free_page((unsigned long) page2); | ||
156 | dprintk("%s: done\n", __FUNCTION__); | 211 | dprintk("%s: done\n", __FUNCTION__); |
157 | return mnt; | 212 | return mnt; |
158 | } | 213 | } |
@@ -165,7 +220,7 @@ out: | |||
165 | */ | 220 | */ |
166 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | 221 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) |
167 | { | 222 | { |
168 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 223 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
169 | struct dentry *parent; | 224 | struct dentry *parent; |
170 | struct nfs4_fs_locations *fs_locations = NULL; | 225 | struct nfs4_fs_locations *fs_locations = NULL; |
171 | struct page *page; | 226 | struct page *page; |
@@ -183,11 +238,16 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr | |||
183 | goto out_free; | 238 | goto out_free; |
184 | 239 | ||
185 | /* Get locations */ | 240 | /* Get locations */ |
241 | mnt = ERR_PTR(-ENOENT); | ||
242 | |||
186 | parent = dget_parent(dentry); | 243 | parent = dget_parent(dentry); |
187 | dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name); | 244 | dprintk("%s: getting locations for %s/%s\n", |
245 | __FUNCTION__, parent->d_name.name, dentry->d_name.name); | ||
246 | |||
188 | err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); | 247 | err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page); |
189 | dput(parent); | 248 | dput(parent); |
190 | if (err != 0 || fs_locations->nlocations <= 0 || | 249 | if (err != 0 || |
250 | fs_locations->nlocations <= 0 || | ||
191 | fs_locations->fs_path.ncomponents <= 0) | 251 | fs_locations->fs_path.ncomponents <= 0) |
192 | goto out_free; | 252 | goto out_free; |
193 | 253 | ||