From 70efac04ab3034e729e6d42c2c2d7f5687f98fb2 Mon Sep 17 00:00:00 2001 From: Clemens Famulla-Conrad Date: Tue, 18 Nov 2025 12:12:28 +0100 Subject: [PATCH] bsc#1236353 (CVE-2025-0650) ovn: egress ACLs may be bypassed via specially crafted UDP packet Reference: bsc#1236353 Upstream: 4140fead049ecef6a6b0f90e74f5de7d5a40fd5d Backported upstream fix 4140fead0 without tests. --- [PATCH 1/1] Skip only OVN DNS responder packets from OUT_ACL. When OVN's DNS caching feature is enabled, due to the OpenFlow rules that OVN installs in Open vSwitch, it is possible for an attacker to craft a UDP packet that can bypass egress ACL rules configured on the same switch that has DNS caching configured. This patch fixes the issue by setting a register bit when OVN's DNS responder replies to an incoming request. Then the flow that allows egress ACL bypass only applies to packets that have this register bit set. This gives the intended effect of allowing internally-generated DNS responses to not be blocked by user-defined ACLs without potentially compromising the security of the switch. Signed-off-by: Numan Siddique Signed-off-by: Mark Michelson Acked-by: Dumitru Ceara --- controller/pinctrl.c | 27 +++++++++++++++++++++++++++ include/ovn/logical-fields.h | 1 + lib/logical-fields.c | 3 +++ northd/northd.c | 3 ++- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 633b73d6a..1e08bb6b9 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -383,6 +383,8 @@ static void pinctrl_handle_put_fdb(const struct flow *md, const struct flow *headers) OVS_REQUIRES(pinctrl_mutex); +static void set_from_ctrl_flag_in_pkt_metadata(struct ofputil_packet_in *); + COVERAGE_DEFINE(pinctrl_drop_put_mac_binding); COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map); COVERAGE_DEFINE(pinctrl_drop_controller_event); @@ -3203,6 +3205,10 @@ exit: union mf_subvalue sv; sv.u8_val = success; mf_write_subfield(&dst, &sv, &pin->flow_metadata); + + /* Indicate that this packet is from ovn-controller. */ + set_from_ctrl_flag_in_pkt_metadata(pin); + } queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto)); dp_packet_uninit(pkt_out_ptr); @@ -8366,3 +8372,24 @@ pinctrl_handle_put_fdb(const struct flow *md, const struct flow *headers) ovn_fdb_add(&put_fdbs, dp_key, headers->dl_src, port_key); notify_pinctrl_main(); } + +/* This function sets the register bit 'MLF_FROM_CTRL_BIT' + * in the register 'MFF_LOG_FLAGS' to indicate that this packet + * is generated/sent by ovn-controller. + * ovn-northd can add logical flows to match on "flags.from_ctrl". + */ +static void +set_from_ctrl_flag_in_pkt_metadata(struct ofputil_packet_in *pin) +{ + const struct mf_field *f = mf_from_id(MFF_LOG_FLAGS); + + struct mf_subfield dst = { + .field = f, + .ofs = MLF_FROM_CTRL_BIT, + .n_bits = 1, + }; + + union mf_subvalue sv; + sv.u8_val = 1; + mf_write_subfield(&dst, &sv, &pin->flow_metadata); +} diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h index 272277ec4..2770705e3 100644 --- a/include/ovn/logical-fields.h +++ b/include/ovn/logical-fields.h @@ -78,6 +78,7 @@ enum mff_log_flags_bits { MLF_LOOKUP_COMMIT_ECMP_NH_BIT = 13, MLF_USE_LB_AFF_SESSION_BIT = 14, MLF_LOCALNET_BIT = 15, + MLF_FROM_CTRL_BIT = 16, }; /* MFF_LOG_FLAGS_REG flag assignments */ diff --git a/lib/logical-fields.c b/lib/logical-fields.c index 7a1e66d0a..4069e6a82 100644 --- a/lib/logical-fields.c +++ b/lib/logical-fields.c @@ -134,6 +134,9 @@ ovn_init_symtab(struct shash *symtab) expr_symtab_add_subfield(symtab, "flags.localnet", NULL, flags_str); + snprintf(flags_str, sizeof flags_str, "flags[%d]", MLF_FROM_CTRL_BIT); + expr_symtab_add_subfield(symtab, "flags.from_ctrl", NULL, flags_str); + /* Connection tracking state. */ expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false, WR_CT_COMMIT); diff --git a/northd/northd.c b/northd/northd.c index 39b5d5ccb..dc67779f9 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -6979,7 +6979,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, if (ls_has_dns_records(od->nbs)) { const char *dns_actions = has_stateful ? "ct_commit; next;" : "next;"; ovn_lflow_add( - lflows, od, S_SWITCH_OUT_ACL, 34000, "udp.src == 53", + lflows, od, S_SWITCH_OUT_ACL, 34000, + "flags.from_ctrl && udp.src == 53", dns_actions); } -- 2.51.0