diff --git a/sys/net/route/route_ctl.h b/sys/net/route/route_ctl.h --- a/sys/net/route/route_ctl.h +++ b/sys/net/route/route_ctl.h @@ -121,6 +121,7 @@ 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 @@ 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, diff --git a/sys/net/route/route_rtentry.c b/sys/net/route/route_rtentry.c --- a/sys/net/route/route_rtentry.c +++ b/sys/net/route/route_rtentry.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -197,6 +198,29 @@ 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 diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -218,8 +218,6 @@ 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 @@ 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 @@ 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 @@ 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)) {