aboutsummaryrefslogtreecommitdiffstats
path: root/fs/romfs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-04-23 11:41:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-24 16:28:31 -0400
commit84baf74bf23bbe9f3deafb5d2f27e2b5dc0bc052 (patch)
tree45af84d051ca760a9f9f24aa3775e5505ccd3627 /fs/romfs
parenta5422a5111811401f7756345e4c237ff06cf6d1e (diff)
ROMFS: romfs_lookup() shouldn't be doing a partial name comparison
romfs_lookup() should be using a routine akin to strcmp() on the backing store, rather than one akin to strncmp(). If it uses the latter, it's liable to match /bin/shutdown when looking up /bin/sh. Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Michal Simek <monstr@monstr.eu> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/romfs')
-rw-r--r--fs/romfs/internal.h4
-rw-r--r--fs/romfs/storage.c67
-rw-r--r--fs/romfs/super.c4
3 files changed, 53 insertions, 22 deletions
diff --git a/fs/romfs/internal.h b/fs/romfs/internal.h
index 06044a9dc62d..95217b830118 100644
--- a/fs/romfs/internal.h
+++ b/fs/romfs/internal.h
@@ -43,5 +43,5 @@ extern int romfs_dev_read(struct super_block *sb, unsigned long pos,
43 void *buf, size_t buflen); 43 void *buf, size_t buflen);
44extern ssize_t romfs_dev_strnlen(struct super_block *sb, 44extern ssize_t romfs_dev_strnlen(struct super_block *sb,
45 unsigned long pos, size_t maxlen); 45 unsigned long pos, size_t maxlen);
46extern int romfs_dev_strncmp(struct super_block *sb, unsigned long pos, 46extern int romfs_dev_strcmp(struct super_block *sb, unsigned long pos,
47 const char *str, size_t size); 47 const char *str, size_t size);
diff --git a/fs/romfs/storage.c b/fs/romfs/storage.c
index 7e3e1e12a081..66ce9ddfe504 100644
--- a/fs/romfs/storage.c
+++ b/fs/romfs/storage.c
@@ -67,26 +67,35 @@ static ssize_t romfs_mtd_strnlen(struct super_block *sb,
67 * compare a string to one in a romfs image on MTD 67 * compare a string to one in a romfs image on MTD
68 * - return 1 if matched, 0 if differ, -ve if error 68 * - return 1 if matched, 0 if differ, -ve if error
69 */ 69 */
70static int romfs_mtd_strncmp(struct super_block *sb, unsigned long pos, 70static int romfs_mtd_strcmp(struct super_block *sb, unsigned long pos,
71 const char *str, size_t size) 71 const char *str, size_t size)
72{ 72{
73 u_char buf[16]; 73 u_char buf[17];
74 size_t len, segment; 74 size_t len, segment;
75 int ret; 75 int ret;
76 76
77 /* scan the string up to 16 bytes at a time */ 77 /* scan the string up to 16 bytes at a time, and attempt to grab the
78 * trailing NUL whilst we're at it */
79 buf[0] = 0xff;
80
78 while (size > 0) { 81 while (size > 0) {
79 segment = min_t(size_t, size, 16); 82 segment = min_t(size_t, size + 1, 17);
80 ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf); 83 ret = ROMFS_MTD_READ(sb, pos, segment, &len, buf);
81 if (ret < 0) 84 if (ret < 0)
82 return ret; 85 return ret;
86 len--;
83 if (memcmp(buf, str, len) != 0) 87 if (memcmp(buf, str, len) != 0)
84 return 0; 88 return 0;
89 buf[0] = buf[len];
85 size -= len; 90 size -= len;
86 pos += len; 91 pos += len;
87 str += len; 92 str += len;
88 } 93 }
89 94
95 /* check the trailing NUL was */
96 if (buf[0])
97 return 0;
98
90 return 1; 99 return 1;
91} 100}
92#endif /* CONFIG_ROMFS_ON_MTD */ 101#endif /* CONFIG_ROMFS_ON_MTD */
@@ -154,28 +163,48 @@ static ssize_t romfs_blk_strnlen(struct super_block *sb,
154 * compare a string to one in a romfs image on a block device 163 * compare a string to one in a romfs image on a block device
155 * - return 1 if matched, 0 if differ, -ve if error 164 * - return 1 if matched, 0 if differ, -ve if error
156 */ 165 */
157static int romfs_blk_strncmp(struct super_block *sb, unsigned long pos, 166static int romfs_blk_strcmp(struct super_block *sb, unsigned long pos,
158 const char *str, size_t size) 167 const char *str, size_t size)
159{ 168{
160 struct buffer_head *bh; 169 struct buffer_head *bh;
161 unsigned long offset; 170 unsigned long offset;
162 size_t segment; 171 size_t segment;
163 bool x; 172 bool matched, terminated = false;
164 173
165 /* scan the string up to 16 bytes at a time */ 174 /* compare string up to a block at a time */
166 while (size > 0) { 175 while (size > 0) {
167 offset = pos & (ROMBSIZE - 1); 176 offset = pos & (ROMBSIZE - 1);
168 segment = min_t(size_t, size, ROMBSIZE - offset); 177 segment = min_t(size_t, size, ROMBSIZE - offset);
169 bh = sb_bread(sb, pos >> ROMBSBITS); 178 bh = sb_bread(sb, pos >> ROMBSBITS);
170 if (!bh) 179 if (!bh)
171 return -EIO; 180 return -EIO;
172 x = (memcmp(bh->b_data + offset, str, segment) != 0); 181 matched = (memcmp(bh->b_data + offset, str, segment) == 0);
173 brelse(bh); 182
174 if (x)
175 return 0;
176 size -= segment; 183 size -= segment;
177 pos += segment; 184 pos += segment;
178 str += segment; 185 str += segment;
186 if (matched && size == 0 && offset + segment < ROMBSIZE) {
187 if (!bh->b_data[offset + segment])
188 terminated = true;
189 else
190 matched = false;
191 }
192 brelse(bh);
193 if (!matched)
194 return 0;
195 }
196
197 if (!terminated) {
198 /* the terminating NUL must be on the first byte of the next
199 * block */
200 BUG_ON((pos & (ROMBSIZE - 1)) != 0);
201 bh = sb_bread(sb, pos >> ROMBSBITS);
202 if (!bh)
203 return -EIO;
204 matched = !bh->b_data[0];
205 brelse(bh);
206 if (!matched)
207 return 0;
179 } 208 }
180 209
181 return 1; 210 return 1;
@@ -234,10 +263,12 @@ ssize_t romfs_dev_strnlen(struct super_block *sb,
234 263
235/* 264/*
236 * compare a string to one in romfs 265 * compare a string to one in romfs
266 * - the string to be compared to, str, may not be NUL-terminated; instead the
267 * string is of the specified size
237 * - return 1 if matched, 0 if differ, -ve if error 268 * - return 1 if matched, 0 if differ, -ve if error
238 */ 269 */
239int romfs_dev_strncmp(struct super_block *sb, unsigned long pos, 270int romfs_dev_strcmp(struct super_block *sb, unsigned long pos,
240 const char *str, size_t size) 271 const char *str, size_t size)
241{ 272{
242 size_t limit; 273 size_t limit;
243 274
@@ -246,16 +277,16 @@ int romfs_dev_strncmp(struct super_block *sb, unsigned long pos,
246 return -EIO; 277 return -EIO;
247 if (size > ROMFS_MAXFN) 278 if (size > ROMFS_MAXFN)
248 return -ENAMETOOLONG; 279 return -ENAMETOOLONG;
249 if (size > limit - pos) 280 if (size + 1 > limit - pos)
250 return -EIO; 281 return -EIO;
251 282
252#ifdef CONFIG_ROMFS_ON_MTD 283#ifdef CONFIG_ROMFS_ON_MTD
253 if (sb->s_mtd) 284 if (sb->s_mtd)
254 return romfs_mtd_strncmp(sb, pos, str, size); 285 return romfs_mtd_strcmp(sb, pos, str, size);
255#endif 286#endif
256#ifdef CONFIG_ROMFS_ON_BLOCK 287#ifdef CONFIG_ROMFS_ON_BLOCK
257 if (sb->s_bdev) 288 if (sb->s_bdev)
258 return romfs_blk_strncmp(sb, pos, str, size); 289 return romfs_blk_strcmp(sb, pos, str, size);
259#endif 290#endif
260 return -EIO; 291 return -EIO;
261} 292}
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index 10ca7d984a8b..c53b5ef8a02f 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -240,8 +240,8 @@ static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
240 goto error; 240 goto error;
241 241
242 /* try to match the first 16 bytes of name */ 242 /* try to match the first 16 bytes of name */
243 ret = romfs_dev_strncmp(dir->i_sb, offset + ROMFH_SIZE, name, 243 ret = romfs_dev_strcmp(dir->i_sb, offset + ROMFH_SIZE, name,
244 len); 244 len);
245 if (ret < 0) 245 if (ret < 0)
246 goto error; 246 goto error;
247 if (ret == 1) 247 if (ret == 1)