Re: [PATCH] hfs: add error checking for hfs_find_init()
Hi Alexey, On Apr 7, 2013, at 1:13 AM, Alexey Khoroshilov wrote: > Hi Vyacheslav, > > On 03/30/2013 03:35 PM, Vyacheslav Dubeyko wrote: >>> Found by Linux Driver Verification project (linuxtesting.org). >>> >>> Signed-off-by: Alexey Khoroshilov >>> --- >>> fs/hfs/catalog.c | 12 +--- >>> fs/hfs/dir.c |8 ++-- >>> fs/hfs/extent.c | 48 +--- >>> fs/hfs/hfs_fs.h |2 +- >>> fs/hfs/inode.c | 11 +-- >>> fs/hfs/super.c |4 +++- >>> 6 files changed, 61 insertions(+), 24 deletions(-) >>> >>> diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c >>> index 424b033..9569b39 100644 >>> --- a/fs/hfs/catalog.c >>> +++ b/fs/hfs/catalog.c >>> @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct >>> qstr *str, struct inode * >>> return -ENOSPC; >>> >>> sb = dir->i_sb; >>> - hfs_find_init(HFS_SB(sb)->cat_tree, ); >>> + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); >>> + if (err) >>> + return err; >>> >>> hfs_cat_build_key(sb, fd.search_key, cnid, NULL); >>> entry_size = hfs_cat_build_thread(sb, , S_ISDIR(inode->i_mode) ? >>> @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct >>> qstr *str) >>> >>> dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, >>> cnid); >>> sb = dir->i_sb; >>> - hfs_find_init(HFS_SB(sb)->cat_tree, ); >>> + res = hfs_find_init(HFS_SB(sb)->cat_tree, ); >>> + if (res) >>> + return res; >>> >>> hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str); >>> res = hfs_brec_find(); >>> @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, >>> struct qstr *src_name, >>> dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, >>> src_dir->i_ino, src_name->name, >>> dst_dir->i_ino, dst_name->name); >>> sb = src_dir->i_sb; >>> - hfs_find_init(HFS_SB(sb)->cat_tree, _fd); >>> + err = hfs_find_init(HFS_SB(sb)->cat_tree, _fd); >>> + if (err) >>> + return err; >>> dst_fd = src_fd; >>> >>> /* find the old dir entry and read the data */ >>> diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c >>> index 5f7f1ab..e1c8048 100644 >>> --- a/fs/hfs/dir.c >>> +++ b/fs/hfs/dir.c >>> @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, >>> struct dentry *dentry, >>> struct inode *inode = NULL; >>> int res; >>> >>> - hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); >>> + res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); >>> + if (res) >>> + return ERR_PTR(res); >>> hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, >>> >d_name); >>> res = hfs_brec_read(, , sizeof(rec)); >>> if (res) { >>> @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, >>> filldir_t filldir) >>> if (filp->f_pos >= inode->i_size) >>> return 0; >>> >>> - hfs_find_init(HFS_SB(sb)->cat_tree, ); >>> + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); >>> + if (err) >>> + return err; >>> hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); >>> err = hfs_brec_find(); >>> if (err) >>> diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c >>> index a67955a..813447b 100644 >>> --- a/fs/hfs/extent.c >>> +++ b/fs/hfs/extent.c >>> @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) >>> return be16_to_cpu(ext->block) + be16_to_cpu(ext->count); >>> } >>> >>> -static void __hfs_ext_write_extent(struct inode *inode, struct >>> hfs_find_data *fd) >>> +static int __hfs_ext_write_extent(struct inode *inode, struct >>> hfs_find_data *fd) >>> { >>> int res; >>> >>> @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode >>> *inode, struct hfs_find_data *fd >>> res = hfs_brec_find(fd); >>> if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) { >>> if (res != -ENOENT) >>> - return; >>> + return res; >>> hfs_brec_insert(fd, HFS_I(inode)->cached_extents, >>> sizeof(hfs_extent_rec)); >>> HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); >>> } else { >>> if (res) >>> - return; >>> + return res; >>> hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, >>> fd->entryoffset, fd->entrylength); >>> HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY; >>> } >>> + return 0; >>> } >> As I see, this fix makes sense and for hfsplus also. Please, make it and for >> hfsplus. > Sorry, I did not catch which fix do you mean. Could you please clarify it. > I meant: (1) correction the issue with returning error in __hfsplus_ext_write_extent() method (http://lxr.free-electrons.com/source/fs/hfsplus/extents.c#L86); (2) adding error processing in hfsplus_ext_write_extent_locked() method (http://lxr.free-electrons.com/source/fs/hfsplus/extents.c#L132); (3) adding error processing in
Re: [PATCH] hfs: add error checking for hfs_find_init()
Hi Alexey, On Apr 7, 2013, at 1:13 AM, Alexey Khoroshilov wrote: Hi Vyacheslav, On 03/30/2013 03:35 PM, Vyacheslav Dubeyko wrote: Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov khoroshi...@ispras.ru --- fs/hfs/catalog.c | 12 +--- fs/hfs/dir.c |8 ++-- fs/hfs/extent.c | 48 +--- fs/hfs/hfs_fs.h |2 +- fs/hfs/inode.c | 11 +-- fs/hfs/super.c |4 +++- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 424b033..9569b39 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * return -ENOSPC; sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, entry, S_ISDIR(inode-i_mode) ? @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) dprint(DBG_CAT_MOD, delete_cat: %s,%u\n, str ? str-name : NULL, cnid); sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (res) + return res; hfs_cat_build_key(sb, fd.search_key, dir-i_ino, str); res = hfs_brec_find(fd); @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, dprint(DBG_CAT_MOD, rename_cat: %u - %lu,%s - %lu,%s\n, cnid, src_dir-i_ino, src_name-name, dst_dir-i_ino, dst_name-name); sb = src_dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + if (err) + return err; dst_fd = src_fd; /* find the old dir entry and read the data */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 5f7f1ab..e1c8048 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + if (res) + return ERR_PTR(res); hfs_cat_build_key(dir-i_sb, fd.search_key, dir-i_ino, dentry-d_name); res = hfs_brec_read(fd, rec, sizeof(rec)); if (res) { @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (filp-f_pos = inode-i_size) return 0; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, inode-i_ino, NULL); err = hfs_brec_find(fd); if (err) diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index a67955a..813447b 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) return be16_to_cpu(ext-block) + be16_to_cpu(ext-count); } -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd res = hfs_brec_find(fd); if (HFS_I(inode)-flags HFS_FLG_EXT_NEW) { if (res != -ENOENT) - return; + return res; hfs_brec_insert(fd, HFS_I(inode)-cached_extents, sizeof(hfs_extent_rec)); HFS_I(inode)-flags = ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else { if (res) - return; + return res; hfs_bnode_write(fd-bnode, HFS_I(inode)-cached_extents, fd-entryoffset, fd-entrylength); HFS_I(inode)-flags = ~HFS_FLG_EXT_DIRTY; } + return 0; } As I see, this fix makes sense and for hfsplus also. Please, make it and for hfsplus. Sorry, I did not catch which fix do you mean. Could you please clarify it. I meant: (1) correction the issue with returning error in __hfsplus_ext_write_extent() method (http://lxr.free-electrons.com/source/fs/hfsplus/extents.c#L86); (2) adding error processing in hfsplus_ext_write_extent_locked() method (http://lxr.free-electrons.com/source/fs/hfsplus/extents.c#L132); (3) adding error processing in __hfsplus_ext_cache_extent() method (http://lxr.free-electrons.com/source/fs/hfsplus/extents.c#L179). Moreover, as I remember, Hin-Tak asks about adding dprint messages. Thanks, Vyacheslav Dubeyko. Thank you, Alexey -- To unsubscribe from this list: send the line unsubscribe linux-fsdevel in the body of a message to majord...@vger.kernel.org More
Re: [PATCH] hfs: add error checking for hfs_find_init()
Hi Vyacheslav, On 03/30/2013 03:35 PM, Vyacheslav Dubeyko wrote: Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov --- fs/hfs/catalog.c | 12 +--- fs/hfs/dir.c |8 ++-- fs/hfs/extent.c | 48 +--- fs/hfs/hfs_fs.h |2 +- fs/hfs/inode.c | 11 +-- fs/hfs/super.c |4 +++- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 424b033..9569b39 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * return -ENOSPC; sb = dir->i_sb; - hfs_find_init(HFS_SB(sb)->cat_tree, ); + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, , S_ISDIR(inode->i_mode) ? @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); sb = dir->i_sb; - hfs_find_init(HFS_SB(sb)->cat_tree, ); + res = hfs_find_init(HFS_SB(sb)->cat_tree, ); + if (res) + return res; hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str); res = hfs_brec_find(); @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name, dst_dir->i_ino, dst_name->name); sb = src_dir->i_sb; - hfs_find_init(HFS_SB(sb)->cat_tree, _fd); + err = hfs_find_init(HFS_SB(sb)->cat_tree, _fd); + if (err) + return err; dst_fd = src_fd; /* find the old dir entry and read the data */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 5f7f1ab..e1c8048 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); + res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); + if (res) + return ERR_PTR(res); hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, >d_name); res = hfs_brec_read(, , sizeof(rec)); if (res) { @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (filp->f_pos >= inode->i_size) return 0; - hfs_find_init(HFS_SB(sb)->cat_tree, ); + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); err = hfs_brec_find(); if (err) diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index a67955a..813447b 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) return be16_to_cpu(ext->block) + be16_to_cpu(ext->count); } -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd res = hfs_brec_find(fd); if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) { if (res != -ENOENT) - return; + return res; hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec)); HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else { if (res) - return; + return res; hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, fd->entryoffset, fd->entrylength); HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY; } + return 0; } As I see, this fix makes sense and for hfsplus also. Please, make it and for hfsplus. Sorry, I did not catch which fix do you mean. Could you please clarify it. Thank you, Alexey -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] hfs: add error checking for hfs_find_init()
Hi Vyacheslav, On 03/30/2013 03:35 PM, Vyacheslav Dubeyko wrote: Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov khoroshi...@ispras.ru --- fs/hfs/catalog.c | 12 +--- fs/hfs/dir.c |8 ++-- fs/hfs/extent.c | 48 +--- fs/hfs/hfs_fs.h |2 +- fs/hfs/inode.c | 11 +-- fs/hfs/super.c |4 +++- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 424b033..9569b39 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * return -ENOSPC; sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, entry, S_ISDIR(inode-i_mode) ? @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) dprint(DBG_CAT_MOD, delete_cat: %s,%u\n, str ? str-name : NULL, cnid); sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (res) + return res; hfs_cat_build_key(sb, fd.search_key, dir-i_ino, str); res = hfs_brec_find(fd); @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, dprint(DBG_CAT_MOD, rename_cat: %u - %lu,%s - %lu,%s\n, cnid, src_dir-i_ino, src_name-name, dst_dir-i_ino, dst_name-name); sb = src_dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + if (err) + return err; dst_fd = src_fd; /* find the old dir entry and read the data */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 5f7f1ab..e1c8048 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + if (res) + return ERR_PTR(res); hfs_cat_build_key(dir-i_sb, fd.search_key, dir-i_ino, dentry-d_name); res = hfs_brec_read(fd, rec, sizeof(rec)); if (res) { @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (filp-f_pos = inode-i_size) return 0; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, inode-i_ino, NULL); err = hfs_brec_find(fd); if (err) diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index a67955a..813447b 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) return be16_to_cpu(ext-block) + be16_to_cpu(ext-count); } -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd res = hfs_brec_find(fd); if (HFS_I(inode)-flags HFS_FLG_EXT_NEW) { if (res != -ENOENT) - return; + return res; hfs_brec_insert(fd, HFS_I(inode)-cached_extents, sizeof(hfs_extent_rec)); HFS_I(inode)-flags = ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else { if (res) - return; + return res; hfs_bnode_write(fd-bnode, HFS_I(inode)-cached_extents, fd-entryoffset, fd-entrylength); HFS_I(inode)-flags = ~HFS_FLG_EXT_DIRTY; } + return 0; } As I see, this fix makes sense and for hfsplus also. Please, make it and for hfsplus. Sorry, I did not catch which fix do you mean. Could you please clarify it. Thank you, Alexey -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] hfs: add error checking for hfs_find_init()
--- On Sat, 30/3/13, Vyacheslav Dubeyko wrote: > From: Vyacheslav Dubeyko > Subject: Re: [PATCH] hfs: add error checking for hfs_find_init() > To: "Alexey Khoroshilov" > Cc: "Al Viro" , "Artem Bityutskiy" > , "Christoph Hellwig" , > linux-fsde...@vger.kernel.org, linux-kernel@vger.kernel.org, > ldv-proj...@linuxtesting.org, "Hin-Tak Leung" > Date: Saturday, 30 March, 2013, 11:35 > Hi Alexey, > > On Mar 30, 2013, at 12:44 AM, Alexey Khoroshilov wrote: > > > 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(). > > > > Thank you for your efforts. I have several remarks. Please, > see below. Argh, interesting. I wonder if that is related to how I can get the hfsplus driver all confused just running 'du' on one large directory in one of my disks repeatedly. I'll be interested to trying the hfsplus version out. Perhaps I would suggest/add a few dprint/printk's so that there is a sign in dmesg when the error condition is triggered. Hin-Tak > > Found by Linux Driver Verification project > (linuxtesting.org). > > > > Signed-off-by: Alexey Khoroshilov > > --- > > fs/hfs/catalog.c | 12 +--- > > fs/hfs/dir.c | 8 > ++-- > > fs/hfs/extent.c | 48 > +--- > > fs/hfs/hfs_fs.h | 2 +- > > fs/hfs/inode.c | 11 > +-- > > fs/hfs/super.c | 4 +++- > > 6 files changed, 61 insertions(+), 24 deletions(-) > > > > diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c > > index 424b033..9569b39 100644 > > --- a/fs/hfs/catalog.c > > +++ b/fs/hfs/catalog.c > > @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct > inode *dir, struct qstr *str, struct inode * > > return -ENOSPC; > > > > sb = dir->i_sb; > > - > hfs_find_init(HFS_SB(sb)->cat_tree, ); > > + err = > hfs_find_init(HFS_SB(sb)->cat_tree, ); > > + if (err) > > + return err; > > > > hfs_cat_build_key(sb, fd.search_key, > cnid, NULL); > > entry_size = > hfs_cat_build_thread(sb, , > S_ISDIR(inode->i_mode) ? > > @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct > inode *dir, struct qstr *str) > > > > dprint(DBG_CAT_MOD, "delete_cat: > %s,%u\n", str ? str->name : NULL, cnid); > > sb = dir->i_sb; > > - > hfs_find_init(HFS_SB(sb)->cat_tree, ); > > + res = > hfs_find_init(HFS_SB(sb)->cat_tree, ); > > + if (res) > > + return res; > > > > hfs_cat_build_key(sb, fd.search_key, > dir->i_ino, str); > > res = hfs_brec_find(); > > @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct > inode *src_dir, struct qstr *src_name, > > dprint(DBG_CAT_MOD, "rename_cat: %u > - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, > src_name->name, > > > dst_dir->i_ino, dst_name->name); > > sb = src_dir->i_sb; > > - > hfs_find_init(HFS_SB(sb)->cat_tree, _fd); > > + err = > hfs_find_init(HFS_SB(sb)->cat_tree, _fd); > > + if (err) > > + return err; > > dst_fd = src_fd; > > > > /* find the old dir entry and read > the data */ > > diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c > > index 5f7f1ab..e1c8048 100644 > > --- a/fs/hfs/dir.c > > +++ b/fs/hfs/dir.c > > @@ -25,7 +25,9 @@ static struct dentry > *hfs_lookup(struct inode *dir, struct dentry *dentry, > > struct inode *inode = NULL; > > int res; > > > > - > hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); > > + res = > hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); > > + if (res) > > + return > ERR_PTR(res); > > hfs_cat_build_key(dir->i_sb, > fd.search_key, dir->i_ino, >d_name); > > res = hfs_brec_read(, > , sizeof(rec)); > > if (res) { > > @@ -63,7 +65,9 @@ static int hfs_readdir(struct file > *filp, void *dirent, filldir_t filldir) > > if (filp->f_pos >= > inode->i_size) > > return 0; > > > > - > hfs_find_init(HFS_SB(sb)->cat_tree, ); > > + err = > hfs_find_init(HFS_SB(sb)->cat_tree, ); > > + if (err) > > + return err; > > hfs_cat_build_key(sb, fd.search_key, > inode->i_ino,
Re: [PATCH] hfs: add error checking for hfs_find_init()
Hi Alexey, On Mar 30, 2013, at 12:44 AM, Alexey Khoroshilov wrote: > 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(). > Thank you for your efforts. I have several remarks. Please, see below. > Found by Linux Driver Verification project (linuxtesting.org). > > Signed-off-by: Alexey Khoroshilov > --- > fs/hfs/catalog.c | 12 +--- > fs/hfs/dir.c |8 ++-- > fs/hfs/extent.c | 48 +--- > fs/hfs/hfs_fs.h |2 +- > fs/hfs/inode.c | 11 +-- > fs/hfs/super.c |4 +++- > 6 files changed, 61 insertions(+), 24 deletions(-) > > diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c > index 424b033..9569b39 100644 > --- a/fs/hfs/catalog.c > +++ b/fs/hfs/catalog.c > @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr > *str, struct inode * > return -ENOSPC; > > sb = dir->i_sb; > - hfs_find_init(HFS_SB(sb)->cat_tree, ); > + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); > + if (err) > + return err; > > hfs_cat_build_key(sb, fd.search_key, cnid, NULL); > entry_size = hfs_cat_build_thread(sb, , S_ISDIR(inode->i_mode) ? > @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct > qstr *str) > > dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, > cnid); > sb = dir->i_sb; > - hfs_find_init(HFS_SB(sb)->cat_tree, ); > + res = hfs_find_init(HFS_SB(sb)->cat_tree, ); > + if (res) > + return res; > > hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str); > res = hfs_brec_find(); > @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct > qstr *src_name, > dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, > src_dir->i_ino, src_name->name, > dst_dir->i_ino, dst_name->name); > sb = src_dir->i_sb; > - hfs_find_init(HFS_SB(sb)->cat_tree, _fd); > + err = hfs_find_init(HFS_SB(sb)->cat_tree, _fd); > + if (err) > + return err; > dst_fd = src_fd; > > /* find the old dir entry and read the data */ > diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c > index 5f7f1ab..e1c8048 100644 > --- a/fs/hfs/dir.c > +++ b/fs/hfs/dir.c > @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct > dentry *dentry, > struct inode *inode = NULL; > int res; > > - hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); > + res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); > + if (res) > + return ERR_PTR(res); > hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, > >d_name); > res = hfs_brec_read(, , sizeof(rec)); > if (res) { > @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, > filldir_t filldir) > if (filp->f_pos >= inode->i_size) > return 0; > > - hfs_find_init(HFS_SB(sb)->cat_tree, ); > + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); > + if (err) > + return err; > hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); > err = hfs_brec_find(); > if (err) > diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c > index a67955a..813447b 100644 > --- a/fs/hfs/extent.c > +++ b/fs/hfs/extent.c > @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) > return be16_to_cpu(ext->block) + be16_to_cpu(ext->count); > } > > -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data > *fd) > +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data > *fd) > { > int res; > > @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, > struct hfs_find_data *fd > res = hfs_brec_find(fd); > if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) { > if (res != -ENOENT) > - return; > + return res; > hfs_brec_insert(fd, HFS_I(inode)->cached_extents, > sizeof(hfs_extent_rec)); > HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); > } else { > if (res) > - return; > + return res; > hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, > fd->entryoffset, fd->entrylength); > HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY; > } > + return 0; > } > As I see, this fix makes sense and for hfsplus also. Please, make it and for hfsplus. > -void hfs_ext_write_extent(struct inode *inode) > +int hfs_ext_write_extent(struct inode *inode) > { > struct hfs_find_data fd; > + int res = 0; > > if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY) { > -
Re: [PATCH] hfs: add error checking for hfs_find_init()
Hi Alexey, On Mar 30, 2013, at 12:44 AM, Alexey Khoroshilov wrote: 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(). Thank you for your efforts. I have several remarks. Please, see below. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov khoroshi...@ispras.ru --- fs/hfs/catalog.c | 12 +--- fs/hfs/dir.c |8 ++-- fs/hfs/extent.c | 48 +--- fs/hfs/hfs_fs.h |2 +- fs/hfs/inode.c | 11 +-- fs/hfs/super.c |4 +++- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 424b033..9569b39 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * return -ENOSPC; sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, entry, S_ISDIR(inode-i_mode) ? @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) dprint(DBG_CAT_MOD, delete_cat: %s,%u\n, str ? str-name : NULL, cnid); sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (res) + return res; hfs_cat_build_key(sb, fd.search_key, dir-i_ino, str); res = hfs_brec_find(fd); @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, dprint(DBG_CAT_MOD, rename_cat: %u - %lu,%s - %lu,%s\n, cnid, src_dir-i_ino, src_name-name, dst_dir-i_ino, dst_name-name); sb = src_dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + if (err) + return err; dst_fd = src_fd; /* find the old dir entry and read the data */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 5f7f1ab..e1c8048 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + if (res) + return ERR_PTR(res); hfs_cat_build_key(dir-i_sb, fd.search_key, dir-i_ino, dentry-d_name); res = hfs_brec_read(fd, rec, sizeof(rec)); if (res) { @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (filp-f_pos = inode-i_size) return 0; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, inode-i_ino, NULL); err = hfs_brec_find(fd); if (err) diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index a67955a..813447b 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) return be16_to_cpu(ext-block) + be16_to_cpu(ext-count); } -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd res = hfs_brec_find(fd); if (HFS_I(inode)-flags HFS_FLG_EXT_NEW) { if (res != -ENOENT) - return; + return res; hfs_brec_insert(fd, HFS_I(inode)-cached_extents, sizeof(hfs_extent_rec)); HFS_I(inode)-flags = ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else { if (res) - return; + return res; hfs_bnode_write(fd-bnode, HFS_I(inode)-cached_extents, fd-entryoffset, fd-entrylength); HFS_I(inode)-flags = ~HFS_FLG_EXT_DIRTY; } + return 0; } As I see, this fix makes sense and for hfsplus also. Please, make it and for hfsplus. -void hfs_ext_write_extent(struct inode *inode) +int hfs_ext_write_extent(struct inode *inode) { struct hfs_find_data fd; + int res = 0; if (HFS_I(inode)-flags HFS_FLG_EXT_DIRTY) { - hfs_find_init(HFS_SB(inode-i_sb)-ext_tree, fd); - __hfs_ext_write_extent(inode, fd); + res =
Re: [PATCH] hfs: add error checking for hfs_find_init()
--- On Sat, 30/3/13, Vyacheslav Dubeyko sl...@dubeyko.com wrote: From: Vyacheslav Dubeyko sl...@dubeyko.com Subject: Re: [PATCH] hfs: add error checking for hfs_find_init() To: Alexey Khoroshilov khoroshi...@ispras.ru Cc: Al Viro v...@zeniv.linux.org.uk, Artem Bityutskiy artem.bityuts...@linux.intel.com, Christoph Hellwig h...@lst.de, linux-fsde...@vger.kernel.org, linux-kernel@vger.kernel.org, ldv-proj...@linuxtesting.org, Hin-Tak Leung ht...@users.sourceforge.net Date: Saturday, 30 March, 2013, 11:35 Hi Alexey, On Mar 30, 2013, at 12:44 AM, Alexey Khoroshilov wrote: 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(). Thank you for your efforts. I have several remarks. Please, see below. Argh, interesting. I wonder if that is related to how I can get the hfsplus driver all confused just running 'du' on one large directory in one of my disks repeatedly. I'll be interested to trying the hfsplus version out. Perhaps I would suggest/add a few dprint/printk's so that there is a sign in dmesg when the error condition is triggered. Hin-Tak Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov khoroshi...@ispras.ru --- fs/hfs/catalog.c | 12 +--- fs/hfs/dir.c | 8 ++-- fs/hfs/extent.c | 48 +--- fs/hfs/hfs_fs.h | 2 +- fs/hfs/inode.c | 11 +-- fs/hfs/super.c | 4 +++- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 424b033..9569b39 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * return -ENOSPC; sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, entry, S_ISDIR(inode-i_mode) ? @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) dprint(DBG_CAT_MOD, delete_cat: %s,%u\n, str ? str-name : NULL, cnid); sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (res) + return res; hfs_cat_build_key(sb, fd.search_key, dir-i_ino, str); res = hfs_brec_find(fd); @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, dprint(DBG_CAT_MOD, rename_cat: %u - %lu,%s - %lu,%s\n, cnid, src_dir-i_ino, src_name-name, dst_dir-i_ino, dst_name-name); sb = src_dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + if (err) + return err; dst_fd = src_fd; /* find the old dir entry and read the data */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 5f7f1ab..e1c8048 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + if (res) + return ERR_PTR(res); hfs_cat_build_key(dir-i_sb, fd.search_key, dir-i_ino, dentry-d_name); res = hfs_brec_read(fd, rec, sizeof(rec)); if (res) { @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (filp-f_pos = inode-i_size) return 0; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, inode-i_ino, NULL); err = hfs_brec_find(fd); if (err) diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index a67955a..813447b 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) return be16_to_cpu(ext-block) + be16_to_cpu(ext-count); } -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd res = hfs_brec_find(fd); if (HFS_I(inode)-flags HFS_FLG_EXT_NEW) { if (res != -ENOENT) - return; + return res; hfs_brec_insert(fd, HFS_I(inode
[PATCH] hfs: 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 --- fs/hfs/catalog.c | 12 +--- fs/hfs/dir.c |8 ++-- fs/hfs/extent.c | 48 +--- fs/hfs/hfs_fs.h |2 +- fs/hfs/inode.c | 11 +-- fs/hfs/super.c |4 +++- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 424b033..9569b39 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * return -ENOSPC; sb = dir->i_sb; - hfs_find_init(HFS_SB(sb)->cat_tree, ); + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, , S_ISDIR(inode->i_mode) ? @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); sb = dir->i_sb; - hfs_find_init(HFS_SB(sb)->cat_tree, ); + res = hfs_find_init(HFS_SB(sb)->cat_tree, ); + if (res) + return res; hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str); res = hfs_brec_find(); @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name, dst_dir->i_ino, dst_name->name); sb = src_dir->i_sb; - hfs_find_init(HFS_SB(sb)->cat_tree, _fd); + err = hfs_find_init(HFS_SB(sb)->cat_tree, _fd); + if (err) + return err; dst_fd = src_fd; /* find the old dir entry and read the data */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 5f7f1ab..e1c8048 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); + res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, ); + if (res) + return ERR_PTR(res); hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, >d_name); res = hfs_brec_read(, , sizeof(rec)); if (res) { @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (filp->f_pos >= inode->i_size) return 0; - hfs_find_init(HFS_SB(sb)->cat_tree, ); + err = hfs_find_init(HFS_SB(sb)->cat_tree, ); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); err = hfs_brec_find(); if (err) diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index a67955a..813447b 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) return be16_to_cpu(ext->block) + be16_to_cpu(ext->count); } -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd res = hfs_brec_find(fd); if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) { if (res != -ENOENT) - return; + return res; hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec)); HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else { if (res) - return; + return res; hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, fd->entryoffset, fd->entrylength); HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY; } + return 0; } -void hfs_ext_write_extent(struct inode *inode) +int hfs_ext_write_extent(struct inode *inode) { struct hfs_find_data fd; + int res = 0; if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY) { - hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, ); - __hfs_ext_write_extent(inode, ); + res = hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, ); + if (res) + return res; + res = __hfs_ext_write_extent(inode, ); hfs_find_exit(); } + return res; } static inline int
[PATCH] hfs: 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 khoroshi...@ispras.ru --- fs/hfs/catalog.c | 12 +--- fs/hfs/dir.c |8 ++-- fs/hfs/extent.c | 48 +--- fs/hfs/hfs_fs.h |2 +- fs/hfs/inode.c | 11 +-- fs/hfs/super.c |4 +++- 6 files changed, 61 insertions(+), 24 deletions(-) diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 424b033..9569b39 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -92,7 +92,9 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode * return -ENOSPC; sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, cnid, NULL); entry_size = hfs_cat_build_thread(sb, entry, S_ISDIR(inode-i_mode) ? @@ -214,7 +216,9 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str) dprint(DBG_CAT_MOD, delete_cat: %s,%u\n, str ? str-name : NULL, cnid); sb = dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (res) + return res; hfs_cat_build_key(sb, fd.search_key, dir-i_ino, str); res = hfs_brec_find(fd); @@ -281,7 +285,9 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name, dprint(DBG_CAT_MOD, rename_cat: %u - %lu,%s - %lu,%s\n, cnid, src_dir-i_ino, src_name-name, dst_dir-i_ino, dst_name-name); sb = src_dir-i_sb; - hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, src_fd); + if (err) + return err; dst_fd = src_fd; /* find the old dir entry and read the data */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 5f7f1ab..e1c8048 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + res = hfs_find_init(HFS_SB(dir-i_sb)-cat_tree, fd); + if (res) + return ERR_PTR(res); hfs_cat_build_key(dir-i_sb, fd.search_key, dir-i_ino, dentry-d_name); res = hfs_brec_read(fd, rec, sizeof(rec)); if (res) { @@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) if (filp-f_pos = inode-i_size) return 0; - hfs_find_init(HFS_SB(sb)-cat_tree, fd); + err = hfs_find_init(HFS_SB(sb)-cat_tree, fd); + if (err) + return err; hfs_cat_build_key(sb, fd.search_key, inode-i_ino, NULL); err = hfs_brec_find(fd); if (err) diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index a67955a..813447b 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c @@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext) return be16_to_cpu(ext-block) + be16_to_cpu(ext-count); } -static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) +static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) { int res; @@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd res = hfs_brec_find(fd); if (HFS_I(inode)-flags HFS_FLG_EXT_NEW) { if (res != -ENOENT) - return; + return res; hfs_brec_insert(fd, HFS_I(inode)-cached_extents, sizeof(hfs_extent_rec)); HFS_I(inode)-flags = ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW); } else { if (res) - return; + return res; hfs_bnode_write(fd-bnode, HFS_I(inode)-cached_extents, fd-entryoffset, fd-entrylength); HFS_I(inode)-flags = ~HFS_FLG_EXT_DIRTY; } + return 0; } -void hfs_ext_write_extent(struct inode *inode) +int hfs_ext_write_extent(struct inode *inode) { struct hfs_find_data fd; + int res = 0; if (HFS_I(inode)-flags HFS_FLG_EXT_DIRTY) { - hfs_find_init(HFS_SB(inode-i_sb)-ext_tree, fd); - __hfs_ext_write_extent(inode, fd); + res = hfs_find_init(HFS_SB(inode-i_sb)-ext_tree, fd); + if (res) + return res; + res = __hfs_ext_write_extent(inode, fd); hfs_find_exit(fd); } + return res; } static inline