Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:bird2
User: [email protected]
Usertags: pu

Upstream released a new bug fixes only release targeting stable.

It contains multiple bug fixes, detailed in the NEWS file, which solve 
actual reliability issues.
Future upstream releases with security updates will be based on this 
release.

git diff debian/2.17.5-0+deb13u1..debian/bird2/trixie 
':(exclude).gitlab-ci.yml' ':(exclude)gitlab/'

diff --git a/NEWS b/NEWS
index d420203e4..52c28ba5c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+Version 2.17.6 (2026-07-30)
+  o BGP: Fix stack buffer overflow in Flowspec NLRI decoder
+  o BGP: Minor improvements in Flowspec parsing
+  o BGP: Fix minor issues with send hold timer
+  o Fix null byte handling in authentication keys
+  o Filter: Fix zero arg handling
+  o Update bird-users mailing list links
+
 Version 2.17.5 (2026-06-09)
   o BGP: Fix several issues in Flowspec handling
   o BMP: Fix off-by-one buffer overflow
diff --git a/README b/README
index 75a4281f1..9edadb033 100644
--- a/README
+++ b/README
@@ -71,8 +71,8 @@ around to see what's going to develop, feel free to subscribe 
to the BIRD
 users mailing list [email protected], just send `subscribe' to
 [email protected].
 
-Subscribe:     http://bird.network.cz/mailman/listinfo/bird-users/
-Archive:       http://bird.network.cz/pipermail/bird-users/
+Subscribe:     https://bird.nic.cz/lists/bird-users/
+Archive:       https://bird.nic.cz/lists/bird-users/archive/
 
 Please don't send security issues to the mailing-list, contact us instead at
 [email protected] which is a private e-mail address where you also can
diff --git a/VERSION b/VERSION
index 00db22659..728789a53 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.17.5
+2.17.6
diff --git a/conf/flowspec.Y b/conf/flowspec.Y
index 3b71e3ff9..d073a1204 100644
--- a/conf/flowspec.Y
+++ b/conf/flowspec.Y
@@ -59,7 +59,7 @@ flow_num_type_:
  | ICMP CODE   { $$ = FLOW_TYPE_ICMP_CODE; }
  | LENGTH      { $$ = FLOW_TYPE_PACKET_LENGTH; }
  | DSCP                { $$ = FLOW_TYPE_DSCP; }
- | LABEL       { $$ = FLOW_TYPE_LABEL; }
+ | LABEL       { $$ = FLOW_TYPE_LABEL; if (!this_flow->ipv6) cf_error("Flow 
label not valid in flow4"); }
  ;
 
 flow_num_type: flow_num_type_{ flow_builder_set_type(this_flow, $1); };
@@ -123,7 +123,7 @@ flow_neg:
  ;
 
 flow_frag_val:
-   DONT_FRAGMENT  { $$ = 1; }
+   DONT_FRAGMENT  { $$ = 1; if (this_flow->ipv6) cf_error("Flag dont_fragment 
not valid in flow6"); }
  | IS_FRAGMENT   { $$ = 2; }
  | FIRST_FRAGMENT { $$ = 4; }
  | LAST_FRAGMENT  { $$ = 8; }
diff --git a/debian/changelog b/debian/changelog
index ec7bbb15e..b72808706 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+bird2 (2.17.6-0+deb13u1) stable; urgency=medium
+
+  * New upstream release.
+
+ -- Marco d'Itri <[email protected]>  Sun, 02 Aug 2026 05:32:37 +0200
+
 bird2 (2.17.5-0+deb13u1) trixie-security; urgency=medium
 
   * New upstream release.
diff --git a/debian/watch b/debian/watch
index cec2d6646..4c8198618 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,2 +1,2 @@
 version=4
-https://bird.network.cz/download/bird-(2\.[\d.]+).tar.gz
+https://bird.nic.cz/download/ bird-(2\.[\d.]+).tar.gz
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 7277b7525..f9c540286 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -6717,7 +6717,7 @@ versions of BIRD:
 (<HTMLURL URL="mailto:[email protected]"; name="[email protected]">)
 where you can share your experiences with the other users and consult
 your problems with the authors. To subscribe to the list, visit
-<HTMLURL URL="https://bird.network.cz/mailman/listinfo/bird-users"; 
name="https://bird.network.cz/mailman/listinfo/bird-users";>.
+<HTMLURL URL="https://bird.nic.cz/lists/bird-users/"; 
name="https://bird.nic.cz/lists/bird-users/";>.
 The home page of BIRD can be found at <HTMLURL URL="http://bird.nic.cz/"; 
name="http://bird.nic.cz/";>.
 
 <p>BIRD is a relatively young system and it probably contains some bugs. You 
can
diff --git a/filter/filter.c b/filter/filter.c
index f17de58c2..1c9b5dbcf 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -170,7 +170,7 @@ interpret(struct filter_state *fs, const struct f_line 
*line, uint argc, const s
 
   /* Set the arguments and top-level variables */
   fstk->vcnt = line->vars + line->args;
-  memcpy(fstk->vstk, argv, sizeof(struct f_val) * line->args);
+  bmemcpy(fstk->vstk, argv, sizeof(struct f_val) * line->args);
   memset(fstk->vstk + line->args, 0, sizeof(struct f_val) * line->vars);
 
   /* The same as with the value stack. Not resetting the stack completely for 
performance reasons. */
diff --git a/lib/flowspec.c b/lib/flowspec.c
index c534054fa..343c296bc 100644
--- a/lib/flowspec.c
+++ b/lib/flowspec.c
@@ -350,17 +350,17 @@ static const u8 flow_max_value_length[FLOW_TYPE_MAX] = {
   [FLOW_TYPE_FRAGMENT]         = 1,
 };
 
-/* Maximum valid numeric values (in bytes), semantically */
+/* Maximum valid numeric values (in bits), semantically */
 static const u8 flow_max_valid_value[FLOW_TYPE_MAX] = {
-  [FLOW_TYPE_IP_PROTOCOL]      = 1,
-  [FLOW_TYPE_PORT]             = 2,
-  [FLOW_TYPE_DST_PORT]         = 2,
-  [FLOW_TYPE_SRC_PORT]         = 2,
-  [FLOW_TYPE_ICMP_TYPE]                = 1,
-  [FLOW_TYPE_ICMP_CODE]                = 1,
-  [FLOW_TYPE_PACKET_LENGTH]    = 2,
-  [FLOW_TYPE_DSCP]             = 1,
-  [FLOW_TYPE_LABEL]            = 4,
+  [FLOW_TYPE_IP_PROTOCOL]      = 8,
+  [FLOW_TYPE_PORT]             = 16,
+  [FLOW_TYPE_DST_PORT]         = 16,
+  [FLOW_TYPE_SRC_PORT]         = 16,
+  [FLOW_TYPE_ICMP_TYPE]                = 8,
+  [FLOW_TYPE_ICMP_CODE]                = 8,
+  [FLOW_TYPE_PACKET_LENGTH]    = 16,
+  [FLOW_TYPE_DSCP]             = 6,
+  [FLOW_TYPE_LABEL]            = 20,
 };
 
 /**
@@ -405,16 +405,10 @@ void
 flow_check_cf_numeric_arg(struct flow_builder *fb, uint val)
 {
   enum flow_type t = fb->this_type;
-  uint max = flow_max_valid_value[t];
+  u64 max = (U64(1) << flow_max_valid_value[t]) - 1;
 
-  if (t == FLOW_TYPE_DSCP && val > 0x3f)
-    cf_error("%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), 
val);
-
-  if (max == 1 && (val > 0xff))
-    cf_error("%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), 
val);
-
-  if (max == 2 && (val > 0xffff))
-    cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), 
val);
+  if (max && (val > max))
+    cf_error("%s value %u out of range (0-%lu)", flow_type_str(t, fb->ipv6), 
val, max);
 }
 
 /* Bitmask of padding bits in last byte of prefix */
diff --git a/lib/string.h b/lib/string.h
index 8831666c7..736ca57f5 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -94,6 +94,14 @@ bmemcpy(void *dest, const void *src, size_t n)
     return dest;
 }
 
+static inline void *
+memcpy0(void *dst, const void *src, size_t dst_len, size_t src_len)
+{
+  memset(dst, 0, dst_len);
+  memcpy(dst, src, MIN_(dst_len, src_len));
+  return dst;
+}
+
 #define ROUTER_ID_64_LENGTH 23
 
 #endif
diff --git a/nest/password.h b/nest/password.h
index 53168bb7c..e3251a31e 100644
--- a/nest/password.h
+++ b/nest/password.h
@@ -26,10 +26,10 @@ struct password_item *password_find_by_id(list *l, uint id);
 struct password_item *password_find_by_value(list *l, char *pass, uint size);
 void password_validate_length(const struct password_item *p);
 
-static inline int password_verify(struct password_item *p1, char *p2, uint 
size)
+static inline int password_verify(const struct password_item *p1, const char 
*p2, uint size)
 {
   char buf[size];
-  strncpy(buf, p1->password, size);
+  memcpy0(buf, p1->password, size, p1->length);
   return !memcmp(buf, p2, size);
 }
 
diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c
index 6097bcae5..2ed6a9f25 100644
--- a/proto/bfd/packets.c
+++ b/proto/bfd/packets.c
@@ -148,7 +148,7 @@ bfd_fill_authentication(struct bfd_proto *p, struct 
bfd_session *s, struct bfd_c
   {
     struct bfd_crypto_auth *auth = (void *) (pkt + 1);
     uint hash_alg = bfd_auth_type_to_hash_alg[cf->auth_type];
-    uint hash_len = mac_type_length(pass->alg);
+    uint hash_len = mac_type_length(hash_alg);
 
     /* Increase CSN about one time per second */
     u32 new_time = (u64) current_time() >> 20;
@@ -169,7 +169,8 @@ bfd_fill_authentication(struct bfd_proto *p, struct 
bfd_session *s, struct bfd_c
     pkt->flags |= BFD_FLAG_AP;
     pkt->length += auth->length;
 
-    strncpy(auth->data, pass->password, hash_len);
+    memcpy0(auth->data, pass->password, hash_len, pass->length);
+
     mac_fill(hash_alg, NULL, 0, (byte *) pkt, pkt->length, auth->data);
     return;
   }
@@ -262,7 +263,7 @@ bfd_check_authentication(struct bfd_proto *p, struct 
bfd_session *s, struct bfd_
 
     byte *auth_data = alloca(hash_len);
     memcpy(auth_data, auth->data, hash_len);
-    strncpy(auth->data, pass->password, hash_len);
+    memcpy0(auth->data, pass->password, hash_len, pass->length);
 
     if (!mac_verify(hash_alg, NULL, 0, (byte *) pkt, pkt->length, auth_data))
       DROP("wrong authentication code", pass->id);
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 818edeeba..29833c1e7 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -2587,6 +2587,9 @@ bgp_postconfig(struct proto_config *CF)
   if (cf->keepalive_time > (cf->hold_time / 2))
     log(L_WARN "Keepalive time should be at most 1/2 of hold time");
 
+  if ((cf->send_hold_time > 0) && (cf->send_hold_time < cf->hold_time))
+    cf_error("Send hold time must be zero or at least hold time");
+
   if (cf->min_hold_time > cf->hold_time)
     cf_error("Min hold time (%u) exceeds hold time (%u)",
             cf->min_hold_time, cf->hold_time);
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index b345283e0..232155ee4 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -922,12 +922,14 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
 
   /* Compute effective hold and keepalive times */
   uint hold_time = MIN(hold, p->cf->hold_time);
+  uint base_hold_time = p->cf->hold_time ?: 1;
+
   uint keepalive_time = p->cf->keepalive_time ?
-    (p->cf->keepalive_time * hold_time / p->cf->hold_time) :
+    (p->cf->keepalive_time * hold_time / base_hold_time) :
     hold_time / 3;
 
   uint send_hold_time = (p->cf->send_hold_time >= 0) ?
-    (p->cf->send_hold_time * hold_time / p->cf->hold_time) :
+    ((u64) p->cf->send_hold_time * hold_time / base_hold_time) :
     2 * hold_time;
 
   /* Keepalive time might be rounded down to zero */
@@ -2104,7 +2106,7 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte 
*pos, uint len, rta *a)
     uint pxlen = 0;
 
     /* Decode dst prefix */
-    if (data[0] == FLOW_TYPE_DST_PREFIX)
+    if (dlen && (data[0] == FLOW_TYPE_DST_PREFIX))
     {
       px = flow_read_ip4_part(data);
       pxlen = flow_read_pxlen(data);
@@ -2199,7 +2201,7 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte 
*pos, uint len, rta *a)
     uint pxlen = 0;
 
     /* Decode dst prefix */
-    if (data[0] == FLOW_TYPE_DST_PREFIX)
+    if (dlen && (data[0] == FLOW_TYPE_DST_PREFIX))
     {
       px = flow_read_ip6_part(data);
       pxlen = flow_read_pxlen(data);
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 1c9aafa4f..9104f9fc9 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -64,7 +64,8 @@ ospf_pkt_finalize2(struct ospf_iface *ifa, struct ospf_packet 
*pkt, uint *plen)
       log(L_ERR "No suitable password found for authentication");
       return;
     }
-    strncpy(auth->password, pass->password, sizeof(auth->password));
+    memcpy0(auth->password, pass->password, sizeof(auth->password), 
pass->length);
+
     /* fallthrough */
 
   case OSPF_AUTH_NONE:
@@ -111,7 +112,7 @@ ospf_pkt_finalize2(struct ospf_iface *ifa, struct 
ospf_packet *pkt, uint *plen)
 
     /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */
     if (pass->alg < ALG_HMAC)
-      strncpy(auth_tail, pass->password, auth_len);
+      memcpy0(auth_tail, pass->password, auth_len, pass->length);
     else
       memset32(auth_tail, HMAC_MAGIC, auth_len / 4);
 
@@ -235,7 +236,7 @@ ospf_pkt_checkauth2(struct ospf_neighbor *n, struct 
ospf_iface *ifa, struct ospf
 
     /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */
     if (pass->alg < ALG_HMAC)
-      strncpy(auth_tail, pass->password, auth_len);
+      memcpy0(auth_tail, pass->password, auth_len, pass->length);
     else
       memset32(auth_tail, HMAC_MAGIC, auth_len / 4);
 
diff --git a/proto/rip/packets.c b/proto/rip/packets.c
index 9c3bd7a3b..7eaa30f38 100644
--- a/proto/rip/packets.c
+++ b/proto/rip/packets.c
@@ -274,7 +274,7 @@ rip_fill_authentication(struct rip_proto *p, struct 
rip_iface *ifa, struct rip_p
   case RIP_AUTH_PLAIN:
     auth->must_be_ffff = htons(0xffff);
     auth->auth_type = htons(RIP_AUTH_PLAIN);
-    strncpy(auth->password, pass->password, RIP_PASSWD_LENGTH);
+    memcpy0(auth->password, pass->password, sizeof(auth->password), 
pass->length);
     return;
 
   case RIP_AUTH_CRYPTO:
@@ -313,7 +313,7 @@ rip_fill_authentication(struct rip_proto *p, struct 
rip_iface *ifa, struct rip_p
 
     /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
     if (pass->alg < ALG_HMAC)
-      strncpy(tail->auth_data, pass->password, auth_len);
+      memcpy0(tail->auth_data, pass->password, auth_len, pass->length);
     else
       memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4);
 
@@ -402,7 +402,7 @@ rip_check_authentication(struct rip_proto *p, struct 
rip_iface *ifa, struct rip_
 
     /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
     if (pass->alg < ALG_HMAC)
-      strncpy(tail->auth_data, pass->password, auth_len);
+      memcpy0(tail->auth_data, pass->password, auth_len, pass->length);
     else
       memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4);
 

-- 
ciao,
Marco

Attachment: signature.asc
Description: PGP signature

Reply via email to