summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Freed <bfreed@chromium.org>2011-11-11 13:05:30 -0800
committerBryan Freed <bfreed@chromium.org>2011-11-14 11:19:52 -0800
commitf8e5f9f2ed1a383d5726d4e55a40c7e6f9bc9744 (patch)
tree7e83ab1405cac6b14d5cd4a91f122fa32e18776d
parent80fbc6c5d03ba9c192f0e406ee0b6ec60711d603 (diff)
downloadrootdev-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.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/rootdev.c b/rootdev.c
index 867974f..3162be9 100644
--- a/rootdev.c
+++ b/rootdev.c
@@ -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;