diff options
author | Bryan Freed <bfreed@chromium.org> | 2011-11-11 13:05:30 -0800 |
---|---|---|
committer | Bryan Freed <bfreed@chromium.org> | 2011-11-14 11:19:52 -0800 |
commit | f8e5f9f2ed1a383d5726d4e55a40c7e6f9bc9744 (patch) | |
tree | 7e83ab1405cac6b14d5cd4a91f122fa32e18776d | |
parent | 80fbc6c5d03ba9c192f0e406ee0b6ec60711d603 (diff) | |
download | rootdev-f8e5f9f2ed1a383d5726d4e55a40c7e6f9bc9744.tar.gz |
rootdev: Prevent infinite recursion when parsing /sys/block.
The mmcblk driver of the 3.0.8 kernel adds mmcblk0boot0 and mmcblk0boot1
directories under /sys/block or /sys/block/mmcblk0. I have seen it both ways.
The device symlink in those directories points to "../../mmcblk0" which
points to the grandparent directory.
When rootdev scans /sys/block looking for a device that matches "/", it
can fall into this loop and recurse until failure.
While a proper fix would detect loops to prevent recursion, that adds
considerable complexity to the directory scan.
This relatively simple solution limits recursion depth to 5 to prevent
infinitely looping. It will fail to find device matches beyond 5 levels
of directories, but we are nowhere near that in today's systems. We find
matches at level 3 as best I can tell.
BUG=chromium-os:22855
TEST=Run rootdev and check for failures.
Change-Id: I9ef3aa0a6d6f8143dd0b9e012ba4bb4adfa0c73b
Reviewed-on: https://gerrit.chromium.org/gerrit/11575
Reviewed-by: Will Drewry <wad@chromium.org>
Commit-Ready: Bryan Freed <bfreed@chromium.org>
Tested-by: Bryan Freed <bfreed@chromium.org>
-rw-r--r-- | rootdev.c | 12 |
1 files changed, 8 insertions, 4 deletions
@@ -79,7 +79,7 @@ static dev_t devt_from_file(const char *file) { * a block device to find sub-devices (partitions). * If dev == 0, the first device in the directory will be returned. */ static int match_sysfs_device(char *name, size_t name_len, - const char *basedir, dev_t *dev) { + const char *basedir, dev_t *dev, int depth) { int found = -1; size_t basedir_len; DIR *dirp = NULL; @@ -165,10 +165,14 @@ static int match_sysfs_device(char *name, size_t name_len, break; } + /* Prevent infinite recursion on symlink loops by limiting depth. */ + if (depth > 5) + break; + /* Recurse one level for devices that may have a matching partition. */ if (major(found_devt) == major(*dev) && minor(*dev) > minor(found_devt)) { sprintf(working_path, "%s/%s", basedir, entry->d_name); - found = match_sysfs_device(name, name_len, working_path, dev); + found = match_sysfs_device(name, name_len, working_path, dev, depth + 1); if (found > 0) break; } @@ -241,7 +245,7 @@ int rootdev_get_device(char *dst, size_t size, dev_t dev, } snprintf(dst, size, "%s", search); - if (match_sysfs_device(dst, size, dst, &dev) <= 0) { + if (match_sysfs_device(dst, size, dst, &dev, 0) <= 0) { fprintf (stderr, "unable to find match\n"); return 1; } @@ -264,7 +268,7 @@ int rootdev_get_device_slave(char *slave, size_t size, dev_t *dev, return -1; } *dev = 0; - if (match_sysfs_device(slave, size, dst, dev) <= 0) + if (match_sysfs_device(slave, size, dst, dev, 0) <= 0) return -1; return 0; |