From nobody Fri Dec 19 03:48:24 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BAC78C77B6E for ; Thu, 13 Apr 2023 13:37:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229671AbjDMNhe (ORCPT ); Thu, 13 Apr 2023 09:37:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37502 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230266AbjDMNhN (ORCPT ); Thu, 13 Apr 2023 09:37:13 -0400 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2F3E2A5C4 for ; Thu, 13 Apr 2023 06:35:03 -0700 (PDT) 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 1153E3F447 for ; Thu, 13 Apr 2023 13:34:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681392875; bh=ZYBDd8fF7mJMcwOJtXeBvNsAOPjTMZCugtV7u0rpGoc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=TZJUIHyOZit/BPy1siQOufvpIILxBptInDQcSabOaCcutKaIB4nrg4Zn9Bmmtoo5v mtxatiy1xRJ076le5nTSx/7+yfOwo3ur+lLq3HANWC/zcvIK8ytDaBUM5cZCgIFaIC rB85NNh/mZLFrtEnULjWgWRoabPbaOWTITTpplJ6PTBrZisQeO1YRkIF3sVBsiGEnB ZU8ttsGU08GMg0R7YI6Zzm+fc74A6j4mRG1o/QtLbr+gowJV+vRxAic6hr9ibOuf4l vzxGSnohx814Ltl+DzuJDZh69voM5/bfZ4A+ihM6X6jRLYmWZLgiyjfr0EUErwc6qh gkD2Wd+aQZzlA== Received: by mail-ed1-f72.google.com with SMTP id f25-20020a50a6d9000000b005049299346fso7728394edc.2 for ; Thu, 13 Apr 2023 06:34:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681392873; x=1683984873; 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=ZYBDd8fF7mJMcwOJtXeBvNsAOPjTMZCugtV7u0rpGoc=; b=ko5bJolGEpJzlqa/G3/ApJna37wsQru4fUT5JlvbnZyT/Gcs/jgf1lSc64lJrYuR8Z Ui88jVezNbN64a9EvrqeHREexB29MSHSWIja6xtXw1DcW2+gFwiVGmM1tu4R5hSAsqmr us/hQ6vC0VVPYYY2VQGvKSfQQG8Y85OtJADiOCqIFYG17+bXL6CQt3c9ZhT3m/hqKQ4A K8Vn+aAHItwIo1nP9rD6Tv2cCZWOImtbk7noC3XqeLcxC8bPm5v3b6r45PIAEa2dZ2aZ pLk83j7q/avClTlSb5y+iKD5aO8FQSP69opxK5q5xHlKL/PF6y7+X9uZ5JxXJ5UCumTu R6+A== X-Gm-Message-State: AAQBX9crILZBwKrKQIA1U5FIQJA8tHNcSr+o5MXeKUxeRTbOW2C7vgEs aAtMAtl5hw0ofxVeliHQ7pEh+ihD2nb2ncebQkDC9b7ke3/VRahBWsUkzM6W3UzJWOsMDhm7EhQ yk+hSBB1kMGMePsci03Tqglp42BdIDQIOKKZRkzUXew== X-Received: by 2002:a17:906:a98:b0:94e:5c27:adb5 with SMTP id y24-20020a1709060a9800b0094e5c27adb5mr2984983ejf.27.1681392872970; Thu, 13 Apr 2023 06:34:32 -0700 (PDT) X-Google-Smtp-Source: AKy350YQFMRtWN6bj6m1WZfzf976J45hZHATf9/AVtYpmorQVWHHDaleZbOdaLP/wz8eh5EGsfEQTw== X-Received: by 2002:a17:906:a98:b0:94e:5c27:adb5 with SMTP id y24-20020a1709060a9800b0094e5c27adb5mr2984966ejf.27.1681392872575; Thu, 13 Apr 2023 06:34:32 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id et22-20020a170907295600b0094a966330fdsm976806ejc.211.2023.04.13.06.34.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Apr 2023 06:34:32 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, daniel@iogearbox.net, Alexander Mikhalitsyn , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Leon Romanovsky , David Ahern , Arnd Bergmann , Kees Cook , Christian Brauner , Kuniyuki Iwashima , Lennart Poettering , Luca Boccassi , linux-arch@vger.kernel.org Subject: [PATCH net-next v4 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD Date: Thu, 13 Apr 2023 15:33:52 +0200 Message-Id: <20230413133355.350571-2-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> References: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Implement SCM_PIDFD, a new type of CMSG type analogical to SCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem. Idea comes from UAPI kernel group: https://uapi-group.org/kernel-features/ Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this. Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: Lennart Poettering Cc: Luca Boccassi Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Tested-by: Luca Boccassi Reviewed-by: Kuniyuki Iwashima Signed-off-by: Alexander Mikhalitsyn Reviewed-by: Christian Brauner --- v4: - fixed silent fd_install if writting of CMSG to the userspace fails (poin= ted by Christian) v2: According to review comments from Kuniyuki Iwashima and Christian Brauner: - use pidfd_create(..) retval as a result - whitespace change --- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 2 ++ include/linux/net.h | 1 + include/linux/socket.h | 1 + include/net/scm.h | 39 +++++++++++++++++++++++-- include/uapi/asm-generic/socket.h | 2 ++ net/core/sock.c | 11 +++++++ net/mptcp/sockopt.c | 1 + net/unix/af_unix.c | 18 ++++++++---- tools/include/uapi/asm-generic/socket.h | 2 ++ 12 files changed, 76 insertions(+), 7 deletions(-) diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi= /asm/socket.h index 739891b94136..ff310613ae64 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -137,6 +137,8 @@ =20 #define SO_RCVMARK 75 =20 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) =20 #if __BITS_PER_LONG =3D=3D 64 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/a= sm/socket.h index 18f3d95ecfec..762dcb80e4ec 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -148,6 +148,8 @@ =20 #define SO_RCVMARK 75 =20 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) =20 #if __BITS_PER_LONG =3D=3D 64 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/ua= pi/asm/socket.h index f486d3dfb6bb..df16a3e16d64 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -129,6 +129,8 @@ =20 #define SO_RCVMARK 0x4049 =20 +#define SO_PASSPIDFD 0x404A + #if !defined(__KERNEL__) =20 #if __BITS_PER_LONG =3D=3D 64 diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi= /asm/socket.h index 2fda57a3ea86..6e2847804fea 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -130,6 +130,8 @@ =20 #define SO_RCVMARK 0x0054 =20 +#define SO_PASSPIDFD 0x0055 + #if !defined(__KERNEL__) =20 =20 diff --git a/include/linux/net.h b/include/linux/net.h index b73ad8e3c212..c234dfbe7a30 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -43,6 +43,7 @@ struct net; #define SOCK_PASSSEC 4 #define SOCK_SUPPORT_ZC 5 #define SOCK_CUSTOM_SOCKOPT 6 +#define SOCK_PASSPIDFD 7 =20 #ifndef ARCH_HAS_SOCKET_TYPES /** diff --git a/include/linux/socket.h b/include/linux/socket.h index 13c3a237b9c9..6bf90f251910 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -177,6 +177,7 @@ static inline size_t msg_data_left(struct msghdr *msg) #define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ #define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ #define SCM_SECURITY 0x03 /* rw: security label */ +#define SCM_PIDFD 0x04 /* ro: pidfd (int) */ =20 struct ucred { __u32 pid; diff --git a/include/net/scm.h b/include/net/scm.h index 585adc1346bd..c67f765a165b 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -120,12 +120,44 @@ static inline bool scm_has_secdata(struct socket *soc= k) } #endif /* CONFIG_SECURITY_NETWORK */ =20 +static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cooki= e *scm) +{ + struct file *pidfd_file =3D NULL; + int pidfd; + + /* + * put_cmsg() doesn't return an error if CMSG is truncated, + * that's why we need to opencode these checks here. + */ + if ((msg->msg_controllen <=3D sizeof(struct cmsghdr)) || + (msg->msg_controllen - sizeof(struct cmsghdr)) < sizeof(int)) { + msg->msg_flags |=3D MSG_CTRUNC; + return; + } + + WARN_ON_ONCE(!scm->pid); + pidfd =3D pidfd_prepare(scm->pid, 0, &pidfd_file); + + if (put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd)) { + if (pidfd_file) { + put_unused_fd(pidfd); + fput(pidfd_file); + } + + return; + } + + if (pidfd_file) + fd_install(pidfd, pidfd_file); +} + static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm, int flags) { if (!msg->msg_control) { - if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp || - scm_has_secdata(sock)) + if (test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags) || + scm->fp || scm_has_secdata(sock)) msg->msg_flags |=3D MSG_CTRUNC; scm_destroy(scm); return; @@ -141,6 +173,9 @@ static __inline__ void scm_recv(struct socket *sock, st= ruct msghdr *msg, put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); } =20 + if (test_bit(SOCK_PASSPIDFD, &sock->flags)) + scm_pidfd_recv(msg, scm); + scm_destroy_cred(scm); =20 scm_passec(sock, msg, scm); diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/s= ocket.h index 638230899e98..b76169fdb80b 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -132,6 +132,8 @@ =20 #define SO_RCVMARK 75 =20 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) =20 #if __BITS_PER_LONG =3D=3D 64 || (defined(__x86_64__) && defined(__ILP32__= )) diff --git a/net/core/sock.c b/net/core/sock.c index c25888795390..3f974246ba3e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1246,6 +1246,13 @@ int sk_setsockopt(struct sock *sk, int level, int op= tname, clear_bit(SOCK_PASSCRED, &sock->flags); break; =20 + case SO_PASSPIDFD: + if (valbool) + set_bit(SOCK_PASSPIDFD, &sock->flags); + else + clear_bit(SOCK_PASSPIDFD, &sock->flags); + break; + case SO_TIMESTAMP_OLD: case SO_TIMESTAMP_NEW: case SO_TIMESTAMPNS_OLD: @@ -1737,6 +1744,10 @@ int sk_getsockopt(struct sock *sk, int level, int op= tname, v.val =3D !!test_bit(SOCK_PASSCRED, &sock->flags); break; =20 + case SO_PASSPIDFD: + v.val =3D !!test_bit(SOCK_PASSPIDFD, &sock->flags); + break; + case SO_PEERCRED: { struct ucred peercred; diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index b655cebda0f3..67be0558862f 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -355,6 +355,7 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_soc= k *msk, int optname, case SO_BROADCAST: case SO_BSDCOMPAT: case SO_PASSCRED: + case SO_PASSPIDFD: case SO_PASSSEC: case SO_RXQ_OVFL: case SO_WIFI_STATUS: diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index fb31e8a4409e..6d5dff4dfe83 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1361,7 +1361,8 @@ static int unix_dgram_connect(struct socket *sock, st= ruct sockaddr *addr, if (err) goto out; =20 - if (test_bit(SOCK_PASSCRED, &sock->flags) && + if ((test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) && !unix_sk(sk)->addr) { err =3D unix_autobind(sk); if (err) @@ -1469,7 +1470,8 @@ static int unix_stream_connect(struct socket *sock, s= truct sockaddr *uaddr, if (err) goto out; =20 - if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) { + if ((test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { err =3D unix_autobind(sk); if (err) goto out; @@ -1670,6 +1672,8 @@ static void unix_sock_inherit_flags(const struct sock= et *old, { if (test_bit(SOCK_PASSCRED, &old->flags)) set_bit(SOCK_PASSCRED, &new->flags); + if (test_bit(SOCK_PASSPIDFD, &old->flags)) + set_bit(SOCK_PASSPIDFD, &new->flags); if (test_bit(SOCK_PASSSEC, &old->flags)) set_bit(SOCK_PASSSEC, &new->flags); } @@ -1819,8 +1823,10 @@ static bool unix_passcred_enabled(const struct socke= t *sock, const struct sock *other) { return test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags) || !other->sk_socket || - test_bit(SOCK_PASSCRED, &other->sk_socket->flags); + test_bit(SOCK_PASSCRED, &other->sk_socket->flags) || + test_bit(SOCK_PASSPIDFD, &other->sk_socket->flags); } =20 /* @@ -1922,7 +1928,8 @@ static int unix_dgram_sendmsg(struct socket *sock, st= ruct msghdr *msg, goto out; } =20 - if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) { + if ((test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { err =3D unix_autobind(sk); if (err) goto out; @@ -2824,7 +2831,8 @@ static int unix_stream_read_generic(struct unix_strea= m_read_state *state, /* Never glue messages from different writers */ if (!unix_skb_scm_eq(skb, &scm)) break; - } else if (test_bit(SOCK_PASSCRED, &sock->flags)) { + } else if (test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) { /* Copy credentials */ scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); unix_set_secdata(&scm, skb); diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/a= sm-generic/socket.h index 8756df13be50..fbbc4bf53ee3 100644 --- a/tools/include/uapi/asm-generic/socket.h +++ b/tools/include/uapi/asm-generic/socket.h @@ -121,6 +121,8 @@ =20 #define SO_RCVMARK 75 =20 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) =20 #if __BITS_PER_LONG =3D=3D 64 || (defined(__x86_64__) && defined(__ILP32__= )) --=20 2.34.1 From nobody Fri Dec 19 03:48:24 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4537DC77B6F for ; Thu, 13 Apr 2023 13:37:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231623AbjDMNhj (ORCPT ); Thu, 13 Apr 2023 09:37:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230502AbjDMNhS (ORCPT ); Thu, 13 Apr 2023 09:37:18 -0400 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 99916B779 for ; Thu, 13 Apr 2023 06:35:05 -0700 (PDT) Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) (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 BC7793F43B for ; Thu, 13 Apr 2023 13:34:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681392880; bh=pU+XkxxaqxIltFz6HAiJgXotXtTecmR/abIbMqTWsWw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fSdLFv6+6AwtL1xo8lr+sbRcMDlnQOpxNFbKF1loIK3JtPIuU6Cd255RADbyUjM1e mApLFFd90uIHUgVuW0iLpUUg0YJEPEjXR6k8cjHWN4co1VfoY1Or5iMisiYttIBwTb A9KQuRa67zJnpLR+BvXFa3ATy0doBYvADt595MduF11TQAmkNZDRm9YGr11p0oENXX J8wyW0JjBZh0ZHpc+qqDyJRF2496so/351JVfa3VVrQetQRY/KQrOuGMCwtEESczD7 KXpMmrZXfgsj7YWYlODOiv+8VH4XTKPC6cFmLhO8bF+KjH05nB+EfDcx4wVJIzOMny H/pLsAFXSbvCA== Received: by mail-ed1-f70.google.com with SMTP id 4fb4d7f45d1cf-505149e1a4eso3102652a12.1 for ; Thu, 13 Apr 2023 06:34:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681392877; x=1683984877; 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=pU+XkxxaqxIltFz6HAiJgXotXtTecmR/abIbMqTWsWw=; b=WWs3p7TZSj6AZDvpabfZHP3K0OxgLmiy5K3FdG3Ljg52wtv2B6UTHE4rr5p7drPECg GoJpfA2CpIrwx7Q3a6K1IybkCyF2J5LaI0Huv1Xfr7fTtSWArJkornOV8r9KInA5U3k2 RR0dLoKg80QnMbU23vGeq8sunqYzgbtNXr+NvCZJCwIq4QtuzBzyjvW7NgcOG0vci0MB AdB1KtJnQXTPugSzijxu0mBSO9MKbSzAhROZumC6WpdFbKEN/DNB6KKEpeVTg5ai0DSp PpwVd4GGf5uUHdEbbySAVyPHqpg/1vXce9sEKJikRjFvXTjLdeBazQpjXhLZaUWb4vgN mAzg== X-Gm-Message-State: AAQBX9fmDXO40ciQz6U1PS71wnvBBfCRvP+0objQ1iuo1FhR0OwX1MhD nGVZ/jVdM/Y8cWqZeaSepBaKxefuhGobT9UvQ9SMOVpgSMzXMI07SLFP6ZMtcHXgXnoygXv+hMJ y00Ip0zKW783xrpbqMFQO8QxRY7k41IH0jAUvrbX0rjkY8tzzqQ== X-Received: by 2002:a05:6402:49:b0:504:8a0f:13ca with SMTP id f9-20020a056402004900b005048a0f13camr1932415edu.10.1681392877052; Thu, 13 Apr 2023 06:34:37 -0700 (PDT) X-Google-Smtp-Source: AKy350aV7p0sn03LCerGeF3KPK9DDJyh86PbUa/oXNvIx8Ve9zsyvkpvXJUqxRJSvXrr+2BQLm/qeg== X-Received: by 2002:a05:6402:49:b0:504:8a0f:13ca with SMTP id f9-20020a056402004900b005048a0f13camr1932387edu.10.1681392876801; Thu, 13 Apr 2023 06:34:36 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id et22-20020a170907295600b0094a966330fdsm976806ejc.211.2023.04.13.06.34.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Apr 2023 06:34:36 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, daniel@iogearbox.net, Alexander Mikhalitsyn , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Leon Romanovsky , David Ahern , Arnd Bergmann , Kees Cook , Christian Brauner , Kuniyuki Iwashima , Lennart Poettering , linux-arch@vger.kernel.org Subject: [PATCH net-next v4 2/4] net: socket: add sockopts blacklist for BPF cgroup hook Date: Thu, 13 Apr 2023 15:33:53 +0200 Message-Id: <20230413133355.350571-3-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> References: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" During work on SO_PEERPIDFD, it was discovered (thanks to Christian), that bpf cgroup hook can cause FD leaks when used with sockopts which install FDs into the process fdtable. After some offlist discussion it was proposed to add a blacklist of socket options those can cause troubles when BPF cgroup hook is enabled. Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: Lennart Poettering Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Suggested-by: Daniel Borkmann Suggested-by: Christian Brauner Signed-off-by: Alexander Mikhalitsyn Tested-by: Luca Boccassi --- net/socket.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/net/socket.c b/net/socket.c index 73e493da4589..9c1ef11de23f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -108,6 +108,8 @@ #include #include =20 +#include + #ifdef CONFIG_NET_RX_BUSY_POLL unsigned int sysctl_net_busy_read __read_mostly; unsigned int sysctl_net_busy_poll __read_mostly; @@ -2227,6 +2229,36 @@ static bool sock_use_custom_sol_socket(const struct = socket *sock) return test_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags); } =20 +#ifdef CONFIG_CGROUP_BPF +static bool sockopt_installs_fd(int level, int optname) +{ + /* + * These options do fd_install(), and if BPF_CGROUP_RUN_PROG_GETSOCKOPT + * hook returns an error after success of the original handler + * sctp_getsockopt(...), userspace will receive an error from getsockopt + * syscall and will be not aware that fd was successfully installed into = fdtable. + * + * Let's prevent bpf cgroup hook from running on them. + */ + if (level =3D=3D SOL_SCTP) { + switch (optname) { + case SCTP_SOCKOPT_PEELOFF: + case SCTP_SOCKOPT_PEELOFF_FLAGS: + return true; + default: + return false; + } + } + + return false; +} +#else /* CONFIG_CGROUP_BPF */ +static inline bool sockopt_installs_fd(int level, int optname) +{ + return false; +} +#endif /* CONFIG_CGROUP_BPF */ + /* * Set a socket option. Because we don't know the option lengths we have * to pass the user mode parameter for the protocols to sort out. @@ -2250,7 +2282,7 @@ int __sys_setsockopt(int fd, int level, int optname, = char __user *user_optval, if (err) goto out_put; =20 - if (!in_compat_syscall()) + if (!in_compat_syscall() && !sockopt_installs_fd(level, optname)) err =3D BPF_CGROUP_RUN_PROG_SETSOCKOPT(sock->sk, &level, &optname, user_optval, &optlen, &kernel_optval); @@ -2304,7 +2336,7 @@ int __sys_getsockopt(int fd, int level, int optname, = char __user *optval, if (err) goto out_put; =20 - if (!in_compat_syscall()) + if (!in_compat_syscall() && !sockopt_installs_fd(level, optname)) max_optlen =3D BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen); =20 if (level =3D=3D SOL_SOCKET) @@ -2315,7 +2347,7 @@ int __sys_getsockopt(int fd, int level, int optname, = char __user *optval, err =3D sock->ops->getsockopt(sock, level, optname, optval, optlen); =20 - if (!in_compat_syscall()) + if (!in_compat_syscall() && !sockopt_installs_fd(level, optname)) err =3D BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock->sk, level, optname, optval, optlen, max_optlen, err); --=20 2.34.1 From nobody Fri Dec 19 03:48:24 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97C98C77B6E for ; Thu, 13 Apr 2023 13:37:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229815AbjDMNhn (ORCPT ); Thu, 13 Apr 2023 09:37:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37072 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231181AbjDMNhT (ORCPT ); Thu, 13 Apr 2023 09:37:19 -0400 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9C252C153 for ; Thu, 13 Apr 2023 06:35:06 -0700 (PDT) Received: from mail-ed1-f69.google.com (mail-ed1-f69.google.com [209.85.208.69]) (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 0D9C23F4A5 for ; Thu, 13 Apr 2023 13:34:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681392882; bh=tINNpmFGgSXRr6eO7vUL42OoLzt52EnFT+KFr84tTSM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=IWDXicU2IQ9anwvlt41gLsLZbPZ1unCTVWeeM7Up+nwwE+5OIiswt8+tchFOFGrpi pveAeyfsJTBEivTaXTd85UCCbRhLx1gMYxi4aBH3GStjvwl5Cg1CmahWFbZGkGNJoH 1xuIhnVWOQgNylub289HfbcFlGKHZgiJQygBmYIzLZSUw3tv34JYlekk71isGeEm4o Ht1z/+wpVNypgc/A5ELZB1zmKY6MMLztwD0YuIavb21KxOWGZfHgPGZ/RQLMO1sohs BHgp1O+dRWB/X8eVoJtejN3GE9sM83UNe0c7WhpgCd6aiPwmfpgD1vGBYpd87MyaP9 CRCYbVg30oVDA== Received: by mail-ed1-f69.google.com with SMTP id x5-20020a50d605000000b005066c2aa22aso1456211edi.17 for ; Thu, 13 Apr 2023 06:34:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681392879; x=1683984879; 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=tINNpmFGgSXRr6eO7vUL42OoLzt52EnFT+KFr84tTSM=; b=P8wOmmtMh6Koh5Y1jw7ZqkLJJx/0iMLT6xJepAQ2Cu3t/2zeAzIPMVW9/QY4YldW2u W+fMGOmk/4pj0xer9ASq9Jxo4m+uz3Oz4QyeLVhPKgo3Mfr6QCnCHy04lrS8BfVu8tZd RwjNhgRRyZxTsE4v+wa8btNk4csAYwpEIu3Q4vFX6vFHOkqfTUIsZH0w8UUMDyhgjV46 uZaq0qN3f9oDgK1J4NmIrBZxMWFKNNZ5Kgdny5rLqfFf8t1KUPaXiNEiuqiTPKAz8GbQ rn5gtjouuGGsh1Oy0ww14ZVTmY+tDukz1aeEBqEWe2+hJyMstZdzihHUqXPyUkwCctEH gi7A== X-Gm-Message-State: AAQBX9chijo4Yq+61s3QMxJxqL8rc8vNvD1iR8Q3/BiN7AcwBlW3hIXV CL3+m3+Q4vKpDtSF9U7cyJtCXOA7LleB+OOkhEx8zkL50XfQEH0ihEiQgHRnLEkqQEnwK3ASZzG O6+q3gNg8W8SqCXtXKudmgh06DlLmW1YDmKrMGY2LVQ== X-Received: by 2002:a17:906:57d0:b0:94a:62e7:70e1 with SMTP id u16-20020a17090657d000b0094a62e770e1mr2718806ejr.68.1681392879595; Thu, 13 Apr 2023 06:34:39 -0700 (PDT) X-Google-Smtp-Source: AKy350bWyh1fpNfKciV+c7c09q66s0vrF8zu0AQeMYpVtpd/3rM0AMu+N1JJw82j5x6TBlII2M7uJA== X-Received: by 2002:a17:906:57d0:b0:94a:62e7:70e1 with SMTP id u16-20020a17090657d000b0094a62e770e1mr2718777ejr.68.1681392879298; Thu, 13 Apr 2023 06:34:39 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id et22-20020a170907295600b0094a966330fdsm976806ejc.211.2023.04.13.06.34.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Apr 2023 06:34:38 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, daniel@iogearbox.net, Alexander Mikhalitsyn , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Leon Romanovsky , David Ahern , Arnd Bergmann , Kees Cook , Christian Brauner , Kuniyuki Iwashima , Lennart Poettering , Luca Boccassi , linux-arch@vger.kernel.org Subject: [PATCH net-next v4 3/4] net: core: add getsockopt SO_PEERPIDFD Date: Thu, 13 Apr 2023 15:33:54 +0200 Message-Id: <20230413133355.350571-4-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> References: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add SO_PEERPIDFD which allows to get pidfd of peer socket holder pidfd. This thing is direct analog of SO_PEERCRED which allows to get plain PID. Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: Lennart Poettering Cc: Luca Boccassi Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Tested-by: Luca Boccassi Signed-off-by: Alexander Mikhalitsyn Reviewed-by: Christian Brauner --- v4: - return -ESRCH if sk->sk_peer_pid is NULL from getsockopt() syscall - return errors from pidfd_prepare() as it is from getsockopt() syscall v3: - fixed possible fd leak (thanks to Christian Brauner) v2: According to review comments from Kuniyuki Iwashima and Christian Brauner: - use pidfd_create(..) retval as a result - whitespace change --- arch/alpha/include/uapi/asm/socket.h | 1 + arch/mips/include/uapi/asm/socket.h | 1 + arch/parisc/include/uapi/asm/socket.h | 1 + arch/sparc/include/uapi/asm/socket.h | 1 + include/uapi/asm-generic/socket.h | 1 + net/core/sock.c | 33 +++++++++++++++++++++++++ net/socket.c | 7 ++++++ tools/include/uapi/asm-generic/socket.h | 1 + 8 files changed, 46 insertions(+) diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi= /asm/socket.h index ff310613ae64..e94f621903fe 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -138,6 +138,7 @@ #define SO_RCVMARK 75 =20 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 =20 #if !defined(__KERNEL__) =20 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/a= sm/socket.h index 762dcb80e4ec..60ebaed28a4c 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -149,6 +149,7 @@ #define SO_RCVMARK 75 =20 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 =20 #if !defined(__KERNEL__) =20 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/ua= pi/asm/socket.h index df16a3e16d64..be264c2b1a11 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -130,6 +130,7 @@ #define SO_RCVMARK 0x4049 =20 #define SO_PASSPIDFD 0x404A +#define SO_PEERPIDFD 0x404B =20 #if !defined(__KERNEL__) =20 diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi= /asm/socket.h index 6e2847804fea..682da3714686 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -131,6 +131,7 @@ #define SO_RCVMARK 0x0054 =20 #define SO_PASSPIDFD 0x0055 +#define SO_PEERPIDFD 0x0056 =20 #if !defined(__KERNEL__) =20 diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/s= ocket.h index b76169fdb80b..8ce8a39a1e5f 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -133,6 +133,7 @@ #define SO_RCVMARK 75 =20 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 =20 #if !defined(__KERNEL__) =20 diff --git a/net/core/sock.c b/net/core/sock.c index 3f974246ba3e..49531c0dc57f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1763,6 +1763,39 @@ int sk_getsockopt(struct sock *sk, int level, int op= tname, goto lenout; } =20 + case SO_PEERPIDFD: + { + struct pid *peer_pid; + struct file *pidfd_file =3D NULL; + int pidfd; + + if (len > sizeof(pidfd)) + len =3D sizeof(pidfd); + + spin_lock(&sk->sk_peer_lock); + peer_pid =3D get_pid(sk->sk_peer_pid); + spin_unlock(&sk->sk_peer_lock); + + if (!peer_pid) + return -ESRCH; + + pidfd =3D pidfd_prepare(peer_pid, 0, &pidfd_file); + put_pid(peer_pid); + if (pidfd < 0) + return pidfd; + + if (copy_to_sockptr(optval, &pidfd, len) || + copy_to_sockptr(optlen, &len, sizeof(int))) { + put_unused_fd(pidfd); + fput(pidfd_file); + + return -EFAULT; + } + + fd_install(pidfd, pidfd_file); + return 0; + } + case SO_PEERGROUPS: { const struct cred *cred; diff --git a/net/socket.c b/net/socket.c index 9c1ef11de23f..505b85489354 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2248,6 +2248,13 @@ static bool sockopt_installs_fd(int level, int optna= me) default: return false; } + } else if (level =3D=3D SOL_SOCKET) { + switch (optname) { + case SO_PEERPIDFD: + return true; + default: + return false; + } } =20 return false; diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/a= sm-generic/socket.h index fbbc4bf53ee3..54d9c8bf7c55 100644 --- a/tools/include/uapi/asm-generic/socket.h +++ b/tools/include/uapi/asm-generic/socket.h @@ -122,6 +122,7 @@ #define SO_RCVMARK 75 =20 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 =20 #if !defined(__KERNEL__) =20 --=20 2.34.1 From nobody Fri Dec 19 03:48:24 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8D662C77B6F for ; Thu, 13 Apr 2023 13:38:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231655AbjDMNiM (ORCPT ); Thu, 13 Apr 2023 09:38:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231555AbjDMNh3 (ORCPT ); Thu, 13 Apr 2023 09:37:29 -0400 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1BFB3CC3B for ; Thu, 13 Apr 2023 06:35:15 -0700 (PDT) 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 261953F550 for ; Thu, 13 Apr 2023 13:34:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681392885; bh=9OFnG70DkKWiYI7WkrGxo4LXdZLPfs21Ye1s1GRVjTU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=QBV+oG6leDNv74fYZb4pNK9FeAhu43ARYt+VaUiHTD8Rdl7tKxrfZPsIpFnRfnBiB MRr/IlxBxydeQmrvfC7OmXQYQbqhcMoOWKjtoQ6pcvQS5n8ciN87T/49Oubf8uvQUe DaLmT7wAz4ADMFJ+Of0yymHqP7kNQi2Bjg3oB7fRiUWJncH4Fw6CjrnDgJWkZcN+ei 9p96IXYLlhoSIy+BYrBVdS/ZANxZEqy9KJxMlj4mVJ5EYQEkVxNQ6f0BJcCpiaOflK unfhkASPDGx0AAvYftQ5oH5XcnXgDHoPrK59BTB0ToabJ3t3m3wUHSt1iIUUV0BJgj lW4INvtg438oQ== Received: by mail-ed1-f71.google.com with SMTP id m17-20020a509991000000b0050463defdabso10943603edb.6 for ; Thu, 13 Apr 2023 06:34:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681392883; x=1683984883; 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=9OFnG70DkKWiYI7WkrGxo4LXdZLPfs21Ye1s1GRVjTU=; b=kXVFqwKpAbv9y3mI3oGwgjuV/id9JJ0j6gmY7y2jxQH+0u2g9VjX3FidhUBZRA+s5Q QusrsJl4234gbloyH04bPPXsS4uPw3ZNFZcOzmav6p3EEMECSvC6dsipG20hM2txlieM a8J/nziAY6lt10md83K9kpMFuXzZEaGXjReTuEIhKT+h608SMKoislpGHk1VacLqG3Qv WBukVQONmQVIQQ9QiFf+tUP21FRv9uJBVPbb0vXsrSX0JN6PIHeaxyT9PWObRMLuJQgZ 5XVGe3NY5OIG2QG0Po6sfmLOspaNaK+AefDSUjpzHUX2Eqh1fpFUj0FNH0OIzWwAVRPb EArw== X-Gm-Message-State: AAQBX9cIbRCnpFBB3wc+83EaLWCPAAEBYDvorc16qgMslA/N2Gnka2Kk 5LGTUUYvJswB6CcuMMaqDTQTqN7KZO7G0d7nYEY83Zpk3RDezxw46Vhcztf+U2TzNZcLFvnzze5 QAzZfkJc4M1GybfkndX2RlfVsJaP0xJajCdJyOfr2Pw== X-Received: by 2002:a17:906:ae8a:b0:882:cdd4:14d9 with SMTP id md10-20020a170906ae8a00b00882cdd414d9mr2639508ejb.46.1681392883229; Thu, 13 Apr 2023 06:34:43 -0700 (PDT) X-Google-Smtp-Source: AKy350Y8Ak1AMedhDxrX0Hch7Jn9DeuDHTYqN/ZQLJbSNTNoYaDS8nhCmAWBIfXbaLlh1gAdP/aUGA== X-Received: by 2002:a17:906:ae8a:b0:882:cdd4:14d9 with SMTP id md10-20020a170906ae8a00b00882cdd414d9mr2639484ejb.46.1681392883023; Thu, 13 Apr 2023 06:34:43 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id et22-20020a170907295600b0094a966330fdsm976806ejc.211.2023.04.13.06.34.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Apr 2023 06:34:42 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, daniel@iogearbox.net, Alexander Mikhalitsyn , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Leon Romanovsky , David Ahern , Arnd Bergmann , Kees Cook , Christian Brauner , Kuniyuki Iwashima , linux-arch@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH net-next v4 4/4] selftests: net: add SCM_PIDFD / SO_PEERPIDFD test Date: Thu, 13 Apr 2023 15:33:55 +0200 Message-Id: <20230413133355.350571-5-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> References: <20230413133355.350571-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Basic test to check consistency between: - SCM_CREDENTIALS and SCM_PIDFD - SO_PEERCRED and SO_PEERPIDFD Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-kselftest@vger.kernel.org Signed-off-by: Alexander Mikhalitsyn Tested-by: Luca Boccassi --- v3: - started using kselftest lib (thanks to Kuniyuki Iwashima for suggestion/= review) - now test covers abstract sockets too and SOCK_DGRAM sockets --- tools/testing/selftests/net/.gitignore | 1 + tools/testing/selftests/net/af_unix/Makefile | 2 +- .../testing/selftests/net/af_unix/scm_pidfd.c | 430 ++++++++++++++++++ 3 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/net/af_unix/scm_pidfd.c diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftes= ts/net/.gitignore index 80f06aa62034..83fd1ebd34ec 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -26,6 +26,7 @@ reuseport_bpf_cpu reuseport_bpf_numa reuseport_dualstack rxtimestamp +scm_pidfd sk_bind_sendto_listen sk_connect_zero_addr socket diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/s= elftests/net/af_unix/Makefile index 1e4b397cece6..f5ca9da8c4d5 100644 --- a/tools/testing/selftests/net/af_unix/Makefile +++ b/tools/testing/selftests/net/af_unix/Makefile @@ -1,3 +1,3 @@ -TEST_GEN_PROGS :=3D diag_uid test_unix_oob unix_connect +TEST_GEN_PROGS :=3D diag_uid test_unix_oob unix_connect scm_pidfd =20 include ../../lib.mk diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testin= g/selftests/net/af_unix/scm_pidfd.c new file mode 100644 index 000000000000..a86222143d79 --- /dev/null +++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest_harness.h" + +#define clean_errno() (errno =3D=3D 0 ? "None" : strerror(errno)) +#define log_err(MSG, ...) = \ + fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", __FILE__, __LINE__, \ + clean_errno(), ##__VA_ARGS__) + +#ifndef SCM_PIDFD +#define SCM_PIDFD 0x04 +#endif + +static void child_die() +{ + exit(1); +} + +static int safe_int(const char *numstr, int *converted) +{ + char *err =3D NULL; + long sli; + + errno =3D 0; + sli =3D strtol(numstr, &err, 0); + if (errno =3D=3D ERANGE && (sli =3D=3D LONG_MAX || sli =3D=3D LONG_MIN)) + return -ERANGE; + + if (errno !=3D 0 && sli =3D=3D 0) + return -EINVAL; + + if (err =3D=3D numstr || *err !=3D '\0') + return -EINVAL; + + if (sli > INT_MAX || sli < INT_MIN) + return -ERANGE; + + *converted =3D (int)sli; + return 0; +} + +static int char_left_gc(const char *buffer, size_t len) +{ + size_t i; + + for (i =3D 0; i < len; i++) { + if (buffer[i] =3D=3D ' ' || buffer[i] =3D=3D '\t') + continue; + + return i; + } + + return 0; +} + +static int char_right_gc(const char *buffer, size_t len) +{ + int i; + + for (i =3D len - 1; i >=3D 0; i--) { + if (buffer[i] =3D=3D ' ' || buffer[i] =3D=3D '\t' || + buffer[i] =3D=3D '\n' || buffer[i] =3D=3D '\0') + continue; + + return i + 1; + } + + return 0; +} + +static char *trim_whitespace_in_place(char *buffer) +{ + buffer +=3D char_left_gc(buffer, strlen(buffer)); + buffer[char_right_gc(buffer, strlen(buffer))] =3D '\0'; + return buffer; +} + +/* borrowed (with all helpers) from pidfd/pidfd_open_test.c */ +static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t k= eylen) +{ + int ret; + char path[512]; + FILE *f; + size_t n =3D 0; + pid_t result =3D -1; + char *line =3D NULL; + + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); + + f =3D fopen(path, "re"); + if (!f) + return -1; + + while (getline(&line, &n, f) !=3D -1) { + char *numstr; + + if (strncmp(line, key, keylen)) + continue; + + numstr =3D trim_whitespace_in_place(line + 4); + ret =3D safe_int(numstr, &result); + if (ret < 0) + goto out; + + break; + } + +out: + free(line); + fclose(f); + return result; +} + +static int cmsg_check(int fd) +{ + struct msghdr msg =3D { 0 }; + struct cmsghdr *cmsg; + 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; + + 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; + } + + 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(*pidfd)) { + log_err("CMSG parse: SCM_PIDFD wrong len"); + return 1; + } + + 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(*ucred)) { + log_err("CMSG parse: SCM_CREDENTIALS wrong len"); + return 1; + } + + ucred =3D (void *)CMSG_DATA(cmsg); + } + } + + /* send(pfd, "x", sizeof(char), 0) */ + if (data !=3D 'x') { + log_err("recvmsg: data corruption"); + return 1; + } + + if (!pidfd) { + log_err("CMSG parse: SCM_PIDFD not found"); + return 1; + } + + if (!ucred) { + log_err("CMSG parse: SCM_CREDENTIALS not found"); + return 1; + } + + /* 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()); + return 1; + } + + return 0; +} + +struct sock_addr { + char sock_name[32]; + struct sockaddr_un listen_addr; + socklen_t addrlen; +}; + +FIXTURE(scm_pidfd) +{ + int server; + pid_t client_pid; + int startup_pipe[2]; + struct sock_addr server_addr; + struct sock_addr *client_addr; +}; + +FIXTURE_VARIANT(scm_pidfd) +{ + int type; + bool abstract; +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, stream_pathname) +{ + .type =3D SOCK_STREAM, + .abstract =3D 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, stream_abstract) +{ + .type =3D SOCK_STREAM, + .abstract =3D 1, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_pathname) +{ + .type =3D SOCK_DGRAM, + .abstract =3D 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_abstract) +{ + .type =3D SOCK_DGRAM, + .abstract =3D 1, +}; + +FIXTURE_SETUP(scm_pidfd) +{ + self->client_addr =3D mmap(NULL, sizeof(*self->client_addr), PROT_READ | = PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, self->client_addr); +} + +FIXTURE_TEARDOWN(scm_pidfd) +{ + close(self->server); + + kill(self->client_pid, SIGKILL); + waitpid(self->client_pid, NULL, 0); + + if (!variant->abstract) { + unlink(self->server_addr.sock_name); + unlink(self->client_addr->sock_name); + } +} + +static void fill_sockaddr(struct sock_addr *addr, bool abstract) +{ + char *sun_path_buf =3D (char *)&addr->listen_addr.sun_path; + + addr->listen_addr.sun_family =3D AF_UNIX; + addr->addrlen =3D offsetof(struct sockaddr_un, sun_path); + snprintf(addr->sock_name, sizeof(addr->sock_name), "scm_pidfd_%d", getpid= ()); + addr->addrlen +=3D strlen(addr->sock_name); + if (abstract) { + *sun_path_buf =3D '\0'; + addr->addrlen++; + sun_path_buf++; + } else { + unlink(addr->sock_name); + } + memcpy(sun_path_buf, addr->sock_name, strlen(addr->sock_name)); +} + +static void client(FIXTURE_DATA(scm_pidfd) *self, + const FIXTURE_VARIANT(scm_pidfd) *variant) +{ + int err; + int cfd; + socklen_t len; + struct ucred peer_cred; + int peer_pidfd; + pid_t peer_pid; + int on =3D 0; + + cfd =3D socket(AF_UNIX, variant->type, 0); + if (cfd < 0) { + log_err("socket"); + child_die(); + } + + if (variant->type =3D=3D 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(); + } + } + + if (connect(cfd, (struct sockaddr *)&self->server_addr.listen_addr, + self->server_addr.addrlen) !=3D 0) { + log_err("connect"); + child_die(); + } + + 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"); + child_die(); + } + + close(self->startup_pipe[1]); + + if (cmsg_check(cfd)) { + log_err("cmsg_check failed"); + child_die(); + } + + /* skip further for SOCK_DGRAM as it's not applicable */ + if (variant->type =3D=3D SOCK_DGRAM) + return; + + len =3D sizeof(peer_cred); + if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) { + log_err("Failed to get SO_PEERCRED"); + child_die(); + } + + len =3D sizeof(peer_pidfd); + if (getsockopt(cfd, SOL_SOCKET, SO_PEERPIDFD, &peer_pidfd, &len)) { + log_err("Failed to get SO_PEERPIDFD"); + child_die(); + } + + /* pid from SO_PEERCRED should point to the parent process PID */ + if (peer_cred.pid !=3D getppid()) { + log_err("peer_cred.pid !=3D getppid(): %d !=3D %d", peer_cred.pid, getpp= id()); + child_die(); + } + + peer_pid =3D get_pid_from_fdinfo_file(peer_pidfd, + "Pid:", sizeof("Pid:") - 1); + if (peer_pid !=3D peer_cred.pid) { + log_err("peer_pid !=3D peer_cred.pid: %d !=3D %d", peer_pid, peer_cred.p= id); + child_die(); + } +} + +TEST_F(scm_pidfd, test) +{ + int err; + int pfd; + int child_status =3D 0; + + self->server =3D socket(AF_UNIX, variant->type, 0); + ASSERT_NE(-1, self->server); + + fill_sockaddr(&self->server_addr, variant->abstract); + + err =3D bind(self->server, (struct sockaddr *)&self->server_addr.listen_a= ddr, self->server_addr.addrlen); + ASSERT_EQ(0, err); + + if (variant->type =3D=3D SOCK_STREAM) { + err =3D listen(self->server, 1); + ASSERT_EQ(0, err); + } + + err =3D pipe(self->startup_pipe); + ASSERT_NE(-1, err); + + self->client_pid =3D fork(); + ASSERT_NE(-1, self->client_pid); + if (self->client_pid =3D=3D 0) { + close(self->server); + close(self->startup_pipe[0]); + client(self, variant); + exit(0); + } + close(self->startup_pipe[1]); + + if (variant->type =3D=3D SOCK_STREAM) { + pfd =3D accept(self->server, NULL, NULL); + ASSERT_NE(-1, pfd); + } else { + pfd =3D self->server; + } + + /* wait until the child arrives at checkpoint */ + read(self->startup_pipe[0], &err, sizeof(int)); + close(self->startup_pipe[0]); + + if (variant->type =3D=3D SOCK_DGRAM) { + err =3D sendto(pfd, "x", sizeof(char), 0, (struct sockaddr *)&self->clie= nt_addr->listen_addr, self->client_addr->addrlen); + ASSERT_NE(-1, err); + } else { + err =3D send(pfd, "x", sizeof(char), 0); + ASSERT_NE(-1, err); + } + + close(pfd); + waitpid(self->client_pid, &child_status, 0); + ASSERT_EQ(0, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1); +} + +TEST_HARNESS_MAIN --=20 2.34.1