Linux Kernel Selftest development
 help / color / mirror / Atom feed
From: Kuniyuki Iwashima <kuniyu@amazon.com>
To: <aleksandr.mikhalitsyn@canonical.com>
Cc: <arnd@arndb.de>, <bluca@debian.org>, <brauner@kernel.org>,
	<cgroups@vger.kernel.org>, <davem@davemloft.net>,
	<edumazet@google.com>, <hannes@cmpxchg.org>, <kuba@kernel.org>,
	<kuniyu@amazon.com>, <leon@kernel.org>,
	<linux-kernel@vger.kernel.org>, <linux-kselftest@vger.kernel.org>,
	<mkoutny@suse.com>, <mzxreary@0pointer.de>,
	<netdev@vger.kernel.org>, <pabeni@redhat.com>, <shuah@kernel.org>,
	<tj@kernel.org>, <willemb@google.com>
Subject: Re: [PATCH net-next 4/4] tools/testing/selftests/cgroup: add test for SO_PEERCGROUPID
Date: Tue, 11 Mar 2025 01:02:32 -0700	[thread overview]
Message-ID: <20250311080233.11136-1-kuniyu@amazon.com> (raw)
In-Reply-To: <20250309132821.103046-5-aleksandr.mikhalitsyn@canonical.com>

From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Date: Sun,  9 Mar 2025 14:28:15 +0100
> +static void client(FIXTURE_DATA(so_peercgroupid) *self,
> +		   const FIXTURE_VARIANT(so_peercgroupid) *variant)
> +{
> +	int cfd, err;
> +	socklen_t len;
> +	uint64_t peer_cgroup_id = 0, test_cgroup1_id = 0, test_cgroup2_id = 0;
> +	char state;
> +
> +	cfd = socket(AF_UNIX, variant->type, 0);
> +	if (cfd < 0) {
> +		log_err("socket");
> +		child_die();
> +	}
> +
> +	if (variant->type == SOCK_DGRAM) {
> +		fill_sockaddr(self->client_addr, variant->abstract);
> +
> +		if (bind(cfd, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen)) {
> +			log_err("bind");
> +			child_die();
> +		}
> +	}
> +
> +	/* negative testcase: no peer for socket yet */
> +	len = sizeof(peer_cgroup_id);
> +	err = getsockopt(cfd, SOL_SOCKET, SO_PEERCGROUPID, &peer_cgroup_id, &len);
> +	if (!err || (errno != ENODATA)) {
> +		log_err("getsockopt must fail with errno == ENODATA when socket has no peer");
> +		child_die();
> +	}
> +
> +	if (connect(cfd, (struct sockaddr *)&self->server_addr.listen_addr,
> +		    self->server_addr.addrlen) != 0) {
> +		log_err("connect");
> +		child_die();
> +	}
> +
> +	state = 'R';
> +	write(self->sync_sk[1], &state, sizeof(state));

nit: This looks unnecessary ?


> +
> +	read(self->sync_sk[1], &test_cgroup1_id, sizeof(uint64_t));
> +	read(self->sync_sk[1], &test_cgroup2_id, sizeof(uint64_t));
> +
> +	len = sizeof(peer_cgroup_id);
> +	if (getsockopt(cfd, SOL_SOCKET, SO_PEERCGROUPID, &peer_cgroup_id, &len)) {
> +		log_err("Failed to get SO_PEERCGROUPID");
> +		child_die();
> +	}
> +
> +	/*
> +	 * There is a difference between connection-oriented sockets
> +	 * and connectionless ones from the perspective of SO_PEERCGROUPID.
> +	 *
> +	 * sk->sk_cgrp_data is getting filled when we allocate struct sock (see call to cgroup_sk_alloc()).
> +	 * For DGRAM socket, self->server socket is our peer and by the time when we allocate it,
> +	 * parent process sits in a test_cgroup1. Then it changes cgroup to test_cgroup2, but it does not
> +	 * affect anything.
> +	 * For STREAM/SEQPACKET socket, self->server is not our peer, but that one we get from accept()
> +	 * syscall. And by the time when we call accept(), parent process sits in test_cgroup2.
> +	 *
> +	 * Let's ensure that it works like that and if it get changed then we should detect it
> +	 * as it's a clear UAPI change.
> +	 */
> +	if (variant->type == SOCK_DGRAM) {
> +		/* cgroup id from SO_PEERCGROUPID should be equal to the test_cgroup1_id */
> +		if (peer_cgroup_id != test_cgroup1_id) {
> +			log_err("peer_cgroup_id != test_cgroup1_id: %" PRId64 " != %" PRId64, peer_cgroup_id, test_cgroup1_id);
> +			child_die();
> +		}
> +	} else {
> +		/* cgroup id from SO_PEERCGROUPID should be equal to the test_cgroup2_id */
> +		if (peer_cgroup_id != test_cgroup2_id) {
> +			log_err("peer_cgroup_id != test_cgroup2_id: %" PRId64 " != %" PRId64, peer_cgroup_id, test_cgroup2_id);
> +			child_die();
> +		}
> +	}
> +}
> +
> +TEST_F(so_peercgroupid, test)
> +{
> +	uint64_t test_cgroup1_id, test_cgroup2_id;
> +	int err;
> +	int pfd;
> +	char state;
> +	int child_status = 0;
> +
> +	if (cg_find_unified_root(self->cgroup_root, sizeof(self->cgroup_root), NULL))
> +		ksft_exit_skip("cgroup v2 isn't mounted\n");
> +
> +	self->test_cgroup1 = cg_name(self->cgroup_root, "so_peercgroupid_cg1");
> +	ASSERT_NE(NULL, self->test_cgroup1);
> +
> +	self->test_cgroup2 = cg_name(self->cgroup_root, "so_peercgroupid_cg2");
> +	ASSERT_NE(NULL, self->test_cgroup2);
> +
> +	err = cg_create(self->test_cgroup1);
> +	ASSERT_EQ(0, err);
> +
> +	err = cg_create(self->test_cgroup2);
> +	ASSERT_EQ(0, err);
> +
> +	test_cgroup1_id = cg_get_id(self->test_cgroup1);
> +	ASSERT_LT(0, test_cgroup1_id);
> +
> +	test_cgroup2_id = cg_get_id(self->test_cgroup2);
> +	ASSERT_LT(0, test_cgroup2_id);
> +
> +	/* enter test_cgroup1 before allocating a socket */
> +	err = cg_enter_current(self->test_cgroup1);
> +	ASSERT_EQ(0, err);
> +
> +	self->server = socket(AF_UNIX, variant->type, 0);
> +	ASSERT_NE(-1, self->server);
> +
> +	/* enter test_cgroup2 after allocating a socket */
> +	err = cg_enter_current(self->test_cgroup2);
> +	ASSERT_EQ(0, err);
> +
> +	fill_sockaddr(&self->server_addr, variant->abstract);
> +
> +	err = bind(self->server, (struct sockaddr *)&self->server_addr.listen_addr, self->server_addr.addrlen);
> +	ASSERT_EQ(0, err);
> +
> +	if (variant->type != SOCK_DGRAM) {
> +		err = listen(self->server, 1);
> +		ASSERT_EQ(0, err);
> +	}
> +
> +	err = socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, self->sync_sk);
> +	EXPECT_EQ(err, 0);
> +
> +	self->client_pid = fork();
> +	ASSERT_NE(-1, self->client_pid);
> +	if (self->client_pid == 0) {
> +		close(self->server);
> +		close(self->sync_sk[0]);
> +		client(self, variant);
> +		exit(0);
> +	}
> +	close(self->sync_sk[1]);
> +
> +	if (variant->type != SOCK_DGRAM) {
> +		pfd = accept(self->server, NULL, NULL);
> +		ASSERT_NE(-1, pfd);

nit: close(self->server) here ?

It's close()d anyway when the process exits.


> +	} else {
> +		pfd = self->server;
> +	}
> +
> +	/* wait until the child arrives at checkpoint */
> +	read(self->sync_sk[0], &state, sizeof(state));
> +	ASSERT_EQ(state, 'R');

The client will wait two write()s without this synchronisation.


> +
> +	write(self->sync_sk[0], &test_cgroup1_id, sizeof(uint64_t));
> +	write(self->sync_sk[0], &test_cgroup2_id, sizeof(uint64_t));
> +
> +	close(pfd);
> +	waitpid(self->client_pid, &child_status, 0);
> +	ASSERT_EQ(0, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1);
> +}
> +
> +TEST_HARNESS_MAIN

      parent reply	other threads:[~2025-03-11  8:02 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20250309132821.103046-1-aleksandr.mikhalitsyn@canonical.com>
2025-03-09 13:28 ` [PATCH net-next 3/4] tools/testing/selftests/cgroup/cgroup_util: add cg_get_id helper Alexander Mikhalitsyn
2025-03-09 13:28 ` [PATCH net-next 4/4] tools/testing/selftests/cgroup: add test for SO_PEERCGROUPID Alexander Mikhalitsyn
2025-03-10 13:59   ` Willem de Bruijn
2025-03-11  8:02   ` Kuniyuki Iwashima [this message]

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=20250311080233.11136-1-kuniyu@amazon.com \
    --to=kuniyu@amazon.com \
    --cc=aleksandr.mikhalitsyn@canonical.com \
    --cc=arnd@arndb.de \
    --cc=bluca@debian.org \
    --cc=brauner@kernel.org \
    --cc=cgroups@vger.kernel.org \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=hannes@cmpxchg.org \
    --cc=kuba@kernel.org \
    --cc=leon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mkoutny@suse.com \
    --cc=mzxreary@0pointer.de \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=shuah@kernel.org \
    --cc=tj@kernel.org \
    --cc=willemb@google.com \
    /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