* [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl()
@ 2025-01-13 5:52 Wei Gao via ltp
2025-01-13 5:57 ` Wei Gao via ltp
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Wei Gao via ltp @ 2025-01-13 5:52 UTC (permalink / raw)
To: ltp
Signed-off-by: Wei Gao <wegao@suse.com>
---
configure.ac | 1 +
runtest/syscalls | 1 +
testcases/kernel/syscalls/ioctl/.gitignore | 1 +
testcases/kernel/syscalls/ioctl/ioctl10.c | 175 +++++++++++++++++++++
4 files changed, 178 insertions(+)
create mode 100644 testcases/kernel/syscalls/ioctl/ioctl10.c
diff --git a/configure.ac b/configure.ac
index 6992d75ca..56380d41e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -179,6 +179,7 @@ AC_CHECK_TYPES([struct fanotify_event_info_fid, struct fanotify_event_info_error
struct fanotify_event_info_header, struct fanotify_event_info_pidfd],,,[#include <sys/fanotify.h>])
AC_CHECK_TYPES([struct file_clone_range],,,[#include <linux/fs.h>])
AC_CHECK_TYPES([struct file_dedupe_range],,,[#include <linux/fs.h>])
+AC_CHECK_TYPES([struct procmap_query],,,[#include <linux/fs.h>])
AC_CHECK_TYPES([struct file_handle],,,[
#define _GNU_SOURCE
diff --git a/runtest/syscalls b/runtest/syscalls
index ded035ee8..a13811855 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -583,6 +583,7 @@ ioctl06 ioctl06
ioctl07 ioctl07
ioctl08 ioctl08
ioctl09 ioctl09
+ioctl10 ioctl10
ioctl_loop01 ioctl_loop01
ioctl_loop02 ioctl_loop02
diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
index 1f099ff95..9c3f66bf1 100644
--- a/testcases/kernel/syscalls/ioctl/.gitignore
+++ b/testcases/kernel/syscalls/ioctl/.gitignore
@@ -7,6 +7,7 @@
/ioctl07
/ioctl08
/ioctl09
+/ioctl10
/ioctl_loop01
/ioctl_loop02
/ioctl_loop03
diff --git a/testcases/kernel/syscalls/ioctl/ioctl10.c b/testcases/kernel/syscalls/ioctl/ioctl10.c
new file mode 100644
index 000000000..cd9e3c528
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl10.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024 Wei Gao <wegao@suse.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Test PROCMAP_QUERY ioctl() for /proc/$PID/maps.
+ * Test base on kernel selftests proc-pid-vm.c.
+ *
+ * 1. Ioctl with exact match query_addr
+ * 2. Ioctl without match query_addr
+ * 3. Check COVERING_OR_NEXT_VMA query_flags
+ * 4. Check PROCMAP_QUERY_VMA_WRITABLE query_flags
+ * 5. Check vma_name_addr content
+ */
+
+#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>
+
+#ifdef HAVE_STRUCT_PROCMAP_QUERY
+#include <linux/fs.h>
+
+struct map_entry {
+ unsigned long vm_start;
+ unsigned long vm_end;
+ char vm_flags_str[5];
+ unsigned long vm_pgoff;
+ unsigned int vm_major;
+ unsigned int vm_minor;
+ unsigned long vm_inode;
+ char vm_name[256];
+ unsigned int vm_flags;
+};
+
+static unsigned int parse_vm_flags(const char *vm_flags_str)
+{
+ unsigned int flags = 0;
+
+ if (strchr(vm_flags_str, 'r'))
+ flags |= PROCMAP_QUERY_VMA_READABLE;
+ if (strchr(vm_flags_str, 'w'))
+ flags |= PROCMAP_QUERY_VMA_WRITABLE;
+ if (strchr(vm_flags_str, 'x'))
+ flags |= PROCMAP_QUERY_VMA_EXECUTABLE;
+ if (strchr(vm_flags_str, 's'))
+ flags |= PROCMAP_QUERY_VMA_SHARED;
+
+ return flags;
+
+}
+
+static int parse_maps_file(const char *filename, const char *keyword, struct map_entry *entry)
+{
+ FILE *fp = SAFE_FOPEN(filename, "r");
+
+ char line[1024];
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (fnmatch(keyword, line, 0) == 0) {
+ if (sscanf(line, "%lx-%lx %s %lx %x:%x %lu %s",
+ &entry->vm_start, &entry->vm_end, entry->vm_flags_str,
+ &entry->vm_pgoff, &entry->vm_major, &entry->vm_minor,
+ &entry->vm_inode, entry->vm_name) < 7)
+ return -1;
+
+ entry->vm_flags = parse_vm_flags(entry->vm_flags_str);
+
+ SAFE_FCLOSE(fp);
+ return 0;
+ }
+ }
+
+ SAFE_FCLOSE(fp);
+ return -1;
+}
+
+static void verify_ioctl(void)
+{
+ char path_buf[256];
+ struct procmap_query q;
+ int fd;
+ struct map_entry entry;
+
+ memset(&entry, 0, sizeof(entry));
+
+ snprintf(path_buf, sizeof(path_buf), "/proc/%u/maps", getpid());
+ fd = SAFE_OPEN(path_buf, O_RDONLY);
+
+ TST_EXP_PASS(parse_maps_file(path_buf, "*", &entry));
+
+ /* CASE 1: exact MATCH at query_addr */
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = (__u64)entry.vm_start;
+ q.query_flags = 0;
+
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
+
+ TST_EXP_EQ_LU(q.query_addr, entry.vm_start);
+ TST_EXP_EQ_LU(q.query_flags, 0);
+ TST_EXP_EQ_LU(q.vma_flags, entry.vm_flags);
+ TST_EXP_EQ_LU(q.vma_start, entry.vm_start);
+ TST_EXP_EQ_LU(q.vma_end, entry.vm_end);
+ TST_EXP_EQ_LU(q.vma_page_size, getpagesize());
+ TST_EXP_EQ_LU(q.vma_offset, entry.vm_pgoff);
+ TST_EXP_EQ_LU(q.inode, entry.vm_inode);
+ TST_EXP_EQ_LU(q.dev_major, entry.vm_major);
+ TST_EXP_EQ_LU(q.dev_minor, entry.vm_minor);
+
+ /* CASE 2: NO MATCH at query_addr */
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start - 1;
+ q.query_flags = 0;
+
+ TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
+
+ /* CASE 3: MATCH COVERING_OR_NEXT_VMA */
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start - 1;
+ q.query_flags = PROCMAP_QUERY_COVERING_OR_NEXT_VMA;
+
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
+
+ /* CASE 4: NO MATCH WRITABLE at query_addr */
+ memset(&entry, 0, sizeof(entry));
+ TST_EXP_PASS(parse_maps_file(path_buf, "*r-?p *", &entry));
+
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start;
+ q.query_flags = PROCMAP_QUERY_VMA_WRITABLE;
+ TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
+
+ /* CASE 5: check vma_name_addr content */
+ char process_name[256];
+ char pattern[256];
+ char buf[256];
+
+ SAFE_READLINK("/proc/self/exe", process_name, sizeof(process_name));
+ sprintf(pattern, "*%s*", process_name);
+ memset(&entry, 0, sizeof(entry));
+ TST_EXP_PASS(parse_maps_file(path_buf, pattern, &entry));
+
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start;
+ q.query_flags = 0;
+ q.vma_name_addr = (__u64)(unsigned long)buf;
+ q.vma_name_size = sizeof(buf);
+
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
+ TST_EXP_EQ_LU(q.vma_name_size, strlen(process_name) + 1);
+ TST_EXP_EQ_STR((char *)q.vma_name_addr, process_name);
+
+ SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+ .test_all = verify_ioctl,
+ .needs_root = 1,
+};
+#else
+ TST_TEST_TCONF(
+ "This system does not provide support for ioctl(PROCMAP_QUERY)");
+#endif
--
2.35.3
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl()
2025-01-13 5:52 [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl() Wei Gao via ltp
@ 2025-01-13 5:57 ` Wei Gao via ltp
2025-01-14 12:08 ` Wei Gao via ltp
2025-02-21 15:04 ` Cyril Hrubis
2025-02-26 12:51 ` [LTP] [PATCH v2] " Wei Gao via ltp
2 siblings, 1 reply; 7+ messages in thread
From: Wei Gao via ltp @ 2025-01-13 5:57 UTC (permalink / raw)
To: ltp
On Mon, Jan 13, 2025 at 12:52:31AM -0500, Wei Gao wrote:
> Signed-off-by: Wei Gao <wegao@suse.com>
> ---
> configure.ac | 1 +
> runtest/syscalls | 1 +
> testcases/kernel/syscalls/ioctl/.gitignore | 1 +
> testcases/kernel/syscalls/ioctl/ioctl10.c | 175 +++++++++++++++++++++
> 4 files changed, 178 insertions(+)
> create mode 100644 testcases/kernel/syscalls/ioctl/ioctl10.c
The test report error when i check tw in my env(wrong dev_minor number). I guess is kernel issue?
susetest:~/ltp # uname -r
6.12.8-2-default
susetest:~/ltp # cat /etc/os-release
NAME="openSUSE Tumbleweed"
# VERSION="20250109"
ID="opensuse-tumbleweed"
ID_LIKE="opensuse suse"
VERSION_ID="20250109"
PRETTY_NAME="openSUSE Tumbleweed"
ANSI_COLOR="0;32"
# CPE 2.3 format, boo#1217921
CPE_NAME="cpe:2.3:o:opensuse:tumbleweed:20250109:*:*:*:*:*:*:*"
#CPE 2.2 format
#CPE_NAME="cpe:/o:opensuse:tumbleweed:20250109"
BUG_REPORT_URL="https://bugzilla.opensuse.org"
SUPPORT_URL="https://bugs.opensuse.org"
HOME_URL="https://www.opensuse.org"
DOCUMENTATION_URL="https://en.opensuse.org/Portal:Tumbleweed"
LOGO="distributor-logo-Tumbleweed"
tst_test.c:1893: TINFO: LTP version: 20240524-413-g96a255983
tst_test.c:1897: TINFO: Tested kernel: 6.12.8-2-default #1 SMP PREEMPT_DYNAMIC Mon Jan 6 06:45:37 UTC 2025 (90b0f5b) x86_64
tst_test.c:1730: TINFO: Timeout per run is 0h 00m 30s
line=00400000-00431000 r-xp 00000000 00:30 14632 /root/ioctl09
ioctl09.c:100: TPASS: parse_maps_file(path_buf, "*", &entry) passed
ID of containing device: [0,15]
ioctl09.c:120: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
ioctl09.c:122: TPASS: q.query_addr == entry.vm_start (4194304)
ioctl09.c:123: TPASS: q.query_flags == 0 (0)
ioctl09.c:124: TPASS: q.vma_flags == entry.vm_flags (5)
ioctl09.c:125: TPASS: q.vma_start == entry.vm_start (4194304)
ioctl09.c:126: TPASS: q.vma_end == entry.vm_end (4395008)
ioctl09.c:127: TPASS: q.vma_page_size == getpagesize() (4096)
ioctl09.c:128: TPASS: q.vma_offset == entry.vm_pgoff (0)
ioctl09.c:129: TPASS: q.inode == entry.vm_inode (14632)
ioctl09.c:130: TPASS: q.dev_major == entry.vm_major (0)
ioctl09.c:131: TFAIL: q.dev_minor (35) != entry.vm_minor (48) <<<<<<<<<<<<<<<<<<<<<<<<
ioctl09.c:139: TPASS: ioctl(fd, PROCMAP_QUERY, &q) : ENOENT (2)
ioctl09.c:147: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
line=00400000-00431000 r-xp 00000000 00:30 14632 /root/ioctl09
ioctl09.c:151: TPASS: parse_maps_file("/proc/self/maps", "*r-?p *", &entry) passed
ioctl09.c:157: TPASS: ioctl(fd, PROCMAP_QUERY, &q) : ENOENT (2)
line=00400000-00431000 r-xp 00000000 00:30 14632 /root/ioctl09
ioctl09.c:166: TPASS: parse_maps_file("/proc/self/maps", pattern, &entry) passed
ioctl09.c:175: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
ioctl09.c:176: TPASS: q.vma_name_size == strlen(process_name) + 1 (14)
ioctl09.c:177: TPASS: (char *)q.vma_name_addr == process_name (/root/ioctl09)
stat /root/ioctl09
File: /root/ioctl09
Size: 873728 Blocks: 1712 IO Block: 4096 regular file
Device: 0,48 <<<<<< Inode: 14632 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2025-01-12 22:29:01.378310333 -0500
Modify: 2025-01-12 22:28:58.043307554 -0500
Change: 2025-01-12 22:28:58.043307554 -0500
Birth: 2025-01-12 21:37:52.621841127 -0500
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl()
2025-01-13 5:57 ` Wei Gao via ltp
@ 2025-01-14 12:08 ` Wei Gao via ltp
0 siblings, 0 replies; 7+ messages in thread
From: Wei Gao via ltp @ 2025-01-14 12:08 UTC (permalink / raw)
To: ltp
Test with 6.13.0-rc7-1.g9a3f661-vanilla kernel, the result is good.
susetest:~/ltp/testcases/kernel/syscalls/ioctl # ./ioctl10
tst_test.c:1900: TINFO: LTP version: 20240930-184-g21afd7d9b
tst_test.c:1904: TINFO: Tested kernel: 6.13.0-rc7-1.g9a3f661-vanilla #1 SMP
PREEMPT_DYNAMIC Mon Jan 13 11:16:27 UTC 2025 (9a3f661) x86_64
tst_kconfig.c:88: TINFO: Parsing kernel config '/proc/config.gz'
tst_kconfig.c:667: TINFO: CONFIG_LATENCYTOP kernel option detected which
might slow the execution
tst_test.c:1722: TINFO: Overall timeout per run is 0h 02m 00s
ioctl10.c:97: TPASS: parse_maps_file(path_buf, "*", &entry) passed
ioctl10.c:105: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
ioctl10.c:107: TPASS: q.query_addr == entry.vm_start (4194304)
ioctl10.c:108: TPASS: q.query_flags == 0 (0)
ioctl10.c:109: TPASS: q.vma_flags == entry.vm_flags (1)
ioctl10.c:110: TPASS: q.vma_start == entry.vm_start (4194304)
ioctl10.c:111: TPASS: q.vma_end == entry.vm_end (4210688)
ioctl10.c:112: TPASS: q.vma_page_size == getpagesize() (4096)
ioctl10.c:113: TPASS: q.vma_offset == entry.vm_pgoff (0)
ioctl10.c:114: TPASS: q.inode == entry.vm_inode (11443)
ioctl10.c:115: TPASS: q.dev_major == entry.vm_major (0)
ioctl10.c:116: TPASS: q.dev_minor == entry.vm_minor (35)
ioctl10.c:124: TPASS: ioctl(fd, PROCMAP_QUERY, &q) : ENOENT (2)
ioctl10.c:132: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
ioctl10.c:136: TPASS: parse_maps_file(path_buf, "*r-?p *", &entry) passed
ioctl10.c:142: TPASS: ioctl(fd, PROCMAP_QUERY, &q) : ENOENT (2)
ioctl10.c:152: TPASS: parse_maps_file(path_buf, pattern, &entry) passed
ioctl10.c:161: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
ioctl10.c:162: TPASS: q.vma_name_size == strlen(process_name) + 1 (50)
ioctl10.c:163: TPASS: (char *)q.vma_name_addr == process_name
(/root/ltp/testcases/kernel/syscalls/ioctl/ioctl10)
Summary:
passed 20
failed 0
broken 0
skipped 0
warnings 0
On Mon, Jan 13, 2025 at 1:57 PM Wei Gao <wegao@suse.com> wrote:
> On Mon, Jan 13, 2025 at 12:52:31AM -0500, Wei Gao wrote:
> > Signed-off-by: Wei Gao <wegao@suse.com>
> > ---
> > configure.ac | 1 +
> > runtest/syscalls | 1 +
> > testcases/kernel/syscalls/ioctl/.gitignore | 1 +
> > testcases/kernel/syscalls/ioctl/ioctl10.c | 175 +++++++++++++++++++++
> > 4 files changed, 178 insertions(+)
> > create mode 100644 testcases/kernel/syscalls/ioctl/ioctl10.c
>
> The test report error when i check tw in my env(wrong dev_minor number). I
> guess is kernel issue?
>
> susetest:~/ltp # uname -r
> 6.12.8-2-default
> susetest:~/ltp # cat /etc/os-release
> NAME="openSUSE Tumbleweed"
> # VERSION="20250109"
> ID="opensuse-tumbleweed"
> ID_LIKE="opensuse suse"
> VERSION_ID="20250109"
> PRETTY_NAME="openSUSE Tumbleweed"
> ANSI_COLOR="0;32"
> # CPE 2.3 format, boo#1217921
> CPE_NAME="cpe:2.3:o:opensuse:tumbleweed:20250109:*:*:*:*:*:*:*"
> #CPE 2.2 format
> #CPE_NAME="cpe:/o:opensuse:tumbleweed:20250109"
> BUG_REPORT_URL="https://bugzilla.opensuse.org"
> SUPPORT_URL="https://bugs.opensuse.org"
> HOME_URL="https://www.opensuse.org"
> DOCUMENTATION_URL="https://en.opensuse.org/Portal:Tumbleweed"
> LOGO="distributor-logo-Tumbleweed"
>
> tst_test.c:1893: TINFO: LTP version: 20240524-413-g96a255983
> tst_test.c:1897: TINFO: Tested kernel: 6.12.8-2-default #1 SMP
> PREEMPT_DYNAMIC Mon Jan 6 06:45:37 UTC 2025 (90b0f5b) x86_64
> tst_test.c:1730: TINFO: Timeout per run is 0h 00m 30s
> line=00400000-00431000 r-xp 00000000 00:30 14632
> /root/ioctl09
>
> ioctl09.c:100: TPASS: parse_maps_file(path_buf, "*", &entry) passed
> ID of containing device: [0,15]
> ioctl09.c:120: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
> ioctl09.c:122: TPASS: q.query_addr == entry.vm_start (4194304)
> ioctl09.c:123: TPASS: q.query_flags == 0 (0)
> ioctl09.c:124: TPASS: q.vma_flags == entry.vm_flags (5)
> ioctl09.c:125: TPASS: q.vma_start == entry.vm_start (4194304)
> ioctl09.c:126: TPASS: q.vma_end == entry.vm_end (4395008)
> ioctl09.c:127: TPASS: q.vma_page_size == getpagesize() (4096)
> ioctl09.c:128: TPASS: q.vma_offset == entry.vm_pgoff (0)
> ioctl09.c:129: TPASS: q.inode == entry.vm_inode (14632)
> ioctl09.c:130: TPASS: q.dev_major == entry.vm_major (0)
> ioctl09.c:131: TFAIL: q.dev_minor (35) != entry.vm_minor (48)
> <<<<<<<<<<<<<<<<<<<<<<<<
> ioctl09.c:139: TPASS: ioctl(fd, PROCMAP_QUERY, &q) : ENOENT (2)
> ioctl09.c:147: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
> line=00400000-00431000 r-xp 00000000 00:30 14632
> /root/ioctl09
>
> ioctl09.c:151: TPASS: parse_maps_file("/proc/self/maps", "*r-?p *",
> &entry) passed
> ioctl09.c:157: TPASS: ioctl(fd, PROCMAP_QUERY, &q) : ENOENT (2)
> line=00400000-00431000 r-xp 00000000 00:30 14632
> /root/ioctl09
>
> ioctl09.c:166: TPASS: parse_maps_file("/proc/self/maps", pattern, &entry)
> passed
> ioctl09.c:175: TPASS: ioctl(fd, PROCMAP_QUERY, &q) passed
> ioctl09.c:176: TPASS: q.vma_name_size == strlen(process_name) + 1 (14)
> ioctl09.c:177: TPASS: (char *)q.vma_name_addr == process_name
> (/root/ioctl09)
>
> stat /root/ioctl09
> File: /root/ioctl09
> Size: 873728 Blocks: 1712 IO Block: 4096 regular file
> Device: 0,48 <<<<<< Inode: 14632 Links: 1
> Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
> Access: 2025-01-12 22:29:01.378310333 -0500
> Modify: 2025-01-12 22:28:58.043307554 -0500
> Change: 2025-01-12 22:28:58.043307554 -0500
> Birth: 2025-01-12 21:37:52.621841127 -0500
>
>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl()
2025-01-13 5:52 [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl() Wei Gao via ltp
2025-01-13 5:57 ` Wei Gao via ltp
@ 2025-02-21 15:04 ` Cyril Hrubis
2025-02-26 12:51 ` [LTP] [PATCH v2] " Wei Gao via ltp
2 siblings, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2025-02-21 15:04 UTC (permalink / raw)
To: Wei Gao; +Cc: ltp
Hi!
> diff --git a/configure.ac b/configure.ac
> index 6992d75ca..56380d41e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -179,6 +179,7 @@ AC_CHECK_TYPES([struct fanotify_event_info_fid, struct fanotify_event_info_error
> struct fanotify_event_info_header, struct fanotify_event_info_pidfd],,,[#include <sys/fanotify.h>])
> AC_CHECK_TYPES([struct file_clone_range],,,[#include <linux/fs.h>])
> AC_CHECK_TYPES([struct file_dedupe_range],,,[#include <linux/fs.h>])
> +AC_CHECK_TYPES([struct procmap_query],,,[#include <linux/fs.h>])
>
> AC_CHECK_TYPES([struct file_handle],,,[
> #define _GNU_SOURCE
> diff --git a/runtest/syscalls b/runtest/syscalls
> index ded035ee8..a13811855 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -583,6 +583,7 @@ ioctl06 ioctl06
> ioctl07 ioctl07
> ioctl08 ioctl08
> ioctl09 ioctl09
> +ioctl10 ioctl10
>
> ioctl_loop01 ioctl_loop01
> ioctl_loop02 ioctl_loop02
> diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
> index 1f099ff95..9c3f66bf1 100644
> --- a/testcases/kernel/syscalls/ioctl/.gitignore
> +++ b/testcases/kernel/syscalls/ioctl/.gitignore
> @@ -7,6 +7,7 @@
> /ioctl07
> /ioctl08
> /ioctl09
> +/ioctl10
> /ioctl_loop01
> /ioctl_loop02
> /ioctl_loop03
> diff --git a/testcases/kernel/syscalls/ioctl/ioctl10.c b/testcases/kernel/syscalls/ioctl/ioctl10.c
> new file mode 100644
> index 000000000..cd9e3c528
> --- /dev/null
> +++ b/testcases/kernel/syscalls/ioctl/ioctl10.c
> @@ -0,0 +1,175 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2024 Wei Gao <wegao@suse.com>
> + */
> +
> +/*\
> + * [Description]
> + *
> + * Test PROCMAP_QUERY ioctl() for /proc/$PID/maps.
> + * Test base on kernel selftests proc-pid-vm.c.
> + *
> + * 1. Ioctl with exact match query_addr
> + * 2. Ioctl without match query_addr
> + * 3. Check COVERING_OR_NEXT_VMA query_flags
> + * 4. Check PROCMAP_QUERY_VMA_WRITABLE query_flags
> + * 5. Check vma_name_addr content
> + */
> +
> +#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>
> +
> +#ifdef HAVE_STRUCT_PROCMAP_QUERY
Instead of this we should add a lapi fallback, as we do for other newly
introduced functionality.
See include/lapi/ficlone.h how that should look like.
> +#include <linux/fs.h>
> +
> +struct map_entry {
> + unsigned long vm_start;
> + unsigned long vm_end;
> + char vm_flags_str[5];
> + unsigned long vm_pgoff;
> + unsigned int vm_major;
> + unsigned int vm_minor;
> + unsigned long vm_inode;
> + char vm_name[256];
> + unsigned int vm_flags;
> +};
> +
> +static unsigned int parse_vm_flags(const char *vm_flags_str)
> +{
> + unsigned int flags = 0;
> +
> + if (strchr(vm_flags_str, 'r'))
> + flags |= PROCMAP_QUERY_VMA_READABLE;
> + if (strchr(vm_flags_str, 'w'))
> + flags |= PROCMAP_QUERY_VMA_WRITABLE;
> + if (strchr(vm_flags_str, 'x'))
> + flags |= PROCMAP_QUERY_VMA_EXECUTABLE;
> + if (strchr(vm_flags_str, 's'))
> + flags |= PROCMAP_QUERY_VMA_SHARED;
> +
> + return flags;
> +
> +}
> +
> +static int parse_maps_file(const char *filename, const char *keyword, struct map_entry *entry)
> +{
> + FILE *fp = SAFE_FOPEN(filename, "r");
> +
> + char line[1024];
> +
> + while (fgets(line, sizeof(line), fp) != NULL) {
> + if (fnmatch(keyword, line, 0) == 0) {
> + if (sscanf(line, "%lx-%lx %s %lx %x:%x %lu %s",
> + &entry->vm_start, &entry->vm_end, entry->vm_flags_str,
> + &entry->vm_pgoff, &entry->vm_major, &entry->vm_minor,
> + &entry->vm_inode, entry->vm_name) < 7)
> + return -1;
> +
> + entry->vm_flags = parse_vm_flags(entry->vm_flags_str);
> +
> + SAFE_FCLOSE(fp);
> + return 0;
> + }
> + }
> +
> + SAFE_FCLOSE(fp);
> + return -1;
> +}
> +
> +static void verify_ioctl(void)
> +{
> + char path_buf[256];
> + struct procmap_query q;
> + int fd;
> + struct map_entry entry;
> +
> + memset(&entry, 0, sizeof(entry));
> +
> + snprintf(path_buf, sizeof(path_buf), "/proc/%u/maps", getpid());
> + fd = SAFE_OPEN(path_buf, O_RDONLY);
You don't have to create the path with $PID you can pass
"/proc/self/maps" to the open() instead.
> + TST_EXP_PASS(parse_maps_file(path_buf, "*", &entry));
This isn't a test, so we should call it in TST_EXP_PASS() instead the
function should call tst_brk() on a failure and shouldn't return a
value.
> + /* CASE 1: exact MATCH at query_addr */
> + memset(&q, 0, sizeof(q));
> + q.size = sizeof(q);
> + q.query_addr = (__u64)entry.vm_start;
^
Should be uint64_t in userspace.
> + q.query_flags = 0;
> +
> + TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
> +
> + TST_EXP_EQ_LU(q.query_addr, entry.vm_start);
> + TST_EXP_EQ_LU(q.query_flags, 0);
> + TST_EXP_EQ_LU(q.vma_flags, entry.vm_flags);
> + TST_EXP_EQ_LU(q.vma_start, entry.vm_start);
> + TST_EXP_EQ_LU(q.vma_end, entry.vm_end);
> + TST_EXP_EQ_LU(q.vma_page_size, getpagesize());
> + TST_EXP_EQ_LU(q.vma_offset, entry.vm_pgoff);
> + TST_EXP_EQ_LU(q.inode, entry.vm_inode);
> + TST_EXP_EQ_LU(q.dev_major, entry.vm_major);
> + TST_EXP_EQ_LU(q.dev_minor, entry.vm_minor);
> +
> + /* CASE 2: NO MATCH at query_addr */
> + memset(&q, 0, sizeof(q));
> + q.size = sizeof(q);
> + q.query_addr = entry.vm_start - 1;
> + q.query_flags = 0;
> +
> + TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
> +
> + /* CASE 3: MATCH COVERING_OR_NEXT_VMA */
> + memset(&q, 0, sizeof(q));
> + q.size = sizeof(q);
> + q.query_addr = entry.vm_start - 1;
> + q.query_flags = PROCMAP_QUERY_COVERING_OR_NEXT_VMA;
> +
> + TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
> +
> + /* CASE 4: NO MATCH WRITABLE at query_addr */
> + memset(&entry, 0, sizeof(entry));
> + TST_EXP_PASS(parse_maps_file(path_buf, "*r-?p *", &entry));
Here as well.
> + memset(&q, 0, sizeof(q));
> + q.size = sizeof(q);
> + q.query_addr = entry.vm_start;
> + q.query_flags = PROCMAP_QUERY_VMA_WRITABLE;
> + TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
> +
> + /* CASE 5: check vma_name_addr content */
> + char process_name[256];
> + char pattern[256];
> + char buf[256];
> +
> + SAFE_READLINK("/proc/self/exe", process_name, sizeof(process_name));
> + sprintf(pattern, "*%s*", process_name);
> + memset(&entry, 0, sizeof(entry));
> + TST_EXP_PASS(parse_maps_file(path_buf, pattern, &entry));
Here as well.
> + memset(&q, 0, sizeof(q));
> + q.size = sizeof(q);
> + q.query_addr = entry.vm_start;
> + q.query_flags = 0;
> + q.vma_name_addr = (__u64)(unsigned long)buf;
Here as well.
> + q.vma_name_size = sizeof(buf);
> +
> + TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
> + TST_EXP_EQ_LU(q.vma_name_size, strlen(process_name) + 1);
> + TST_EXP_EQ_STR((char *)q.vma_name_addr, process_name);
> +
> + SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> + .test_all = verify_ioctl,
> + .needs_root = 1,
> +};
> +#else
> + TST_TEST_TCONF(
> + "This system does not provide support for ioctl(PROCMAP_QUERY)");
> +#endif
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
* [LTP] [PATCH v2] ioctl10.c: New case test PROCMAP_QUERY ioctl()
2025-01-13 5:52 [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl() Wei Gao via ltp
2025-01-13 5:57 ` Wei Gao via ltp
2025-02-21 15:04 ` Cyril Hrubis
@ 2025-02-26 12:51 ` Wei Gao via ltp
2025-07-10 15:26 ` Cyril Hrubis
2 siblings, 1 reply; 7+ messages in thread
From: Wei Gao via ltp @ 2025-02-26 12:51 UTC (permalink / raw)
To: ltp
Signed-off-by: Wei Gao <wegao@suse.com>
---
configure.ac | 1 +
include/lapi/ioctl.h | 133 ++++++++++++++++
runtest/syscalls | 1 +
testcases/kernel/syscalls/ioctl/.gitignore | 1 +
testcases/kernel/syscalls/ioctl/ioctl10.c | 177 +++++++++++++++++++++
5 files changed, 313 insertions(+)
create mode 100644 testcases/kernel/syscalls/ioctl/ioctl10.c
diff --git a/configure.ac b/configure.ac
index 6992d75ca..56380d41e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -179,6 +179,7 @@ AC_CHECK_TYPES([struct fanotify_event_info_fid, struct fanotify_event_info_error
struct fanotify_event_info_header, struct fanotify_event_info_pidfd],,,[#include <sys/fanotify.h>])
AC_CHECK_TYPES([struct file_clone_range],,,[#include <linux/fs.h>])
AC_CHECK_TYPES([struct file_dedupe_range],,,[#include <linux/fs.h>])
+AC_CHECK_TYPES([struct procmap_query],,,[#include <linux/fs.h>])
AC_CHECK_TYPES([struct file_handle],,,[
#define _GNU_SOURCE
diff --git a/include/lapi/ioctl.h b/include/lapi/ioctl.h
index f91a9e68c..d0f8bf254 100644
--- a/include/lapi/ioctl.h
+++ b/include/lapi/ioctl.h
@@ -9,6 +9,7 @@
#include "config.h"
#include <sys/ioctl.h>
+#include <stdint.h>
/* musl not including it in <sys/ioctl.h> */
#include <sys/ttydefaults.h>
@@ -37,4 +38,136 @@ struct termio
};
#endif /* HAVE_STRUCT_TERMIO */
+#ifndef HAVE_STRUCT_PROCMAP_QUERY
+#define PROCFS_IOCTL_MAGIC 'f'
+#define PROCMAP_QUERY _IOWR(PROCFS_IOCTL_MAGIC, 17, struct procmap_query)
+enum procmap_query_flags {
+ /*
+ * VMA permission flags.
+ *
+ * Can be used as part of procmap_query.query_flags field to look up
+ * only VMAs satisfying specified subset of permissions. E.g., specifying
+ * PROCMAP_QUERY_VMA_READABLE only will return both readable and read/write VMAs,
+ * while having PROCMAP_QUERY_VMA_READABLE | PROCMAP_QUERY_VMA_WRITABLE will only
+ * return read/write VMAs, though both executable/non-executable and
+ * private/shared will be ignored.
+ *
+ * PROCMAP_QUERY_VMA_* flags are also returned in procmap_query.vma_flags
+ * field to specify actual VMA permissions.
+ */
+ PROCMAP_QUERY_VMA_READABLE = 0x01,
+ PROCMAP_QUERY_VMA_WRITABLE = 0x02,
+ PROCMAP_QUERY_VMA_EXECUTABLE = 0x04,
+ PROCMAP_QUERY_VMA_SHARED = 0x08,
+ /*
+ * Query modifier flags.
+ *
+ * By default VMA that covers provided address is returned, or -ENOENT
+ * is returned. With PROCMAP_QUERY_COVERING_OR_NEXT_VMA flag set, closest
+ * VMA with vma_start > addr will be returned if no covering VMA is
+ * found.
+ *
+ * PROCMAP_QUERY_FILE_BACKED_VMA instructs query to consider only VMAs that
+ * have file backing. Can be combined with PROCMAP_QUERY_COVERING_OR_NEXT_VMA
+ * to iterate all VMAs with file backing.
+ */
+ PROCMAP_QUERY_COVERING_OR_NEXT_VMA = 0x10,
+ PROCMAP_QUERY_FILE_BACKED_VMA = 0x20,
+};
+
+struct procmap_query {
+ /* Query struct size, for backwards/forward compatibility */
+ uint64_t size;
+ /*
+ * Query flags, a combination of enum procmap_query_flags values.
+ * Defines query filtering and behavior, see enum procmap_query_flags.
+ *
+ * Input argument, provided by user. Kernel doesn't modify it.
+ */
+ uint64_t query_flags; /* in */
+ /*
+ * Query address. By default, VMA that covers this address will
+ * be looked up. PROCMAP_QUERY_* flags above modify this default
+ * behavior further.
+ *
+ * Input argument, provided by user. Kernel doesn't modify it.
+ */
+ uint64_t query_addr; /* in */
+ /* VMA starting (inclusive) and ending (exclusive) address, if VMA is found. */
+ uint64_t vma_start; /* out */
+ uint64_t vma_end; /* out */
+ /* VMA permissions flags. A combination of PROCMAP_QUERY_VMA_* flags. */
+ uint64_t vma_flags; /* out */
+ /* VMA backing page size granularity. */
+ uint64_t vma_page_size; /* out */
+ /*
+ * VMA file offset. If VMA has file backing, this specifies offset
+ * within the file that VMA's start address corresponds to.
+ * Is set to zero if VMA has no backing file.
+ */
+ uint64_t vma_offset; /* out */
+ /* Backing file's inode number, or zero, if VMA has no backing file. */
+ uint64_t inode; /* out */
+ /* Backing file's device major/minor number, or zero, if VMA has no backing file. */
+ uint32_t dev_major; /* out */
+ uint32_t dev_minor; /* out */
+ /*
+ * If set to non-zero value, signals the request to return VMA name
+ * (i.e., VMA's backing file's absolute path, with " (deleted)" suffix
+ * appended, if file was unlinked from FS) for matched VMA. VMA name
+ * can also be some special name (e.g., "[heap]", "[stack]") or could
+ * be even user-supplied with prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME).
+ *
+ * Kernel will set this field to zero, if VMA has no associated name.
+ * Otherwise kernel will return actual amount of bytes filled in
+ * user-supplied buffer (see vma_name_addr field below), including the
+ * terminating zero.
+ *
+ * If VMA name is longer that user-supplied maximum buffer size,
+ * -E2BIG error is returned.
+ *
+ * If this field is set to non-zero value, vma_name_addr should point
+ * to valid user space memory buffer of at least vma_name_size bytes.
+ * If set to zero, vma_name_addr should be set to zero as well
+ */
+ uint32_t vma_name_size; /* in/out */
+ /*
+ * If set to non-zero value, signals the request to extract and return
+ * VMA's backing file's build ID, if the backing file is an ELF file
+ * and it contains embedded build ID.
+ *
+ * Kernel will set this field to zero, if VMA has no backing file,
+ * backing file is not an ELF file, or ELF file has no build ID
+ * embedded.
+ *
+ * Build ID is a binary value (not a string). Kernel will set
+ * build_id_size field to exact number of bytes used for build ID.
+ * If build ID is requested and present, but needs more bytes than
+ * user-supplied maximum buffer size (see build_id_addr field below),
+ * -E2BIG error will be returned.
+ *
+ * If this field is set to non-zero value, build_id_addr should point
+ * to valid user space memory buffer of at least build_id_size bytes.
+ * If set to zero, build_id_addr should be set to zero as well
+ */
+ uint32_t build_id_size; /* in/out */
+ /*
+ * User-supplied address of a buffer of at least vma_name_size bytes
+ * for kernel to fill with matched VMA's name (see vma_name_size field
+ * description above for details).
+ *
+ * Should be set to zero if VMA name should not be returned.
+ */
+ uint64_t vma_name_addr; /* in */
+ /*
+ * User-supplied address of a buffer of at least build_id_size bytes
+ * for kernel to fill with matched VMA's ELF build ID, if available
+ * (see build_id_size field description above for details).
+ *
+ * Should be set to zero if build ID should not be returned.
+ */
+ uint64_t build_id_addr; /* in */
+};
+#endif /* HAVE_STRUCT_PROCMAP_QUERY */
+
#endif /* LAPI_IOCTL_H__ */
diff --git a/runtest/syscalls b/runtest/syscalls
index ded035ee8..a13811855 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -583,6 +583,7 @@ ioctl06 ioctl06
ioctl07 ioctl07
ioctl08 ioctl08
ioctl09 ioctl09
+ioctl10 ioctl10
ioctl_loop01 ioctl_loop01
ioctl_loop02 ioctl_loop02
diff --git a/testcases/kernel/syscalls/ioctl/.gitignore b/testcases/kernel/syscalls/ioctl/.gitignore
index 1f099ff95..9c3f66bf1 100644
--- a/testcases/kernel/syscalls/ioctl/.gitignore
+++ b/testcases/kernel/syscalls/ioctl/.gitignore
@@ -7,6 +7,7 @@
/ioctl07
/ioctl08
/ioctl09
+/ioctl10
/ioctl_loop01
/ioctl_loop02
/ioctl_loop03
diff --git a/testcases/kernel/syscalls/ioctl/ioctl10.c b/testcases/kernel/syscalls/ioctl/ioctl10.c
new file mode 100644
index 000000000..7ab3e4c43
--- /dev/null
+++ b/testcases/kernel/syscalls/ioctl/ioctl10.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024 Wei Gao <wegao@suse.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * Test PROCMAP_QUERY ioctl() for /proc/$PID/maps.
+ * Test base on kernel selftests proc-pid-vm.c.
+ *
+ * 1. Ioctl with exact match query_addr
+ * 2. Ioctl without match query_addr
+ * 3. Check COVERING_OR_NEXT_VMA query_flags
+ * 4. Check PROCMAP_QUERY_VMA_WRITABLE query_flags
+ * 5. Check vma_name_addr content
+ */
+
+#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 map_entry {
+ unsigned long vm_start;
+ unsigned long vm_end;
+ char vm_flags_str[5];
+ unsigned long vm_pgoff;
+ unsigned int vm_major;
+ unsigned int vm_minor;
+ unsigned long vm_inode;
+ char vm_name[256];
+ unsigned int vm_flags;
+};
+
+static unsigned int parse_vm_flags(const char *vm_flags_str)
+{
+ unsigned int flags = 0;
+
+ if (strchr(vm_flags_str, 'r'))
+ flags |= PROCMAP_QUERY_VMA_READABLE;
+ if (strchr(vm_flags_str, 'w'))
+ flags |= PROCMAP_QUERY_VMA_WRITABLE;
+ if (strchr(vm_flags_str, 'x'))
+ flags |= PROCMAP_QUERY_VMA_EXECUTABLE;
+ if (strchr(vm_flags_str, 's'))
+ flags |= PROCMAP_QUERY_VMA_SHARED;
+
+ return flags;
+
+}
+
+static void parse_maps_file(const char *filename, const char *keyword, struct map_entry *entry)
+{
+ FILE *fp = SAFE_FOPEN(filename, "r");
+
+ char line[1024];
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (fnmatch(keyword, line, 0) == 0) {
+ if (sscanf(line, "%lx-%lx %s %lx %x:%x %lu %s",
+ &entry->vm_start, &entry->vm_end, entry->vm_flags_str,
+ &entry->vm_pgoff, &entry->vm_major, &entry->vm_minor,
+ &entry->vm_inode, entry->vm_name) < 7)
+ tst_brk(TFAIL, "parse maps file /proc/self/maps failed");
+
+ entry->vm_flags = parse_vm_flags(entry->vm_flags_str);
+
+ SAFE_FCLOSE(fp);
+ return;
+ }
+ }
+
+ SAFE_FCLOSE(fp);
+ tst_brk(TFAIL, "parse maps file /proc/self/maps failed");
+}
+
+static void verify_ioctl(void)
+{
+ struct procmap_query q;
+ int fd;
+ struct map_entry entry;
+
+ memset(&entry, 0, sizeof(entry));
+
+ fd = SAFE_OPEN("/proc/self/maps", O_RDONLY);
+
+ parse_maps_file(PROC_MAP_PATH, "*", &entry);
+
+ /* CASE 1: exact MATCH at query_addr */
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = (uint64_t)entry.vm_start;
+ q.query_flags = 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)");
+
+
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
+
+ TST_EXP_EQ_LU(q.query_addr, entry.vm_start);
+ TST_EXP_EQ_LU(q.query_flags, 0);
+ TST_EXP_EQ_LU(q.vma_flags, entry.vm_flags);
+ TST_EXP_EQ_LU(q.vma_start, entry.vm_start);
+ TST_EXP_EQ_LU(q.vma_end, entry.vm_end);
+ TST_EXP_EQ_LU(q.vma_page_size, getpagesize());
+ TST_EXP_EQ_LU(q.vma_offset, entry.vm_pgoff);
+ TST_EXP_EQ_LU(q.inode, entry.vm_inode);
+ TST_EXP_EQ_LU(q.dev_major, entry.vm_major);
+ TST_EXP_EQ_LU(q.dev_minor, entry.vm_minor);
+
+ /* CASE 2: NO MATCH at query_addr */
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start - 1;
+ q.query_flags = 0;
+
+ TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
+
+ /* CASE 3: MATCH COVERING_OR_NEXT_VMA */
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start - 1;
+ q.query_flags = PROCMAP_QUERY_COVERING_OR_NEXT_VMA;
+
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
+
+ /* CASE 4: NO MATCH WRITABLE at query_addr */
+ memset(&entry, 0, sizeof(entry));
+ parse_maps_file(PROC_MAP_PATH, "*r-?p *", &entry);
+
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start;
+ q.query_flags = PROCMAP_QUERY_VMA_WRITABLE;
+ TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
+
+ /* CASE 5: check vma_name_addr content */
+ char process_name[256];
+ char pattern[256];
+ char buf[256];
+
+ SAFE_READLINK("/proc/self/exe", process_name, sizeof(process_name));
+ sprintf(pattern, "*%s*", process_name);
+ memset(&entry, 0, sizeof(entry));
+ parse_maps_file(PROC_MAP_PATH, pattern, &entry);
+
+ memset(&q, 0, sizeof(q));
+ q.size = sizeof(q);
+ q.query_addr = entry.vm_start;
+ q.query_flags = 0;
+ q.vma_name_addr = (uint64_t)(unsigned long)buf;
+ q.vma_name_size = sizeof(buf);
+
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
+ TST_EXP_EQ_LU(q.vma_name_size, strlen(process_name) + 1);
+ TST_EXP_EQ_STR((char *)q.vma_name_addr, process_name);
+
+ SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+ .test_all = verify_ioctl,
+ .needs_root = 1,
+};
--
2.35.3
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2] ioctl10.c: New case test PROCMAP_QUERY ioctl()
2025-02-26 12:51 ` [LTP] [PATCH v2] " Wei Gao via ltp
@ 2025-07-10 15:26 ` Cyril Hrubis
2025-07-11 15:47 ` Wei Gao via ltp
0 siblings, 1 reply; 7+ messages in thread
From: Cyril Hrubis @ 2025-07-10 15:26 UTC (permalink / raw)
To: Wei Gao; +Cc: ltp
Hi!
I've pushed the patch with following changes:
- removed .needs_root since the test runs fine without root
- moved the check for ioctl() support into the test setup() and the
check for availability is only done on kernels older than 6.11 since
it has to be available since that kernel version
- made use of guarded buffers for the procmap_query structure passed to
the syscalls
What should still be done:
- we miss a few more 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->qma_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
- possibly ESRCH if we attempt to get memory map of a process that did exit and was waited for
- the invalid tests should be split into a separate test and stored in
a tcase structure as we usually do, which makes it easier to add tests
Full diff:
diff --git a/testcases/kernel/syscalls/ioctl/ioctl10.c b/testcases/kernel/syscalls/ioctl/ioctl10.c
index 7ab3e4c43..6af2bb1f2 100644
--- a/testcases/kernel/syscalls/ioctl/ioctl10.c
+++ b/testcases/kernel/syscalls/ioctl/ioctl10.c
@@ -41,6 +41,9 @@ struct map_entry {
unsigned int vm_flags;
};
+struct procmap_query *q;
+static int fd = -1;
+
static unsigned int parse_vm_flags(const char *vm_flags_str)
{
unsigned int flags = 0;
@@ -85,93 +88,108 @@ static void parse_maps_file(const char *filename, const char *keyword, struct ma
static void verify_ioctl(void)
{
- struct procmap_query q;
- int fd;
struct map_entry entry;
memset(&entry, 0, sizeof(entry));
- fd = SAFE_OPEN("/proc/self/maps", O_RDONLY);
-
parse_maps_file(PROC_MAP_PATH, "*", &entry);
/* CASE 1: exact MATCH at query_addr */
- memset(&q, 0, sizeof(q));
- q.size = sizeof(q);
- q.query_addr = (uint64_t)entry.vm_start;
- q.query_flags = 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)");
-
-
- TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
-
- TST_EXP_EQ_LU(q.query_addr, entry.vm_start);
- TST_EXP_EQ_LU(q.query_flags, 0);
- TST_EXP_EQ_LU(q.vma_flags, entry.vm_flags);
- TST_EXP_EQ_LU(q.vma_start, entry.vm_start);
- TST_EXP_EQ_LU(q.vma_end, entry.vm_end);
- TST_EXP_EQ_LU(q.vma_page_size, getpagesize());
- TST_EXP_EQ_LU(q.vma_offset, entry.vm_pgoff);
- TST_EXP_EQ_LU(q.inode, entry.vm_inode);
- TST_EXP_EQ_LU(q.dev_major, entry.vm_major);
- TST_EXP_EQ_LU(q.dev_minor, entry.vm_minor);
+ memset(q, 0, sizeof(*q));
+ q->size = sizeof(*q);
+ q->query_addr = (uint64_t)entry.vm_start;
+ q->query_flags = 0;
+
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, q));
+
+ TST_EXP_EQ_LU(q->query_addr, entry.vm_start);
+ TST_EXP_EQ_LU(q->query_flags, 0);
+ TST_EXP_EQ_LU(q->vma_flags, entry.vm_flags);
+ TST_EXP_EQ_LU(q->vma_start, entry.vm_start);
+ TST_EXP_EQ_LU(q->vma_end, entry.vm_end);
+ TST_EXP_EQ_LU(q->vma_page_size, getpagesize());
+ TST_EXP_EQ_LU(q->vma_offset, entry.vm_pgoff);
+ TST_EXP_EQ_LU(q->inode, entry.vm_inode);
+ TST_EXP_EQ_LU(q->dev_major, entry.vm_major);
+ TST_EXP_EQ_LU(q->dev_minor, entry.vm_minor);
/* CASE 2: NO MATCH at query_addr */
- memset(&q, 0, sizeof(q));
- q.size = sizeof(q);
- q.query_addr = entry.vm_start - 1;
- q.query_flags = 0;
+ memset(q, 0, sizeof(*q));
+ q->size = sizeof(*q);
+ q->query_addr = entry.vm_start - 1;
+ q->query_flags = 0;
- TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
+ TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, q), ENOENT);
/* CASE 3: MATCH COVERING_OR_NEXT_VMA */
- memset(&q, 0, sizeof(q));
- q.size = sizeof(q);
- q.query_addr = entry.vm_start - 1;
- q.query_flags = PROCMAP_QUERY_COVERING_OR_NEXT_VMA;
+ memset(q, 0, sizeof(*q));
+ q->size = sizeof(*q);
+ q->query_addr = entry.vm_start - 1;
+ q->query_flags = PROCMAP_QUERY_COVERING_OR_NEXT_VMA;
- TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, q));
/* CASE 4: NO MATCH WRITABLE at query_addr */
memset(&entry, 0, sizeof(entry));
parse_maps_file(PROC_MAP_PATH, "*r-?p *", &entry);
- memset(&q, 0, sizeof(q));
- q.size = sizeof(q);
- q.query_addr = entry.vm_start;
- q.query_flags = PROCMAP_QUERY_VMA_WRITABLE;
- TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, &q), ENOENT);
+ memset(q, 0, sizeof(*q));
+ q->size = sizeof(*q);
+ q->query_addr = entry.vm_start;
+ q->query_flags = PROCMAP_QUERY_VMA_WRITABLE;
+ TST_EXP_FAIL(ioctl(fd, PROCMAP_QUERY, q), ENOENT);
/* CASE 5: check vma_name_addr content */
char process_name[256];
- char pattern[256];
+ char pattern[258];
char buf[256];
SAFE_READLINK("/proc/self/exe", process_name, sizeof(process_name));
- sprintf(pattern, "*%s*", process_name);
+ snprintf(pattern, sizeof(pattern), "*%s*", process_name);
memset(&entry, 0, sizeof(entry));
parse_maps_file(PROC_MAP_PATH, pattern, &entry);
- memset(&q, 0, sizeof(q));
- q.size = sizeof(q);
- q.query_addr = entry.vm_start;
- q.query_flags = 0;
- q.vma_name_addr = (uint64_t)(unsigned long)buf;
- q.vma_name_size = sizeof(buf);
+ memset(q, 0, sizeof(*q));
+ q->size = sizeof(*q);
+ q->query_addr = entry.vm_start;
+ q->query_flags = 0;
+ q->vma_name_addr = (uint64_t)(unsigned long)buf;
+ q->vma_name_size = sizeof(buf);
- TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, &q));
- TST_EXP_EQ_LU(q.vma_name_size, strlen(process_name) + 1);
- TST_EXP_EQ_STR((char *)q.vma_name_addr, process_name);
+ TST_EXP_PASS(ioctl(fd, PROCMAP_QUERY, q));
+ TST_EXP_EQ_LU(q->vma_name_size, strlen(process_name) + 1);
+ TST_EXP_EQ_STR((char *)q->vma_name_addr, process_name);
SAFE_CLOSE(fd);
}
+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,
+ .cleanup = cleanup,
.test_all = verify_ioctl,
- .needs_root = 1,
+ .bufs = (struct tst_buffers []) {
+ {&q, .size = sizeof(*q)},
+ {}
+ }
};
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [LTP] [PATCH v2] ioctl10.c: New case test PROCMAP_QUERY ioctl()
2025-07-10 15:26 ` Cyril Hrubis
@ 2025-07-11 15:47 ` Wei Gao via ltp
0 siblings, 0 replies; 7+ messages in thread
From: Wei Gao via ltp @ 2025-07-11 15:47 UTC (permalink / raw)
To: Cyril Hrubis; +Cc: ltp
On Thu, Jul 10, 2025 at 05:26:29PM +0200, Cyril Hrubis wrote:
> Hi!
> I've pushed the patch with following changes:
>
> - removed .needs_root since the test runs fine without root
>
> - moved the check for ioctl() support into the test setup() and the
> check for availability is only done on kernels older than 6.11 since
> it has to be available since that kernel version
>
> - made use of guarded buffers for the procmap_query structure passed to
> the syscalls
>
> What should still be done:
>
> - we miss a few more 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->qma_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
> - possibly ESRCH if we attempt to get memory map of a process that did exit and was waited for
>
> - the invalid tests should be split into a separate test and stored in
> a tcase structure as we usually do, which makes it easier to add tests
Thanks, i will check it.
>
> Full diff:
> --
> Cyril Hrubis
> chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-07-11 3:48 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-13 5:52 [LTP] [PATCH v1] ioctl10.c: New case test PROCMAP_QUERY ioctl() Wei Gao via ltp
2025-01-13 5:57 ` Wei Gao via ltp
2025-01-14 12:08 ` Wei Gao via ltp
2025-02-21 15:04 ` Cyril Hrubis
2025-02-26 12:51 ` [LTP] [PATCH v2] " Wei Gao via ltp
2025-07-10 15:26 ` Cyril Hrubis
2025-07-11 15:47 ` Wei Gao via ltp
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.