Re: git: eb8dcdeac22d - main - jail: network epoch protection for IP address lists
Date: Sun, 26 Dec 2021 19:07:06 UTC
On 26 Dec 2021, at 18:46, Gleb Smirnoff <glebius@FreeBSD.org> wrote: > > The branch main has been updated by glebius: > > URL: https://cgit.FreeBSD.org/src/commit/?id=eb8dcdeac22daadbf07be81d7338e14ec4cc7d7f > > commit eb8dcdeac22daadbf07be81d7338e14ec4cc7d7f > Author: Gleb Smirnoff <glebius@FreeBSD.org> > AuthorDate: 2021-12-26 18:45:50 +0000 > Commit: Gleb Smirnoff <glebius@FreeBSD.org> > CommitDate: 2021-12-26 18:45:50 +0000 > > jail: network epoch protection for IP address lists > > Now struct prison has two pointers (IPv4 and IPv6) of struct > prison_ip type. Each points into epoch context, address count > and variable size array of addresses. These structures are > freed with network epoch deferred free and are not edited in > place, instead a new structure is allocated and set. > > While here, the change also generalizes a lot (but not enough) > of IPv4 and IPv6 processing. E.g. address family agnostic helpers > for kern_jail_set() are provided, that reduce v4-v6 copy-paste. > > The fast-path prison_check_ip[46]_locked() is also generalized > into prison_ip_check() that can be executed with network epoch > protection only. > > Reviewed by: jamie > Differential revision: https://reviews.freebsd.org/D33339 > --- > sys/kern/kern_jail.c | 770 +++++++++++++++++++++++++++++++----------------- > sys/netinet/in.c | 2 + > sys/netinet/in_jail.c | 139 ++------- > sys/netinet6/in6_jail.c | 133 ++------- > sys/sys/jail.h | 25 +- > 5 files changed, 572 insertions(+), 497 deletions(-) > > diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c > index e505e9bf1276..f1c81d8813bd 100644 > --- a/sys/kern/kern_jail.c > +++ b/sys/kern/kern_jail.c > @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); > #include <sys/osd.h> > #include <sys/priv.h> > #include <sys/proc.h> > +#include <sys/epoch.h> > #include <sys/taskqueue.h> > #include <sys/fcntl.h> > #include <sys/jail.h> > @@ -531,15 +532,407 @@ sys_jail_set(struct thread *td, struct jail_set_args *uap) > return (error); > } > > +#if defined(INET) || defined(INET6) > +typedef int prison_addr_cmp_t(const void *, const void *); > +typedef bool prison_addr_valid_t(const void *); > +static const struct pr_family { > + size_t size; > + prison_addr_cmp_t *cmp; > + prison_addr_valid_t *valid; > + int ip_flag; > +} pr_families[PR_FAMILY_MAX] = { > +#ifdef INET > + [PR_INET] = { > + .size = sizeof(struct in_addr), > + .cmp = prison_qcmp_v4, > + .valid = prison_valid_v4, > + .ip_flag = PR_IP4_USER, > + }, > +#endif > +#ifdef INET6 > + [PR_INET6] = { > + .size = sizeof(struct in6_addr), > + .cmp = prison_qcmp_v6, > + .valid = prison_valid_v6, > + .ip_flag = PR_IP6_USER, > + }, > +#endif > +}; > + > +/* > + * Network address lists (pr_addrs) allocation for jails. The addresses > + * are accessed locklessly by the network stack, thus need to be protected by > + * the network epoch. > + */ > +struct prison_ip { > + struct epoch_context ctx; > + uint32_t ips; > +#ifdef FUTURE_C > + union { > + struct in_addr pr_ip4[]; > + struct in6_addr pr_ip6[]; > + }; > +#else /* No future C :( */ > +#define PR_IP(pip, i) ((const char *)((pip) + 1) + pr_families[af].size * (i)) > +#define PR_IPD(pip, i) ((char *)((pip) + 1) + pr_families[af].size * (i)) > +#endif > +}; You can make this work with a prison_ip base and prison_ipv[46] derived structs. As it stands this is quite gross, you’re assuming things about alignment, and don’t even have a flexible char[] at the end to represent the extra data. Jess