aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Khoroshilov <khoroshilov@ispras.ru>2011-07-05 18:29:59 -0400
committerChristoph Hellwig <hch@lst.de>2011-07-07 11:45:46 -0400
commit5bd9d99d107c56ff7b35a29e930d85f91a07b2fd (patch)
treeb5db237ebff38c90b95f01d8cca28bc8c2536e7f
parentc6d5f5fa658f2569a7baaff5acda261a1316cee9 (diff)
hfsplus: add error checking for hfs_find_init()
hfs_find_init() may fail with ENOMEM, but there are places, where the returned value is not checked. The consequences can be very unpleasant, e.g. kfree uninitialized pointer and inappropriate mutex unlocking. The patch adds checks for errors in hfs_find_init(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/hfsplus/catalog.c14
-rw-r--r--fs/hfsplus/dir.c8
-rw-r--r--fs/hfsplus/extents.c27
-rw-r--r--fs/hfsplus/inode.c12
-rw-r--r--fs/hfsplus/super.c16
5 files changed, 51 insertions, 26 deletions
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index b4ba1b319333..4dfbfec357e8 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -212,7 +212,9 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
212 212
213 dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", 213 dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n",
214 str->name, cnid, inode->i_nlink); 214 str->name, cnid, inode->i_nlink);
215 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 215 err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
216 if (err)
217 return err;
216 218
217 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); 219 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
218 entry_size = hfsplus_fill_cat_thread(sb, &entry, 220 entry_size = hfsplus_fill_cat_thread(sb, &entry,
@@ -269,7 +271,9 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
269 271
270 dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", 272 dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n",
271 str ? str->name : NULL, cnid); 273 str ? str->name : NULL, cnid);
272 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 274 err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
275 if (err)
276 return err;
273 277
274 if (!str) { 278 if (!str) {
275 int len; 279 int len;
@@ -347,12 +351,14 @@ int hfsplus_rename_cat(u32 cnid,
347 struct hfs_find_data src_fd, dst_fd; 351 struct hfs_find_data src_fd, dst_fd;
348 hfsplus_cat_entry entry; 352 hfsplus_cat_entry entry;
349 int entry_size, type; 353 int entry_size, type;
350 int err = 0; 354 int err;
351 355
352 dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", 356 dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
353 cnid, src_dir->i_ino, src_name->name, 357 cnid, src_dir->i_ino, src_name->name,
354 dst_dir->i_ino, dst_name->name); 358 dst_dir->i_ino, dst_name->name);
355 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); 359 err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
360 if (err)
361 return err;
356 dst_fd = src_fd; 362 dst_fd = src_fd;
357 363
358 /* find the old dir entry and read the data */ 364 /* find the old dir entry and read the data */
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 4df5059c25da..25b2443a004c 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -38,7 +38,9 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
38 sb = dir->i_sb; 38 sb = dir->i_sb;
39 39
40 dentry->d_fsdata = NULL; 40 dentry->d_fsdata = NULL;
41 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 41 err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
42 if (err)
43 return ERR_PTR(err);
42 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); 44 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
43again: 45again:
44 err = hfs_brec_read(&fd, &entry, sizeof(entry)); 46 err = hfs_brec_read(&fd, &entry, sizeof(entry));
@@ -132,7 +134,9 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
132 if (filp->f_pos >= inode->i_size) 134 if (filp->f_pos >= inode->i_size)
133 return 0; 135 return 0;
134 136
135 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 137 err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
138 if (err)
139 return err;
136 hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); 140 hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
137 err = hfs_brec_find(&fd); 141 err = hfs_brec_find(&fd);
138 if (err) 142 if (err)
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
index b9c1a4b5ba89..95065a89e7e2 100644
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -124,9 +124,10 @@ static void hfsplus_ext_write_extent_locked(struct inode *inode)
124 if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { 124 if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
125 struct hfs_find_data fd; 125 struct hfs_find_data fd;
126 126
127 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); 127 if (!hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd)) {
128 __hfsplus_ext_write_extent(inode, &fd); 128 __hfsplus_ext_write_extent(inode, &fd);
129 hfs_find_exit(&fd); 129 hfs_find_exit(&fd);
130 }
130 } 131 }
131} 132}
132 133
@@ -194,9 +195,11 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
194 block < hip->cached_start + hip->cached_blocks) 195 block < hip->cached_start + hip->cached_blocks)
195 return 0; 196 return 0;
196 197
197 hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); 198 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
198 res = __hfsplus_ext_cache_extent(&fd, inode, block); 199 if (!res) {
199 hfs_find_exit(&fd); 200 res = __hfsplus_ext_cache_extent(&fd, inode, block);
201 hfs_find_exit(&fd);
202 }
200 return res; 203 return res;
201} 204}
202 205
@@ -374,7 +377,9 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid,
374 if (total_blocks == blocks) 377 if (total_blocks == blocks)
375 return 0; 378 return 0;
376 379
377 hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); 380 res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
381 if (res)
382 return res;
378 do { 383 do {
379 res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid, 384 res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid,
380 total_blocks, type); 385 total_blocks, type);
@@ -503,7 +508,6 @@ void hfsplus_file_truncate(struct inode *inode)
503 struct page *page; 508 struct page *page;
504 void *fsdata; 509 void *fsdata;
505 u32 size = inode->i_size; 510 u32 size = inode->i_size;
506 int res;
507 511
508 res = pagecache_write_begin(NULL, mapping, size, 0, 512 res = pagecache_write_begin(NULL, mapping, size, 0,
509 AOP_FLAG_UNINTERRUPTIBLE, 513 AOP_FLAG_UNINTERRUPTIBLE,
@@ -526,7 +530,12 @@ void hfsplus_file_truncate(struct inode *inode)
526 goto out; 530 goto out;
527 531
528 mutex_lock(&hip->extents_lock); 532 mutex_lock(&hip->extents_lock);
529 hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd); 533 res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
534 if (res) {
535 mutex_unlock(&hip->extents_lock);
536 /* XXX: We lack error handling of hfsplus_file_truncate() */
537 return;
538 }
530 while (1) { 539 while (1) {
531 if (alloc_cnt == hip->first_blocks) { 540 if (alloc_cnt == hip->first_blocks) {
532 hfsplus_free_extents(sb, hip->first_extents, 541 hfsplus_free_extents(sb, hip->first_extents,
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index b248a6cfcad9..010cd363d085 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -195,11 +195,13 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir,
195 hip->flags = 0; 195 hip->flags = 0;
196 set_bit(HFSPLUS_I_RSRC, &hip->flags); 196 set_bit(HFSPLUS_I_RSRC, &hip->flags);
197 197
198 hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 198 err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
199 err = hfsplus_find_cat(sb, dir->i_ino, &fd); 199 if (!err) {
200 if (!err) 200 err = hfsplus_find_cat(sb, dir->i_ino, &fd);
201 err = hfsplus_cat_read_inode(inode, &fd); 201 if (!err)
202 hfs_find_exit(&fd); 202 err = hfsplus_cat_read_inode(inode, &fd);
203 hfs_find_exit(&fd);
204 }
203 if (err) { 205 if (err) {
204 iput(inode); 206 iput(inode);
205 return ERR_PTR(err); 207 return ERR_PTR(err);
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index acaef57e3606..2c1a72287fb5 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -73,11 +73,13 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
73 73
74 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID || 74 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
75 inode->i_ino == HFSPLUS_ROOT_CNID) { 75 inode->i_ino == HFSPLUS_ROOT_CNID) {
76 hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 76 err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
77 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 77 if (!err) {
78 if (!err) 78 err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
79 err = hfsplus_cat_read_inode(inode, &fd); 79 if (!err)
80 hfs_find_exit(&fd); 80 err = hfsplus_cat_read_inode(inode, &fd);
81 hfs_find_exit(&fd);
82 }
81 } else { 83 } else {
82 err = hfsplus_system_read_inode(inode); 84 err = hfsplus_system_read_inode(inode);
83 } 85 }
@@ -456,7 +458,9 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
456 458
457 str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; 459 str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
458 str.name = HFSP_HIDDENDIR_NAME; 460 str.name = HFSP_HIDDENDIR_NAME;
459 hfs_find_init(sbi->cat_tree, &fd); 461 err = hfs_find_init(sbi->cat_tree, &fd);
462 if (err)
463 goto out_put_root;
460 hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); 464 hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
461 if (!hfs_brec_read(&fd, &entry, sizeof(entry))) { 465 if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
462 hfs_find_exit(&fd); 466 hfs_find_exit(&fd);