routing: add public rt_is_exportable() version to check if

the route can be exported to userland when jailed.

Differential Revision: https://reviews.freebsd.org/D39204
MFC after:	2 weeks
This commit is contained in:
Alexander V. Chernikov 2023-03-26 08:19:56 +00:00
parent 328ebd4680
commit 2cda6a2fb0
3 changed files with 30 additions and 25 deletions

View File

@ -121,6 +121,7 @@ void rib_foreach_table_walk_del(int family, rib_filter_f_t *filter_f, void *arg)
struct nhop_object;
struct nhgrp_object;
struct ucred;
const struct rtentry *rib_lookup_prefix(uint32_t fibnum, int family,
const struct sockaddr *dst, const struct sockaddr *netmask,
@ -133,6 +134,7 @@ bool rt_is_host(const struct rtentry *rt);
sa_family_t rt_get_family(const struct rtentry *);
struct nhop_object *rt_get_raw_nhop(const struct rtentry *rt);
void rt_get_rnd(const struct rtentry *rt, struct route_nhop_data *rnd);
bool rt_is_exportable(const struct rtentry *rt, struct ucred *cred);
#ifdef INET
struct in_addr;
void rt_get_inet_prefix_plen(const struct rtentry *rt, struct in_addr *paddr,

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/rmlock.h>
@ -197,6 +198,29 @@ rt_get_rnd(const struct rtentry *rt, struct route_nhop_data *rnd)
rnd->rnd_weight = rt->rt_weight;
}
/*
* If the process in in jail w/o VNET, export only host routes for the
* addresses assigned to the jail.
* Otherwise, allow exporting the entire table.
*/
bool
rt_is_exportable(const struct rtentry *rt, struct ucred *cred)
{
if (!rt_is_host(rt)) {
/*
* Performance optimisation: only host routes are allowed
* in the jail w/o vnet.
*/
if (jailed_without_vnet(cred))
return (false);
} else {
if (prison_if(cred, rt_key_const(rt)) != 0)
return (false);
}
return (true);
}
#ifdef INET
/*
* Stores IPv4 address and prefix length of @rt inside

View File

@ -218,8 +218,6 @@ static int update_rtm_from_rc(struct rt_addrinfo *info,
static void send_rtm_reply(struct socket *so, struct rt_msghdr *rtm,
struct mbuf *m, sa_family_t saf, u_int fibnum,
int rtm_errno);
static bool can_export_rte(struct ucred *td_ucred, bool rt_is_host,
const struct sockaddr *rt_dst);
static void rtsock_notify_event(uint32_t fibnum, const struct rib_cmd_info *rc);
static void rtsock_ifmsg(struct ifnet *ifp, int if_flags_mask);
@ -1168,11 +1166,8 @@ rts_send(struct socket *so, int flags, struct mbuf *m,
senderr(error);
nh = rc.rc_nh_new;
if (!can_export_rte(curthread->td_ucred,
info.rti_info[RTAX_NETMASK] == NULL,
info.rti_info[RTAX_DST])) {
if (!rt_is_exportable(rc.rc_rt, curthread->td_ucred))
senderr(ESRCH);
}
break;
default:
@ -2198,23 +2193,6 @@ rt_dispatch(struct mbuf *m, sa_family_t saf)
netisr_queue(NETISR_ROUTE, m); /* mbuf is free'd on failure. */
}
/*
* Checks if rte can be exported w.r.t jails/vnets.
*
* Returns true if it can, false otherwise.
*/
static bool
can_export_rte(struct ucred *td_ucred, bool rt_is_host,
const struct sockaddr *rt_dst)
{
if ((!rt_is_host) ? jailed_without_vnet(td_ucred)
: prison_if(td_ucred, rt_dst) != 0)
return (false);
return (true);
}
/*
* This is used in dumping the kernel table via sysctl().
*/
@ -2226,9 +2204,10 @@ sysctl_dumpentry(struct rtentry *rt, void *vw)
NET_EPOCH_ASSERT();
export_rtaddrs(rt, w->dst, w->mask);
if (!can_export_rte(w->w_req->td->td_ucred, rt_is_host(rt), w->dst))
if (!rt_is_exportable(rt, w->w_req->td->td_ucred))
return (0);
export_rtaddrs(rt, w->dst, w->mask);
nh = rt_get_raw_nhop(rt);
#ifdef ROUTE_MPATH
if (NH_IS_NHGRP(nh)) {