cg_find_root() parses /proc/self/mounts with strtok() and assumes that every field group it walks over is a complete "device mountpoint type options freq passno" tuple. That only holds while the buffer is big enough for the whole file: if the buffer is too small, the last tuple is cut short, strtok() returns NULL for the missing fields, and the strcmp(type, ...) and strstr(options, ...) calls that follow dereference it.
The current buffer is 10 * BUF_SIZE, so reaching this needs a mount table over 40K, but the crash is easy to hit in a sandbox: with BUF_SIZE overridden to 6, which leaves a 60-byte buffer, cg_find_unified_root() segfaults instead of failing. Stop parsing as soon as a field is missing. Nothing follows a truncated entry, so there is nothing to parse after it either. Signed-off-by: Shaojie Sun <[email protected]> --- tools/testing/selftests/cgroup/lib/cgroup_util.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/testing/selftests/cgroup/lib/cgroup_util.c b/tools/testing/selftests/cgroup/lib/cgroup_util.c index 65cd85c467bb..cd73471e13d7 100644 --- a/tools/testing/selftests/cgroup/lib/cgroup_util.c +++ b/tools/testing/selftests/cgroup/lib/cgroup_util.c @@ -302,6 +302,16 @@ static int cg_find_root(char *root, size_t len, const char *controller, options = strtok(NULL, delim); strtok(NULL, delim); strtok(NULL, delim); + + /* + * A mount entry is "device mountpoint type options freq + * passno". A field can only be missing if the last entry was + * cut short by the buffer being too small for the file, and + * there is no complete entry left to look at. + */ + if (!mount || !type || !options) + break; + if (strcmp(type, "cgroup") == 0) { if (!controller || !strstr(options, controller)) continue; -- 2.50.1

