From 6e196011ca8a1eba5be16f57e05ff6f152672f7a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 8 Apr 2025 12:13:12 +0200 Subject: [PATCH] sd-netlink: allow configuration of flags parameter when creating message object We soon want to add for sock_diag(7) netlink sockets. Those reuse the same message type codes for request and response but with different message formats. Hence we need to look at NLM_F_REQUEST to determine which message policy to apply. Hence it is essential to know the flags parameters right away when creating a message, since we cannot do early validation otherwise. This only adds support for setting the flags value right at the moment of creation of the message object, it does not otherwise add sock_diag(7) support, that is added in a later message. This also corrects the flag for synthetic NLMSG_ERROR messages which should not have the NLM_F_REQUEST flag set (since they are responses, not requests). --- src/libsystemd/sd-netlink/netlink-genl.c | 2 +- src/libsystemd/sd-netlink/netlink-internal.h | 3 +- .../sd-netlink/netlink-message-nfnl.c | 2 +- .../sd-netlink/netlink-message-rtnl.c | 78 ++++++++++--------- src/libsystemd/sd-netlink/netlink-message.c | 19 +++-- src/libsystemd/sd-netlink/netlink-socket.c | 2 +- src/libsystemd/sd-netlink/netlink-types.c | 1 + src/libsystemd/sd-netlink/netlink-types.h | 1 + 8 files changed, 59 insertions(+), 49 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-genl.c b/src/libsystemd/sd-netlink/netlink-genl.c index 8d2269b54d5..9c31105772f 100644 --- a/src/libsystemd/sd-netlink/netlink-genl.c +++ b/src/libsystemd/sd-netlink/netlink-genl.c @@ -244,7 +244,7 @@ static int genl_message_new( if (!policy_set) return -EOPNOTSUPP; - r = message_new_full(nl, family->id, policy_set, + r = message_new_full(nl, family->id, NLM_F_REQUEST | NLM_F_ACK, policy_set, sizeof(struct genlmsghdr) + family->additional_header_size, &m); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 5b9ccb336ec..7346902bdc9 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -131,10 +131,11 @@ int message_new_empty(sd_netlink *nl, sd_netlink_message **ret); int message_new_full( sd_netlink *nl, uint16_t nlmsg_type, + uint16_t nlmsg_flags, const NLAPolicySet *policy_set, size_t header_size, sd_netlink_message **ret); -int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type); +int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type, uint16_t flags); int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret); static inline uint32_t message_get_serial(sd_netlink_message *m) { diff --git a/src/libsystemd/sd-netlink/netlink-message-nfnl.c b/src/libsystemd/sd-netlink/netlink-message-nfnl.c index 72bcdde1bdd..321b9b2006d 100644 --- a/src/libsystemd/sd-netlink/netlink-message-nfnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-nfnl.c @@ -34,7 +34,7 @@ int sd_nfnl_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int nfproto, assert_return(nfproto_is_valid(nfproto), -EINVAL); assert_return(NFNL_MSG_TYPE(msg_type) == msg_type, -EINVAL); - r = message_new(nfnl, &m, subsys << 8 | msg_type); + r = message_new(nfnl, &m, subsys << 8 | msg_type, NLM_F_REQUEST | NLM_F_ACK); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-message-rtnl.c b/src/libsystemd/sd-netlink/netlink-message-rtnl.c index fdde1fb2c80..b730b63fb02 100644 --- a/src/libsystemd/sd-netlink/netlink-message-rtnl.c +++ b/src/libsystemd/sd-netlink/netlink-message-rtnl.c @@ -244,13 +244,13 @@ int sd_rtnl_message_new_route( IN_SET(family, AF_INET, AF_INET6), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, + ret, + nlmsg_type, + NLM_F_REQUEST|NLM_F_ACK|(nlmsg_type == RTM_NEWROUTE ? NLM_F_CREATE | NLM_F_APPEND : 0)); if (r < 0) return r; - if (nlmsg_type == RTM_NEWROUTE) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND; - rtm = NLMSG_DATA((*ret)->hdr); rtm->rtm_family = family; @@ -281,13 +281,13 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, } assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, + ret, + nlmsg_type, + NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWNEXTHOP ? NLM_F_CREATE | NLM_F_REPLACE : 0)); if (r < 0) return r; - if (nlmsg_type == RTM_NEWNEXTHOP) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - nhm = NLMSG_DATA((*ret)->hdr); nhm->nh_family = family; @@ -311,17 +311,18 @@ int sd_rtnl_message_new_neigh( assert_return(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); - if (r < 0) - return r; - + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; if (nlmsg_type == RTM_NEWNEIGH) { if (family == AF_BRIDGE) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND; + flags |= NLM_F_CREATE | NLM_F_APPEND; else - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; + flags |= NLM_F_CREATE | NLM_F_REPLACE; } + r = message_new(rtnl, ret, nlmsg_type, flags); + if (r < 0) + return r; + ndm = NLMSG_DATA((*ret)->hdr); ndm->ndm_family = family; @@ -337,14 +338,15 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret, uint16_ assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); - if (r < 0) - return r; - + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; if (nlmsg_type == RTM_NEWLINK && ifindex == 0) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + flags |= NLM_F_CREATE | NLM_F_EXCL; else if (nlmsg_type == RTM_NEWLINKPROP) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND; + flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND; + + r = message_new(rtnl, ret, nlmsg_type, flags); + if (r < 0) + return r; ifi = NLMSG_DATA((*ret)->hdr); @@ -371,7 +373,7 @@ int sd_rtnl_message_new_addr( IN_SET(family, AF_INET, AF_INET6), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK); if (r < 0) return r; @@ -439,13 +441,13 @@ int sd_rtnl_message_new_addrlabel( assert_return(rtnl_message_type_is_addrlabel(nlmsg_type), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, + ret, + nlmsg_type, + NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWADDRLABEL ? NLM_F_CREATE | NLM_F_REPLACE : 0)); if (r < 0) return r; - if (nlmsg_type == RTM_NEWADDRLABEL) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - addrlabel = NLMSG_DATA((*ret)->hdr); addrlabel->ifal_family = family; @@ -466,13 +468,13 @@ int sd_rtnl_message_new_routing_policy_rule( assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, + ret, + nlmsg_type, + NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWRULE ? NLM_F_CREATE | NLM_F_EXCL : 0)); if (r < 0) return r; - if (nlmsg_type == RTM_NEWRULE) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; - frh = NLMSG_DATA((*ret)->hdr); frh->family = family; @@ -493,13 +495,13 @@ int sd_rtnl_message_new_traffic_control( assert_return(rtnl_message_type_is_traffic_control(nlmsg_type), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, + ret, + nlmsg_type, + NLM_F_REQUEST | NLM_F_ACK | (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS) ? NLM_F_CREATE | NLM_F_REPLACE : 0)); if (r < 0) return r; - if (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS)) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - tcm = NLMSG_DATA((*ret)->hdr); tcm->tcm_ifindex = ifindex; tcm->tcm_handle = handle; @@ -520,13 +522,13 @@ int sd_rtnl_message_new_mdb( assert_return(rtnl_message_type_is_mdb(nlmsg_type), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, + ret, + nlmsg_type, + NLM_F_REQUEST | NLM_F_ACK | (nlmsg_type == RTM_NEWMDB ? NLM_F_CREATE | NLM_F_REPLACE : 0)); if (r < 0) return r; - if (nlmsg_type == RTM_NEWMDB) - (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - bpm = NLMSG_DATA((*ret)->hdr); bpm->family = AF_BRIDGE; bpm->ifindex = ifindex; @@ -545,7 +547,7 @@ int sd_rtnl_message_new_nsid( assert_return(rtnl_message_type_is_nsid(nlmsg_type), -EINVAL); assert_return(ret, -EINVAL); - r = message_new(rtnl, ret, nlmsg_type); + r = message_new(rtnl, ret, nlmsg_type, NLM_F_REQUEST | NLM_F_ACK); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index eb88ae5e2b7..8052e46768e 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -44,6 +44,7 @@ int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) { int message_new_full( sd_netlink *nl, uint16_t nlmsg_type, + uint16_t nlmsg_flags, const NLAPolicySet *policy_set, size_t header_size, sd_netlink_message **ret) { @@ -69,7 +70,7 @@ int message_new_full( if (!m->hdr) return -ENOMEM; - m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + m->hdr->nlmsg_flags = nlmsg_flags; m->hdr->nlmsg_len = size; m->hdr->nlmsg_type = nlmsg_type; @@ -77,7 +78,7 @@ int message_new_full( return 0; } -int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type) { +int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, uint16_t nlmsg_flags) { const NLAPolicySet *policy_set; size_t size; int r; @@ -85,11 +86,11 @@ int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type) { assert_return(nl, -EINVAL); assert_return(ret, -EINVAL); - r = netlink_get_policy_set_and_header_size(nl, nlmsg_type, &policy_set, &size); + r = netlink_get_policy_set_and_header_size(nl, nlmsg_type, nlmsg_flags, &policy_set, &size); if (r < 0) return r; - return message_new_full(nl, nlmsg_type, policy_set, size, ret); + return message_new_full(nl, nlmsg_type, nlmsg_flags, policy_set, size, ret); } int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) { @@ -98,7 +99,7 @@ int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_n assert(error <= 0); - r = message_new(nl, ret, NLMSG_ERROR); + r = message_new(nl, ret, NLMSG_ERROR, 0); if (r < 0) return r; @@ -1328,8 +1329,12 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) { assert(m->hdr); - r = netlink_get_policy_set_and_header_size(nl, m->hdr->nlmsg_type, - &m->containers[0].policy_set, &size); + r = netlink_get_policy_set_and_header_size( + nl, + m->hdr->nlmsg_type, + m->hdr->nlmsg_flags, + &m->containers[0].policy_set, + &size); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 1b098cadeeb..0f00e3f2fcc 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -307,7 +307,7 @@ static int parse_message_one(sd_netlink *nl, uint32_t group, const struct nlmsgh goto finalize; /* check that we support this message type */ - r = netlink_get_policy_set_and_header_size(nl, hdr->nlmsg_type, NULL, &size); + r = netlink_get_policy_set_and_header_size(nl, hdr->nlmsg_type, hdr->nlmsg_flags, NULL, &size); if (r == -EOPNOTSUPP) { log_debug("sd-netlink: ignored message with unknown type: %i", hdr->nlmsg_type); goto finalize; diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 21ef80c2ece..8ce3fc0ec9a 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -51,6 +51,7 @@ const NLAPolicySetUnion *policy_get_policy_set_union(const NLAPolicy *policy) { int netlink_get_policy_set_and_header_size( sd_netlink *nl, uint16_t type, + uint16_t flags, const NLAPolicySet **ret_policy_set, size_t *ret_header_size) { diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index e034a984e9b..46439527299 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -52,6 +52,7 @@ const NLAPolicySetUnion *policy_get_policy_set_union(const NLAPolicy *policy); int netlink_get_policy_set_and_header_size( sd_netlink *nl, uint16_t type, + uint16_t flags, const NLAPolicySet **ret_policy_set, size_t *ret_header_size); -- 2.47.3