Hey there, I spoke with Daniel in April about a bug in the affs file system parser, so I'm trying to post a patch for it here along with the details. Sorry for the delay.
in affs.c, line 412: ```c /* Create the directory entries for `.' and `..'. */ node = orig_node = grub_zalloc (sizeof (*node)); if (!node) return 1; *node = *dir; if (hook (".", GRUB_FSHELP_DIR, node, hook_data)) return 1; if (dir->parent) { *node = *dir->parent; if (hook ("..", GRUB_FSHELP_DIR, node, hook_data)) return 1; } ``` Inside `grub_affs_iterate_dir`, `node` will be freed inside `hook` if the path does not match ".". If the hook returns 0, then when returning to `grub_affs_iterate_dir` we eventually reach line 472, where `node` will be freed again -- at this point `node` and `orig_node` have the same value. Another potential path for this is entering the function and after returning from `grub_affs_create_node` it will also be free'd on line 462. Both of these stem from the fact that both node and orig_node still have the same value assigned on line 413 which can be freed when going into the hook logic. I've attached a reproducer affs filesystem file and a simple grub script to be run inside grub-emu which demonstrates the bug, all that's needed is to: ``` grub-emu -d <path to grub.cfg dir> ``` You may also have to change the path inside grub.cfg to point to the affs filesystem file. When done correctly you should observe a double free error. To mitigate this the attached patch should work but might not be the optimal solution. Instead of using `node` for the hook logic, we allocate a separate node which is used. This is very similar to the code in the `grub_hfsplus_iterate_dir` function: hfsplus.c, line 851 ```c { struct grub_fshelp_node *fsnode; fsnode = grub_malloc (sizeof (*fsnode)); if (!fsnode) return 1; *fsnode = *dir; if (hook (".", GRUB_FSHELP_DIR, fsnode, hook_data)) return 1; } ``` This area from what I can tell doesnt have this issue. Please let me know if there are any problems, thanks. Here's the patch: diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c index 520a001c7..9e3564b33 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -414,15 +414,19 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, if (!node) return 1; - *node = *dir; - if (hook (".", GRUB_FSHELP_DIR, node, hook_data)) - return 1; - if (dir->parent) - { - *node = *dir->parent; - if (hook ("..", GRUB_FSHELP_DIR, node, hook_data)) - return 1; + { + struct grub_fshelp_node *temp_node = grub_zalloc(sizeof(*node)); + if (!temp_node) + return 1; + *temp_node = *dir; + if (hook(".", GRUB_FSHELP_DIR, temp_node, hook_data)) + return 1; + if (dir->parent) { + *temp_node = *dir->parent; + if (hook("..", GRUB_FSHELP_DIR, temp_node, hook_data)) + return 1; + } + }
tst.affs
Description: Binary data
grub.cfg
Description: Binary data
diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c index 520a001c7..9e3564b33 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -414,15 +414,19 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, if (!node) return 1; - *node = *dir; - if (hook (".", GRUB_FSHELP_DIR, node, hook_data)) - return 1; - if (dir->parent) - { - *node = *dir->parent; - if (hook ("..", GRUB_FSHELP_DIR, node, hook_data)) - return 1; + { + struct grub_fshelp_node *temp_node = grub_zalloc(sizeof(*node)); + if (!temp_node) + return 1; + *temp_node = *dir; + if (hook(".", GRUB_FSHELP_DIR, temp_node, hook_data)) + return 1; + if (dir->parent) { + *temp_node = *dir->parent; + if (hook("..", GRUB_FSHELP_DIR, temp_node, hook_data)) + return 1; } + } hashtable = grub_calloc (data->htsize, sizeof (*hashtable)); if (!hashtable)
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel