1 // SPDX-License-Identifier: GPL-2.0
7 #include <linux/types.h>
9 #include <sys/syscall.h>
13 #include "linux/ptrace.h"
15 static int sys_rt_sigqueueinfo(pid_t tgid
, int sig
, siginfo_t
*uinfo
)
17 return syscall(SYS_rt_sigqueueinfo
, tgid
, sig
, uinfo
);
20 static int sys_rt_tgsigqueueinfo(pid_t tgid
, pid_t tid
,
21 int sig
, siginfo_t
*uinfo
)
23 return syscall(SYS_rt_tgsigqueueinfo
, tgid
, tid
, sig
, uinfo
);
26 static int sys_ptrace(int request
, pid_t pid
, void *addr
, void *data
)
28 return syscall(SYS_ptrace
, request
, pid
, addr
, data
);
32 #define TEST_SICODE_PRIV -1
33 #define TEST_SICODE_SHARE -2
36 #define PAGE_SIZE sysconf(_SC_PAGESIZE)
39 #define err(fmt, ...) \
41 "Error (%s:%d): " fmt, \
42 __FILE__, __LINE__, ##__VA_ARGS__)
44 static int check_error_paths(pid_t child
)
46 struct ptrace_peeksiginfo_args arg
;
47 int ret
, exit_code
= -1;
48 void *addr_rw
, *addr_ro
;
51 * Allocate two contiguous pages. The first one is for read-write,
52 * another is for read-only.
54 addr_rw
= mmap(NULL
, 2 * PAGE_SIZE
, PROT_READ
| PROT_WRITE
,
55 MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
56 if (addr_rw
== MAP_FAILED
) {
57 err("mmap() failed: %m\n");
61 addr_ro
= mmap(addr_rw
+ PAGE_SIZE
, PAGE_SIZE
, PROT_READ
,
62 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED
, -1, 0);
63 if (addr_ro
== MAP_FAILED
) {
64 err("mmap() failed: %m\n");
71 /* Unsupported flags */
73 ret
= sys_ptrace(PTRACE_PEEKSIGINFO
, child
, &arg
, addr_rw
);
74 if (ret
!= -1 || errno
!= EINVAL
) {
75 err("sys_ptrace() returns %d (expected -1),"
76 " errno %d (expected %d): %m\n",
82 /* A part of the buffer is read-only */
83 ret
= sys_ptrace(PTRACE_PEEKSIGINFO
, child
, &arg
,
84 addr_ro
- sizeof(siginfo_t
) * 2);
86 err("sys_ptrace() returns %d (expected 2): %m\n", ret
);
90 /* Read-only buffer */
91 ret
= sys_ptrace(PTRACE_PEEKSIGINFO
, child
, &arg
, addr_ro
);
92 if (ret
!= -1 && errno
!= EFAULT
) {
93 err("sys_ptrace() returns %d (expected -1),"
94 " errno %d (expected %d): %m\n",
101 munmap(addr_rw
, 2 * PAGE_SIZE
);
105 int check_direct_path(pid_t child
, int shared
, int nr
)
107 struct ptrace_peeksiginfo_args arg
= {.flags
= 0, .nr
= nr
, .off
= 0};
108 int i
, j
, ret
, exit_code
= -1;
109 siginfo_t siginfo
[SIGNR
];
113 arg
.flags
= PTRACE_PEEKSIGINFO_SHARED
;
114 si_code
= TEST_SICODE_SHARE
;
117 si_code
= TEST_SICODE_PRIV
;
120 for (i
= 0; i
< SIGNR
; ) {
122 ret
= sys_ptrace(PTRACE_PEEKSIGINFO
, child
, &arg
, siginfo
);
124 err("ptrace() failed: %m\n");
131 for (j
= 0; j
< ret
; j
++, i
++) {
132 if (siginfo
[j
].si_code
== si_code
&&
133 siginfo
[j
].si_int
== i
)
136 err("%d: Wrong siginfo i=%d si_code=%d si_int=%d\n",
137 shared
, i
, siginfo
[j
].si_code
, siginfo
[j
].si_int
);
143 err("Only %d signals were read\n", i
);
152 int main(int argc
, char *argv
[])
154 siginfo_t siginfo
[SIGNR
];
155 int i
, exit_code
= 1;
159 sigemptyset(&blockmask
);
160 sigaddset(&blockmask
, SIGRTMIN
);
161 sigprocmask(SIG_BLOCK
, &blockmask
, NULL
);
165 err("fork() failed: %m");
167 } else if (child
== 0) {
168 pid_t ppid
= getppid();
170 if (ppid
!= getppid())
177 /* Send signals in process-wide and per-thread queues */
178 for (i
= 0; i
< SIGNR
; i
++) {
179 siginfo
->si_code
= TEST_SICODE_SHARE
;
181 sys_rt_sigqueueinfo(child
, SIGRTMIN
, siginfo
);
183 siginfo
->si_code
= TEST_SICODE_PRIV
;
185 sys_rt_tgsigqueueinfo(child
, child
, SIGRTMIN
, siginfo
);
188 if (sys_ptrace(PTRACE_ATTACH
, child
, NULL
, NULL
) == -1)
191 waitpid(child
, NULL
, 0);
193 /* Dump signals one by one*/
194 if (check_direct_path(child
, 0, 1))
196 /* Dump all signals for one call */
197 if (check_direct_path(child
, 0, SIGNR
))
201 * Dump signal from the process-wide queue.
202 * The number of signals is not multible to the buffer size
204 if (check_direct_path(child
, 1, 3))
207 if (check_error_paths(child
))
213 if (sys_ptrace(PTRACE_KILL
, child
, NULL
, NULL
) == -1)
216 waitpid(child
, NULL
, 0);