[LTP] [PATCH] sigrelse01: Fix out-of-bounds read when invoking write()
Florian Schmaus
florian.schmaus@codasip.com
Tue Jul 15 11:20:15 CEST 2025
The sigrelse01 test would invoke write(fd, msg, MAXMESG), where
MAXMESG=512. However, msg is often as short as "ready", i.e., 6
bytes (5 bytes + \0).
This mismatch causes write() to read additional bytes outside the *msg
buffer and write everything to the file descriptor. For example, the
strace output of sigrelese01 contains the following:
write(6, "ready\0Unable to tell child to go"..., 512)
Fix the out-of-bounds read in sigrelse01 by invoking write() with the
correct number of bytes to (read and) write by using strlen(). There
is one case where sigrelese01 invoked write_pipe() not passing a
string: when the child sends sig_array to its parent process. We
convert this case from write_pipe() to write() using the proper
arguments. After doing so, the memcpy() of sig_array is no longer
required.
We identified this issue on a CHERI [1] system, which provides
fine-grained memory protection through architectural
capabilities. Unlike traditional MMU-based protection, which would not
detect this specific out-of-bounds access, CHERI precisely bounds
memory regions. In sigrelse01's case, CHERI correctly identified that
the 6-byte buffer containing "ready" was being overread. Consequently,
this out-of-bounds read during the write() syscall would cause the
Linux kernel to return -EFAULT, revealing this hidden bug.
1: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
Signed-off-by: Florian Schmaus <florian.schmaus@codasip.com>
---
testcases/kernel/syscalls/sigrelse/sigrelse01.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/testcases/kernel/syscalls/sigrelse/sigrelse01.c b/testcases/kernel/syscalls/sigrelse/sigrelse01.c
index 95754212053e..f7fdfbab3a28 100644
--- a/testcases/kernel/syscalls/sigrelse/sigrelse01.c
+++ b/testcases/kernel/syscalls/sigrelse/sigrelse01.c
@@ -486,12 +486,14 @@ static void child(void)
* then PASS, otherwise FAIL.
*/
- if (exit_val == EXIT_OK) {
- (void)memcpy(note, (char *)sig_array, sizeof(sig_array));
- }
-
/* send note to parent and exit */
- if (write_pipe(pipe_fd[1], note) < 0) {
+ if (exit_val == EXIT_OK) {
+ if (write(pipe_fd[1], sig_array, sizeof(sig_array)) < 0) {
+ tst_resm(TBROK, "write() pipe failed. error:%d %s.\n", errno, strerror(errno));
+ exit(WRITE_BROK);
+ }
+ }
+ else if (write_pipe(pipe_fd[1], note) < 0) {
/*
* write_pipe() failed. Set exit value to WRITE_BROK to let
* parent know what happened
@@ -622,7 +624,7 @@ static int write_pipe(int fd, char *msg)
printf("write_pipe: pid=%d, sending %s.\n", getpid(), msg);
#endif
- if (write(fd, msg, MAXMESG) < 0) {
+ if (write(fd, msg, strlen(msg) + 1) < 0) {
(void)sprintf(mesg, "write() pipe failed. error:%d %s.",
errno, strerror(errno));
--
2.49.1
More information about the ltp
mailing list