From nobody Wed Oct 8 02:04:19 2025 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (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 A522A2BFC70 for ; Thu, 3 Jul 2025 22:24:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751581443; cv=none; b=retPm5FAq5cd6zBZ+wZ31wIv0VkUsiMqGv7Vdiia0J1eB8CEdbdm0T/CbiKE1X3VA6wTKWCTJjQ9YStNrbqojmK+nDDDQyf2TQUyAk+UNoiEUeGezzGhZTQFfXdXWK5WbJIVJu4neH97WBlcGcRChZbpnIfo+TxuYoB2Yh7663w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751581443; c=relaxed/simple; bh=sNMgYuRRHDM5tU1JOzxhsMgU93et6+sqxnzyafhvyOg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=abyLCr1eHvequ4v4+YNiisaMH49KrV2q+q7rNUKEtX9JnDqxBMKcqzjm6W+LqgG4ZXJhaCaPX+FpZYCEfvXyMQ6ZzqC9Y0VYxK3zUpgtmRtyqVAZdXvzUxhXz3Sg1M9D7wShn39InH6GUDRW4mRuSXQuTZlEPUTQyo1PrSKyyew= 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=asUeR8TR; arc=none smtp.client-ip=185.125.188.123 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="asUeR8TR" Received: from mail-ed1-f71.google.com (mail-ed1-f71.google.com [209.85.208.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-1.canonical.com (Postfix) with ESMTPS id C9E123F830 for ; Thu, 3 Jul 2025 22:23:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1751581438; bh=3ACJj1pibTp1hDCcnssHwfTz2N2iBLhUH85nRukXflM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=asUeR8TR9GbL1qfkoTTltlOJ8GwlKyU/UcEhMXJduDWZLU9EUweP+fzG6usdxPjXX F+VIEzuw60olVt+ivoeKdzHvPfLbzh3CD+xZDKBkGsU6IG0usxbMWQ4w6xQ3dfhZuv AyQjCOzNkuwNdPLqBlZJG2GJZDXUTzEOghdHHkVI2ut5ncGktigu/N1A4nxr+qBv/G 2bZVAFR58GbvD4mXbijrZJzMYi3zMSyAyAyWXWwtA+Dk5SZW/KUKFLDVkwLCSCQcR8 Dq0yGKI6HO8c7f+xn4fU6/bxAgkYqKHO0s7qeyqVqDDryAK21PvzgcunzjAd81OHF7 py6Ieo5NEHHIg== Received: by mail-ed1-f71.google.com with SMTP id 4fb4d7f45d1cf-60c9d8a1701so190680a12.3 for ; Thu, 03 Jul 2025 15:23:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751581437; x=1752186237; 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=J8h7NH88CNqbT429ufyiRrjMYY/a9REQHNfG7wNEC6TK1Nwg4sDESNl37RpgMrqw1P 0vZffWiCEH+JnUR+JCFtfxbNogOrUv/MEe0USNguhtOFiBPXotLDH1KPzEfDGwlnFybh 5IKVsYd0O9bkg2mGQmGY/RXZq6l6j/UH70Z81LuK2j0DJ/DhDcV/epzmD6sAabc1kdmh PaiBp58vJRfoIVo/YVwV10/S97D+0mFJmJuum65co+XVEQHBHeZCRyZi/NZssycV6oaD DZT6EQCp14R6dxD7FXGw0prQoi2pwk/6IScOUuC6/EPfdfPx5G77HCP3VEy1cnovA/ay ie+w== X-Forwarded-Encrypted: i=1; AJvYcCVG/mQCWYMdfiCLTEfzx+lYJRI8lmJZLElXGTJ2RagQvDyo7dajb+tayda6qvi4irS9tZfsYIfNUsb95w0=@vger.kernel.org X-Gm-Message-State: AOJu0YwcqiIA2NrqSYBcJlYERg+2TfAvSA0Vxax6emgbwea2tICQSDG0 7mJ+EWdgBcQ0RkYJRXzdzo/P35bYfkDlsddjsW8agVCN35tMnhApWNCaoqm8bF6iC45KbPlvV7q kWOmj9E8gDvUsj5nPscBEvJ5j/bT0f4YESHr2xuDTYBe3+57iF7G7j7/PCV1A1ZydnSzndlTlke pNJ3KNNg== X-Gm-Gg: ASbGncsn0cZiWpLrXnMuGYux2P9cfhtC1lwR24VXYHIT+aZuZ4cUmRsk4Yudp3CDa0F qhGPe5jNjo3n5XN0ilHEXETNHydKGTGe7P8RNJF4S/ksCF4EF/2e+2YUR0KWHU4bXvILoVmhzGh ltfYlXGiblslFVy1SLvOdVzSdWcamPO7P7SAMGKdz4nJWidzRm3o/GcUGG5oUjpiDmeCp8HB16J Ht3u38p1Y5fAAtM3Ns+SuxdAcf+f8kx3ZAIpBqeDuAPERqKowWfPUkaTXozYdf4AA9eKtziFCVk y4mRTOTHCp1xyxQxoLcD8GTqN0yZdPBqiiSdMvKFqKJSzNeV1g== X-Received: by 2002:a05:6402:1e8f:b0:609:b263:41d3 with SMTP id 4fb4d7f45d1cf-60fd35ccd36mr251530a12.32.1751581437566; Thu, 03 Jul 2025 15:23:57 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHGlaGtUtTk/shaqKHwURRpox5xAWe2POPldC6erKPQZ/gqhODJsBfGMjz4VC064N+v+5R1VQ== X-Received: by 2002:a05:6402:1e8f:b0:609:b263:41d3 with SMTP id 4fb4d7f45d1cf-60fd35ccd36mr251502a12.32.1751581437110; Thu, 03 Jul 2025 15:23:57 -0700 (PDT) Received: from amikhalitsyn.lan ([178.24.219.243]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-60fcb1fb083sm355164a12.62.2025.07.03.15.23.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jul 2025 15:23:56 -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 v3 7/7] selftests: net: extend SCM_PIDFD test to cover stale pidfds Date: Fri, 4 Jul 2025 00:23:11 +0200 Message-ID: <20250703222314.309967-8-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250703222314.309967-1-aleksandr.mikhalitsyn@canonical.com> References: <20250703222314.309967-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