From patchwork Tue Apr 11 10:42:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Mikhalitsyn X-Patchwork-Id: 13207335 X-Patchwork-Delegate: kuba@kernel.org 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 6A8ADC76196 for ; Tue, 11 Apr 2023 10:43:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229845AbjDKKnk (ORCPT ); Tue, 11 Apr 2023 06:43:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229838AbjDKKnb (ORCPT ); Tue, 11 Apr 2023 06:43:31 -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 22CF5358E for ; Tue, 11 Apr 2023 03:43:24 -0700 (PDT) Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.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 E633C3F23C for ; Tue, 11 Apr 2023 10:43:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681209801; bh=a+6gxbvn4hYwO5enGV6t44vz4Ixp1BNaXg7ewl6XAKs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=G0YVvrClP/ECbYR2p9g+vxmzL4iBKxAF8VI8S1ZU1LDeoR6ABjadB5UzaIRPMinOn W/2Nr+tMH/NZxrnsviGBFNy6+CgbCJvEPxnewydM+jUce9s+d917/OSb/1ORm3NfMW uTKbHQF1rZzFXA2eXroMdTTFKOJu1ygAteuSYfkTE8iAjlmymHzRY/EzbslXLjrys0 cDaQBAuW5/CP0zy/XMEokr+IZcgUa5cfdFpWjo37kCKz4/jAB+GWjJ8AS1BhWp4/M4 ByC505Z/+OgRHexYchAZugpgv9YCkeUtdp02Bt6D3CyuCJHTF+bNtrvspLIf4VsFEC 2+YFs9CrJPVow== Received: by mail-ej1-f72.google.com with SMTP id sz19-20020a1709078b1300b009497c250e96so3343596ejc.15 for ; Tue, 11 Apr 2023 03:43:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1681209800; 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=a+6gxbvn4hYwO5enGV6t44vz4Ixp1BNaXg7ewl6XAKs=; b=DnNrbUoJZ9XUNgSr+8HXbyr78kKnKngd83+LvaBp2L/OvRMLWUF3ZnsVF306CAHFnP k0nd3HrqqX9o5BFA4kZWkgF2HTF87NbWMtQ2pxCLF4jwV0RlhE7VYOVqT3fi+Xays9op 5yY4XRwQTi0GteaWPjm93d3ayxTMfzExN5gfMUonpEFg7TYTLWy0T1AFfWRsydHBRHoR RH08/AgGdgvMERrZlAivM41IGLZ8MqSd5q+X5utCwKubFBtffOCsl4ibdc+rvVI6Ezcu yOvdvldRvlcQ+wJeheLLDbWGCwxfPXUad+3FXwzUdAuv2EevJUBL97AiCMKrUJVHcFlC WsbQ== X-Gm-Message-State: AAQBX9dhY6/B/C31WJxQ2qP0P5H2LRifHGrnZUmdXw909ngFfFB35pGc T4Xaqgn7tYdCxq893P1AiLRovazIVVgTbQ2k+exLV9ZTUrsmALeoG9ibyOh+El6A6rmH69DXPK9 6CWxETWtd5983E+lmQotg3h3ickf+xrA06w== X-Received: by 2002:a17:906:a859:b0:94c:784f:7569 with SMTP id dx25-20020a170906a85900b0094c784f7569mr4265433ejb.30.1681209800371; Tue, 11 Apr 2023 03:43:20 -0700 (PDT) X-Google-Smtp-Source: AKy350ZqUXeqS9O98LMdWi8cTD/jnZQD62JAh31WY6ycJqD3j95xAzxzQ0fKW3ItweqMjoUkTG9epQ== X-Received: by 2002:a17:906:a859:b0:94c:784f:7569 with SMTP id dx25-20020a170906a85900b0094c784f7569mr4265406ejb.30.1681209799970; Tue, 11 Apr 2023 03:43:19 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id ne7-20020a1709077b8700b00948c320fcfdsm5921805ejc.202.2023.04.11.03.43.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Apr 2023 03:43:19 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, 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 v3 1/4] scm: add SO_PASSPIDFD and SCM_PIDFD Date: Tue, 11 Apr 2023 12:42:28 +0200 Message-Id: <20230411104231.160837-2-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> References: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 --- 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 | 14 ++++++++++++-- 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, 51 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 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/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 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/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 @@ #define SO_RCVMARK 0x4049 +#define SO_PASSPIDFD 0x404A + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 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 @@ #define SO_RCVMARK 0x0054 +#define SO_PASSPIDFD 0x0055 + #if !defined(__KERNEL__) 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 #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) */ struct ucred { __u32 pid; diff --git a/include/net/scm.h b/include/net/scm.h index 585adc1346bd..0c717ae9c8db 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -124,8 +124,9 @@ 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 |= MSG_CTRUNC; scm_destroy(scm); return; @@ -141,6 +142,15 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); } + if (test_bit(SOCK_PASSPIDFD, &sock->flags)) { + int pidfd; + + WARN_ON_ONCE(!scm->pid); + pidfd = pidfd_create(scm->pid, 0); + + put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd); + } + scm_destroy_cred(scm); scm_passec(sock, msg, scm); diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h index 638230899e98..b76169fdb80b 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -132,6 +132,8 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 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 optname, clear_bit(SOCK_PASSCRED, &sock->flags); break; + 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 optname, v.val = !!test_bit(SOCK_PASSCRED, &sock->flags); break; + case SO_PASSPIDFD: + v.val = !!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_sock *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, struct sockaddr *addr, if (err) goto out; - 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 = unix_autobind(sk); if (err) @@ -1469,7 +1470,8 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, if (err) goto out; - 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 = unix_autobind(sk); if (err) goto out; @@ -1670,6 +1672,8 @@ static void unix_sock_inherit_flags(const struct socket *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 socket *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); } /* @@ -1922,7 +1928,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, goto out; } - 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 = unix_autobind(sk); if (err) goto out; @@ -2824,7 +2831,8 @@ static int unix_stream_read_generic(struct unix_stream_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/asm-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 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) From patchwork Tue Apr 11 10:42:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Mikhalitsyn X-Patchwork-Id: 13207336 X-Patchwork-Delegate: kuba@kernel.org 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 57C0EC76196 for ; Tue, 11 Apr 2023 10:43:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229876AbjDKKnx (ORCPT ); Tue, 11 Apr 2023 06:43:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229844AbjDKKnq (ORCPT ); Tue, 11 Apr 2023 06:43:46 -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 430403C35 for ; Tue, 11 Apr 2023 03:43:33 -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-0.canonical.com (Postfix) with ESMTPS id DFEB13F238 for ; Tue, 11 Apr 2023 10:43:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681209810; bh=pU+XkxxaqxIltFz6HAiJgXotXtTecmR/abIbMqTWsWw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Z06CA+JcDdJSFA9PnH61/Q3e0p+z11skMn3k+JedjsCMAnWO3NCgcJES26N4PNFfs 3S5I/ZLknwsf3zB991NJIy0DPB9P7ps9Qyfr/N5hpVr4WAdf+aRhvQFcus2d2rChn/ lk446tSYDUX6ooVqg9Nf0fW6Ec8X42j0wTauiriComSpNn4RRjoNZw0D5ISr2oED/9 fUQgYjYw+YE77RvMSw+SpBnfZ4224/8gyPDLdYI0sgusM3RQlhYPH2okArpyL1pLvu P4GRnceeOPPH7X/JtXEZIN13S7xdLyFEsu1RDb8WowET8yEARhQLp+BTQ0tB4D0r7m fdrp7mYQiI2zg== Received: by mail-ed1-f71.google.com with SMTP id c30-20020a50f61e000000b005047e0a0a24so5530184edn.8 for ; Tue, 11 Apr 2023 03:43:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1681209810; 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=czEubwW7Yion3L4jxxfLP5VdUSwTCE9EwMZ2TZqsied+05uwOpBp5c0wYwbxJXnh6p c136MwLhKwvMBsWy5Q1RwyGpirQTJ0bttLdNwII+CQlMmGonUuuCT57Rd2gmt4hwEGjk KvrJ2gfrvw43wCnk5konu57Fd/d/kxu/E23Bz9LgJDa0BYsFYeI3kShmSqsnD5aW1CQw h0mVWHcGDaMWRJUPdhRmmASSUjTYo6Akier7PvXaowm1Xxe++DIGrxKeoarfHzW8ayo0 MAXQz/x2443rTmcCUJ/fMWSv1gUMuVLa9UTeYRCtBQiVgEawkEqQLOOLPk5ZhhO+v4mV pSLA== X-Gm-Message-State: AAQBX9eqtZofbYwLNJJ0McqHInPczzxrWkdHRUU/bPmXnOaSybqZOSFT qm2NK4M1M6EIC3pZv/vH23fd3Qf6VDgcXSa1QU824zSDbF8hTcP7MtQJJHdHbaBHFYtY3ohUp9p /aXWmUDRbs9iQM7jOERoZ8x2o2zFifRACEA== X-Received: by 2002:a17:907:6a12:b0:94a:474a:4dd7 with SMTP id rf18-20020a1709076a1200b0094a474a4dd7mr7376325ejc.60.1681209810562; Tue, 11 Apr 2023 03:43:30 -0700 (PDT) X-Google-Smtp-Source: AKy350ZNewLrXNZ6daAOHQgJi0nkKHwQAVXgrGhHW2GSMumryIkh965UAbKXhAPWjtH8AEfHFA4Kaw== X-Received: by 2002:a17:907:6a12:b0:94a:474a:4dd7 with SMTP id rf18-20020a1709076a1200b0094a474a4dd7mr7376308ejc.60.1681209810274; Tue, 11 Apr 2023 03:43:30 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id ne7-20020a1709077b8700b00948c320fcfdsm5921805ejc.202.2023.04.11.03.43.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Apr 2023 03:43:29 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, 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, Daniel Borkmann Subject: [PATCH net-next v3 2/4] net: socket: add sockopts blacklist for BPF cgroup hook Date: Tue, 11 Apr 2023 12:42:29 +0200 Message-Id: <20230411104231.160837-3-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> References: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 Acked-by: Christian Brauner --- 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 +#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); } +#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 == 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; - if (!in_compat_syscall()) + if (!in_compat_syscall() && !sockopt_installs_fd(level, optname)) err = 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; - if (!in_compat_syscall()) + if (!in_compat_syscall() && !sockopt_installs_fd(level, optname)) max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen); if (level == SOL_SOCKET) @@ -2315,7 +2347,7 @@ int __sys_getsockopt(int fd, int level, int optname, char __user *optval, err = sock->ops->getsockopt(sock, level, optname, optval, optlen); - if (!in_compat_syscall()) + if (!in_compat_syscall() && !sockopt_installs_fd(level, optname)) err = BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock->sk, level, optname, optval, optlen, max_optlen, err); From patchwork Tue Apr 11 10:42:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Mikhalitsyn X-Patchwork-Id: 13207337 X-Patchwork-Delegate: kuba@kernel.org 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 367AFC7619A for ; Tue, 11 Apr 2023 10:44:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229878AbjDKKoI (ORCPT ); Tue, 11 Apr 2023 06:44:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35524 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229898AbjDKKn4 (ORCPT ); Tue, 11 Apr 2023 06:43:56 -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 893174499 for ; Tue, 11 Apr 2023 03:43:43 -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-0.canonical.com (Postfix) with ESMTPS id 58C3B3F23E for ; Tue, 11 Apr 2023 10:43:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681209822; bh=pRf5xzGSUbwksyzKh9EFSxutG5TUV/lwNKq2bZMboXc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=XAUkEp8M/o0ghMlZfDQhVPwg6IPf9rLy1xesFMuzeje25FcXwewNnRh6oCJf1CIHw ladLv8bhDYiiH6a71G3u9Curlk66rzN6roWtMr/0Qy3pY3A8thmtH+bm7gVz6MT9ZX KXqX6Rfb4enZYzqFW+NdESEMNcGgU0rJ8RGNvVIopls65NP+HgZP2EKC07jKZNUNWL pSS+BsA4k5+tPt4UvI3H184Z1xgFMempjOZbgpxQwsvGomtwQ0VaZlJHLoCJJ4AGh8 XgVNEG8gEK9kHIF5oT3qwJNCm7Yon+wIDOI5biRgi4vW4yAiEdf+QdbWGyhoiZavEq WxvgYwbuumW2Q== Received: by mail-ed1-f71.google.com with SMTP id n6-20020a5099c6000000b00502c2f26133so14147678edb.12 for ; Tue, 11 Apr 2023 03:43:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1681209820; 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=pRf5xzGSUbwksyzKh9EFSxutG5TUV/lwNKq2bZMboXc=; b=UM1tBEKILE39CsbyQSxf2T7VYno8h8z0prwnbRkOyzD6ruQiLRcV5QQ4KTWIQqpliO IBionoj5Ik5nzVBDEfZDfUX/AFhGa5d7oMxJ/vTZ4dzRsDs9dOkVC3v/Dffpj+pUrOmn uHhqBQ6Jp11UBEQQYV03mttfwOWmJg1Th/0So/b6vhuP//3bhflY7635XZvlt10fOXkN hu/PpxRdRO3g3J8pBXzLGzIEGmKiw7O5cZZQzjFQTSRnaj+hvqGvgdcg0fxLAN/GVF26 0xmRcOJawgF7tqhkqQ+fMyehoACfcgs71vlJu0n7pU48vVWMeOR2nFRCATrVdMHdtf9Z JFsg== X-Gm-Message-State: AAQBX9eQS2gRi1m4AsQvX5tA/3sbojWUxHiqQcJE4Wb5AsmroQWehoXm 2xtEHkkjlObuFwfj/jyQ3VjN6RWANhbAc/EF7iccz/KSfbQd1bW8lDiHvrTlnC1hA4yXWw231JT HhC1De+n8CjeTae8cnmXv9jCXdCah6v81Hg== X-Received: by 2002:a17:907:2ced:b0:8ee:babc:d40b with SMTP id hz13-20020a1709072ced00b008eebabcd40bmr9069388ejc.58.1681209820504; Tue, 11 Apr 2023 03:43:40 -0700 (PDT) X-Google-Smtp-Source: AKy350Y3a3e+i3YZE1zWCwJczevi7Xil2MO7ybttWW7IbAD0C/PVvpcEOpKeHeLj+dOjXcXoDH7LPQ== X-Received: by 2002:a17:907:2ced:b0:8ee:babc:d40b with SMTP id hz13-20020a1709072ced00b008eebabcd40bmr9069360ejc.58.1681209820244; Tue, 11 Apr 2023 03:43:40 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id ne7-20020a1709077b8700b00948c320fcfdsm5921805ejc.202.2023.04.11.03.43.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Apr 2023 03:43:39 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, 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 v3 3/4] net: core: add getsockopt SO_PEERPIDFD Date: Tue, 11 Apr 2023 12:42:30 +0200 Message-Id: <20230411104231.160837-4-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> References: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 --- 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 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/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 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/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 #define SO_PASSPIDFD 0x404A +#define SO_PEERPIDFD 0x404B #if !defined(__KERNEL__) 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 #define SO_PASSPIDFD 0x0055 +#define SO_PEERPIDFD 0x0056 #if !defined(__KERNEL__) diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.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 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) diff --git a/net/core/sock.c b/net/core/sock.c index 3f974246ba3e..2b040a69e355 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1763,6 +1763,39 @@ int sk_getsockopt(struct sock *sk, int level, int optname, goto lenout; } + case SO_PEERPIDFD: + { + struct pid *peer_pid; + struct file *pidfd_file = NULL; + int pidfd; + + if (len > sizeof(pidfd)) + len = sizeof(pidfd); + + spin_lock(&sk->sk_peer_lock); + peer_pid = get_pid(sk->sk_peer_pid); + spin_unlock(&sk->sk_peer_lock); + + pidfd = pidfd_prepare(peer_pid, 0, &pidfd_file); + + put_pid(peer_pid); + + if (copy_to_sockptr(optval, &pidfd, len) || + copy_to_sockptr(optlen, &len, sizeof(int))) { + if (pidfd >= 0) { + put_unused_fd(pidfd); + fput(pidfd_file); + } + + return -EFAULT; + } + + if (pidfd_file) + 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 optname) default: return false; } + } else if (level == SOL_SOCKET) { + switch (optname) { + case SO_PEERPIDFD: + return true; + default: + return false; + } } return false; diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-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 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) From patchwork Tue Apr 11 10:42:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Mikhalitsyn X-Patchwork-Id: 13207339 X-Patchwork-Delegate: kuba@kernel.org 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 9DEFAC7619A for ; Tue, 11 Apr 2023 10:44:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229978AbjDKKof (ORCPT ); Tue, 11 Apr 2023 06:44:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36042 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229881AbjDKKoQ (ORCPT ); Tue, 11 Apr 2023 06:44:16 -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 C76A64495 for ; Tue, 11 Apr 2023 03:43:55 -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 3B0593F23C for ; Tue, 11 Apr 2023 10:43:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1681209833; bh=9OFnG70DkKWiYI7WkrGxo4LXdZLPfs21Ye1s1GRVjTU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=X9qHTVN9SM+FFmB3lLEm4r1y6fcfgHzs8IoQ6HqT4Gmd4FG9Xoeeoj/Pubd4XNnDg AI4GIyQ4oKFA/YwV+AmQiM1WFrU45AT5Xz80uklcpkeoPXkjZljhS3M/+p1MSjAPin pkujjLtN2a5Vh0G+x5KklFu0C57nt3leXulA8pdDQd8CRQG488PtqfJEvDFG245MVh BSvUIBOvtdBzcOrbE6GDknsXmzfhZzaxg7DzfPsUTNumggJoECaCzHQbcnI5XYgo4G U4cZ10FaB6OrGveRocOxuW+xUQr38qilMuMD1hx7aZNwzTrWJsEjG9Iw8I0ZVLmmCu z7vVcRSEzu62A== Received: by mail-ed1-f72.google.com with SMTP id i19-20020a508713000000b004bc2358ac04so4641673edb.21 for ; Tue, 11 Apr 2023 03:43:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1681209828; 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=1wuHKPR0YhYx/KeNyjgyWm//zOuNOzeU8ElL8BI9oYMUnuNlhlv2THJuME2YAPwNAx iUs93NAaT5ryXop5xy+vwUxflXkOabNQ75O0OAChdwRp4yyT1UsSpUq5Y9X+M1WKbOzu C2hMXXqccowBorI1/hoXN87tMU5F+xbeQbSra9pZ0G8EBnK5VThCF2CxK9LrSgaDhllo zwOINVHFt0mtFlVp56F8e1bGDJoc2e5yvsgRGbD3w9d7g82Hra20aY5k9y2/R/IP9+bO Ss7Vg60Xfi7Bd4ygGcbWZho7CRFMnHu67Ok/n3CYpK6zdIjJOU6FAm/9aasaNInKDYPe u3gg== X-Gm-Message-State: AAQBX9ff8E0hrw6T6Yey8nlubjA9UyYEyb+ogDtaFrlFwHqhoHdru6Cp /s02FLOJ1kWXI91GiNubILvD/H+CAozSRZ9eIX2dZpJsuJgv6Q05aq0QYgoP+VaEIV3gkgpY+/n gSnwNXN/zG6wMR5yfpk7IeL1Fb5ZPDwbtKg== X-Received: by 2002:a17:906:2556:b0:94a:a887:c29f with SMTP id j22-20020a170906255600b0094aa887c29fmr1899822ejb.68.1681209828471; Tue, 11 Apr 2023 03:43:48 -0700 (PDT) X-Google-Smtp-Source: AKy350aPj4l4EguNKVwAy3tUb9yNWl1KWtjghlt/o5OZuyumoMgj4+/OOqc96wryk78ruct1L/77LQ== X-Received: by 2002:a17:906:2556:b0:94a:a887:c29f with SMTP id j22-20020a170906255600b0094aa887c29fmr1899802ejb.68.1681209828078; Tue, 11 Apr 2023 03:43:48 -0700 (PDT) Received: from amikhalitsyn.. ([95.91.208.118]) by smtp.gmail.com with ESMTPSA id ne7-20020a1709077b8700b00948c320fcfdsm5921805ejc.202.2023.04.11.03.43.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Apr 2023 03:43:47 -0700 (PDT) From: Alexander Mikhalitsyn To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, 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 v3 4/4] selftests: net: add SCM_PIDFD / SO_PEERPIDFD test Date: Tue, 11 Apr 2023 12:42:31 +0200 Message-Id: <20230411104231.160837-5-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> References: <20230411104231.160837-1-aleksandr.mikhalitsyn@canonical.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org 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 --- 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/selftests/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/selftests/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 := diag_uid test_unix_oob unix_connect +TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect scm_pidfd include ../../lib.mk diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/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 == 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 = NULL; + long sli; + + errno = 0; + sli = strtol(numstr, &err, 0); + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) + return -ERANGE; + + if (errno != 0 && sli == 0) + return -EINVAL; + + if (err == numstr || *err != '\0') + return -EINVAL; + + if (sli > INT_MAX || sli < INT_MIN) + return -ERANGE; + + *converted = (int)sli; + return 0; +} + +static int char_left_gc(const char *buffer, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (buffer[i] == ' ' || buffer[i] == '\t') + continue; + + return i; + } + + return 0; +} + +static int char_right_gc(const char *buffer, size_t len) +{ + int i; + + for (i = len - 1; i >= 0; i--) { + if (buffer[i] == ' ' || buffer[i] == '\t' || + buffer[i] == '\n' || buffer[i] == '\0') + continue; + + return i + 1; + } + + return 0; +} + +static char *trim_whitespace_in_place(char *buffer) +{ + buffer += char_left_gc(buffer, strlen(buffer)); + buffer[char_right_gc(buffer, strlen(buffer))] = '\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 keylen) +{ + int ret; + char path[512]; + FILE *f; + size_t n = 0; + pid_t result = -1; + char *line = NULL; + + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); + + f = fopen(path, "re"); + if (!f) + return -1; + + while (getline(&line, &n, f) != -1) { + char *numstr; + + if (strncmp(line, key, keylen)) + continue; + + numstr = trim_whitespace_in_place(line + 4); + ret = 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 = { 0 }; + struct cmsghdr *cmsg; + struct iovec iov; + struct ucred *ucred = NULL; + int data = 0; + char control[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int))] = { 0 }; + int *pidfd = NULL; + pid_t parent_pid; + int err; + + iov.iov_base = &data; + iov.iov_len = sizeof(data); + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + err = 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 = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_PIDFD) { + if (cmsg->cmsg_len < sizeof(*pidfd)) { + log_err("CMSG parse: SCM_PIDFD wrong len"); + return 1; + } + + pidfd = (void *)CMSG_DATA(cmsg); + } + + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS) { + if (cmsg->cmsg_len < sizeof(*ucred)) { + log_err("CMSG parse: SCM_CREDENTIALS wrong len"); + return 1; + } + + ucred = (void *)CMSG_DATA(cmsg); + } + } + + /* send(pfd, "x", sizeof(char), 0) */ + if (data != '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 = + get_pid_from_fdinfo_file(*pidfd, "Pid:", sizeof("Pid:") - 1); + if (parent_pid != getppid()) { + log_err("wrong SCM_PIDFD %d != %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 = SOCK_STREAM, + .abstract = 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, stream_abstract) +{ + .type = SOCK_STREAM, + .abstract = 1, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_pathname) +{ + .type = SOCK_DGRAM, + .abstract = 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_abstract) +{ + .type = SOCK_DGRAM, + .abstract = 1, +}; + +FIXTURE_SETUP(scm_pidfd) +{ + self->client_addr = 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 = (char *)&addr->listen_addr.sun_path; + + addr->listen_addr.sun_family = AF_UNIX; + addr->addrlen = offsetof(struct sockaddr_un, sun_path); + snprintf(addr->sock_name, sizeof(addr->sock_name), "scm_pidfd_%d", getpid()); + addr->addrlen += strlen(addr->sock_name); + if (abstract) { + *sun_path_buf = '\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 = 0; + + cfd = socket(AF_UNIX, variant->type, 0); + if (cfd < 0) { + log_err("socket"); + child_die(); + } + + if (variant->type == 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) != 0) { + log_err("connect"); + child_die(); + } + + on = 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 == SOCK_DGRAM) + return; + + len = sizeof(peer_cred); + if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) { + log_err("Failed to get SO_PEERCRED"); + child_die(); + } + + len = 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 != getppid()) { + log_err("peer_cred.pid != getppid(): %d != %d", peer_cred.pid, getppid()); + child_die(); + } + + peer_pid = get_pid_from_fdinfo_file(peer_pidfd, + "Pid:", sizeof("Pid:") - 1); + if (peer_pid != peer_cred.pid) { + log_err("peer_pid != peer_cred.pid: %d != %d", peer_pid, peer_cred.pid); + child_die(); + } +} + +TEST_F(scm_pidfd, test) +{ + int err; + int pfd; + int child_status = 0; + + self->server = socket(AF_UNIX, variant->type, 0); + ASSERT_NE(-1, self->server); + + fill_sockaddr(&self->server_addr, variant->abstract); + + err = bind(self->server, (struct sockaddr *)&self->server_addr.listen_addr, self->server_addr.addrlen); + ASSERT_EQ(0, err); + + if (variant->type == SOCK_STREAM) { + err = listen(self->server, 1); + ASSERT_EQ(0, err); + } + + err = pipe(self->startup_pipe); + ASSERT_NE(-1, err); + + self->client_pid = fork(); + ASSERT_NE(-1, self->client_pid); + if (self->client_pid == 0) { + close(self->server); + close(self->startup_pipe[0]); + client(self, variant); + exit(0); + } + close(self->startup_pipe[1]); + + if (variant->type == SOCK_STREAM) { + pfd = accept(self->server, NULL, NULL); + ASSERT_NE(-1, pfd); + } else { + pfd = 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 == SOCK_DGRAM) { + err = sendto(pfd, "x", sizeof(char), 0, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen); + ASSERT_NE(-1, err); + } else { + err = 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