Exercise a tcp_rmem default below 4096 and verify that it is rejected. A tiny default can make TCP receive-window accounting space zero and trigger a divide-by-zero when the receive buffer grows. Run the test in a fresh network namespace and verify that rejection leaves the setting unchanged. Signed-off-by: Sahaj Chaudhari --- tools/testing/selftests/net/.gitignore | 1 + tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/tcp_rmem_min.c | 78 ++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 tools/testing/selftests/net/tcp_rmem_min.c diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index dacd36ed8455..44de061e3eef 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -48,6 +48,7 @@ tcp_fastopen_backup_key tcp_inq tcp_mmap tcp_port_share +tcp_rmem_min tfo timestamping tls diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 590b33e16d9f..595f0e6c38b0 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -198,6 +198,7 @@ TEST_GEN_PROGS := \ so_incoming_cpu \ tap \ tcp_port_share \ + tcp_rmem_min \ tls \ udp_splice_checksum \ # end of TEST_GEN_PROGS diff --git a/tools/testing/selftests/net/tcp_rmem_min.c b/tools/testing/selftests/net/tcp_rmem_min.c new file mode 100644 index 000000000000..dd2305d7e599 --- /dev/null +++ b/tools/testing/selftests/net/tcp_rmem_min.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "kselftest.h" + +#define TCP_RMEM_PATH "/proc/sys/net/ipv4/tcp_rmem" + +static int read_tcp_rmem(char *buf, size_t size) +{ + int fd = open(TCP_RMEM_PATH, O_RDONLY | O_CLOEXEC); + ssize_t len; + + if (fd < 0) + return -1; + + len = read(fd, buf, size - 1); + close(fd); + if (len < 0) + return -1; + + buf[len] = '\0'; + return 0; +} + +int main(void) +{ + /* tcp_rmem is min, default, max; keep min valid and lower the default. */ + static const char invalid_default[] = "4096 1 6291456"; + char before[128], after[128]; + ssize_t len; + int fd, write_errno; + + ksft_print_header(); + ksft_set_plan(1); + + if (unshare(CLONE_NEWNET)) { + if (errno == EPERM || errno == EACCES) + ksft_exit_skip("network namespace unavailable\n"); + ksft_exit_fail_perror("unshare(CLONE_NEWNET)"); + } + + if (read_tcp_rmem(before, sizeof(before))) + ksft_exit_fail_perror("read tcp_rmem before write"); + + fd = open(TCP_RMEM_PATH, O_WRONLY | O_CLOEXEC); + if (fd < 0) + ksft_exit_fail_perror("open tcp_rmem"); + + len = write(fd, invalid_default, sizeof(invalid_default) - 1); + write_errno = errno; + close(fd); + + if (len >= 0) { + ksft_test_result_fail("tcp_rmem accepted a default below 4096\n"); + ksft_finished(); + } + if (write_errno != EINVAL && write_errno != ERANGE) { + errno = write_errno; + ksft_exit_fail_perror("write tcp_rmem"); + } + + if (read_tcp_rmem(after, sizeof(after))) + ksft_exit_fail_perror("read tcp_rmem after rejected write"); + if (strcmp(before, after)) { + ksft_test_result_fail("tcp_rmem changed after rejecting invalid input\n"); + ksft_finished(); + } + + ksft_test_result_pass("tcp_rmem rejects a default below 4096\n"); + ksft_finished(); +} -- 2.43.0