Recent changes (master)

Jens Axboe <[email protected]> Fri, 1 May 2026 06:00:01 -0600
Newsgroups org.kernel.vger.fio
Message-ID <[email protected]>
The following changes since commit a95f84caad2300e73ec9bf7077879f30246f3185:

  sprandom: relax power of 2 block size requirement (2026-04-28 12:25:01 -0400)

are available in the Git repository at:

  git://git.kernel.dk/fio.git master

for you to fetch changes up to 72156dca3d41df7d05ea4e5a4e59623c2d393a92:

  Merge branch 'codex/cgroup-path-overflows' of https://github.com/linuxholic/fio (2026-04-30 06:53:46 -0600)

----------------------------------------------------------------
Jens Axboe (1):
      Merge branch 'codex/cgroup-path-overflows' of https://github.com/linuxholic/fio

yangpeng (1):
      cgroup: fix path buffer overflows for long cgroup names

 Makefile             |   6 ++
 cgroup.c             |  48 +++++++++++++---
 unittests/cgroup.c   | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++
 unittests/unittest.c |   3 +
 unittests/unittest.h |   3 +
 5 files changed, 212 insertions(+), 8 deletions(-)
 create mode 100644 unittests/cgroup.c

---

Diff of recent changes:

diff --git a/Makefile b/Makefile
index 099e2f94..e3960ece 100644
--- a/Makefile
+++ b/Makefile
@@ -455,6 +455,12 @@ UT_OBJS += unittests/oslib/strlcat.o
 UT_OBJS += unittests/oslib/strndup.o
 UT_OBJS += unittests/oslib/strcasestr.o
 UT_OBJS += unittests/oslib/strsep.o
+ifeq ($(CONFIG_TARGET_OS), Linux)
+UT_OBJS += unittests/cgroup.o
+endif
+ifeq ($(CONFIG_TARGET_OS), Android)
+UT_OBJS += unittests/cgroup.o
+endif
 UT_TARGET_OBJS = lib/memalign.o
 UT_TARGET_OBJS += lib/num2str.o
 UT_TARGET_OBJS += lib/strntol.o
diff --git a/cgroup.c b/cgroup.c
index 77e31a4d..0a26fc8d 100644
--- a/cgroup.c
+++ b/cgroup.c
@@ -18,6 +18,32 @@ struct cgroup_member {
 	unsigned int cgroup_nodelete;
 };
 
+static char *cgroup_path(struct thread_data *td, const char *path,
+			 const char *name, const char *onerr)
+{
+	size_t path_len = strlen(path);
+	size_t name_len = strlen(name);
+	size_t len;
+	char *str;
+	int err;
+
+	if (path_len > SIZE_MAX - name_len - 2) {
+		td_verror(td, ENAMETOOLONG, onerr);
+		return NULL;
+	}
+
+	len = path_len + name_len + 2;
+	str = malloc(len);
+	if (!str) {
+		err = errno;
+		td_verror(td, err, onerr);
+		return NULL;
+	}
+
+	snprintf(str, len, "%s/%s", path, name);
+	return str;
+}
+
 static struct cgroup_mnt *find_cgroup_mnt(struct thread_data *td)
 {
 	struct cgroup_mnt *cgroup_mnt = NULL;
@@ -113,32 +139,35 @@ void cgroup_kill(struct flist_head *clist)
 
 static char *get_cgroup_root(struct thread_data *td, struct cgroup_mnt *mnt)
 {
-	char *str = malloc(64);
-
 	if (td->o.cgroup)
-		sprintf(str, "%s/%s", mnt->path, td->o.cgroup);
+		return cgroup_path(td, mnt->path, td->o.cgroup,
+				   "cgroup root path");
 	else
-		sprintf(str, "%s/%s", mnt->path, td->o.name);
-
-	return str;
+		return cgroup_path(td, mnt->path, td->o.name,
+				   "cgroup root path");
 }
 
 static int write_int_to_file(struct thread_data *td, const char *path,
 			     const char *filename, unsigned int val,
 			     const char *onerr)
 {
-	char tmp[256];
+	char *tmp;
 	FILE *f;
 
-	sprintf(tmp, "%s/%s", path, filename);
+	tmp = cgroup_path(td, path, filename, onerr);
+	if (!tmp)
+		return 1;
+
 	f = fopen(tmp, "w");
 	if (!f) {
+		free(tmp);
 		td_verror(td, errno, onerr);
 		return 1;
 	}
 
 	fprintf(f, "%u", val);
 	fclose(f);
+	free(tmp);
 	return 0;
 
 }
@@ -178,6 +207,9 @@ int cgroup_setup(struct thread_data *td, struct flist_head *clist, struct cgroup
 	 * Create container, if it doesn't exist
 	 */
 	root = get_cgroup_root(td, *mnt);
+	if (!root)
+		return 1;
+
 	if (mkdir(root, 0755) < 0) {
 		int __e = errno;
 
diff --git a/unittests/cgroup.c b/unittests/cgroup.c
new file mode 100644
index 00000000..cc99c3d1
--- /dev/null
+++ b/unittests/cgroup.c
@@ -0,0 +1,160 @@
+#include "../fio.h"
+#include "./unittest.h"
+
+ssize_t log_err(const char *format, ...)
+{
+	return 0;
+}
+
+void *smalloc(size_t size)
+{
+	return malloc(size);
+}
+
+void *scalloc(size_t nmemb, size_t size)
+{
+	return calloc(nmemb, size);
+}
+
+void sfree(void *ptr)
+{
+	free(ptr);
+}
+
+char *smalloc_strdup(const char *str)
+{
+	return strdup(str);
+}
+
+void sinit(void)
+{
+}
+
+void scleanup(void)
+{
+}
+
+void smalloc_debug(size_t size)
+{
+}
+
+unsigned int smalloc_pool_size;
+
+struct fio_sem *fio_sem_init(int value)
+{
+	return NULL;
+}
+
+void fio_sem_remove(struct fio_sem *sem)
+{
+}
+
+void fio_sem_down(struct fio_sem *sem)
+{
+}
+
+void fio_sem_up(struct fio_sem *sem)
+{
+}
+
+#include "../cgroup.c"
+
+static char *test_path_join(const char *path, const char *name)
+{
+	size_t path_len = strlen(path);
+	size_t name_len = strlen(name);
+	size_t len = path_len + name_len + 2;
+	char *joined = malloc(len);
+
+	CU_ASSERT_PTR_NOT_NULL_FATAL(joined);
+	snprintf(joined, len, "%s/%s", path, name);
+	return joined;
+}
+
+static void test_get_cgroup_root_long_path(void)
+{
+	struct thread_data td = { 0 };
+	char mnt_path[] = "/sys/fs/cgroup/blkio";
+	char cgroup_name[] =
+		"/system/pod51ec34a2-12b8-4a51-8b98-b49dace8366f/"
+		"af7853ad741dee19af1b8e14ee2142a7a9314b2dc98a091a29f8aa96106c0a22";
+	struct cgroup_mnt mnt = {
+		.path = mnt_path,
+		.cgroup2 = false,
+	};
+	char *root;
+	char *expected;
+
+	td.o.cgroup = cgroup_name;
+
+	root = get_cgroup_root(&td, &mnt);
+	CU_ASSERT_PTR_NOT_NULL_FATAL(root);
+
+	expected = test_path_join(mnt.path, td.o.cgroup);
+	CU_ASSERT_STRING_EQUAL(root, expected);
+	CU_ASSERT(strlen(root) > 64);
+	CU_ASSERT_EQUAL(td.error, 0);
+
+	free(expected);
+	free(root);
+}
+
+static void test_write_int_to_file_long_path(void)
+{
+	struct thread_data td = { 0 };
+	char tmpdir[] = "/tmp/fio-cgroup-XXXXXX";
+	char leaf[231];
+	char *dir;
+	char *file_path;
+	FILE *f;
+	char buf[32];
+
+	CU_ASSERT_PTR_NOT_NULL_FATAL(mkdtemp(tmpdir));
+
+	memset(leaf, 'x', sizeof(leaf) - 1);
+	leaf[sizeof(leaf) - 1] = '\0';
+
+	dir = test_path_join(tmpdir, leaf);
+	CU_ASSERT_EQUAL_FATAL(mkdir(dir, 0700), 0);
+
+	file_path = test_path_join(dir, "blkio.weight");
+	CU_ASSERT(strlen(file_path) > 256);
+	free(file_path);
+
+	CU_ASSERT_EQUAL(write_int_to_file(&td, dir, "blkio.weight", 1234,
+					  "write_int_to_file"), 0);
+	CU_ASSERT_EQUAL(td.error, 0);
+
+	file_path = test_path_join(dir, "blkio.weight");
+	f = fopen(file_path, "r");
+	CU_ASSERT_PTR_NOT_NULL_FATAL(f);
+	CU_ASSERT_PTR_NOT_NULL(fgets(buf, sizeof(buf), f));
+	CU_ASSERT_STRING_EQUAL(buf, "1234");
+	fclose(f);
+
+	CU_ASSERT_EQUAL(unlink(file_path), 0);
+	CU_ASSERT_EQUAL(rmdir(dir), 0);
+	CU_ASSERT_EQUAL(rmdir(tmpdir), 0);
+
+	free(file_path);
+	free(dir);
+}
+
+static struct fio_unittest_entry tests[] = {
+	{
+		.name	= "cgroup/get-root-long-path",
+		.fn	= test_get_cgroup_root_long_path,
+	},
+	{
+		.name	= "cgroup/write-int-to-file-long-path",
+		.fn	= test_write_int_to_file_long_path,
+	},
+	{
+		.name	= NULL,
+	},
+};
+
+CU_ErrorCode fio_unittest_cgroup(void)
+{
+	return fio_unittest_add_suite("cgroup.c", NULL, NULL, tests);
+}
diff --git a/unittests/unittest.c b/unittests/unittest.c
index 4a034b40..c4316322 100644
--- a/unittests/unittest.c
+++ b/unittests/unittest.c
@@ -55,6 +55,9 @@ int main(void)
 	fio_unittest_register(fio_unittest_oslib_strndup);
 	fio_unittest_register(fio_unittest_oslib_strcasestr);
 	fio_unittest_register(fio_unittest_oslib_strsep);
+#if defined(__linux__) || defined(__ANDROID__)
+	fio_unittest_register(fio_unittest_cgroup);
+#endif
 
 	CU_basic_set_mode(CU_BRM_VERBOSE);
 	CU_basic_run_tests();
diff --git a/unittests/unittest.h b/unittests/unittest.h
index 0f45bfbd..6f2ac776 100644
--- a/unittests/unittest.h
+++ b/unittests/unittest.h
@@ -22,5 +22,8 @@ CU_ErrorCode fio_unittest_oslib_strlcat(void);
 CU_ErrorCode fio_unittest_oslib_strndup(void);
 CU_ErrorCode fio_unittest_oslib_strcasestr(void);
 CU_ErrorCode fio_unittest_oslib_strsep(void);
+#if defined(__linux__) || defined(__ANDROID__)
+CU_ErrorCode fio_unittest_cgroup(void);
+#endif
 
 #endif