public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Ondrej Mosnacek <omosnace@redhat.com>
To: git-commits@fedoraproject.org
Subject: [tests/selinux] pr775-checkpolicy-revdeps: Add a test for two-way SCTP association setup
Date: Fri, 11 Sep 2026 13:21:55 GMT	[thread overview]
Message-ID: <178913291533.1.9711287180412306592.tests-selinux-5e03405ed4f7@fedoraproject.org> (raw)

            A new commit has been pushed.

            Repo   : tests/selinux
            Branch : pr775-checkpolicy-revdeps
            Commit : 5e03405ed4f761adcf79e479ebf33c0dc76e4ad5
            Author : Ondrej Mosnacek <omosnace@redhat.com>
            Date   : 2024-08-29T10:06:21+00:00
            Stats  : +312/-0 in 3 file(s)
            URL    : https://src.fedoraproject.org/tests/selinux/c/5e03405ed4f761adcf79e479ebf33c0dc76e4ad5?branch=pr775-checkpolicy-revdeps

            Log:
            Add a test for two-way SCTP association setup

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>

---
diff --git a/kernel/sctp_peeloff_corner_case/main.fmf b/kernel/sctp_peeloff_corner_case/main.fmf
new file mode 100644
index 0000000..582248e
--- /dev/null
+++ b/kernel/sctp_peeloff_corner_case/main.fmf
@@ -0,0 +1,25 @@
+summary: Verify that two-way SCTP association setup doesn't trigger AVCs
+description: |
+    When two SCTP endpoints try to initiate an association
+    simultaneously with each other, they may hit various corner cases.
+    This test verifies that this scenario works correctly and that the
+    resulting association is properly labeled (by peeling it off, which
+    transfers the label onto the new socket).
+contact: Ondrej Mosnacek <omosnace@redhat.com>
+component:
+  - kernel
+framework: beakerlib
+require:
+  - make
+  - gcc
+  - lksctp-tools-devel
+  - audit
+duration: 10m
+tier: 2
+enabled: true
+adjust:
+  - enabled: false
+    when: distro < rhel-8
+    because: RHEL-7 and below don't have SCTP SELinux support
+link:
+  - verifies: https://issues.redhat.com/browse/RHEL-48647

diff --git a/kernel/sctp_peeloff_corner_case/reproducer.c b/kernel/sctp_peeloff_corner_case/reproducer.c
new file mode 100644
index 0000000..de6cedb
--- /dev/null
+++ b/kernel/sctp_peeloff_corner_case/reproducer.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPLv2
+/*
+ * Copyright (c) 2024 Red Hat, Inc.
+ * Author: Ondrej Mosnacek <omosnace@redhat.com>
+ */
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/sctp.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+static const char * const TEST_PORTS[] = { "9998", "9999" };
+
+#define ITERATIONS 1000
+
+#define member_size(type, member) sizeof(((type *)0)->member)
+#define sizeof_up_to(type, member) (offsetof(type, member) + member_size(type, member))
+
+enum {
+	PIPE_R = 0,
+	PIPE_W,
+};
+
+int main(int argc, char **argv)
+{
+	int sock, psock, result, flags, index, i, pipefd[2], pipes[2][2];
+	struct addrinfo hints, *info;
+	struct sctp_event_subscribe subscr_events;
+	pid_t fork_pid;
+	char byte = 0x41, data[1024];
+	sctp_assoc_t assoc_id;
+	union sctp_notification *notif;
+
+	result = pipe(pipefd);
+	if (result < 0) {
+		perror("pipe");
+		return 1;
+	}
+	pipes[0][PIPE_R] = pipefd[0];
+	pipes[1][PIPE_W] = pipefd[1];
+
+	result = pipe(pipefd);
+	if (result < 0) {
+		perror("pipe");
+		return 1;
+	}
+	pipes[1][PIPE_R] = pipefd[0];
+	pipes[0][PIPE_W] = pipefd[1];
+
+	fork_pid = fork();
+	if (fork_pid < 0) {
+		perror("fork");
+		return 1;
+	}
+
+	index = !!fork_pid;
+	close(pipes[!index][PIPE_R]);
+	close(pipes[!index][PIPE_W]);
+
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_flags = AI_PASSIVE;
+	hints.ai_protocol = IPPROTO_SCTP;
+	hints.ai_family = AF_INET;
+	hints.ai_socktype = SOCK_SEQPACKET;
+
+	result = getaddrinfo(NULL, TEST_PORTS[index], &hints, &info);
+	if (result < 0) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
+		return 1;
+	}
+
+	sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
+	if (sock < 0) {
+		perror("socket");
+		return 1;
+	}
+
+	result = bind(sock, info->ai_addr, info->ai_addrlen);
+	if (result < 0) {
+		perror("bind");
+		return 1;
+	}
+
+	if (listen(sock, SOMAXCONN)) {
+		perror("listen");
+		return 1;
+	}
+
+	memset(&subscr_events, 0, sizeof(subscr_events));
+	subscr_events.sctp_association_event = 1;
+	result = setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, &subscr_events,
+			    sizeof_up_to(struct sctp_event_subscribe,
+					 sctp_association_event));
+
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_protocol = IPPROTO_SCTP;
+	hints.ai_socktype = SOCK_SEQPACKET;
+
+	result = getaddrinfo("127.0.0.1", TEST_PORTS[!index], &hints, &info);
+	if (result < 0) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(result));
+		return 1;
+	}
+
+	for (i = 0; i < ITERATIONS; i++) {
+		printf("[%i] ITERATION %i...\n", index, i);
+
+		/* synchronize */
+		result = write(pipes[index][PIPE_W], &byte, 1);
+		if (result < 0) {
+			perror("pipe");
+			return 1;
+		}
+		result = read(pipes[index][PIPE_R], &byte, 1);
+		if (result < 0) {
+			perror("pipe");
+			return 1;
+		}
+
+		result = connect(sock, info->ai_addr, info->ai_addrlen);
+		if (result < 0 && errno != EISCONN) {
+			perror("connect");
+			return 1;
+		}
+
+		/* Get assoc_id for sctp_peeloff() */
+		flags = 0;
+		result = sctp_recvmsg(sock, data, sizeof(data),
+				NULL, 0, NULL, &flags);
+		if (result < 0) {
+			perror("sctp_recvmsg");
+			return 1;
+		}
+
+		if ((flags & (MSG_NOTIFICATION | MSG_EOR)) != (MSG_NOTIFICATION | MSG_EOR)) {
+			fprintf(stderr, "[%i] Invalid sctp_recvmsg response FLAGS: %x\n", index, flags);
+			return 1;
+		}
+
+		notif = (union sctp_notification *)data;
+		if (notif->sn_header.sn_type != SCTP_ASSOC_CHANGE) {
+			fprintf(stderr, "[%i] Invalid sctp_recvmsg response type: %x\n", index, notif->sn_header.sn_type);
+			return 1;
+		}
+		assoc_id = notif->sn_assoc_change.sac_assoc_id;
+		psock = sctp_peeloff(sock, assoc_id);
+		if (psock < 0) {
+			perror("sctp_peeloff");
+			return 1;
+		}
+
+		data[0] = 42;
+		result = sctp_sendmsg(psock, data, 1, NULL, 0,
+				      0, 0, 0, 0, 0);
+		if (result < 0) {
+			perror("sctp_sendmsg");
+			return 1;
+		}
+
+		result = sctp_recvmsg(psock, data, sizeof(data),
+				      NULL, 0, NULL, NULL);
+		if (result < 0) {
+			perror("sctp_recvmsg");
+			return 1;
+		}
+
+		if (data[0] != 42) {
+			fprintf(stderr, "[%i] Invalid sctp_recvmsg response: %d\n", index, (int)data[0]);
+			return 1;
+		}
+
+		close(psock);
+		printf("[%i] ITERATION %i SUCCESS!\n", index, i);
+	}
+	close(sock);
+	return 0;
+}

diff --git a/kernel/sctp_peeloff_corner_case/runtest.sh b/kernel/sctp_peeloff_corner_case/runtest.sh
new file mode 100755
index 0000000..19649bd
--- /dev/null
+++ b/kernel/sctp_peeloff_corner_case/runtest.sh
@@ -0,0 +1,100 @@
+#!/bin/bash
+# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
+# SPDX-License-Identifier: GPLv2
+# Copyright (c) 2024 Red Hat, Inc.
+# Author: Ondrej Mosnacek <omosnace@redhat.com>
+
+# Include Beakerlib environment
+. /usr/share/beakerlib/beakerlib.sh || exit 1
+
+function installDepsYum() {
+    local yum="$1"; shift
+
+    if "$yum" install --help | grep -q -- --skip-unavailable; then
+        "$yum" install -y --skip-unavailable $*
+    elif "$yum" install --help | grep -q -- --skip-broken; then
+        "$yum" install -y --skip-broken $*
+    else
+        for req in $*; do
+            if ! rpm -q --quiet --whatprovides "$req"; then
+                "$yum" install -y "$req" || true
+            fi
+        done
+    fi
+}
+
+function installDeps() {
+    if [ -e /run/ostree-booted ]; then
+        for item in "$@"; do
+            if ! rpm -q --quiet --whatprovides "$item"; then
+                rpm-ostree --apply-live -y install "$item"
+            fi
+        done
+    elif type yum >/dev/null; then
+        installDepsYum yum "$@"
+    elif type dnf >/dev/null; then
+        installDepsYum dnf "$@"
+    fi
+}
+
+function check_avc_begin() {
+    sleep 1.1
+    date +'%x %T'
+    sleep 1.1
+}
+
+function check_avc_end() {
+    marker="marker-$RANDOM"
+
+    auditctl -m "$marker"
+
+    for (( i = 0; i < 100; i++ )); do
+        if ausearch -i -m user -ts $1 2>/dev/null </dev/null | \
+            grep -q "$marker"
+        then
+            echo $i
+            break
+        fi
+        sleep 0.1
+    done
+
+    ausearch -i -m avc -ts $1 </dev/null
+}
+
+rlJournalStart
+    rlPhaseStartSetup
+        rlRun "uname -r" 0 "Print kernel version"
+        # Determine the base kernel package name and version corresponding
+        # to the currently running kernel. Use this information to derive
+        # the correct kernel subpackages to install.
+        if KERNEL_CORE_NVRA="$(rpm -qf "/lib/modules/$(uname -r)/config")"; then
+            KERNEL_CORE_NV="${KERNEL_CORE_NVRA%-*}"
+            KERNEL_CORE_N="${KERNEL_CORE_NV%-*}"
+
+            KERNEL_PKG_VRA="${KERNEL_CORE_NVRA#$KERNEL_CORE_N-}"
+            KERNEL_PKG_BASE="${KERNEL_CORE_N%-core}"
+
+            rlLog "Detected kernel package base name '$KERNEL_PKG_BASE' and version-release.arch '$KERNEL_PKG_VRA'"
+            rlRun "installDeps  $KERNEL_PKG_BASE-modules-extra-$KERNEL_PKG_VRA" 0 "Install extra kernel modules"
+        else
+            rlLog "Detected non-RPM running kernel - no extra kernel packages will be installed"
+        fi
+
+        rlRun "gcc -O2 -Wall -o reproducer reproducer.c -lsctp" 0 \
+                "Compile the reproducer"
+        rlRun "modprobe sctp" 0 "Ensure SCTP module is loaded"
+    rlPhaseEnd
+
+    rlPhaseStartTest
+        rlRun "audit_ts=\"\$(check_avc_begin)\""
+
+        rlRun "./reproducer" 0 "Run the reproducer"
+
+        rlRun "check_avc_end \"\$audit_ts\"" 1 "Check if there are AVC denials"
+    rlPhaseEnd
+
+    rlPhaseStartCleanup
+        rlRun "rm -f reproducer"
+    rlPhaseEnd
+rlJournalPrintText
+rlJournalEnd

             reply	other threads:[~2026-09-11 13:21 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-11 13:21 Ondrej Mosnacek [this message]
  -- strict thread matches above, loose matches on Subject: below --
2026-09-11 13:19 [tests/selinux] pr775-checkpolicy-revdeps: Add a test for two-way SCTP association setup Ondrej Mosnacek

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178913291533.1.9711287180412306592.tests-selinux-5e03405ed4f7@fedoraproject.org \
    --to=omosnace@redhat.com \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox