From 844c9666eb966696bffc72e34edb3164f26e9a98 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 21 May 2025 14:45:16 +0000 Subject: [PATCH] UPSTREAM: af_unix: Allocate struct unix_edge for each inflight AF_UNIX fd. commit 29b64e354029cfcf1eea4d91b146c7b769305930 upstream. As with the previous patch, we preallocate to skb's scm_fp_list an array of struct unix_edge in the number of inflight AF_UNIX fds. There we just preallocate memory and do not use immediately because sendmsg() could fail after this point. The actual use will be in the next patch. When we queue skb with inflight edges, we will set the inflight socket's unix_sock as unix_edge->predecessor and the receiver's unix_sock as successor, and then we will link the edge to the inflight socket's unix_vertex.edges. Note that we set NULL to cloned scm_fp_list.edges in scm_fp_dup() so that MSG_PEEK does not change the shape of the directed graph. Bug: 404256079 Signed-off-by: Kuniyuki Iwashima Acked-by: Paolo Abeni Link: https://lore.kernel.org/r/20240325202425.60930-3-kuniyu@amazon.com Signed-off-by: Jakub Kicinski Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 4fc7df1c6da14aef3ad9d2ea39565c020ec09aaa) Signed-off-by: Lee Jones Change-Id: I9b0d639f1ac8fb3b9c032aebcca6d5bb59e3fc79 --- include/net/af_unix.h | 6 ++++++ include/net/scm.h | 7 +++++++ net/core/scm.c | 2 ++ net/unix/garbage.c | 6 ++++++ 4 files changed, 21 insertions(+) diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 07f0f698c949..dd5750daf0b9 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -33,6 +33,12 @@ struct unix_vertex { unsigned long out_degree; }; +struct unix_edge { + struct unix_sock *predecessor; + struct unix_sock *successor; + struct list_head vertex_entry; +}; + struct sock *unix_peer_get(struct sock *sk); #define UNIX_HASH_MOD (256 - 1) diff --git a/include/net/scm.h b/include/net/scm.h index c93ef577d20d..7baa86686709 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -22,9 +22,16 @@ struct scm_creds { kgid_t gid; }; +#ifdef CONFIG_UNIX +struct unix_edge; +#endif + struct scm_fp_list { short count; short max; +#ifdef CONFIG_UNIX + struct unix_edge *edges; +#endif struct user_struct *user; struct file *fp[SCM_MAX_FD]; #ifndef __GENKSYMS__ diff --git a/net/core/scm.c b/net/core/scm.c index 099e4fb519b3..f3814d9dccba 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -90,6 +90,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) fpl->max = SCM_MAX_FD; fpl->user = NULL; #if IS_ENABLED(CONFIG_UNIX) + fpl->edges = NULL; INIT_LIST_HEAD(&fpl->vertices); #endif } @@ -382,6 +383,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) new_fpl->max = new_fpl->count; new_fpl->user = get_uid(fpl->user); #if IS_ENABLED(CONFIG_UNIX) + new_fpl->edges = NULL; INIT_LIST_HEAD(&new_fpl->vertices); #endif } diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 8ea7640e032e..912b7945692c 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -127,6 +127,11 @@ int unix_prepare_fpl(struct scm_fp_list *fpl) list_add(&vertex->entry, &fpl->vertices); } + fpl->edges = kvmalloc_array(fpl->count_unix, sizeof(*fpl->edges), + GFP_KERNEL_ACCOUNT); + if (!fpl->edges) + goto err; + return 0; err: @@ -136,6 +141,7 @@ err: void unix_destroy_fpl(struct scm_fp_list *fpl) { + kvfree(fpl->edges); unix_free_vertices(fpl); }