From nobody Sat Apr 08 19:44:55 2023 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Pv5L0006qz44nsR; Sat, 8 Apr 2023 19:44:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Pv5Kz6F0Tz44Cn; Sat, 8 Apr 2023 19:44:55 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680983095; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=lFMBQRiUBxB2umhjziqxA+tOfRuMfEUUBOh8xs/GQ0o=; b=TsZwslGVncyZhJT+/C/c5nltvUTn7UmenxGgZ/tvOQZ3DkEt9mJT7moQ2LOsHFg5xYDKCq RaZGKHMYveEtmUd5mLFkaUsPT8mosfAx5Fo6WoA+8xTaBct9qLgGh7Nb24a1NedOQxim8E iBfWOE6SokZbZxOAdA1W6nvebi/zmVD0cmisXi8kfb8svKf8V46xhIZq8FWNgvzmlozyDI IZJySL5F5FyrHF27FmsM5zyORrS1fkfrPLZUl9V3JTT1S6yRmF8is0C+NPLfAIf44Wv+Nn P5wJaB5YUSwygUoqgB2k6KmUeZHhXW10buNCRTiQzsXUhuPoMylxo38NEIDMWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680983095; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=lFMBQRiUBxB2umhjziqxA+tOfRuMfEUUBOh8xs/GQ0o=; b=ni4w9VVfem0bOJzI8CGfWKNmsO6Rojxn2WWp29eVJ25Th7Jd8qKVkxMYCzDqRcSI5UOY8e jzugkMOoQEiyHfk248O6axGGQMr6b1r4U3pgnBQddWtQM/n/sTvBBN4HNzjeflUmlOsbe+ rR4BA/SpdRSJceiD36VwgFb90vMkK/56uo6CfYyqqTiu+/a8MTdcPaZBv1ixKtgf6C1rcE CwaXbgxgI7P87n99x07UzYfpcxU1GYHkKJ+nkfHMQTKTMvs4SLK3EARTUKkfpEZKmiyCwY RyV3l/BV9J1aQQtgPLBWT3nIBeI9bMqVG7LozYK6uqlpjQl8MEpfidjEoLzrfQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1680983095; a=rsa-sha256; cv=none; b=NFu85cnjcrC6F4CLiac+a77LoO6jD7FWkkxP3SOkCauGR7T0oH9vNO0ZKLRHhrme3+d1Dl upxZJTq6v8utURVd8fRA+HNrf4qZ+J9XHSe+HK65W1Z6locg8FkkwuvWFShPmxWGNTwcVX EU6sZEGhSWD3R+ZYzoxDlzoHP76ZuXnveWmkalkfKLtNe1WWAvrhiOW5cbiQIIfBgtb9EX U3NiHfxOB6pG4742Mn9CgIv6uCxpco/MvkWQrT6e28SA0rnrcJlFaDmP8U521yCpD2Inwt 5qZTMe8Ni8RptJK4cmH0090gb4ajwXZx5DHHrNn8+rfsod5euXX2y5IqEscMyQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Pv5Kz52g8zg3M; Sat, 8 Apr 2023 19:44:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 338JitQQ018796; Sat, 8 Apr 2023 19:44:55 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 338JitK0018795; Sat, 8 Apr 2023 19:44:55 GMT (envelope-from git) Date: Sat, 8 Apr 2023 19:44:55 GMT Message-Id: <202304081944.338JitK0018795@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: 95b86c887b33 - stable/13 - netlink: fix capped uncapped ack handling in snl(3). List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 95b86c887b33fff3ea6ac53364b359f485dba7fd Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=95b86c887b33fff3ea6ac53364b359f485dba7fd commit 95b86c887b33fff3ea6ac53364b359f485dba7fd Author: Alexander V. Chernikov AuthorDate: 2023-03-17 14:27:08 +0000 Commit: Alexander V. Chernikov CommitDate: 2023-04-08 19:12:57 +0000 netlink: fix capped uncapped ack handling in snl(3). Reviewed by: kp Differential Revision: https://reviews.freebsd.org/D39144 MFC after: 2 weeks (cherry picked from commit 568a645ba55a1c3fc4fc74735cb0fab08bfe4cbf) --- sys/netlink/netlink_snl.h | 52 ++++++++++++++---- tests/sys/netlink/test_snl.c | 126 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 11 deletions(-) diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h index be512b67c7ec..935012885362 100644 --- a/sys/netlink/netlink_snl.h +++ b/sys/netlink/netlink_snl.h @@ -388,18 +388,25 @@ snl_parse_attrs(struct snl_state *ss, struct nlmsghdr *hdr, int hdrlen, return (snl_parse_attrs_raw(ss, nla_head, len, ps, pslen, target)); } -static inline bool -snl_parse_header(struct snl_state *ss, void *hdr, int len, - const struct snl_hdr_parser *parser, void *target) +static inline void +snl_parse_fields(struct snl_state *ss, struct nlmsghdr *hdr, int hdrlen __unused, + const struct snl_field_parser *ps, int pslen, void *target) { - /* Extract fields first (if any) */ - for (int i = 0; i < parser->fp_size; i++) { - const struct snl_field_parser *fp = &parser->fp[i]; + for (int i = 0; i < pslen; i++) { + const struct snl_field_parser *fp = &ps[i]; void *src = (char *)hdr + fp->off_in; void *dst = (char *)target + fp->off_out; fp->cb(ss, src, dst); } +} + +static inline bool +snl_parse_header(struct snl_state *ss, void *hdr, int len, + const struct snl_hdr_parser *parser, void *target) +{ + /* Extract fields first (if any) */ + snl_parse_fields(ss, hdr, parser->hdr_off, parser->fp, parser->fp_size, target); struct nlattr *nla_head = (struct nlattr *)(void *)((char *)hdr + parser->hdr_off); bool result = snl_parse_attrs_raw(ss, nla_head, len - parser->hdr_off, @@ -575,13 +582,20 @@ snl_field_get_uint32(struct snl_state *ss __unused, void *src, void *target) *((uint32_t *)target) = *((uint32_t *)src); } +static inline void +snl_field_get_ptr(struct snl_state *ss __unused, void *src, void *target) +{ + *((void **)target) = src; +} + struct snl_errmsg_data { - uint32_t nlmsg_seq; + struct nlmsghdr *orig_hdr; int error; - char *error_str; uint32_t error_offs; + char *error_str; struct nlattr *cookie; }; + #define _IN(_field) offsetof(struct nlmsgerr, _field) #define _OUT(_field) offsetof(struct snl_errmsg_data, _field) static const struct snl_attr_parser nla_p_errmsg[] = { @@ -592,7 +606,7 @@ static const struct snl_attr_parser nla_p_errmsg[] = { static const struct snl_field_parser nlf_p_errmsg[] = { { .off_in = _IN(error), .off_out = _OUT(error), .cb = snl_field_get_uint32 }, - { .off_in = _IN(msg.nlmsg_seq), .off_out = _OUT(nlmsg_seq), .cb = snl_field_get_uint32 }, + { .off_in = _IN(msg), .off_out = _OUT(orig_hdr), .cb = snl_field_get_ptr }, }; #undef _IN #undef _OUT @@ -609,6 +623,22 @@ static const struct snl_field_parser nlf_p_donemsg[] = { #undef _OUT SNL_DECLARE_PARSER(snl_donemsg_parser, struct nlmsgerr, nlf_p_donemsg, nla_p_donemsg); +static inline bool +snl_parse_errmsg(struct snl_state *ss, struct nlmsghdr *hdr, struct snl_errmsg_data *e) +{ + if ((hdr->nlmsg_flags & NLM_F_CAPPED) != 0) + return (snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e)); + + const struct snl_hdr_parser *ps = &snl_errmsg_parser; + struct nlmsgerr *errmsg = (struct nlmsgerr *)(hdr + 1); + int hdrlen = sizeof(int) + NLMSG_ALIGN(errmsg->msg.nlmsg_len); + struct nlattr *attr_head = (struct nlattr *)(void *)((char *)errmsg + hdrlen); + int attr_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; + + snl_parse_fields(ss, (struct nlmsghdr *)errmsg, hdrlen, ps->fp, ps->fp_size, e); + return (snl_parse_attrs_raw(ss, attr_head, attr_len, ps->np, ps->np_size, e)); +} + static inline bool snl_read_reply_code(struct snl_state *ss, uint32_t nlmsg_seq, struct snl_errmsg_data *e) { @@ -617,7 +647,7 @@ snl_read_reply_code(struct snl_state *ss, uint32_t nlmsg_seq, struct snl_errmsg_ if (hdr == NULL) { e->error = EINVAL; } else if (hdr->nlmsg_type == NLMSG_ERROR) { - if (!snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e)) + if (!snl_parse_errmsg(ss, hdr, e)) e->error = EINVAL; return (e->error == 0); } @@ -636,7 +666,7 @@ snl_read_reply_multi(struct snl_state *ss, uint32_t nlmsg_seq, struct snl_errmsg if (hdr == NULL) { e->error = EINVAL; } else if (hdr->nlmsg_type == NLMSG_ERROR) { - if (!snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e)) + if (!snl_parse_errmsg(ss, hdr, e)) e->error = EINVAL; } if (hdr->nlmsg_type == NLMSG_DONE) { snl_parse_nlmsg(ss, hdr, &snl_donemsg_parser, e); diff --git a/tests/sys/netlink/test_snl.c b/tests/sys/netlink/test_snl.c index 85bdff7fb163..8c6d72f6893b 100644 --- a/tests/sys/netlink/test_snl.c +++ b/tests/sys/netlink/test_snl.c @@ -44,6 +44,129 @@ ATF_TC_BODY(snl_verify_route_parsers, tc) } +ATF_TC(snl_parse_errmsg_capped); +ATF_TC_HEAD(snl_parse_errmsg_capped, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests snl(3) correctly parsing capped errors"); +} + +ATF_TC_BODY(snl_parse_errmsg_capped, tc) +{ + struct snl_state ss; + struct snl_writer nw; + + require_netlink(); + + if (!snl_init(&ss, NETLINK_ROUTE)) + atf_tc_fail("snl_init() failed"); + + int optval = 1; + ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_CAP_ACK, &optval, sizeof(optval)) == 0); + + snl_init_writer(&ss, &nw); + + struct nlmsghdr *hdr = snl_create_msg_request(&nw, 255); + ATF_CHECK(hdr != NULL); + ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL); + snl_add_msg_attr_string(&nw, 143, "some random string"); + ATF_CHECK(snl_finalize_msg(&nw) != NULL); + + ATF_CHECK(snl_send_message(&ss, hdr)); + + struct nlmsghdr *rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq); + ATF_CHECK(rx_hdr != NULL); + ATF_CHECK(rx_hdr->nlmsg_type == NLMSG_ERROR); + + struct snl_errmsg_data e = {}; + ATF_CHECK(rx_hdr->nlmsg_len == sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr)); + ATF_CHECK(snl_parse_errmsg(&ss, rx_hdr, &e)); + ATF_CHECK(e.error != 0); + ATF_CHECK(!memcmp(hdr, e.orig_hdr, sizeof(struct nlmsghdr))); +} + +ATF_TC(snl_parse_errmsg_capped_extack); +ATF_TC_HEAD(snl_parse_errmsg_capped_extack, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests snl(3) correctly parsing capped errors with extack"); +} + +ATF_TC_BODY(snl_parse_errmsg_capped_extack, tc) +{ + struct snl_state ss; + struct snl_writer nw; + + require_netlink(); + + if (!snl_init(&ss, NETLINK_ROUTE)) + atf_tc_fail("snl_init() failed"); + + int optval = 1; + ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_CAP_ACK, &optval, sizeof(optval)) == 0); + optval = 1; + ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval, sizeof(optval)) == 0); + + snl_init_writer(&ss, &nw); + + struct nlmsghdr *hdr = snl_create_msg_request(&nw, 255); + ATF_CHECK(hdr != NULL); + ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL); + snl_add_msg_attr_string(&nw, 143, "some random string"); + ATF_CHECK(snl_finalize_msg(&nw) != NULL); + + ATF_CHECK(snl_send_message(&ss, hdr)); + + struct nlmsghdr *rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq); + ATF_CHECK(rx_hdr != NULL); + ATF_CHECK(rx_hdr->nlmsg_type == NLMSG_ERROR); + + struct snl_errmsg_data e = {}; + ATF_CHECK(snl_parse_errmsg(&ss, rx_hdr, &e)); + ATF_CHECK(e.error != 0); + ATF_CHECK(!memcmp(hdr, e.orig_hdr, sizeof(struct nlmsghdr))); + + ATF_CHECK(e.error_str != NULL); +} + +ATF_TC(snl_parse_errmsg_uncapped_extack); +ATF_TC_HEAD(snl_parse_errmsg_uncapped_extack, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests snl(3) correctly parsing errors with extack"); +} + +ATF_TC_BODY(snl_parse_errmsg_uncapped_extack, tc) +{ + struct snl_state ss; + struct snl_writer nw; + + require_netlink(); + + ATF_CHECK(snl_init(&ss, NETLINK_ROUTE)); + + int optval = 1; + ATF_CHECK(setsockopt(ss.fd, SOL_NETLINK, NETLINK_EXT_ACK, &optval, sizeof(optval)) == 0); + + snl_init_writer(&ss, &nw); + + struct nlmsghdr *hdr = snl_create_msg_request(&nw, 255); + ATF_CHECK(hdr != NULL); + ATF_CHECK(snl_reserve_msg_object(&nw, struct ifinfomsg) != NULL); + snl_add_msg_attr_string(&nw, 143, "some random string"); + ATF_CHECK(snl_finalize_msg(&nw) != NULL); + + ATF_CHECK(snl_send_message(&ss, hdr)); + + struct nlmsghdr *rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq); + ATF_CHECK(rx_hdr != NULL); + ATF_CHECK(rx_hdr->nlmsg_type == NLMSG_ERROR); + + struct snl_errmsg_data e = {}; + ATF_CHECK(snl_parse_errmsg(&ss, rx_hdr, &e)); + ATF_CHECK(e.error != 0); + ATF_CHECK(!memcmp(hdr, e.orig_hdr, hdr->nlmsg_len)); + + ATF_CHECK(e.error_str != NULL); +} + ATF_TC(snl_list_ifaces); ATF_TC_HEAD(snl_list_ifaces, tc) { @@ -105,6 +228,9 @@ ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, snl_verify_core_parsers); ATF_TP_ADD_TC(tp, snl_verify_route_parsers); + ATF_TP_ADD_TC(tp, snl_parse_errmsg_capped); + ATF_TP_ADD_TC(tp, snl_parse_errmsg_capped_extack); + ATF_TP_ADD_TC(tp, snl_parse_errmsg_uncapped_extack); ATF_TP_ADD_TC(tp, snl_list_ifaces); return (atf_no_error());