From nobody Wed Oct 8 11:45:34 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 A89E0245000 for ; Sun, 29 Jun 2025 21:45:20 +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=1751233522; cv=none; b=ShmS3FwKpaOrT/AK8j1hQV7+e3WbY3H+j2D2gwRbtSTZxhGUF1MxQDDYH2tcKq3CcNre7lbZk0+YNYclwSljP4w3lBp+8GS/94UnteNNy73bcwRDyYG0dWD8ExCrrcqJA3wwZTx6F4jFminKui4ygf0L5t4xzWu+fUg7AKepoow= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751233522; c=relaxed/simple; bh=G/61B5x6m5HWYLNss1aWHcp1JZl7vwCXB6QgizYMTKk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KROzQuedz0j0gsAyl1t6SKcmvGyoItLSCM1O714THUeRXp49LwKOWylx1BpVPH/o9OqX+oGuotN7pd0xbdPWAxtBLZb65CMiqzo5LGQkkb9sFEWyBV0VlOqc788/p5syzb7oCNVKbCqz17VOgCDBPjQofEpERJJxf8/sKs4qZy8= 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=iy2yalHB; 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="iy2yalHB" Received: from mail-ed1-f72.google.com (mail-ed1-f72.google.com [209.85.208.72]) (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 46E833F52A for ; Sun, 29 Jun 2025 21:45:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1751233519; bh=/1BBk1xnWMXbQKeMLQK9jlxe2oTJlnw7Zx+SrOAU8+o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=iy2yalHBCVi1ft/uVQPQHBC5xmP7IEdaD66MrEOlxmux+b8z+nkL/+SWxxC6/f4iw dko8cjgXxtreCP62jiBrP84OGMZXr0nVZQtWmtruCGI1OBWNK9s0Cw9C+cYLFFRxYY llPOjXqoOWeB8XB/ZkK8eLwSMbdCjzgTO1WLRHBuEsprbTYKG6pzV0pjhJ8XXIvBj6 UxpwBJcDfoFA2jMNRNVeGJCx0b0+8T1f1tHxvE+TwUbFYO5zJqeyOdeOV9+GfZfphr mqq3ze71l3XCL4Ss2E5PvH0OsGBeXMWEBrm4CJqw5isCM9zPIAJAGMZzx0T0AzkCav 0fyhBmFFSZ6wg== Received: by mail-ed1-f72.google.com with SMTP id 4fb4d7f45d1cf-6090274dd37so1324897a12.0 for ; Sun, 29 Jun 2025 14:45:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751233517; x=1751838317; 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=/1BBk1xnWMXbQKeMLQK9jlxe2oTJlnw7Zx+SrOAU8+o=; b=lbG5Wrkiq3PEhGTLdVFWAlh+x6l+yISBUlBLaRQVbY3Ef6OcWJOwFEu023ZRksQBG3 9Jid54Mvfhn3kqYmgIonpqWpZzqcRrIWux6sAox2e0HPMeWL/g1ZlTd5XpYz59E3aEYO EzWvLm2/l5W/tAEkDN5UMYe82JmDp0Ej0Xb7BunG69BNl3ivCfJLb0PKKOP6vLTzECpp NJBBrIEEBoXJ1kM2crt4oMUi1HD73Gl8d7Qqe80Q/aWbBapC8j0Ypz75AYWJOJQiS3LQ 93B7o/rqZl06UB3JbQFXownqAHJxHbacZP9HW+YVt/B23sfoRottx7vOk46XaxXTEp1p LHtg== X-Forwarded-Encrypted: i=1; AJvYcCXdOmSKvGGI8eyrkWiMMgy8BZEH/GCTicTRGn2kdf+tqYKdn5D1tM24bbL0pupSUqQY3Psz7WPzWThGdTs=@vger.kernel.org X-Gm-Message-State: AOJu0YwwypMHZz3X3uhptfOTPe/tfKWUglW5SjIIw1mu7PQPuOl3zrwQ i5Vzh4KLkRma4TS0tZ7tpX8NbZOffz1UnvkqoSxLwF5GtJIKg9IANtnxSX2ZXbXfFGD+/sVmzAZ 1lwi23kofIFXe0b+Li7rqvSTpS6z5XbJ+bLLU82q0TUuwv0Ee22IToGuDL7IGER5vjnmpgjlEAW E8IE9gqw== X-Gm-Gg: ASbGncvSeSAXE7f/YRkZHMtOVwWK7NG5TZTGz7Ew7u+T8PMHq4iIRuKpUon9etpjMw4 QY3YTOsiYTq5BRp3dKKZqXhN/oKmXYrKDz0bFGw+KfL943DhorpJBqsSEW2NHvb2B1i+IdiatsE rsvaBd/C28fSB0wi1WKoZfWxsjIM1JL9BTh0w9Wqw/yMrUFQs91BHYKPNOJMA4WNw12iL3Uo+ze cpbpTyFPrdtbRojNifDvpIxM2uvzGfRkbR9us/P+cd3EJb6zKY/KKemHISLLMwApos+FPa26cAA bTCnfF02Wbt2N/2Ab59HKTTgtV5lucC4nuZrL5xkie7xESvbxA== X-Received: by 2002:a05:6402:254b:b0:5fd:1c90:e5cd with SMTP id 4fb4d7f45d1cf-60c88dd96b1mr9221547a12.20.1751233517191; Sun, 29 Jun 2025 14:45:17 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE8jizv2tS0inqrEmzuPiGpHZgTWGHT7Ac+lf6PwaXUePpN1H8DVPNfjkvYGk+DrsJzND/r4Q== X-Received: by 2002:a05:6402:254b:b0:5fd:1c90:e5cd with SMTP id 4fb4d7f45d1cf-60c88dd96b1mr9221537a12.20.1751233516749; Sun, 29 Jun 2025 14:45:16 -0700 (PDT) Received: from amikhalitsyn.lan ([178.24.219.243]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-60c828e1a96sm4712037a12.19.2025.06.29.14.45.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 29 Jun 2025 14:45:15 -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 , Kuniyuki Iwashima Subject: [RESEND PATCH net-next 6/6] selftests: net: extend SCM_PIDFD test to cover stale pidfds Date: Sun, 29 Jun 2025 23:44:43 +0200 Message-ID: <20250629214449.14462-7-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250629214449.14462-1-aleksandr.mikhalitsyn@canonical.com> References: <20250629214449.14462-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