sctp: add bpf_bypass_getsockopt proto callback
authorAlexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Thu, 11 May 2023 13:25:06 +0000 (15:25 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Jul 2023 14:21:04 +0000 (16:21 +0200)
[ Upstream commit 2598619e012cee5273a2821441b9a051ad931249 ]

Implement ->bpf_bypass_getsockopt proto callback and filter out
SCTP_SOCKOPT_PEELOFF, SCTP_SOCKOPT_PEELOFF_FLAGS and SCTP_SOCKOPT_CONNECTX3
socket options from running eBPF hook on them.

SCTP_SOCKOPT_PEELOFF and SCTP_SOCKOPT_PEELOFF_FLAGS 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 a fdtable.

As pointed by Marcelo Ricardo Leitner it seems reasonable to skip
bpf getsockopt hook for SCTP_SOCKOPT_CONNECTX3 sockopt too.
Because internaly, it triggers connect() and if error is masked
then userspace will be confused.

This patch was born as a result of discussion around a new SCM_PIDFD interface:
https://lore.kernel.org/all/20230413133355.350571-3-aleksandr.mikhalitsyn@canonical.com/

Fixes: 0d01da6afc54 ("bpf: implement getsockopt and setsockopt hooks")
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Stanislav Fomichev <sdf@google.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Cc: Xin Long <lucien.xin@gmail.com>
Cc: linux-sctp@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org
Suggested-by: Stanislav Fomichev <sdf@google.com>
Acked-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Acked-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/sctp/socket.c

index bc3d08b..e101131 100644 (file)
@@ -8279,6 +8279,22 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
        return retval;
 }
 
+static bool sctp_bpf_bypass_getsockopt(int level, int optname)
+{
+       if (level == SOL_SCTP) {
+               switch (optname) {
+               case SCTP_SOCKOPT_PEELOFF:
+               case SCTP_SOCKOPT_PEELOFF_FLAGS:
+               case SCTP_SOCKOPT_CONNECTX3:
+                       return true;
+               default:
+                       return false;
+               }
+       }
+
+       return false;
+}
+
 static int sctp_hash(struct sock *sk)
 {
        /* STUB */
@@ -9643,6 +9659,7 @@ struct proto sctp_prot = {
        .shutdown    =  sctp_shutdown,
        .setsockopt  =  sctp_setsockopt,
        .getsockopt  =  sctp_getsockopt,
+       .bpf_bypass_getsockopt  = sctp_bpf_bypass_getsockopt,
        .sendmsg     =  sctp_sendmsg,
        .recvmsg     =  sctp_recvmsg,
        .bind        =  sctp_bind,
@@ -9698,6 +9715,7 @@ struct proto sctpv6_prot = {
        .shutdown       = sctp_shutdown,
        .setsockopt     = sctp_setsockopt,
        .getsockopt     = sctp_getsockopt,
+       .bpf_bypass_getsockopt  = sctp_bpf_bypass_getsockopt,
        .sendmsg        = sctp_sendmsg,
        .recvmsg        = sctp_recvmsg,
        .bind           = sctp_bind,