From nobody Wed Oct 8 09:26:45 2025 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2828E25C6EC for ; Tue, 1 Jul 2025 08:41:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751359312; cv=none; b=ZF8lieoPzxWPyrlgr+jy5TbfycORNMNd/YAMH+WDICVhCqNdfCTquuu8qiD5iIBiU0XuGW4QdP7Hv2U3C08RD0fs0jz98TGJlgAmS6MI8T7uf8nd6IJWap9tbNf5bt+mWgnB0Vs655aqt4qb1vK1z0gYd2TyDNFihfVY2FF8/ng= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751359312; c=relaxed/simple; bh=sNMgYuRRHDM5tU1JOzxhsMgU93et6+sqxnzyafhvyOg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Jas6PIUJBf2DHC/Rgb5PigY14kaunavD1AeY+h10M4tRgEOMVhNhUOa5ocR48Bz8QCTTcjSBWpYYWMcxMtLr8cb2SxkZ0hlAZSc6hIqskAw4ksH5gaPD/4iu93EdSj13ZgUcG5jYv17BA+Nt5Sy1+5AFd11wAiSJOmyIvB7mNGI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=kM0G5mz2; arc=none smtp.client-ip=185.125.188.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="kM0G5mz2" Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id AAF073FE20 for ; Tue, 1 Jul 2025 08:41:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1751359309; bh=3ACJj1pibTp1hDCcnssHwfTz2N2iBLhUH85nRukXflM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kM0G5mz2pMxPJB5zRYHp+KjnQrbo9HDrLRCBOZDY2uSJtTn7j8F89HOgjjMuePkqA Cz0k/w1CZ4Rq9ZTdYuCl/Tau8xNEewyQCfjMJOSfXlb/ZXs6DVHBUBP10n+3cWV8WS bg3GBvNX+FdwxVISGElXIOiyf7FMUpmBOB9HfPjU2CHhEiLbYMFZ6sf2AybK5JFUeH yXkZvOVpQ4QkS85LfdS4Pfo5pNBpWn/wd83LgBL0UfQwu8g61CabIRwVRYp0H7Ay6H UR7HRjhykX4iX9XYvPKQ5WjV6/Hms98woqgEMB1E1Ym3jkvt+0W3lFV00TdD6YoP7O OK6rARG2nN8DA== Received: by mail-ej1-f71.google.com with SMTP id a640c23a62f3a-ade81d27cddso521477466b.0 for ; Tue, 01 Jul 2025 01:41:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751359309; x=1751964109; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3ACJj1pibTp1hDCcnssHwfTz2N2iBLhUH85nRukXflM=; b=gkOIdxQped/Llv9IGvjYQFQjB8XqLPw/MMsei3KQNAKwEIQVDWyJ+7TI+jlsGUpp7a FEdYN2clAP2o571okZQruuewcTLBJZRaeLrW6l9Xd0puUSp+MiM/qkD7LYmbFk6U4u+P kBrl3Szf+VybqiGK2nYM2FAk3rplvNjvQTOFgwMfnGVHDbY+BP2RWyH+kNsSlR9aR+rF XTc2pHXsCe6/UuU/6n84MJbdSmEhRRnEwfAdizq5qgZFbVxpkYku/XPDLwY903VsJURO HERsLP1gDK6wV/osjAEyrnXh5Ftw7ZxjIpiG9+jGb4SGYfxTrULJ/DLweqtmilwRx8AS 0gSQ== X-Forwarded-Encrypted: i=1; AJvYcCWaEnkKGsehP7OXj7zgSHKoWfHzn6mc9dBDb1Pnu+Bp9ckLNhZUCfeQ3iDCr1kAQgEBr58FWWyiDNO85Io=@vger.kernel.org X-Gm-Message-State: AOJu0YwGALqnfE40BEfdAlGpOOwmpannwi7Aesew0/f+WJ5rvUWQ+wtP sVFk1zsLJoO4CeTc55nS2Jjl70sGr2t3YVPMg8O6Rv0q/60o+tUyqAqpFUOGaYlQGh66unr5jm9 S+l/uCqvuxxyGadmL2Np/kEIG6O3rwUVmuxKacbvOjPfgli0PJKhr8i9B7G/34j4bonIcA+LwfT WPRKya0g== X-Gm-Gg: ASbGncvjWfaTwJ7V/gU8En2/us+DBM8hXNKJ3Bgg0io58BxycxyMO9U98Sd3jEe7iMi aNF3E5H9PPFHqlGKrWmf7XqHP51JcRPxkTHw9vtDZOnlcXfP+VDSy13Z8Y5Ja400YkEKHpQ0xeP MLRMXjymh0oBeckedgrTU0nrsXwDd0Vf0X74MJ93Ik+QMeXgNrlukYTqd9RJ+2oqCyolzI+cY3A 2MtJIB1eR9oKWfO3QO67n23wZKtqXHo4OilbDwWc1jp0J5UiNliSk5ajPGlfBodr/3kaQd/Baho Ybm/WjQawjUrVtGF2CWh5uwYespAT3fKjuzPEHe9I+98gJeZKg== X-Received: by 2002:a17:907:d2c8:b0:ae3:b654:165b with SMTP id a640c23a62f3a-ae3b6542a2bmr37281866b.24.1751359309008; Tue, 01 Jul 2025 01:41:49 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGPvyXkJ7xxlUFVfvGUBKe1qmn9gYzE1YPTdbDiV+whqqCBKDQi+KNw6Dqm3Yw3xYlwRh9jZg== X-Received: by 2002:a17:907:d2c8:b0:ae3:b654:165b with SMTP id a640c23a62f3a-ae3b6542a2bmr37278266b.24.1751359308447; Tue, 01 Jul 2025 01:41:48 -0700 (PDT) Received: from amikhalitsyn.lan ([178.24.219.243]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae35363b416sm812427166b.28.2025.07.01.01.41.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Jul 2025 01:41:48 -0700 (PDT) From: Alexander Mikhalitsyn To: kuniyu@google.com Cc: Alexander Mikhalitsyn , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Shuah Khan , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Christian Brauner , Lennart Poettering , Luca Boccassi , David Rheinsberg Subject: [PATCH net-next v2 6/6] selftests: net: extend SCM_PIDFD test to cover stale pidfds Date: Tue, 1 Jul 2025 10:39:21 +0200 Message-ID: <20250701083922.97928-13-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250701083922.97928-1-aleksandr.mikhalitsyn@canonical.com> References: <20250701083922.97928-1-aleksandr.mikhalitsyn@canonical.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend SCM_PIDFD test scenarios to also cover dead task's pidfd retrieval and reading its exit info. Cc: linux-kselftest@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Shuah Khan Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Simon Horman Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: Lennart Poettering Cc: Luca Boccassi Cc: David Rheinsberg Signed-off-by: Alexander Mikhalitsyn Reviewed-by: Christian Brauner --- .../testing/selftests/net/af_unix/scm_pidfd.c | 217 ++++++++++++++---- 1 file changed, 173 insertions(+), 44 deletions(-) diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testin= g/selftests/net/af_unix/scm_pidfd.c index 7e534594167e..37e034874034 100644 --- a/tools/testing/selftests/net/af_unix/scm_pidfd.c +++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c @@ -15,6 +15,7 @@ #include #include =20 +#include "../../pidfd/pidfd.h" #include "../../kselftest_harness.h" =20 #define clean_errno() (errno =3D=3D 0 ? "None" : strerror(errno)) @@ -26,6 +27,8 @@ #define SCM_PIDFD 0x04 #endif =20 +#define CHILD_EXIT_CODE_OK 123 + static void child_die() { exit(1); @@ -126,16 +129,65 @@ static pid_t get_pid_from_fdinfo_file(int pidfd, cons= t char *key, size_t keylen) return result; } =20 +struct cmsg_data { + struct ucred *ucred; + int *pidfd; +}; + +static int parse_cmsg(struct msghdr *msg, struct cmsg_data *res) +{ + struct cmsghdr *cmsg; + int data =3D 0; + + if (msg->msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { + log_err("recvmsg: truncated"); + return 1; + } + + for (cmsg =3D CMSG_FIRSTHDR(msg); cmsg !=3D NULL; + cmsg =3D CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level =3D=3D SOL_SOCKET && + cmsg->cmsg_type =3D=3D SCM_PIDFD) { + if (cmsg->cmsg_len < sizeof(*res->pidfd)) { + log_err("CMSG parse: SCM_PIDFD wrong len"); + return 1; + } + + res->pidfd =3D (void *)CMSG_DATA(cmsg); + } + + if (cmsg->cmsg_level =3D=3D SOL_SOCKET && + cmsg->cmsg_type =3D=3D SCM_CREDENTIALS) { + if (cmsg->cmsg_len < sizeof(*res->ucred)) { + log_err("CMSG parse: SCM_CREDENTIALS wrong len"); + return 1; + } + + res->ucred =3D (void *)CMSG_DATA(cmsg); + } + } + + if (!res->pidfd) { + log_err("CMSG parse: SCM_PIDFD not found"); + return 1; + } + + if (!res->ucred) { + log_err("CMSG parse: SCM_CREDENTIALS not found"); + return 1; + } + + return 0; +} + static int cmsg_check(int fd) { struct msghdr msg =3D { 0 }; - struct cmsghdr *cmsg; + struct cmsg_data res; struct iovec iov; - struct ucred *ucred =3D NULL; int data =3D 0; char control[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int))] =3D { 0 }; - int *pidfd =3D NULL; pid_t parent_pid; int err; =20 @@ -158,53 +210,99 @@ static int cmsg_check(int fd) return 1; } =20 - for (cmsg =3D CMSG_FIRSTHDR(&msg); cmsg !=3D NULL; - cmsg =3D CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level =3D=3D SOL_SOCKET && - cmsg->cmsg_type =3D=3D SCM_PIDFD) { - if (cmsg->cmsg_len < sizeof(*pidfd)) { - log_err("CMSG parse: SCM_PIDFD wrong len"); - return 1; - } + /* send(pfd, "x", sizeof(char), 0) */ + if (data !=3D 'x') { + log_err("recvmsg: data corruption"); + return 1; + } =20 - pidfd =3D (void *)CMSG_DATA(cmsg); - } + if (parse_cmsg(&msg, &res)) { + log_err("CMSG parse: parse_cmsg() failed"); + return 1; + } =20 - if (cmsg->cmsg_level =3D=3D SOL_SOCKET && - cmsg->cmsg_type =3D=3D SCM_CREDENTIALS) { - if (cmsg->cmsg_len < sizeof(*ucred)) { - log_err("CMSG parse: SCM_CREDENTIALS wrong len"); - return 1; - } + /* pidfd from SCM_PIDFD should point to the parent process PID */ + parent_pid =3D + get_pid_from_fdinfo_file(*res.pidfd, "Pid:", sizeof("Pid:") - 1); + if (parent_pid !=3D getppid()) { + log_err("wrong SCM_PIDFD %d !=3D %d", parent_pid, getppid()); + close(*res.pidfd); + return 1; + } =20 - ucred =3D (void *)CMSG_DATA(cmsg); - } + close(*res.pidfd); + return 0; +} + +static int cmsg_check_dead(int fd, int expected_pid) +{ + int err; + struct msghdr msg =3D { 0 }; + struct cmsg_data res; + struct iovec iov; + int data =3D 0; + char control[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int))] =3D { 0 }; + pid_t client_pid; + struct pidfd_info info =3D { + .mask =3D PIDFD_INFO_EXIT, + }; + + iov.iov_base =3D &data; + iov.iov_len =3D sizeof(data); + + msg.msg_iov =3D &iov; + msg.msg_iovlen =3D 1; + msg.msg_control =3D control; + msg.msg_controllen =3D sizeof(control); + + err =3D recvmsg(fd, &msg, 0); + if (err < 0) { + log_err("recvmsg"); + return 1; } =20 - /* send(pfd, "x", sizeof(char), 0) */ - if (data !=3D 'x') { + if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { + log_err("recvmsg: truncated"); + return 1; + } + + /* send(cfd, "y", sizeof(char), 0) */ + if (data !=3D 'y') { log_err("recvmsg: data corruption"); return 1; } =20 - if (!pidfd) { - log_err("CMSG parse: SCM_PIDFD not found"); + if (parse_cmsg(&msg, &res)) { + log_err("CMSG parse: parse_cmsg() failed"); return 1; } =20 - if (!ucred) { - log_err("CMSG parse: SCM_CREDENTIALS not found"); + /* + * pidfd from SCM_PIDFD should point to the client_pid. + * Let's read exit information and check if it's what + * we expect to see. + */ + if (ioctl(*res.pidfd, PIDFD_GET_INFO, &info)) { + log_err("%s: ioctl(PIDFD_GET_INFO) failed", __func__); + close(*res.pidfd); return 1; } =20 - /* pidfd from SCM_PIDFD should point to the parent process PID */ - parent_pid =3D - get_pid_from_fdinfo_file(*pidfd, "Pid:", sizeof("Pid:") - 1); - if (parent_pid !=3D getppid()) { - log_err("wrong SCM_PIDFD %d !=3D %d", parent_pid, getppid()); + if (!(info.mask & PIDFD_INFO_EXIT)) { + log_err("%s: No exit information from ioctl(PIDFD_GET_INFO)", __func__); + close(*res.pidfd); return 1; } =20 + err =3D WIFEXITED(info.exit_code) ? WEXITSTATUS(info.exit_code) : 1; + if (err !=3D CHILD_EXIT_CODE_OK) { + log_err("%s: wrong exit_code %d !=3D %d", __func__, err, CHILD_EXIT_CODE= _OK); + close(*res.pidfd); + return 1; + } + + close(*res.pidfd); return 0; } =20 @@ -291,6 +389,24 @@ static void fill_sockaddr(struct sock_addr *addr, bool= abstract) memcpy(sun_path_buf, addr->sock_name, strlen(addr->sock_name)); } =20 +static int sk_enable_cred_pass(int sk) +{ + int on =3D 0; + + on =3D 1; + if (setsockopt(sk, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { + log_err("Failed to set SO_PASSCRED"); + return 1; + } + + if (setsockopt(sk, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) { + log_err("Failed to set SO_PASSPIDFD"); + return 1; + } + + return 0; +} + static void client(FIXTURE_DATA(scm_pidfd) *self, const FIXTURE_VARIANT(scm_pidfd) *variant) { @@ -299,7 +415,6 @@ static void client(FIXTURE_DATA(scm_pidfd) *self, struct ucred peer_cred; int peer_pidfd; pid_t peer_pid; - int on =3D 0; =20 cfd =3D socket(AF_UNIX, variant->type, 0); if (cfd < 0) { @@ -322,14 +437,8 @@ static void client(FIXTURE_DATA(scm_pidfd) *self, child_die(); } =20 - on =3D 1; - if (setsockopt(cfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { - log_err("Failed to set SO_PASSCRED"); - child_die(); - } - - if (setsockopt(cfd, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) { - log_err("Failed to set SO_PASSPIDFD"); + if (sk_enable_cred_pass(cfd)) { + log_err("sk_enable_cred_pass() failed"); child_die(); } =20 @@ -340,6 +449,12 @@ static void client(FIXTURE_DATA(scm_pidfd) *self, child_die(); } =20 + /* send something to the parent so it can receive SCM_PIDFD too and valid= ate it */ + if (send(cfd, "y", sizeof(char), 0) =3D=3D -1) { + log_err("Failed to send(cfd, \"y\", sizeof(char), 0)"); + child_die(); + } + /* skip further for SOCK_DGRAM as it's not applicable */ if (variant->type =3D=3D SOCK_DGRAM) return; @@ -398,7 +513,13 @@ TEST_F(scm_pidfd, test) close(self->server); close(self->startup_pipe[0]); client(self, variant); - exit(0); + + /* + * It's a bit unusual, but in case of success we return non-zero + * exit code (CHILD_EXIT_CODE_OK) and then we expect to read it + * from ioctl(PIDFD_GET_INFO) in cmsg_check_dead(). + */ + exit(CHILD_EXIT_CODE_OK); } close(self->startup_pipe[1]); =20 @@ -421,9 +542,17 @@ TEST_F(scm_pidfd, test) ASSERT_NE(-1, err); } =20 - close(pfd); waitpid(self->client_pid, &child_status, 0); - ASSERT_EQ(0, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1); + /* see comment before exit(CHILD_EXIT_CODE_OK) */ + ASSERT_EQ(CHILD_EXIT_CODE_OK, WIFEXITED(child_status) ? WEXITSTATUS(child= _status) : 1); + + err =3D sk_enable_cred_pass(pfd); + ASSERT_EQ(0, err); + + err =3D cmsg_check_dead(pfd, self->client_pid); + ASSERT_EQ(0, err); + + close(pfd); } =20 TEST_HARNESS_MAIN --=20 2.43.0