From nobody Wed Oct 8 11:42:51 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 EF238245007 for ; Sun, 29 Jun 2025 21:40:42 +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=1751233246; cv=none; b=S/qHlIg/alKsqnwQm32jJZ0uXZTzc5ZA4oB9PgyI7xClyxNDV9ktdU0CP4V3o8n0WlAL1FO0IZywp+2+aBZBraaeSzmTsVEgZY739t03/n1omqCxDdE8Ti87En8w2M7dyvXUTquD7R4jbxvuJNfJIUQl+N9dJ66z7G3FJTARv3Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751233246; c=relaxed/simple; bh=I7t351s+kUb5SKDYgWQJ8NHDqYpbh8iSwRK42UG3IKE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UTjz61ybj/avWEdasdS6nG/RAFcc6dLrIw3/2JvcwCk7BIITpVsZJ75XMLImQHB9O2hV5P1C8oGIuDWXZVbXsJGwMvONGBwzw/ZrxdA7yRJyviV7w6yOs0e36KNt7sxfgES3fQyw++48MIDL54uiTBGrCtuf5hSrbLcO6bonr9U= 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=itbNwgcP; 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="itbNwgcP" 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 F014C3F528 for ; Sun, 29 Jun 2025 21:40:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1751233240; bh=j2/MTcAm+iCIzDDUxW3OLNpgwibHH9urPgNAxzLNo0E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=itbNwgcPqIIdQ/Z1hO9aqt5IzhBfL+rElFvM6oe00PqFVdhy20g42LLxKgORvV3pM qQlOGrATIxXSMx59+2OkTTXSpMG4oCbDtFe3nDQ7Wh+Wj0bO3oVqWnEMIV2Avm0OVL F3q0sbEGYcNcYGAkVs02xJaGev1xNco1hfVeacqbUoe0OW2f+ADt6G2KhEZ0T7x6xM Yn9mtZPYAv26yR4eWEdb7ydEJt9WZ+zPojUL65ND4dCJkGFe3fuNo2scxdXs2ZnEPu tZvJfKfGhQKJXVoBxvhkykiJbIymg2jnwANkyNlK5whe9baPhdZqiznh2MQh/8PgO0 gw7LiB+SuTPFw== Received: by mail-ej1-f71.google.com with SMTP id a640c23a62f3a-ae0dffaa8aeso284448266b.0 for ; Sun, 29 Jun 2025 14:40:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751233240; x=1751838040; 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=j2/MTcAm+iCIzDDUxW3OLNpgwibHH9urPgNAxzLNo0E=; b=Vfk/04ffEupYsPgwyg+yi0zTUkTASnJmw0+i190quCNyA0CHbD4vaMc/Drw+XBxvZX yOczs+sJczWx4hf0Umsakr480uhJbqpVjRyzMT0S24mxcQbNkhWMZHLQqSm4++o9A0oE dOOUqSXJY7L+cFDiaYPRkaCPRbLuib8FXBy+W+2G6eWO095OSD7z3YXlkDXzKGUyFesP eDA5TlyiS/YZb4MhYBO6x/qLedphgOdDWGpW3HZeX23j/qvtK47E3azWu6mX7SXj1Plm uSXxolgwqo6PlZIo5oeVs+SED+dovmZ2mVyYN9XqPbhITntukjnihnQFgtDhD7ud/tge HJpg== X-Forwarded-Encrypted: i=1; AJvYcCXdVPwohiFHg8XFfAZBQkFACvWJurI4jRqmlV4p32xAIGrWzxPUjO/EDe5Lmn5nzIgfcPIGSOvW3+3ctHc=@vger.kernel.org X-Gm-Message-State: AOJu0YzU3m6ajQxnn/hy8mRMxx9pc0/EYMEAbK5NrAo2sg8E6fq+R4+2 /kJoxsY2hAUG3MNR7F5r+z3yc0CX5NkJlEyD8IW6QLrnfx7oFvzrYlGrdN8X9V9FkNKdcq/2kzU eWG0OKdnykAcVPRZfHBgvYu1OofHrA40pi5uNF8ielYiOhmiqPpk9nuXqT3/0IA5b7vTwZUfmU9 2yXlXUdA== X-Gm-Gg: ASbGncvs70sRrfDITAFhwdR3nFqc11hims4E1YwqqVI3Kug97K8FgN8EvQt0Wuhp8uc X/WZuwmPz7aURMH7VS0mEYMrb+JToYjZ8ItkHo/bC95lm6HzqEMicuQ7PGCdAyVlQmaRtvCrnFw MBy+tI3zbAVRjsZrK/qdJOLbwX2FP2yH6e0tdzxXL/PZtXnk0CjTO6PHegmOLdrrC92YvpNL9gl 9LWlHHdgaoF0bKnjHYfeVesQzoCAsZT+T9zbzDolTPR9Y0hDFfn0cuYER6027SjjUER6w6aBl7I nvibaefS6Qo2bQwE3+YBllcP4555io6bVtP4PQQ9FAClLQvQ6A== X-Received: by 2002:a17:907:9623:b0:ae0:d4ef:e35e with SMTP id a640c23a62f3a-ae350486cacmr995588166b.20.1751233240406; Sun, 29 Jun 2025 14:40:40 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFkTtVlij26vBAiiZO/u0kO89Wxwd6uDfzJ8K4cKBe9bdZeQtpkg4ArxaKG5xcqAMPgFZ3dVg== X-Received: by 2002:a17:907:9623:b0:ae0:d4ef:e35e with SMTP id a640c23a62f3a-ae350486cacmr995587366b.20.1751233239975; Sun, 29 Jun 2025 14:40:39 -0700 (PDT) Received: from amikhalitsyn.lan ([178.24.219.243]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ae35365a754sm557263366b.62.2025.06.29.14.40.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 29 Jun 2025 14:40:39 -0700 (PDT) From: Alexander Mikhalitsyn To: kuniyu@amazon.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 6/6] selftests: net: extend SCM_PIDFD test to cover stale pidfds Date: Sun, 29 Jun 2025 23:39:58 +0200 Message-ID: <20250629214004.13100-7-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250629214004.13100-1-aleksandr.mikhalitsyn@canonical.com> References: <20250629214004.13100-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 --- .../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