diff options
Diffstat (limited to 'lib/libc/sys')
| -rw-r--r-- | lib/libc/sys/t_aio_cancel.c | 223 | ||||
| -rw-r--r-- | lib/libc/sys/t_aio_lio.c | 264 | ||||
| -rw-r--r-- | lib/libc/sys/t_aio_rw.c | 167 | ||||
| -rw-r--r-- | lib/libc/sys/t_aio_suspend.c | 170 | ||||
| -rw-r--r-- | lib/libc/sys/t_ptrace_kill.c | 131 |
5 files changed, 955 insertions, 0 deletions
diff --git a/lib/libc/sys/t_aio_cancel.c b/lib/libc/sys/t_aio_cancel.c new file mode 100644 index 000000000000..43965cada251 --- /dev/null +++ b/lib/libc/sys/t_aio_cancel.c @@ -0,0 +1,223 @@ +/* $NetBSD: t_aio_cancel.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_all(const struct aiocb * const [], size_t); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_cancel.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_all(const struct aiocb * const list[], size_t nent) +{ + size_t i; + int pending, rv; + + for (;;) { + pending = 0; + + for (i = 0; i < nent; i++) { + int err; + + if (list[i] == NULL) { + continue; + } + + err = aio_error(list[i]); + if (err == EINPROGRESS) { + pending = 1; + } + } + + if (!pending) { + break; + } + + rv = aio_suspend(list, (int)nent, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", + strerror(errno)); + } +} + +ATF_TC_WITHOUT_HEAD(cancel_active_write); +ATF_TC_BODY(cancel_active_write, tc) +{ + char path[64]; + int fd, rv, crv, err; + const size_t blksz = 0x1000; + uint8_t *wbuf; + struct aiocb cb; + const struct aiocb *list[1]; + + fd = mktemp_file(path, sizeof(path)); + + wbuf = malloc(blksz); + ATF_REQUIRE(wbuf != NULL); + fill_pattern(wbuf, blksz, 0x33); + + memset(&cb, 0, sizeof(cb)); + cb.aio_fildes = fd; + cb.aio_buf = wbuf; + cb.aio_nbytes = blksz; + cb.aio_offset = 0; + + rv = aio_write(&cb); + ATF_REQUIRE_EQ(0, rv); + + crv = aio_cancel(fd, &cb); + ATF_REQUIRE(crv == AIO_CANCELED || crv == AIO_NOTCANCELED + || crv == AIO_ALLDONE); + + if (crv == AIO_CANCELED) { + do { + err = aio_error(&cb); + } while (err == EINPROGRESS); + ATF_REQUIRE_EQ(ECANCELED, err); + ATF_REQUIRE_EQ(-1, aio_return(&cb)); + } else if (crv == AIO_NOTCANCELED) { + list[0] = &cb; + wait_all(list, 1); + ATF_REQUIRE_EQ(0, aio_error(&cb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); + } else { + do { + err = aio_error(&cb); + } while (err == EINPROGRESS); + ATF_REQUIRE_EQ(0, err); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(wbuf); +} + +ATF_TC_WITHOUT_HEAD(cancel_completed_request); +ATF_TC_BODY(cancel_completed_request, tc) +{ + char path[64]; + int fd, rv, crv; + const size_t blksz = 4096; + uint8_t *wbuf; + struct aiocb cb; + const struct aiocb *list[1]; + + fd = mktemp_file(path, sizeof(path)); + + wbuf = malloc(blksz); + ATF_REQUIRE(wbuf != NULL); + memset(wbuf, 0x7E, blksz); + + memset(&cb, 0, sizeof(cb)); + cb.aio_fildes = fd; + cb.aio_buf = wbuf; + cb.aio_nbytes = blksz; + cb.aio_offset = 0; + + rv = aio_write(&cb); + ATF_REQUIRE_EQ(0, rv); + + list[0] = &cb; + wait_all(list, 1); + ATF_REQUIRE_EQ(0, aio_error(&cb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); + + crv = aio_cancel(fd, &cb); + ATF_REQUIRE_EQ(AIO_ALLDONE, crv); + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(wbuf); +} + +ATF_TC_WITHOUT_HEAD(cancel_invalid_fd); +ATF_TC_BODY(cancel_invalid_fd, tc) +{ + struct aiocb cb; + int crv; + + memset(&cb, 0, sizeof(cb)); + cb.aio_fildes = -1; + + errno = 0; + crv = aio_cancel(-1, &cb); + ATF_REQUIRE_EQ(-1, crv); + ATF_REQUIRE_EQ(EBADF, errno); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, cancel_active_write); + ATF_TP_ADD_TC(tp, cancel_completed_request); + ATF_TP_ADD_TC(tp, cancel_invalid_fd); + return atf_no_error(); +} diff --git a/lib/libc/sys/t_aio_lio.c b/lib/libc/sys/t_aio_lio.c new file mode 100644 index 000000000000..991db8d5a7cd --- /dev/null +++ b/lib/libc/sys/t_aio_lio.c @@ -0,0 +1,264 @@ +/* $NetBSD: t_aio_lio.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_all(const struct aiocb * const [], size_t); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_lio.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_all(const struct aiocb * const list[], size_t nent) +{ + size_t i; + int pending, rv; + + for (;;) { + pending = 0; + + for (i = 0; i < nent; i++) { + int err; + + if (list[i] == NULL) { + continue; + } + + err = aio_error(list[i]); + if (err == EINPROGRESS) { + pending = 1; + } + } + + if (!pending) { + break; + } + + rv = aio_suspend(list, (int)nent, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", + strerror(errno)); + } +} + +ATF_TC_WITHOUT_HEAD(lio_nowait); +ATF_TC_BODY(lio_nowait, tc) +{ + char path[64]; + int fd, rv; +#define NW_REQS 8 +#define NW_BLKSIZ 8192 + uint8_t *bufs[NW_REQS]; + struct aiocb cbs[NW_REQS]; + struct aiocb *list[NW_REQS]; + off_t off; + size_t i; + + fd = mktemp_file(path, sizeof(path)); + + off = 0; + for (i = 0; i < NW_REQS; i++) { + bufs[i] = malloc(NW_BLKSIZ); + ATF_REQUIRE(bufs[i] != NULL); + + fill_pattern(bufs[i], NW_BLKSIZ, (uint8_t)i); + + memset(&cbs[i], 0, sizeof(cbs[i])); + cbs[i].aio_fildes = fd; + cbs[i].aio_buf = bufs[i]; + cbs[i].aio_nbytes = NW_BLKSIZ; + cbs[i].aio_offset = off; + cbs[i].aio_lio_opcode = LIO_WRITE; + + list[i] = &cbs[i]; + off += (off_t)NW_BLKSIZ; + } + + rv = lio_listio(LIO_NOWAIT, list, (int)NW_REQS, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio failed: %s", + strerror(errno)); + + wait_all((const struct aiocb * const *)list, NW_REQS); + + for (i = 0; i < NW_REQS; i++) { + int err; + ssize_t done; + + err = aio_error(&cbs[i]); + ATF_REQUIRE_EQ(0, err); + + done = aio_return(&cbs[i]); + ATF_REQUIRE_EQ(NW_BLKSIZ, done); + + free(bufs[i]); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); +} + +ATF_TC_WITHOUT_HEAD(lio_wait_write_then_read); +ATF_TC_BODY(lio_wait_write_then_read, tc) +{ + char path[64]; + int fd, rv; +#define WWTR_REQS 4 +#define WWTR_BLKSIZ 4096 + + uint8_t *wbufs[WWTR_REQS]; + struct aiocb wcbs[WWTR_REQS]; + struct aiocb *wlist[WWTR_REQS]; + + uint8_t *rbufs[WWTR_REQS]; + struct aiocb rcbs[WWTR_REQS]; + struct aiocb *rlist[WWTR_REQS]; + + size_t i; + off_t off; + + fd = mktemp_file(path, sizeof(path)); + + off = 0; + for (i = 0; i < WWTR_REQS; i++) { + wbufs[i] = malloc(WWTR_BLKSIZ); + ATF_REQUIRE(wbufs[i] != NULL); + + fill_pattern(wbufs[i], WWTR_BLKSIZ, (uint8_t)(0xA0 + i)); + + memset(&wcbs[i], 0, sizeof(wcbs[i])); + wcbs[i].aio_fildes = fd; + wcbs[i].aio_buf = wbufs[i]; + wcbs[i].aio_nbytes = WWTR_BLKSIZ; + wcbs[i].aio_offset = off; + wcbs[i].aio_lio_opcode = LIO_WRITE; + + wlist[i] = &wcbs[i]; + off += WWTR_BLKSIZ; + } + + rv = lio_listio(LIO_WAIT, wlist, (int)WWTR_REQS, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio write failed: %s", + strerror(errno)); + + for (i = 0; i < WWTR_REQS; i++) { + int err; + ssize_t done; + + err = aio_error(&wcbs[i]); + ATF_REQUIRE_EQ(0, err); + + done = aio_return(&wcbs[i]); + ATF_REQUIRE_EQ(WWTR_BLKSIZ, done); + } + + for (i = 0; i < WWTR_REQS; i++) { + rbufs[i] = calloc(1, WWTR_BLKSIZ); + ATF_REQUIRE(rbufs[i] != NULL); + + memset(&rcbs[i], 0, sizeof(rcbs[i])); + rcbs[i].aio_fildes = fd; + rcbs[i].aio_buf = rbufs[i]; + rcbs[i].aio_nbytes = WWTR_BLKSIZ; + rcbs[i].aio_offset = (off_t)i * WWTR_BLKSIZ; + rcbs[i].aio_lio_opcode = LIO_READ; + + rlist[i] = &rcbs[i]; + } + + rv = lio_listio(LIO_NOWAIT, rlist, WWTR_REQS, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio read failed: %s", + strerror(errno)); + + wait_all((const struct aiocb * const *)rlist, WWTR_REQS); + + for (i = 0; i < WWTR_REQS; i++) { + int err; + ssize_t done; + + err = aio_error(&rcbs[i]); + ATF_REQUIRE_EQ(0, err); + + done = aio_return(&rcbs[i]); + ATF_REQUIRE_EQ(WWTR_BLKSIZ, done); + + ATF_REQUIRE_EQ(0, memcmp(wbufs[i], rbufs[i], WWTR_BLKSIZ)); + + free(wbufs[i]); + free(rbufs[i]); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, lio_nowait); + ATF_TP_ADD_TC(tp, lio_wait_write_then_read); + + return atf_no_error(); +} diff --git a/lib/libc/sys/t_aio_rw.c b/lib/libc/sys/t_aio_rw.c new file mode 100644 index 000000000000..e7a5b4fa67d1 --- /dev/null +++ b/lib/libc/sys/t_aio_rw.c @@ -0,0 +1,167 @@ +/* $NetBSD: t_aio_rw.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_all(const struct aiocb * const [], size_t); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_rw.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_all(const struct aiocb * const list[], size_t nent) +{ + size_t i; + int pending, rv, error; + + for (;;) { + pending = 0; + + for (i = 0; i < nent; i++) { + if (list[i] == NULL) { + continue; + } + + error = aio_error(list[i]); + if (error == EINPROGRESS) { + pending = 1; + } + } + + if (!pending) { + break; + } + + rv = aio_suspend(list, (int)nent, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", + strerror(errno)); + } +} + +/* + * write_then_read_back + * Write a block then read it back asynchronously and compare. + */ +ATF_TC_WITHOUT_HEAD(write_then_read_back); +ATF_TC_BODY(write_then_read_back, tc) +{ + char path[64]; + int fd, rv; + const size_t blksz = 0x2000; + uint8_t *wbuf, *rbuf; + struct aiocb wcb, rcb; + const struct aiocb *wlist[1], *rlist[1]; + + fd = mktemp_file(path, sizeof(path)); + + wbuf = malloc(blksz); + rbuf = calloc(1, blksz); + ATF_REQUIRE(wbuf != NULL && rbuf != NULL); + + fill_pattern(wbuf, blksz, 0xA0); + + memset(&wcb, 0, sizeof(wcb)); + wcb.aio_fildes = fd; + wcb.aio_buf = wbuf; + wcb.aio_nbytes = blksz; + wcb.aio_offset = 0; + + rv = aio_write(&wcb); + ATF_REQUIRE_EQ(0, rv); + wlist[0] = &wcb; + wait_all(wlist, 1); + + ATF_REQUIRE_EQ(0, aio_error(&wcb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&wcb)); + + memset(&rcb, 0, sizeof(rcb)); + rcb.aio_fildes = fd; + rcb.aio_buf = rbuf; + rcb.aio_nbytes = blksz; + rcb.aio_offset = 0; + + rv = aio_read(&rcb); + ATF_REQUIRE_EQ(0, rv); + rlist[0] = &rcb; + wait_all(rlist, 1); + + ATF_REQUIRE_EQ(0, aio_error(&rcb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&rcb)); + ATF_REQUIRE_EQ(0, memcmp(wbuf, rbuf, blksz)); + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(wbuf); + free(rbuf); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, write_then_read_back); + return atf_no_error(); +} diff --git a/lib/libc/sys/t_aio_suspend.c b/lib/libc/sys/t_aio_suspend.c new file mode 100644 index 000000000000..96b0dc2cf6d0 --- /dev/null +++ b/lib/libc/sys/t_aio_suspend.c @@ -0,0 +1,170 @@ +/* $NetBSD: t_aio_suspend.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_cb(struct aiocb *); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_suspend.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_cb(struct aiocb *cb) +{ + const struct aiocb *one[1]; + int rv; + + one[0] = cb; + while (aio_error(cb) == EINPROGRESS) { + rv = aio_suspend(one, 1, NULL); + ATF_REQUIRE_EQ(0, rv); + } + if (aio_error(cb) == 0) { + aio_return(cb); + } +} + +ATF_TC_WITHOUT_HEAD(suspend_any); +ATF_TC_BODY(suspend_any, tc) +{ + char path[64]; + int fd, rv; + const size_t blksz = 4096; + uint8_t *buf0, *buf1; + struct aiocb cb0, cb1; + const struct aiocb *list[2]; + int done; + + fd = mktemp_file(path, sizeof(path)); + + buf0 = malloc(blksz); + buf1 = malloc(blksz); + ATF_REQUIRE(buf0 != NULL && buf1 != NULL); + fill_pattern(buf0, blksz, 0x20); + fill_pattern(buf1, blksz, 0x40); + + memset(&cb0, 0, sizeof(cb0)); + cb0.aio_fildes = fd; + cb0.aio_buf = buf0; + cb0.aio_nbytes = blksz; + cb0.aio_offset = 0; + + memset(&cb1, 0, sizeof(cb1)); + cb1.aio_fildes = fd; + cb1.aio_buf = buf1; + cb1.aio_nbytes = blksz; + cb1.aio_offset = blksz; + + ATF_REQUIRE_EQ(0, aio_write(&cb0)); + ATF_REQUIRE_EQ(0, aio_write(&cb1)); + + list[0] = &cb0; + list[1] = &cb1; + + rv = aio_suspend(list, 2, NULL); + ATF_REQUIRE_EQ(0, rv); + + done = 0; + if (aio_error(&cb0) != EINPROGRESS) { + done++; + if (aio_error(&cb0) == 0) { + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb0)); + } else { + ATF_REQUIRE_EQ(ECANCELED, aio_error(&cb0)); + ATF_REQUIRE_EQ(-1, aio_return(&cb0)); + } + } + if (aio_error(&cb1) != EINPROGRESS) { + done++; + if (aio_error(&cb1) == 0) { + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb1)); + } else { + ATF_REQUIRE_EQ(ECANCELED, aio_error(&cb1)); + ATF_REQUIRE_EQ(-1, aio_return(&cb1)); + } + } + ATF_REQUIRE(done >= 1); + + if (aio_error(&cb0) == EINPROGRESS) { + wait_cb(&cb0); + } + if (aio_error(&cb1) == EINPROGRESS) { + wait_cb(&cb1); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(buf0); + free(buf1); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, suspend_any); + return atf_no_error(); +} diff --git a/lib/libc/sys/t_ptrace_kill.c b/lib/libc/sys/t_ptrace_kill.c new file mode 100644 index 000000000000..fdd6298c2a8a --- /dev/null +++ b/lib/libc/sys/t_ptrace_kill.c @@ -0,0 +1,131 @@ +/* $NetBSD: t_ptrace_kill.c,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_ptrace_kill.c,v 1.2 2025/05/02 02:24:32 riastradh Exp $"); + +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/wait.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <err.h> +#include <atf-c.h> + +#define SYSCALL(a, b) ATF_REQUIRE_EQ_MSG(a, b, "%s got %s", #a, strerror(errno)) + +ATF_TC(pt_kill); +ATF_TC_HEAD(pt_kill, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test PT_KILL of a PT_STOP'ed process"); +} + +static void +child(int *fdto, int *fdfrom) +{ + char p = '2', q; + printf("%d: born\n", getpid()); + write(fdfrom[1], &p, 1); + read(fdto[0], &q, 1); + printf("%d: seppuku %c\n", getpid(), q); + write(fdfrom[1], &p, 1); + read(fdto[0], &q, 1); +// *(int *)1 = 0; +// kill(getpid(), SIGSEGV); +// kill(getpid(), SIGSTOP); + for (;;) + sleep(1); + +} + +static void * +waitthread(void *pidp) +{ + int status = 0; + pid_t rpid, pid; + + pid = *(pid_t *)pidp; + printf("waiting for %d\n", pid); + while ((rpid = waitpid(pid, &status, 0)) != pid) { + printf("waitpid %d = %d status = %#x", pid, rpid, status); + } + printf("done waitpid %d = %d status = %#x", pid, rpid, status); + return NULL; +} + +ATF_TC_BODY(pt_kill, tc) +{ + pid_t pid; + int fdto[2], fdfrom[2]; + char p = '1', q; + int status; + pthread_t thread; + + SYSCALL(pipe(fdto), 0); + SYSCALL(pipe(fdfrom), 0); + switch (pid = fork()) { + case 0: + child(fdto, fdfrom); + break; + case -1: + err(EXIT_FAILURE, "fork failed"); + default: + SYSCALL(pthread_create(&thread, NULL, waitthread, &pid), 0); + sleep(1); // XXX: too lazy to sync properly + SYSCALL(read(fdfrom[0], &q, 1), 1); + printf("%d: read %c\n", pid, q); + SYSCALL(ptrace(PT_ATTACH, pid, NULL, 0), 0); + printf("%d: attached\n", pid); + SYSCALL(write(fdto[1], &p, 1), 1); + waitpid(pid, NULL, WNOHANG); + printf("%d: sent\n", pid); + SYSCALL(ptrace(PT_CONTINUE, pid, (void *)1, 0), 0); + SYSCALL(read(fdfrom[0], &p, 1), 1); + printf("%d: received\n", pid); + SYSCALL(ptrace(PT_STOP, pid, NULL, 0), 0); + SYSCALL(ptrace(PT_KILL, pid, NULL, 0), 0); + SYSCALL(waitpid(pid, &status, 0), pid); + ATF_REQUIRE(status == 9); + break; + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, pt_kill); + + return atf_no_error(); +} |
