From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ed1-f43.google.com (mail-ed1-f43.google.com [209.85.208.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E4401352034 for ; Wed, 22 Jul 2026 12:30:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.43 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784723412; cv=none; b=hng8ZbBiSWIlCAg4cCL7zwWfhoELtC57wuTL2PO4S6fSixhADCbop7exjXVpvRyN1kPCaXsiT3Z8Vk7fAEwL2BfX+N8j/CGpg/McBvg6Lg3GGujZ18Ph6zfQGxTYja/b4FgQCCYMJtoEXIpp2Imr45gztdaQjD+3UzKY8Fgr3mw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784723412; c=relaxed/simple; bh=YR2dh10ivQfLZOGXOR0YDRUBJQfvgY5D+ot0FwvSBHQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Q+HHadAHjnaQHF/hDIeqONt6Mfk8x2FaaiTh6C/IH6kUouBWdUvx7d4xXaFcz8lVQp8Aasxehamo2VBPCmMbmZ3g49S/erTTyJKP+eUaIJnfyikz7x+KE/I/G8r0++T6BxzMLJWplcqRsFreEQBtDr0EDwkX4Bl9MsA4vXId1f0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com; spf=pass smtp.mailfrom=cloudflare.com; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b=LvMoaC6F; arc=none smtp.client-ip=209.85.208.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cloudflare.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="LvMoaC6F" Received: by mail-ed1-f43.google.com with SMTP id 4fb4d7f45d1cf-69e8ea2783aso6151379a12.3 for ; Wed, 22 Jul 2026 05:30:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google09082023; t=1784723408; x=1785328208; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=pCH9TsY6JjijtowAyR28vJoTPq1XXv7UbsDDuJ5wjzE=; b=LvMoaC6FYktPJKtCVMEod50E1DExWVG/Alx7avZfHuSmArPvQfr9zQ2BvVu9OPi3Tq Tjs0u2Mfk5yhTSG5gWtAD0rZpSvtVsxMElAJK7fhSe9WUe8/WK77ithC4X8A8+ffCEp3 CdHMl0WxXLA6t9SKI8mJFvrSCp8cbya3aDR/x/LAHkxcK0sIYHMUHzB+qi04tSIXP/J9 j1a2eSVs3SMUeREoLeieh0h54GQgFGoLq30NUJ6b2PVOGb1ie1P4THkeXiOC5a7Gzlso 4bVlrVRuePWffottrIiwUIDTMJovFxzZIykAlzkaF62oLrFkDko9U3wzSlH6Z4W+6K+4 G/qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784723408; x=1785328208; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=pCH9TsY6JjijtowAyR28vJoTPq1XXv7UbsDDuJ5wjzE=; b=bxKDoeB70TyeP0EoWK0JqaMWqR80087E2po94M+hEb0calAdzuCh7if0e3Ss16434k Rm9pNqTc7Dn8kt3u1e0o2G73vkiG0yphFIPIywt2/1j2M6k46cupTFejnNKCv2pqXA4w TMvMlN/u5PFaRBRYsc6js/VqjFK9TSS4JelNsJF7UzKLXpOdMZxqCVteXvl5yd+i5yk4 1125EqOlAH3IanqvYB2WVqx8MPFVKbAKlTLMoYt193uxaeWgd3qLIJUS0AiqkT1H3F2J A71Vwi/GhNyQqKwnieDIdVt+0zytUYIi1DL6IEg4qWAbQBHF+ax7BCEyJmre6q/h1/K6 n8Mg== X-Forwarded-Encrypted: i=1; AHgh+Rrum4Ji74ewuFFOS/y5hXGeuiQfX5h98JtFiV7HhUid1v3j54tZpgtES1TC4E0IrzICTLsVerMU1YKAg0s=@vger.kernel.org X-Gm-Message-State: AOJu0Yw+IhLUAv8ryKNZH3uMWhaJVG4sCNwNz8faRjs05KCwGNv0e1PL 8u85x7N6P2u9pFwPZYJufpJsEIS0z+gsSLxpE+0oX0l7j1ogkZlrLQ1fuEhZoLBNJdk= X-Gm-Gg: AR+sD13zJ2m3OuUE4ciTPF9rV4mHC+fRdagaTidSBf69m7l3HCNT8PcXFwduSoH2bKf iXULR9CtpgECoLujjgQdLeYuzAi83bjEbZZACWydv6RGWRfIisg1bFo8GkaVWjtpTbOxWKtLs1D J0g88pFkFoOeNFs4msCR+b2YkDvmg0tMW/06+vhPvQSrsAf1O306OMuDU7WHZEl0QPkN6n4Wq2m 1yPjsa+XyVuwKMKQGyuFSyvU+Er1cqOe4WbDGP3BhVPN5qLnXpcMcUQaKIwLMd42Hrj+g0+ZBur hvPAaX2CslqyrAhMQ9tYjho21I4Tlej5V4Ct09uhagbfmlfaBQfxnZgLqqnem4sVu9AitMPkLJE jCGJ1vy0mm7QNZDa6C969RBFsEMPJhUotTNCUO4KwST1tPuLyC12gcC+Dzm0KtRE= X-Received: by 2002:a05:6402:4590:b0:69c:2ffe:114a with SMTP id 4fb4d7f45d1cf-69e65327a22mr7487794a12.39.1784723407932; Wed, 22 Jul 2026 05:30:07 -0700 (PDT) Received: from DW927H4LGF ([2a09:bac6:37e6:1e5a::306:2]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-69f34f1b867sm835007a12.14.2026.07.22.05.30.05 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Wed, 22 Jul 2026 05:30:06 -0700 (PDT) From: Oxana Kharitonova To: mic@digikod.net, gnoack@google.com Cc: paul@paul-moore.com, jmorris@namei.or, serge@hallyn.com, wangyan01@kylinos.cn, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, landlock@lists.linux.dev, oxana@cloudflare.com, webprosto@gmail.com Subject: [PATCH 4/6] selftests/landlock: Test POSIX message queue scoping Date: Wed, 22 Jul 2026 13:29:40 +0100 Message-ID: <20260722122952.42149-5-oxana@cloudflare.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260722122952.42149-1-oxana@cloudflare.com> References: <20260722122952.42149-1-oxana@cloudflare.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for LANDLOCK_SCOPE_POSIX_MSG_QUEUE. Verify that opening a queue created outside the current scoped domain is denied, and that opening a queue created within the same domain remains allowed. Signed-off-by: Oxana Kharitonova --- .../landlock/scoped_posix_msg_queue_test.c | 223 ++++++++++++++++++ .../testing/selftests/landlock/scoped_test.c | 2 +- 2 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c diff --git a/tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c b/tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c new file mode 100644 index 000000000000..602ba5c7a83d --- /dev/null +++ b/tools/testing/selftests/landlock/scoped_posix_msg_queue_test.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Landlock tests - POSIX message queue scoping + * + * Copyright © 2024-2026 Microsoft Corporation + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "scoped_common.h" + +static void set_mq_name(char *const name, const size_t size) +{ + snprintf(name, size, "/selftests-landlock-mq-tid%d", sys_gettid()); +} + +FIXTURE(scoped_domains) +{ + char mq_name[NAME_MAX]; +}; + +#include "scoped_base_variants.h" + +FIXTURE_SETUP(scoped_domains) +{ + drop_caps(_metadata); + + set_mq_name(self->mq_name, sizeof(self->mq_name)); + /* Removes a possibly stale queue from a previous run. */ + mq_unlink(self->mq_name); +} + +FIXTURE_TEARDOWN(scoped_domains) +{ +} + +/* + * The parent creates the message queue, then the child tries + * to open it, with scoped domain(s) or no domain at all. + */ +TEST_F(scoped_domains, open_parent_queue) +{ + pid_t child; + int status; + int pipe_parent[2], pipe_child[2]; + char buf; + mqd_t mq; + + ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); + ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); + + if (variant->domain_both) + create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE); + + child = fork(); + ASSERT_LE(0, child); + if (child == 0) { + mqd_t mq_child; + + EXPECT_EQ(0, close(pipe_parent[1])); + EXPECT_EQ(0, close(pipe_child[0])); + + if (variant->domain_child) + create_scoped_domain(_metadata, + LANDLOCK_SCOPE_POSIX_MSG_QUEUE); + + /* Waits for the parent to create the queue. */ + ASSERT_EQ(1, read(pipe_parent[0], &buf, 1)); + + mq_child = mq_open(self->mq_name, O_RDWR); + if (!variant->domain_child) { + EXPECT_LE(0, mq_child); + if (mq_child >= 0) + EXPECT_EQ(0, mq_close(mq_child)); + } else { + EXPECT_EQ(-1, mq_child); + EXPECT_EQ(EPERM, errno); + } + + ASSERT_EQ(1, write(pipe_child[1], ".", 1)); + _exit(_metadata->exit_code); + return; + } + EXPECT_EQ(0, close(pipe_parent[0])); + EXPECT_EQ(0, close(pipe_child[1])); + + if (variant->domain_parent) + create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE); + + mq = mq_open(self->mq_name, O_CREAT | O_RDWR, 0600, NULL); + ASSERT_LE(0, mq); + + ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); + ASSERT_EQ(1, read(pipe_child[0], &buf, 1)); + + ASSERT_EQ(child, waitpid(child, &status, 0)); + EXPECT_EQ(0, mq_close(mq)); + EXPECT_EQ(0, mq_unlink(self->mq_name)); + + if (WIFSIGNALED(status) || !WIFEXITED(status) || + WEXITSTATUS(status) != EXIT_SUCCESS) + _metadata->exit_code = KSFT_FAIL; +} + +/* + * The child creates the message queue, then the parent tries + * to open it, with scoped domain(s) or no domain at all. + */ +TEST_F(scoped_domains, open_child_queue) +{ + pid_t child; + bool can_open_child_queue; + int status; + int pipe_parent[2], pipe_child[2]; + char buf; + mqd_t mq; + + can_open_child_queue = !variant->domain_parent; + + ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC)); + ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC)); + + if (variant->domain_both) + create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE); + + child = fork(); + ASSERT_LE(0, child); + if (child == 0) { + mqd_t mq_child; + + EXPECT_EQ(0, close(pipe_parent[1])); + EXPECT_EQ(0, close(pipe_child[0])); + + if (variant->domain_child) + create_scoped_domain(_metadata, + LANDLOCK_SCOPE_POSIX_MSG_QUEUE); + + /* Waits for the parent to be in a domain, if any. */ + ASSERT_EQ(1, read(pipe_parent[0], &buf, 1)); + + mq_child = mq_open(self->mq_name, O_CREAT | O_RDWR, 0600, NULL); + ASSERT_LE(0, mq_child); + + ASSERT_EQ(1, write(pipe_child[1], ".", 1)); + + ASSERT_EQ(1, read(pipe_parent[0], &buf, 1)); + EXPECT_EQ(0, mq_close(mq_child)); + EXPECT_EQ(0, mq_unlink(self->mq_name)); + _exit(_metadata->exit_code); + return; + } + EXPECT_EQ(0, close(pipe_parent[0])); + EXPECT_EQ(0, close(pipe_child[1])); + + if (variant->domain_parent) + create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE); + + /* Signals that the parent is in a domain, if any. */ + ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); + + /* Waits for the child to create the queue. */ + ASSERT_EQ(1, read(pipe_child[0], &buf, 1)); + + mq = mq_open(self->mq_name, O_RDWR); + if (can_open_child_queue) { + EXPECT_LE(0, mq); + if (mq >= 0) + EXPECT_EQ(0, mq_close(mq)); + } else { + EXPECT_EQ(-1, mq); + EXPECT_EQ(EPERM, errno); + } + + /* Signals to the child that the open attempt is done. */ + ASSERT_EQ(1, write(pipe_parent[1], ".", 1)); + + ASSERT_EQ(child, waitpid(child, &status, 0)); + if (WIFSIGNALED(status) || !WIFEXITED(status) || + WEXITSTATUS(status) != EXIT_SUCCESS) + _metadata->exit_code = KSFT_FAIL; +} + +/* + * A process must always be able to open a queue it created within its own + * domain, whatever the enforced scope is. + */ +TEST(create_and_open_same_domain) +{ + char mq_name[NAME_MAX]; + mqd_t mq_create, mq_open_again; + + drop_caps(_metadata); + set_mq_name(mq_name, sizeof(mq_name)); + mq_unlink(mq_name); + + create_scoped_domain(_metadata, LANDLOCK_SCOPE_POSIX_MSG_QUEUE); + + mq_create = mq_open(mq_name, O_CREAT | O_RDWR, 0600, NULL); + ASSERT_LE(0, mq_create); + + mq_open_again = mq_open(mq_name, O_RDWR); + EXPECT_LE(0, mq_open_again); + if (mq_open_again >= 0) + EXPECT_EQ(0, mq_close(mq_open_again)); + + EXPECT_EQ(0, mq_close(mq_create)); + EXPECT_EQ(0, mq_unlink(mq_name)); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/landlock/scoped_test.c b/tools/testing/selftests/landlock/scoped_test.c index b90f76ed0d9c..c530baa50948 100644 --- a/tools/testing/selftests/landlock/scoped_test.c +++ b/tools/testing/selftests/landlock/scoped_test.c @@ -12,7 +12,7 @@ #include "common.h" -#define ACCESS_LAST LANDLOCK_SCOPE_SIGNAL +#define ACCESS_LAST LANDLOCK_SCOPE_POSIX_MSG_QUEUE TEST(ruleset_with_unknown_scope) { -- 2.50.1 (Apple Git-155)