* [LTP] [PATCH v1] iocl11.c: New case check PROCMAP_QUERY ioctl() errnos @ 2025-08-07 13:48 Wei Gao via ltp 2025-08-07 8:36 ` Petr Vorel 2025-08-08 16:30 ` [LTP] [PATCH v2] ioctl11.c: " Wei Gao via ltp 0 siblings, 2 replies; 5+ messages in thread From: Wei Gao via ltp @ 2025-08-07 13:48 UTC (permalink / raw) To: ltp Signed-off-by: Wei Gao <wegao@suse.com> --- runtest/syscalls | 1 + testcases/kernel/syscalls/ioctl/.gitignore | 1 + testcases/kernel/syscalls/ioctl/ioctl11.c | 183 +++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 testcases/kernel/syscalls/ioctl/ioctl11.c diff --git a/runtest/syscalls b/runtest/syscalls index 6a17a34f8..8bc7f60d2 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -588,6 +588,7 @@ ioctl07 ioctl07 ioctl08 ioctl08 ioctl09 ioctl09 ioctl10 ioctl10 +ioctl11 ioctl11 ioctl_loop01 ioctl_loop01 ioctl_loop02 ioctl_loop02 diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore index dac4583fa..54685e916 100644 --- a/testcases/kernel/syscalls/ioctl/.gitignore +++ b/testcases/kernel/syscalls/ioctl/.gitignore @@ -8,6 +8,7 @@ /ioctl08 /ioctl09 /ioctl10 +/ioctl11 /ioctl_loop01 /ioctl_loop02 /ioctl_loop03 diff --git a/testcases/kernel/syscalls/ioctl/ioctl11.c b/testcases/kernel/syscalls/ioctl/ioctl11.c new file mode 100644 index 000000000..aef2105cc --- /dev/null +++ b/testcases/kernel/syscalls/ioctl/ioctl11.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2024 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] + * + * Test PROCMAP_QUERY ioctl() errnos: + * + * - EINVAL if q->size is too small + * - E2BIG if q->size is larger than page size + * - EINVAL on invalid q->flags + * - EINVAL if only one of q->vma_name_size and q->vma_name_addr is set + * - EINVAL if only one of q->build_id_size and q->build_id_addr is set + * - ENAMETOOLONG if build_id_size or name_buf_size is too small + */ + +#include "config.h" +#include <stdlib.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <fnmatch.h> +#include "tst_test.h" +#include "tst_safe_stdio.h" +#include <sys/sysmacros.h> +#include <linux/fs.h> +#include "lapi/ioctl.h" + +#define PROC_MAP_PATH "/proc/self/maps" + +struct procmap_query *q; +static int fd = -1; +static char buf[PATH_MAX]; +static char small_buf[1]; + +static void setup_normal(void); +static void setup_big_size(void); + +static struct tcase { + uint64_t size; + uint64_t query_addr; + uint64_t query_flags; + uint64_t vma_name_addr; + uint32_t vma_name_size; + uint64_t build_id_addr; + uint32_t build_id_size; + int exp_errno; + void (*setup)(void); +} tcases[] = { + { + .size = 1, + .exp_errno = EINVAL, + .setup = setup_normal + }, + { + .exp_errno = E2BIG, + .setup = setup_big_size + }, + { + .query_flags = -1, + .exp_errno = EINVAL, + .setup = setup_normal + }, + { + .vma_name_size = sizeof(buf), + .exp_errno = EINVAL, + .setup = setup_normal + }, + { + .vma_name_addr = (uint64_t)(unsigned long)buf, + .exp_errno = EINVAL, + .setup = setup_normal + }, + { + .build_id_size = sizeof(buf), + .exp_errno = EINVAL, + .setup = setup_normal + }, + { + .build_id_addr = (uint64_t)(unsigned long)buf, + .exp_errno = EINVAL, + .setup = setup_normal + }, + { + .vma_name_addr = (uint64_t)(unsigned long)small_buf, + .vma_name_size = sizeof(small_buf), + .exp_errno = ENAMETOOLONG, + .setup = setup_normal + }, + { + .build_id_addr = (uint64_t)(unsigned long)small_buf, + .build_id_size = sizeof(small_buf), + .exp_errno = ENAMETOOLONG, + .setup = setup_normal + }, +}; + +static unsigned long get_vm_start(void) +{ + FILE *fp = SAFE_FOPEN(PROC_MAP_PATH, "r"); + char line[1024]; + unsigned long start_addr = 0; + + if (fgets(line, sizeof(line), fp) != NULL) { + if (sscanf(line, "%lx-", &start_addr) != 1) + tst_brk(TFAIL, "parse maps file /proc/self/maps failed"); + return start_addr; + } + + SAFE_FCLOSE(fp); + tst_brk(TFAIL, "parse maps file /proc/self/maps failed"); +} + +static void setup_normal(void) +{ + q->size = sizeof(*q); + q->query_addr = (uint64_t)get_vm_start(); + q->query_flags = 0; +} + +static void setup_big_size(void) +{ + setup_normal(); + q->size = getpagesize() + 1; +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + + memset(q, 0, sizeof(*q)); + + tc->setup(); + + if (tc->size != 0) + q->size = tc->size; + if (tc->query_flags != 0) + q->query_flags = tc->query_flags; + if (tc->vma_name_addr != 0) + q->vma_name_addr = tc->vma_name_addr; + if (tc->vma_name_size != 0) + q->vma_name_size = tc->vma_name_size; + if (tc->build_id_addr != 0) + q->build_id_addr = tc->build_id_addr; + if (tc->build_id_size != 0) + q->build_id_size = tc->build_id_size; + + TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, q), tc->exp_errno); +} + +static void setup(void) +{ + struct procmap_query q = {}; + + fd = SAFE_OPEN(PROC_MAP_PATH, O_RDONLY); + + if (tst_kvercmp(6, 11, 0) < 0) { + TEST(ioctl(fd, PROCMAP_QUERY, q)); + + if ((TST_RET == -1) && (TST_ERR == ENOTTY)) + tst_brk(TCONF, + "This system does not provide support for ioctl(PROCMAP_QUERY)"); + } + +} + +static void cleanup(void) +{ + if (fd != -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .setup = setup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&q, .size = sizeof(*q)}, + {} + } +}; -- 2.49.0 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [LTP] [PATCH v1] iocl11.c: New case check PROCMAP_QUERY ioctl() errnos 2025-08-07 13:48 [LTP] [PATCH v1] iocl11.c: New case check PROCMAP_QUERY ioctl() errnos Wei Gao via ltp @ 2025-08-07 8:36 ` Petr Vorel 2025-08-08 16:30 ` [LTP] [PATCH v2] ioctl11.c: " Wei Gao via ltp 1 sibling, 0 replies; 5+ messages in thread From: Petr Vorel @ 2025-08-07 8:36 UTC (permalink / raw) To: Wei Gao; +Cc: ltp Hi Wei, Thanks for writing new test. Generally LGTM. Also, FYI upstream developer enhanced existing tools/testing/selftests/proc/proc-pid-vm.c https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=81510a0eaa6916c2fbb0b2639f3e617a296979a3 That might be a good source for real PROCMAP_QUERY testing. Few common errors: 1) git commit subject contains typo: iocl11 => ioctl11 Please remember to fix it. 2) Warning $ make check-ioctl11 CHECK testcases/kernel/syscalls/ioctl/ioctl11.c ioctl11.c:32:22: warning: Symbol 'q' has no prototype or library ('tst_') prefix. Should it be static? 3) EMFILE (Too many open files) => missing SAFE_FCLOSE(fp) before return start_addr; # ./ioctl11 -i1200 ioctl11.c:149: TPASS: ioctl(fd, PROCMAP_QUERY, q) : E2BIG (7) ioctl11.c:149: TPASS: ioctl(fd, PROCMAP_QUERY, q) : EINVAL (22) ioctl11.c:101: TBROK: fopen(/proc/self/maps,r) failed: EMFILE (24) ioctl11.c: In function ‘get_vm_start’: ioctl11.c:113:1: warning: control reaches end of non-void function [-Wreturn-type] 113 | } | ^ Other notes below. ... > diff --git a/testcases/kernel/syscalls/ioctl/ioctl11.c b/testcases/kernel/syscalls/ioctl/ioctl11.c > new file mode 100644 > index 000000000..aef2105cc > --- /dev/null > +++ b/testcases/kernel/syscalls/ioctl/ioctl11.c > @@ -0,0 +1,183 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (c) 2024 Wei Gao <wegao@suse.com> Maybe update to 2025? > + */ > + > +/*\ > + * [Description] > + * > + * Test PROCMAP_QUERY ioctl() errnos: > + * > + * - EINVAL if q->size is too small > + * - E2BIG if q->size is larger than page size > + * - EINVAL on invalid q->flags > + * - EINVAL if only one of q->vma_name_size and q->vma_name_addr is set > + * - EINVAL if only one of q->build_id_size and q->build_id_addr is set > + * - ENAMETOOLONG if build_id_size or name_buf_size is too small What is name_buf_size? Do you mean vma_name_size? I wonder whether pointing out in doc some of the relevant commits (6 commits mentioned in "(FEATURED) ioctl()-based API to query VMAs from /proc/<pid>" section in [1]) or just put [2] (or [3] would make sense. [1] https://kernelnewbies.org/Linux_6.11#Memory_management [2] https://kernelnewbies.org/Linux_6.11#Binary_interface_for_.2Fproc.2F.3Cpid.3E.2Fmaps [3] https://lore.kernel.org/all/20240627170900.1672542-1-andrii@kernel.org/ ed5d583a88a9 ("fs/procfs: implement efficient VMA querying API for /proc/<pid>/maps") > + */ > + > +#include "config.h" > +#include <stdlib.h> Either <stdlib.h> is not needed or some of LTP headers probably adds it as it builds without it. > +#include <sys/ioctl.h> <sys/ioctl.h> is not needed (loaded as part of lapi/ioctl.h. https://github.com/linux-test-project/ltp/blob/master/doc/old/C-Test-API.asciidoc#lapi-headers > +#include <errno.h> > +#include <fnmatch.h> Why this header? IMHO not needed. > +#include "tst_test.h" > +#include "tst_safe_stdio.h" > +#include <sys/sysmacros.h> Why this header? IMHO not needed. very nit: Also I would first add system headers (these with <>) and then LTP headers. i.e. not mixing them. > +#include <linux/fs.h> > +#include "lapi/ioctl.h" > + #include "config.h" #include <errno.h> #include <linux/fs.h> #include "tst_test.h" #include "tst_safe_stdio.h" #include "lapi/ioctl.h" > +#define PROC_MAP_PATH "/proc/self/maps" > + > +struct procmap_query *q; This should be static. > +static int fd = -1; > +static char buf[PATH_MAX]; > +static char small_buf[1]; > + > +static void setup_normal(void); > +static void setup_big_size(void); > + > +static struct tcase { > + uint64_t size; > + uint64_t query_addr; > + uint64_t query_flags; > + uint64_t vma_name_addr; > + uint32_t vma_name_size; > + uint64_t build_id_addr; > + uint32_t build_id_size; > + int exp_errno; > + void (*setup)(void); > +} tcases[] = { > + { > + .size = 1, > + .exp_errno = EINVAL, > + .setup = setup_normal > + }, > + { > + .exp_errno = E2BIG, > + .setup = setup_big_size > + }, > + { > + .query_flags = -1, > + .exp_errno = EINVAL, > + .setup = setup_normal > + }, > + { > + .vma_name_size = sizeof(buf), > + .exp_errno = EINVAL, > + .setup = setup_normal > + }, > + { > + .vma_name_addr = (uint64_t)(unsigned long)buf, > + .exp_errno = EINVAL, > + .setup = setup_normal > + }, > + { > + .build_id_size = sizeof(buf), > + .exp_errno = EINVAL, > + .setup = setup_normal > + }, > + { > + .build_id_addr = (uint64_t)(unsigned long)buf, > + .exp_errno = EINVAL, > + .setup = setup_normal > + }, > + { > + .vma_name_addr = (uint64_t)(unsigned long)small_buf, > + .vma_name_size = sizeof(small_buf), > + .exp_errno = ENAMETOOLONG, > + .setup = setup_normal > + }, > + { > + .build_id_addr = (uint64_t)(unsigned long)small_buf, > + .build_id_size = sizeof(small_buf), > + .exp_errno = ENAMETOOLONG, > + .setup = setup_normal > + }, > +}; > + > +static unsigned long get_vm_start(void) > +{ > + FILE *fp = SAFE_FOPEN(PROC_MAP_PATH, "r"); > + char line[1024]; > + unsigned long start_addr = 0; > + > + if (fgets(line, sizeof(line), fp) != NULL) { > + if (sscanf(line, "%lx-", &start_addr) != 1) > + tst_brk(TFAIL, "parse maps file /proc/self/maps failed"); nit: Maybe "map not found in /proc/self/maps"? Also, PROC_MAP_PATH will never change from /proc/self/maps, so it's probably safe to use it hardcoded. But using just "map not found" would avoid hardcoded file. Here you needs to also close fp. > + return start_addr; > + } > + > + SAFE_FCLOSE(fp); > + tst_brk(TFAIL, "parse maps file /proc/self/maps failed"); > +} > + > +static void setup_normal(void) > +{ > + q->size = sizeof(*q); > + q->query_addr = (uint64_t)get_vm_start(); > + q->query_flags = 0; > +} > + > +static void setup_big_size(void) > +{ > + setup_normal(); IMHO content of setup_normal() should be moved to run(), before tc->setup(). Then all ".setup = setup_normal" could be removed. > + q->size = getpagesize() + 1; > +} > + > +static void run(unsigned int n) > +{ > + struct tcase *tc = &tcases[n]; > + > + memset(q, 0, sizeof(*q)); > + > + tc->setup(); > + > + if (tc->size != 0) > + q->size = tc->size; Spaces between each if would make code for me more readable. > + if (tc->query_flags != 0) > + q->query_flags = tc->query_flags; > + if (tc->vma_name_addr != 0) > + q->vma_name_addr = tc->vma_name_addr; > + if (tc->vma_name_size != 0) > + q->vma_name_size = tc->vma_name_size; > + if (tc->build_id_addr != 0) > + q->build_id_addr = tc->build_id_addr; > + if (tc->build_id_size != 0) > + q->build_id_size = tc->build_id_size; > + > + TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, q), tc->exp_errno); > +} > + > +static void setup(void) > +{ > + struct procmap_query q = {}; > + > + fd = SAFE_OPEN(PROC_MAP_PATH, O_RDONLY); > + > + if (tst_kvercmp(6, 11, 0) < 0) { If you reverse the condition code is more compact. > + TEST(ioctl(fd, PROCMAP_QUERY, q)); > + > + if ((TST_RET == -1) && (TST_ERR == ENOTTY)) Brackets between && are not needed. > + tst_brk(TCONF, > + "This system does not provide support for ioctl(PROCMAP_QUERY)"); if (tst_kvercmp(6, 11, 0) >= 0) return; TEST(ioctl(fd, PROCMAP_QUERY, q)); if (TST_RET == -1 && TST_ERR == ENOTTY) { tst_brk(TCONF, "This system does not provide support for ioctl(PROCMAP_QUERY)"); } > + } > + Please remove this blank line ^. > +} Kind regards, Petr -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 5+ messages in thread
* [LTP] [PATCH v2] ioctl11.c: New case check PROCMAP_QUERY ioctl() errnos 2025-08-07 13:48 [LTP] [PATCH v1] iocl11.c: New case check PROCMAP_QUERY ioctl() errnos Wei Gao via ltp 2025-08-07 8:36 ` Petr Vorel @ 2025-08-08 16:30 ` Wei Gao via ltp 2025-08-12 6:14 ` [LTP] [PATCH v3] " Wei Gao via ltp 1 sibling, 1 reply; 5+ messages in thread From: Wei Gao via ltp @ 2025-08-08 16:30 UTC (permalink / raw) To: ltp Signed-off-by: Wei Gao <wegao@suse.com> --- runtest/syscalls | 1 + testcases/kernel/syscalls/ioctl/.gitignore | 1 + testcases/kernel/syscalls/ioctl/ioctl11.c | 183 +++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 testcases/kernel/syscalls/ioctl/ioctl11.c diff --git a/runtest/syscalls b/runtest/syscalls index 6a17a34f8..8bc7f60d2 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -588,6 +588,7 @@ ioctl07 ioctl07 ioctl08 ioctl08 ioctl09 ioctl09 ioctl10 ioctl10 +ioctl11 ioctl11 ioctl_loop01 ioctl_loop01 ioctl_loop02 ioctl_loop02 diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore index dac4583fa..54685e916 100644 --- a/testcases/kernel/syscalls/ioctl/.gitignore +++ b/testcases/kernel/syscalls/ioctl/.gitignore @@ -8,6 +8,7 @@ /ioctl08 /ioctl09 /ioctl10 +/ioctl11 /ioctl_loop01 /ioctl_loop02 /ioctl_loop03 diff --git a/testcases/kernel/syscalls/ioctl/ioctl11.c b/testcases/kernel/syscalls/ioctl/ioctl11.c new file mode 100644 index 000000000..86dc56bbe --- /dev/null +++ b/testcases/kernel/syscalls/ioctl/ioctl11.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] + * + * Test PROCMAP_QUERY ioctl() errnos: + * + * - EINVAL if q->size is too small + * - E2BIG if q->size is larger than page size + * - EINVAL on invalid q->flags + * - EINVAL if only one of q->vma_name_size and q->vma_name_addr is set + * - EINVAL if only one of q->build_id_size and q->build_id_addr is set + * - ENAMETOOLONG if build_id_size or name_buf_size is too small + * + * [1] https://kernelnewbies.org/Linux_6.11#Memory_management + * [2] https://kernelnewbies.org/Linux_6.11#Binary_interface_for_.2Fproc.2F.3Cpid.3E.2Fmaps + * [3] https://lore.kernel.org/all/20240627170900.1672542-1-andrii@kernel.org/ + * ed5d583a88a9 ("fs/procfs: implement efficient VMA querying API for /proc/<pid>/maps") + */ + +#include <errno.h> +#include <linux/fs.h> +#include "config.h" +#include "tst_test.h" +#include "tst_safe_stdio.h" +#include "lapi/ioctl.h" + +#define PROC_MAP_PATH "/proc/self/maps" + +static struct procmap_query *q; +static int fd = -1; +static char buf[PATH_MAX]; +static char small_buf[1]; +static unsigned long vm_start_addr; + +static void setup_normal(void); +static void setup_big_size(void); + +static struct tcase { + uint64_t size; + uint64_t query_addr; + uint64_t query_flags; + uint64_t vma_name_addr; + uint32_t vma_name_size; + uint64_t build_id_addr; + uint32_t build_id_size; + int exp_errno; + void (*setup)(void); +} tcases[] = { + { + .size = 1, + .exp_errno = EINVAL, + }, + { + .exp_errno = E2BIG, + .setup = setup_big_size + }, + { + .query_flags = -1, + .exp_errno = EINVAL, + }, + { + .vma_name_size = sizeof(buf), + .exp_errno = EINVAL, + }, + { + .vma_name_addr = (uint64_t)(unsigned long)buf, + .exp_errno = EINVAL, + }, + { + .build_id_size = sizeof(buf), + .exp_errno = EINVAL, + }, + { + .build_id_addr = (uint64_t)(unsigned long)buf, + .exp_errno = EINVAL, + }, + { + .vma_name_addr = (uint64_t)(unsigned long)small_buf, + .vma_name_size = sizeof(small_buf), + .exp_errno = ENAMETOOLONG, + }, + { + .build_id_addr = (uint64_t)(unsigned long)small_buf, + .build_id_size = sizeof(small_buf), + .exp_errno = ENAMETOOLONG, + }, +}; + +static void get_vm_start(void) +{ + FILE *fp = SAFE_FOPEN(PROC_MAP_PATH, "r"); + char line[1024]; + + if (fgets(line, sizeof(line), fp) != NULL) { + if (sscanf(line, "%lx-", &vm_start_addr) != 1) + tst_brk(TFAIL, "maps not found in %s", PROC_MAP_PATH); + } else { + tst_brk(TFAIL, "maps not found in %s", PROC_MAP_PATH); + } + + SAFE_FCLOSE(fp); +} + +static void setup_normal(void) +{ + q->size = sizeof(*q); + q->query_addr = (uint64_t)vm_start_addr; + q->query_flags = 0; +} + +static void setup_big_size(void) +{ + q->size = getpagesize() + 1; +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + + memset(q, 0, sizeof(*q)); + + setup_normal(); + if (tc->setup) + tc->setup(); + + if (tc->size != 0) + q->size = tc->size; + + if (tc->query_flags != 0) + q->query_flags = tc->query_flags; + + if (tc->vma_name_addr != 0) + q->vma_name_addr = tc->vma_name_addr; + + if (tc->vma_name_size != 0) + q->vma_name_size = tc->vma_name_size; + + if (tc->build_id_addr != 0) + q->build_id_addr = tc->build_id_addr; + + if (tc->build_id_size != 0) + q->build_id_size = tc->build_id_size; + + TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, q), tc->exp_errno); +} + +static void setup(void) +{ + struct procmap_query q = {}; + + fd = SAFE_OPEN(PROC_MAP_PATH, O_RDONLY); + + if (tst_kvercmp(6, 11, 0) < 0) + return; + + TEST(ioctl(fd, PROCMAP_QUERY, q)); + if ((TST_RET == -1) && (TST_ERR == ENOTTY)) + tst_brk(TCONF, + "This system does not provide support for ioctl(PROCMAP_QUERY)"); + + get_vm_start(); +} + +static void cleanup(void) +{ + if (fd != -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .setup = setup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&q, .size = sizeof(*q)}, + {} + } +}; -- 2.49.0 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [LTP] [PATCH v3] ioctl11.c: New case check PROCMAP_QUERY ioctl() errnos 2025-08-08 16:30 ` [LTP] [PATCH v2] ioctl11.c: " Wei Gao via ltp @ 2025-08-12 6:14 ` Wei Gao via ltp 2025-08-12 14:07 ` Petr Vorel 0 siblings, 1 reply; 5+ messages in thread From: Wei Gao via ltp @ 2025-08-12 6:14 UTC (permalink / raw) To: ltp Signed-off-by: Wei Gao <wegao@suse.com> --- runtest/syscalls | 1 + testcases/kernel/syscalls/ioctl/.gitignore | 1 + testcases/kernel/syscalls/ioctl/ioctl11.c | 214 +++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 testcases/kernel/syscalls/ioctl/ioctl11.c diff --git a/runtest/syscalls b/runtest/syscalls index 6a17a34f8..8bc7f60d2 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -588,6 +588,7 @@ ioctl07 ioctl07 ioctl08 ioctl08 ioctl09 ioctl09 ioctl10 ioctl10 +ioctl11 ioctl11 ioctl_loop01 ioctl_loop01 ioctl_loop02 ioctl_loop02 diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore index dac4583fa..54685e916 100644 --- a/testcases/kernel/syscalls/ioctl/.gitignore +++ b/testcases/kernel/syscalls/ioctl/.gitignore @@ -8,6 +8,7 @@ /ioctl08 /ioctl09 /ioctl10 +/ioctl11 /ioctl_loop01 /ioctl_loop02 /ioctl_loop03 diff --git a/testcases/kernel/syscalls/ioctl/ioctl11.c b/testcases/kernel/syscalls/ioctl/ioctl11.c new file mode 100644 index 000000000..68e5cc275 --- /dev/null +++ b/testcases/kernel/syscalls/ioctl/ioctl11.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2025 Wei Gao <wegao@suse.com> + */ + +/*\ + * [Description] + * + * Test PROCMAP_QUERY ioctl() errnos: + * + * - EINVAL if q->size is too small + * - E2BIG if q->size is larger than page size + * - EINVAL on invalid q->flags + * - EINVAL if only one of q->vma_name_size and q->vma_name_addr is set + * - EINVAL if only one of q->build_id_size and q->build_id_addr is set + * - ENAMETOOLONG if build_id_size or name_buf_size is too small + * - ESRCH if attempt to get memory map of a process that did exit and was waited for + * + * [1] https://kernelnewbies.org/Linux_6.11#Memory_management + * [2] https://kernelnewbies.org/Linux_6.11#Binary_interface_for_.2Fproc.2F.3Cpid.3E.2Fmaps + * [3] https://lore.kernel.org/all/20240627170900.1672542-1-andrii@kernel.org/ + * ed5d583a88a9 ("fs/procfs: implement efficient VMA querying API for /proc/<pid>/maps") + */ + +#include <errno.h> +#include <linux/fs.h> +#include "config.h" +#include "tst_test.h" +#include "tst_safe_stdio.h" +#include "lapi/ioctl.h" + +#define PROC_MAP_PATH "/proc/self/maps" + +static struct procmap_query *q; +static int fd = -1; +static char buf[PATH_MAX]; +static char small_buf[1]; +static unsigned long vm_start_addr; + +static void setup_normal(void); +static void setup_big_size(void); +static void fork_child_setup(void); + +static struct tcase { + uint64_t size; + uint64_t query_addr; + uint64_t query_flags; + uint64_t vma_name_addr; + uint32_t vma_name_size; + uint64_t build_id_addr; + uint32_t build_id_size; + int exp_errno; + void (*setup)(void); +} tcases[] = { + { + .size = 1, + .exp_errno = EINVAL, + }, + { + .exp_errno = E2BIG, + .setup = setup_big_size + }, + { + .query_flags = -1, + .exp_errno = EINVAL, + }, + { + .vma_name_size = sizeof(buf), + .exp_errno = EINVAL, + }, + { + .vma_name_addr = (uint64_t)(unsigned long)buf, + .exp_errno = EINVAL, + }, + { + .build_id_size = sizeof(buf), + .exp_errno = EINVAL, + }, + { + .build_id_addr = (uint64_t)(unsigned long)buf, + .exp_errno = EINVAL, + }, + { + .vma_name_addr = (uint64_t)(unsigned long)small_buf, + .vma_name_size = sizeof(small_buf), + .exp_errno = ENAMETOOLONG, + }, + { + .build_id_addr = (uint64_t)(unsigned long)small_buf, + .build_id_size = sizeof(small_buf), + .exp_errno = ENAMETOOLONG, + }, + { + .exp_errno = ESRCH, + .setup = fork_child_setup + }, +}; + +static void fork_child_setup(void) +{ + int pid = SAFE_FORK(); + + if (pid == 0) { + TST_CHECKPOINT_WAKE(0); + TST_CHECKPOINT_WAIT(1); + exit(0); + } + + TST_CHECKPOINT_WAIT(0); + + char proc_path[PATH_MAX]; + + snprintf(proc_path, PATH_MAX, "/proc/%d/maps", pid); + fd = SAFE_OPEN(proc_path, O_RDONLY); + + TST_CHECKPOINT_WAKE(1); + SAFE_WAITPID(pid, NULL, 0); +} + +static void get_vm_start(void) +{ + FILE *fp = SAFE_FOPEN(PROC_MAP_PATH, "r"); + char line[1024]; + + if (fgets(line, sizeof(line), fp) != NULL) { + if (sscanf(line, "%lx-", &vm_start_addr) != 1) + tst_brk(TFAIL, "maps not found in %s", PROC_MAP_PATH); + } else { + tst_brk(TFAIL, "maps not found in %s", PROC_MAP_PATH); + } + + SAFE_FCLOSE(fp); +} + +static void setup_normal(void) +{ + fd = SAFE_OPEN(PROC_MAP_PATH, O_RDONLY); + + q->size = sizeof(*q); + q->query_addr = (uint64_t)vm_start_addr; + q->query_flags = 0; +} + +static void setup_big_size(void) +{ + q->size = getpagesize() + 1; +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + + memset(q, 0, sizeof(*q)); + + setup_normal(); + if (tc->setup) + tc->setup(); + + if (tc->size != 0) + q->size = tc->size; + + if (tc->query_flags != 0) + q->query_flags = tc->query_flags; + + if (tc->vma_name_addr != 0) + q->vma_name_addr = tc->vma_name_addr; + + if (tc->vma_name_size != 0) + q->vma_name_size = tc->vma_name_size; + + if (tc->build_id_addr != 0) + q->build_id_addr = tc->build_id_addr; + + if (tc->build_id_size != 0) + q->build_id_size = tc->build_id_size; + + TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, q), tc->exp_errno); +} + +static void setup(void) +{ + struct procmap_query q = {}; + + fd = SAFE_OPEN(PROC_MAP_PATH, O_RDONLY); + + if (tst_kvercmp(6, 11, 0) < 0) + return; + + TEST(ioctl(fd, PROCMAP_QUERY, q)); + if ((TST_RET == -1) && (TST_ERR == ENOTTY)) + tst_brk(TCONF, + "This system does not provide support for ioctl(PROCMAP_QUERY)"); + + get_vm_start(); +} + +static void cleanup(void) +{ + if (fd != -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .setup = setup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, + .needs_checkpoints = 1, + .forks_child = 1, + .bufs = (struct tst_buffers []) { + {&q, .size = sizeof(*q)}, + {} + } +}; -- 2.43.0 -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [LTP] [PATCH v3] ioctl11.c: New case check PROCMAP_QUERY ioctl() errnos 2025-08-12 6:14 ` [LTP] [PATCH v3] " Wei Gao via ltp @ 2025-08-12 14:07 ` Petr Vorel 0 siblings, 0 replies; 5+ messages in thread From: Petr Vorel @ 2025-08-12 14:07 UTC (permalink / raw) To: Wei Gao; +Cc: ltp Hi Wei, Andrea, > +/*\ > + * [Description] nit: we stopped using this. Could it be removed before merge? > + * > + * Test PROCMAP_QUERY ioctl() errnos: > + * > + * - EINVAL if q->size is too small > + * - E2BIG if q->size is larger than page size > + * - EINVAL on invalid q->flags > + * - EINVAL if only one of q->vma_name_size and q->vma_name_addr is set > + * - EINVAL if only one of q->build_id_size and q->build_id_addr is set > + * - ENAMETOOLONG if build_id_size or name_buf_size is too small > + * - ESRCH if attempt to get memory map of a process that did exit and was waited for > + * > + * [1] https://kernelnewbies.org/Linux_6.11#Memory_management > + * [2] https://kernelnewbies.org/Linux_6.11#Binary_interface_for_.2Fproc.2F.3Cpid.3E.2Fmaps > + * [3] https://lore.kernel.org/all/20240627170900.1672542-1-andrii@kernel.org/ > + * ed5d583a88a9 ("fs/procfs: implement efficient VMA querying API for /proc/<pid>/maps") nit: [1] and other numbers will look ugly in generated doc: [1] https://kernelnewbies.org/Linux_6.11#Memory_management [2] https://kernelnewbies.org/Linux_6.11#Binary_interface_for_.2Fproc.2F.3Cpid.3E.2Fmaps [3] https://lore.kernel.org/all/20240627170900.1672542-1-andrii@kernel.org/ => inlined and [1] [2] [3] does not make sense when they refer to nothing. Instead of > + * [1] https://kernelnewbies.org/Linux_6.11#Memory_management > + * [2] https://kernelnewbies.org/Linux_6.11#Binary_interface_for_.2Fproc.2F.3Cpid.3E.2Fmaps > + * [3] https://lore.kernel.org/all/20240627170900.1672542-1-andrii@kernel.org/ > + * ed5d583a88a9 ("fs/procfs: implement efficient VMA querying API for /proc/<pid>/maps") I suggest to change before merge to something like: PROCMAP_QUERY was introduced in 6.11. * * https://kernelnewbies.org/Linux_6.11#Binary_interface_for_.2Fproc.2F.3Cpid.3E.2Fmaps * * ed5d583a88a9 ("fs/procfs: implement efficient VMA querying API for /proc/<pid>/maps") Reviewed-by: Petr Vorel <pvorel@suse.cz> ... > +static void fork_child_setup(void) > +{ > + int pid = SAFE_FORK(); > + > + if (pid == 0) { > + TST_CHECKPOINT_WAKE(0); > + TST_CHECKPOINT_WAIT(1); > + exit(0); > + } > + > + TST_CHECKPOINT_WAIT(0); > + > + char proc_path[PATH_MAX]; > + > + snprintf(proc_path, PATH_MAX, "/proc/%d/maps", pid); > + fd = SAFE_OPEN(proc_path, O_RDONLY); > + > + TST_CHECKPOINT_WAKE(1); Using of the checkpoints LGTM, but hopefully somebody else recheck it. Kind regards, Petr > + SAFE_WAITPID(pid, NULL, 0); > +} Kind regards, Petr -- Mailing list info: https://lists.linux.it/listinfo/ltp ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-08-12 14:08 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-08-07 13:48 [LTP] [PATCH v1] iocl11.c: New case check PROCMAP_QUERY ioctl() errnos Wei Gao via ltp 2025-08-07 8:36 ` Petr Vorel 2025-08-08 16:30 ` [LTP] [PATCH v2] ioctl11.c: " Wei Gao via ltp 2025-08-12 6:14 ` [LTP] [PATCH v3] " Wei Gao via ltp 2025-08-12 14:07 ` Petr Vorel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox