summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYi Zhao <yi.zhao@windriver.com>2026-04-23 09:48:19 +0800
committerKhem Raj <khem.raj@oss.qualcomm.com>2026-04-23 07:54:07 -0700
commitecaeb93da324bb582936db13729b1017a9560730 (patch)
treec595f04a4bee61645cd3c5fa4cef80218fbe66ca
parent41a7fe71a7444dc073fa6afb99971367d2ade010 (diff)
downloadmeta-openembedded-ecaeb93da324bb582936db13729b1017a9560730.tar.gz
frr: fix mgmtd crash on ARM32
Backport fix[1] for MGMT crash on first start on ARM32 platforms[2]. [1] https://github.com/FRRouting/frr/pull/21651 [2] https://github.com/FRRouting/frr/issues/20087 Signed-off-by: Yi Zhao <yi.zhao@windriver.com> Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
-rw-r--r--meta-networking/recipes-protocols/frr/frr/0001-lib-fix-mgmt_msg-recv-to-deal-with-mis-alignment.patch352
-rw-r--r--meta-networking/recipes-protocols/frr/frr_10.6.1.bb1
2 files changed, 353 insertions, 0 deletions
diff --git a/meta-networking/recipes-protocols/frr/frr/0001-lib-fix-mgmt_msg-recv-to-deal-with-mis-alignment.patch b/meta-networking/recipes-protocols/frr/frr/0001-lib-fix-mgmt_msg-recv-to-deal-with-mis-alignment.patch
new file mode 100644
index 0000000000..22cc10cf31
--- /dev/null
+++ b/meta-networking/recipes-protocols/frr/frr/0001-lib-fix-mgmt_msg-recv-to-deal-with-mis-alignment.patch
@@ -0,0 +1,352 @@
1From 5959a3d0cbc73b0c41134bf0d9944a6bd40ba510 Mon Sep 17 00:00:00 2001
2From: Christian Hopps <chopps@labn.net>
3Date: Sat, 18 Apr 2026 03:01:46 +0000
4Subject: [PATCH] lib: fix mgmt_msg recv to deal with mis-alignment
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9We need our messages to start on 64 bit boundaries as the message buffer
10is accessed directly as structured data. In particular on ARM32 arch
11using the data this way lead to unaligned access and SIGBUS.
12
13The minor optimization of reading multiple messages into a single stream
14buffer complicated this. Instead we KISS and switch to one message per
15stream buffer.
16
17Fixes #20087.
18
19Signed-off-by: Christian Hopps <chopps@labn.net>
20Co-developed-by: Samir MOUHOUNE <samir.mouhoune@nav-timing.safrangroup.com>
21Co-developed-by: Alexis Lothoré <alexis.lothore@bootlin.com>
22
23See also PR #20985
24
25This issue was identified and another solution was provided by Samir
26MOUHOUNE with the following commit message comments:
27
28On ARM32 systems, mgmtd crashes at startup on an alignment fault:
29
30```
31 frrinit.sh[158]: Starting watchfrr with command: ' /usr/sbin/watchfrr -d mgmtd zebra staticd'
32 watchfrr[168]: [T83RR-8SM5G] watchfrr 10.5.2 starting: vty@0
33 watchfrr[168]: [ZCJ3S-SPH5S] mgmtd state -> down : initial connection attempt failed
34 watchfrr[168]: [ZCJ3S-SPH5S] zebra state -> down : initial connection attempt failed
35 watchfrr[168]: [ZCJ3S-SPH5S] staticd state -> down : initial connection attempt failed
36 watchfrr[168]: [YFT0P-5Q5YX] Forked background command [pid 169]: /usr/sbin/watchfrr.sh restart all
37 frrinit.sh[180]: 2026/02/27 09:14:13 ZEBRA: [KGY44-D47GD][EC 4043309111] Disabling MPLS support (no kernel support)
38 watchfrr[168]: [QDG3Y-BY5TN] zebra state -> up : connect succeeded
39 kernel: Alignment trap: not handling instruction edc30b02 at [<004c3c1c>]
40 kernel: 8<--- cut here ---
41 kernel: Unhandled fault: alignment exception (0x801) at 0x008879f6
42 kernel: [008879f6] *pgd=9baf6831
43 watchfrr[168]: [YFT0P-5Q5YX] Forked background command [pid 189]: /usr/sbin/watchfrr.sh restart mgmtd
44 frrinit.sh[189]: Cannot stop mgmtd: pid 179 not running
45 watchfrr.sh[196]: Cannot stop mgmtd: pid 179 not running
46 frrinit.sh[202]: [202|zebra] sending configuration
47 frrinit.sh[202]: [202|zebra] done
48 frrinit.sh[216]: [216|watchfrr] sending configuration
49 frrinit.sh[218]: [218|staticd] sending configuration
50 watchfrr[168]: [VTVCM-Y2NW3] Configuration Read in Took: 00:00:00
51 frrinit.sh[199]: Waiting for children to finish applying config...
52 frrinit.sh[216]: [216|watchfrr] done
53```
54
55When checking crashlogs in /var/tmp/frr, mgmt gives the following:
56
57```
58 MGMTD: Received signal 7 at 1772183653 (si_addr 0x8879f6); aborting...
59 MGMTD: /lib/libfrr.so.0(zlog_backtrace_sigsafe+0x5c) [0xb6e89c90]
60 MGMTD: /lib/libfrr.so.0(zlog_signal+0xe0) [0xb6e89e80]
61 MGMTD: /lib/libfrr.so.0(+0xd4374) [0xb6ed3374]
62 MGMTD: /lib/libc.so.6(__default_rt_sa_restorer+0) [0xb6ab4d90]
63 MGMTD: /usr/sbin/mgmtd(mgmt_fe_adapter_send_notify+0x6b8) [0x4c3c20]
64 MGMTD: /lib/libfrr.so.0(mgmt_msg_procbufs+0x124) [0xb6e976b8]
65 MGMTD: /lib/libfrr.so.0(+0x98798) [0xb6e97798]
66 MGMTD: /lib/libfrr.so.0(event_call+0xa8) [0xb6ee739c]
67 MGMTD: /lib/libfrr.so.0(frr_run+0xd4) [0xb6e80fc8]
68 MGMTD: /usr/sbin/mgmtd(main+0x188) [0x4bd7ec]
69 MGMTD: /lib/libc.so.6(+0x236b0) [0xb6a9f6b0]
70 MGMTD: /lib/libc.so.6(__libc_start_main+0x98) [0xb6a9f790]
71 MGMTD: in thread msg_conn_proc_msgs scheduled from lib/mgmt_msg.c:543 msg_conn_sched_proc_msgs()
72```
73
74The issue is that messages are queued for sending/receive back-to-back
75with no padding. This means that when mgmt creates a pointer back to the
76data waiting in queue and tries to access fields inside the dereferenced
77message, those accesses are not performed with the alignment constraints
78required by some architectures. For example, ARM ABI AAPCS32 ([1])
79states that structures alignment should be the same as the "most
80aligned" member; so a struct mgmt_msg_header, which contains some
81uint64_t fields (which are 8-bytes alignes), should be 8-bytes aligned
82as well.
83
84On x86, this goes unnoticed because the CPU handles unaligned access
85transparently. On ARM 32-bit with NEON/VFP, the compiler generates
8664-bit store instructions that trap on unaligned addresses. The kernel
87cannot emulate these instructions and kills the process with SIGBUS.
88
89[1] https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#data-types-and-alignment
90
91Upstream-Status: Backport [https://github.com/FRRouting/frr/commit/5959a3d0cbc73b0c41134bf0d9944a6bd40ba510]
92
93Signed-off-by: Christian Hopps <chopps@labn.net>
94(cherry picked from commit ae7d79f8ff25d5750e5796567ff6317030900d40)
95Signed-off-by: Yi Zhao <yi.zhao@windriver.com>
96---
97 lib/mgmt_be_client.h | 3 +-
98 lib/mgmt_fe_client.h | 3 +-
99 lib/mgmt_msg.c | 157 ++++++++++++++++++-------------------------
100 3 files changed, 68 insertions(+), 95 deletions(-)
101
102diff --git a/lib/mgmt_be_client.h b/lib/mgmt_be_client.h
103index f5627e3c4e..2f412a6fbd 100644
104--- a/lib/mgmt_be_client.h
105+++ b/lib/mgmt_be_client.h
106@@ -21,7 +21,8 @@ extern "C" {
107
108 #define MGMTD_BE_MAX_NUM_MSG_PROC 500
109 #define MGMTD_BE_MAX_NUM_MSG_WRITE 1000
110-#define MGMTD_BE_MAX_MSG_LEN (64 * 1024)
111+/* Messages can be any size, this is just the preallocated buffer size */
112+#define MGMTD_BE_MAX_MSG_LEN (4 * 1024)
113
114 #define MGMTD_BE_CONTAINER_NODE_VAL "<<container>>"
115
116diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
117index 8ff08b566a..3005c5dd01 100644
118--- a/lib/mgmt_fe_client.h
119+++ b/lib/mgmt_fe_client.h
120@@ -29,7 +29,8 @@ extern "C" {
121
122 #define MGMTD_FE_MAX_NUM_MSG_PROC 500
123 #define MGMTD_FE_MAX_NUM_MSG_WRITE 100
124-#define MGMTD_FE_MAX_MSG_LEN (64 * 1024)
125+/* Messages can be any size, this is just the preallocated buffer size */
126+#define MGMTD_FE_MAX_MSG_LEN (4 * 1024)
127
128 /***************************************************************
129 * Data-structures
130diff --git a/lib/mgmt_msg.c b/lib/mgmt_msg.c
131index f299b52873..fb56f58ab5 100644
132--- a/lib/mgmt_msg.c
133+++ b/lib/mgmt_msg.c
134@@ -13,6 +13,7 @@
135 #include "network.h"
136 #include "sockopt.h"
137 #include "stream.h"
138+#include "zlog.h"
139 #include "frrevent.h"
140 #include "mgmt_msg.h"
141 #include "mgmt_msg_native.h"
142@@ -39,8 +40,8 @@ static bool trace;
143 DEFINE_MTYPE(LIB, MSG_CONN, "msg connection state");
144
145 /**
146- * Read data from a socket into streams containing 1 or more full msgs headed by
147- * mgmt_msg_hdr which contain API messages (currently protobuf).
148+ * Read data from a socket into a stream containing 1 full msg headed by
149+ * mgmt_msg_hdr.
150 *
151 * Args:
152 * ms: mgmt_msg_state for this process.
153@@ -57,96 +58,80 @@ enum mgmt_msg_rsched mgmt_msg_read(struct mgmt_msg_state *ms, int fd,
154 bool debug)
155 {
156 const char *dbgtag = debug ? ms->idtag : NULL;
157- size_t avail = STREAM_WRITEABLE(ms->ins);
158 struct mgmt_msg_hdr *mhdr = NULL;
159- size_t total = 0;
160- size_t mcount = 0;
161- ssize_t n, left;
162+ struct stream *news;
163+ size_t nread;
164+ ssize_t n;
165
166 assert(ms && fd != -1);
167- MGMT_MSG_TRACE(dbgtag, "enter with %zu bytes available to read on fd %d", avail, fd);
168+ MGMT_MSG_TRACE(dbgtag, "enter to read from fd %d", fd);
169+
170+ assert(stream_get_getp(ms->ins) == 0);
171+ nread = stream_get_endp(ms->ins);
172
173 /*
174- * Read as much as we can into the stream.
175+ * Get header, validate, and resize the stream, if needed, to fit incoming message.
176 */
177- while (avail > sizeof(struct mgmt_msg_hdr)) {
178- n = stream_read_try(ms->ins, fd, avail);
179-
180- /* -2 is normal nothing read, and to retry */
181- if (n == -2) {
182- MGMT_MSG_TRACE(dbgtag, "nothing more to read on fd %d", fd);
183- break;
184- }
185- if (n <= 0) {
186- if (n == 0)
187- MGMT_MSG_ERR(ms, "got EOF/disconnect on fd %d", fd);
188- else
189- MGMT_MSG_ERR(ms, "got error while reading on fd %d: '%s'", fd,
190- safe_strerror(errno));
191- return MSR_DISCONNECT;
192+ if (nread < sizeof(struct mgmt_msg_hdr)) {
193+ while (nread < sizeof(struct mgmt_msg_hdr)) {
194+ n = stream_read_try(ms->ins, fd, sizeof(struct mgmt_msg_hdr) - nread);
195+ if (n <= 0)
196+ goto not_done;
197+ nread += n;
198+ ms->nrxb += n;
199 }
200- MGMT_MSG_TRACE(dbgtag, "read %zd bytes on fd %d", n, fd);
201- ms->nrxb += n;
202- avail -= n;
203- }
204
205- /*
206- * Check if we have read a complete messages or not.
207- */
208- assert(stream_get_getp(ms->ins) == 0);
209- left = stream_get_endp(ms->ins);
210- while (left > (ssize_t)sizeof(struct mgmt_msg_hdr)) {
211- mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(ms->ins) + total);
212+ /* Validate the header is sane */
213+ mhdr = (struct mgmt_msg_hdr *)STREAM_DATA(ms->ins);
214 if (!MGMT_MSG_IS_MARKER(mhdr->marker)) {
215 MGMT_MSG_DBG(dbgtag, "recv corrupt buffer on fd %d, disconnect", fd);
216 return MSR_DISCONNECT;
217+ } else if (mhdr->len <= sizeof(struct mgmt_msg_hdr)) {
218+ MGMT_MSG_DBG(dbgtag, "recv invalid message length %u on fd %d, disconnect",
219+ mhdr->len, fd);
220+ return MSR_DISCONNECT;
221 }
222- if ((ssize_t)mhdr->len > left)
223- break;
224-
225- MGMT_MSG_TRACE(dbgtag, "read full message on fd %d len %u", fd, mhdr->len);
226- total += mhdr->len;
227- left -= mhdr->len;
228- mcount++;
229- }
230
231- if (!mcount) {
232- /* Didn't manage to read a full message */
233- if (mhdr && avail == 0) {
234- struct stream *news;
235- /*
236- * Message was longer than what was left and we have no
237- * available space to read more in. B/c mcount == 0 the
238- * message starts at the beginning of the stream so
239- * therefor the stream is too small to fit the message..
240- * Resize the stream to fit.
241- */
242+ /* See if message will fit in the stream, realloc if not */
243+ if (mhdr->len > ms->ins->size) {
244+ MGMT_MSG_DBG(dbgtag,
245+ "message length %u is greater than available %zu on fd %d",
246+ mhdr->len, ms->ins->size, fd);
247 news = stream_new(mhdr->len);
248- stream_put(news, mhdr, left);
249- stream_set_endp(news, left);
250+ stream_put(news, mhdr, sizeof(struct mgmt_msg_hdr));
251 stream_free(ms->ins);
252 ms->ins = news;
253 }
254- return MSR_SCHED_STREAM;
255 }
256
257- /*
258- * We have read at least one message into the stream, queue it up.
259- */
260- mhdr = (struct mgmt_msg_hdr *)(STREAM_DATA(ms->ins) + total);
261- stream_set_endp(ms->ins, total);
262- stream_fifo_push(&ms->inq, ms->ins);
263- if (left < (ssize_t)sizeof(struct mgmt_msg_hdr))
264- ms->ins = stream_new(ms->max_msg_sz);
265- else
266- /* handle case where message is greater than max */
267- ms->ins = stream_new(MAX(ms->max_msg_sz, mhdr->len));
268- if (left) {
269- stream_put(ms->ins, mhdr, left);
270- stream_set_endp(ms->ins, left);
271+ /* Read the rest of the message. */
272+ mhdr = (struct mgmt_msg_hdr *)STREAM_DATA(ms->ins);
273+ while (nread < mhdr->len) {
274+ n = stream_read_try(ms->ins, fd, mhdr->len - nread);
275+ if (n <= 0)
276+ goto not_done;
277+ nread += n;
278+ ms->nrxb += n;
279+ MGMT_MSG_TRACE(dbgtag, "read %zd from fd %d (%zu of %u)", n, fd, nread, mhdr->len);
280 }
281
282+ /* We've got a full message, push it onto the FIFO and setup for the next message. */
283+ MGMT_MSG_TRACE(dbgtag, "read full msg %zu/%u from fd %d", nread, mhdr->len, fd);
284+ stream_fifo_push(&ms->inq, ms->ins);
285+ ms->ins = stream_new(ms->max_msg_sz);
286 return MSR_SCHED_BOTH;
287+
288+not_done:
289+ if (n == -2) {
290+ MGMT_MSG_TRACE(dbgtag, "nothing more to read on fd %d", fd);
291+ return MSR_SCHED_STREAM;
292+ }
293+ if (n == 0)
294+ MGMT_MSG_ERR(ms, "got EOF/disconnect on fd %d", fd);
295+ else
296+ MGMT_MSG_ERR(ms, "got error while reading on fd %d: '%s'", fd,
297+ safe_strerror(errno));
298+ return MSR_DISCONNECT;
299 }
300
301 /**
302@@ -171,7 +156,6 @@ bool mgmt_msg_procbufs(struct mgmt_msg_state *ms,
303 const char *dbgtag = debug ? ms->idtag : NULL;
304 struct mgmt_msg_hdr *mhdr;
305 struct stream *work;
306- uint8_t *data;
307 size_t left, nproc;
308
309 MGMT_MSG_TRACE(dbgtag, "Have %zu streams to process", ms->inq.count);
310@@ -182,30 +166,17 @@ bool mgmt_msg_procbufs(struct mgmt_msg_state *ms,
311 if (!work)
312 break;
313
314- data = STREAM_DATA(work);
315 left = stream_get_endp(work);
316 MGMT_MSG_TRACE(dbgtag, "Processing stream of len %zu", left);
317-
318- for (; left > sizeof(struct mgmt_msg_hdr);
319- left -= mhdr->len, data += mhdr->len) {
320- mhdr = (struct mgmt_msg_hdr *)data;
321-
322- assert(MGMT_MSG_IS_MARKER(mhdr->marker));
323- assert(left >= mhdr->len);
324-
325- /*
326- * Q: if the handler disconnects should stop/flush?
327- */
328- handle_msg(MGMT_MSG_MARKER_VERSION(mhdr->marker), (uint8_t *)(mhdr + 1),
329- mhdr->len - sizeof(struct mgmt_msg_hdr), user);
330- ms->nrxm++;
331- nproc++;
332- }
333-
334- if (work != ms->ins)
335- stream_free(work); /* Free it up */
336- else
337- stream_reset(work); /* Reset stream for next read */
338+ /*
339+ * Q: if the handler disconnects should we stop/flush?
340+ */
341+ mhdr = (struct mgmt_msg_hdr *)STREAM_DATA(work);
342+ handle_msg(MGMT_MSG_MARKER_VERSION(mhdr->marker), (uint8_t *)(mhdr + 1),
343+ mhdr->len - sizeof(struct mgmt_msg_hdr), user);
344+ ms->nrxm++;
345+ nproc++;
346+ stream_free(work); /* Free it up */
347 }
348
349 /* return true if should reschedule b/c more to process. */
350--
3512.43.0
352
diff --git a/meta-networking/recipes-protocols/frr/frr_10.6.1.bb b/meta-networking/recipes-protocols/frr/frr_10.6.1.bb
index e86e0f3153..1cd102f0da 100644
--- a/meta-networking/recipes-protocols/frr/frr_10.6.1.bb
+++ b/meta-networking/recipes-protocols/frr/frr_10.6.1.bb
@@ -12,6 +12,7 @@ LIC_FILES_CHKSUM = "file://doc/licenses/GPL-2.0;md5=b234ee4d69f5fce4486a80fdaf4a
12 12
13SRC_URI = "git://github.com/FRRouting/frr.git;protocol=https;branch=stable/10.6;tag=frr-${PV} \ 13SRC_URI = "git://github.com/FRRouting/frr.git;protocol=https;branch=stable/10.6;tag=frr-${PV} \
14 file://frr.pam \ 14 file://frr.pam \
15 file://0001-lib-fix-mgmt_msg-recv-to-deal-with-mis-alignment.patch \
15 " 16 "
16SRCREV = "71da51baee6fb2a02b24262defc46591c86e8a81" 17SRCREV = "71da51baee6fb2a02b24262defc46591c86e8a81"
17 18