Page MenuHomeFreeBSD

netlink/route: make route deletion behavior match route(4) socket
AcceptedPublic

Authored by glebius on Aug 15 2024, 1:04 AM.
Tags
None
Referenced Files
Unknown Object (File)
Sun, Dec 1, 8:54 AM
Unknown Object (File)
Fri, Nov 29, 4:46 PM
Unknown Object (File)
Thu, Nov 14, 5:33 PM
Unknown Object (File)
Tue, Nov 12, 2:42 PM
Unknown Object (File)
Wed, Nov 6, 3:57 PM
Unknown Object (File)
Sep 25 2024, 9:14 AM
Unknown Object (File)
Sep 25 2024, 2:58 AM
Unknown Object (File)
Sep 10 2024, 7:29 AM

Details

Reviewers
melifaro
zlei
Group Reviewers
network
Summary

Deleting a route with help of route(8) command in pre-netlink times was a
two step action: first the route(8) would RTM_GET the route from the
kernel and then copy its parameters into the RTM_DEL request. This
allowed deletion of pinned (RTF_PINNED) routes, as the flag was carried
over. The flag enforced call into rt_delete_conditional() with prio=2
parameter.

With netlink(4) enabled route(8), we construct the NL_RTM_DELROUTE request
from scratch and this ends in rt_delete_conditional() being called with
prio=1, which effectively blocks deleting a pinned route.

Make the netlink(4) code provide RTM_F_FORCE flag for rib_del_route_px(),
which would end up with prio=2 for rt_delete_conditional(). The rationale
is here that netlink(4) path isn't something automatic, it is either an
explicit request from an operator with route(8) or some other routing
daemon, and the RTF_PINNED protection shall be bypassed for any call via
netlink(4).

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 59026
Build 55913: arc lint + arc unit

Event Timeline

I would really like to do EN for this to 14.1.

zlei added a subscriber: zlei.

Looks good to me.

This revision is now accepted and ready to land.Aug 21 2024, 2:13 AM

What else is needed to commit this patch?

I'm going to come up with a different version of this patch (likely using a new flag rtmsg->rtm_flags to signal RTM_F_FORCE) in a day or two. The current version allows all netlink customers to fully bypass PINNED route protection, which defeats its purpose.

I'm going to come up with a different version of this patch (likely using a new flag rtmsg->rtm_flags to signal RTM_F_FORCE) in a day or two. The current version allows all netlink customers to fully bypass PINNED route protection, which defeats its purpose.

Did this ever happen? Chased the bug with a user and D47534 did not fix it but that was likely intended. Unable to locate another commit or review.

I don't like the idea that you can easily remove PINNED route, but it seems it always worked before.
However as I see, route(8) should pass RTF_PINNED flag to netlink via attrs.rta_rtflags. At least we should reduce use of RTM_F_FORCE only for case when RTF_PINNED was sent from userland.

Like this?

(attrs.rta_rtflags & RTF_PINNED) ? RTM_F_FORCE : 0

It seemed strange to me the user said a binary from a 13.2 system was able to drop the route in a 14.1 system while the native binary was not able to. Could hint at netlink getting in the way? Nevermind, this is the netlink code after all so here's the reason why it differs.

(attrs.rta_rtflags & RTF_PINNED) ? RTM_F_FORCE : 0

Yes, like this.

It seemed strange to me the user said a binary from a 13.2 system was able to drop the route in a 14.1 system while the native binary was not able to. Could hint at netlink getting in the way? Nevermind, this is the netlink code after all so here's the reason why it differs.

The binary from 13.2 probably uses old rtsock interface, new binary by default is build with netlink support.

I just tested these commands from PR:

ifconfig tun0 create
ifconfig tun0 10.10.10.10 20.20.20.20
route -n delete -host 20.20.20.20 -interface tun0

with this patch:

--- a/sys/netlink/route/rt.c
+++ b/sys/netlink/route/rt.c
@@ -1010,8 +1010,9 @@ rtnl_handle_delroute(struct nlmsghdr *hdr, struct nlpcb *nlp,
                return (EINVAL);
        }

+       int op_flags = (attrs.rta_rtflags & RTF_PINNED) ? RTM_F_FORCE : 0;
        error = rib_del_route_px(attrs.rta_table, attrs.rta_dst,
-           attrs.rtm_dst_len, path_match_func, &attrs, 0, &rc);
+           attrs.rtm_dst_len, path_match_func, &attrs, op_flags, &rc);
        if (error == 0)
                report_operation(attrs.rta_table, &rc, nlp, hdr);
        return (error);

It seems works as expected.

Offered a test kernel to the user in the meantime. @glebius is probably busy (last I spoke with him) and doesn't mind if you commit?