From: Sasha Levin Date: Sat, 1 Aug 2026 01:39:44 +0000 (-0400) Subject: Fixes for all trees X-Git-Tag: v6.6.148~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=df6f16472a45966aa0e18cf9ed40752c5fce57f1;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/staging-5.10/media-uvcvideo-fix-sequence-number-when-no-eof.patch b/staging-5.10/media-uvcvideo-fix-sequence-number-when-no-eof.patch new file mode 100644 index 0000000000..92f09dd9dd --- /dev/null +++ b/staging-5.10/media-uvcvideo-fix-sequence-number-when-no-eof.patch @@ -0,0 +1,157 @@ +From dea91bcd3205ee67f1b69217c6a8ea4c0c7f68a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 10:43:20 +0000 +Subject: media: uvcvideo: Fix sequence number when no EOF + +From: Ricardo Ribalda + +commit f078966ca1fb1b3865d8e6bbe2705cfd277fc637 upstream. + +If the driver could not detect the EOF, the sequence number is increased +twice: + 1) When we enter uvc_video_decode_start() with the old buffer and FID has + flipped => We return -EAGAIN and last_fid is not flipped + 2) When we enter uvc_video_decode_start() with the new buffer. + +Fix this issue by moving the new frame detection logic earlier in +uvc_video_decode_start(). + +This also has some nice side affects: + +- The error status from the new packet will no longer get propagated + to the previous frame-buffer. +- uvc_video_clock_decode() will no longer update the previous frame + buf->stf with info from the new packet. +- uvc_video_clock_decode() and uvc_video_stats_decode() will no longer + get called twice for the same packet. + +Cc: stable@kernel.org +Fixes: 650b95feee35 ("[media] uvcvideo: Generate discontinuous sequence numbers when frames are lost") +Reported-by: Hans de Goede +Closes: https://lore.kernel.org/linux-media/CANiDSCuj4cPuB5_v2xyvAagA5FjoN8V5scXiFFOeD3aKDMqkCg@mail.gmail.com/T/#me39fb134e8c2c085567a31548c3403eb639625e4 +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +Signed-off-by: Hans Verkuil +Signed-off-by: Ricardo Ribalda +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 94 ++++++++++++++++--------------- + 1 file changed, 49 insertions(+), 45 deletions(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 7d462e346abd..909e158a017a 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1093,7 +1093,55 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + header_len = data[0]; + fid = data[1] & UVC_STREAM_FID; + +- /* Increase the sequence number regardless of any buffer states, so ++ /* ++ * Mark the buffer as done if we're at the beginning of a new frame. ++ * End of frame detection is better implemented by checking the EOF ++ * bit (FID bit toggling is delayed by one frame compared to the EOF ++ * bit), but some devices don't set the bit at end of frame (and the ++ * last payload can be lost anyway). We thus must check if the FID has ++ * been toggled. ++ * ++ * stream->last_fid is initialized to -1, and buf->bytesused to 0, ++ * so the first isochronous frame will never trigger an end of frame ++ * detection. ++ * ++ * Empty buffers (bytesused == 0) don't trigger end of frame detection ++ * as it doesn't make sense to return an empty buffer. This also ++ * avoids detecting end of frame conditions at FID toggling if the ++ * previous payload had the EOF bit set. ++ */ ++ if (fid != stream->last_fid && buf && buf->bytesused != 0) { ++ uvc_trace(UVC_TRACE_FRAME, ++ "Frame complete (FID bit toggled)\n"); ++ buf->state = UVC_BUF_STATE_READY; ++ ++ return -EAGAIN; ++ } ++ ++ /* ++ * Some cameras, when running two parallel streams (one MJPEG alongside ++ * another non-MJPEG stream), are known to lose the EOF packet for a frame. ++ * We can detect the end of a frame by checking for a new SOI marker, as ++ * the SOI always lies on the packet boundary between two frames for ++ * these devices. ++ */ ++ if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && ++ (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || ++ stream->cur_format->fcc == V4L2_PIX_FMT_JPEG) && ++ buf && buf->bytesused != 0) { ++ const u8 *packet = data + header_len; ++ ++ if (len >= header_len + 2 && ++ packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI) { ++ buf->state = UVC_BUF_STATE_READY; ++ buf->error = 1; ++ stream->last_fid ^= UVC_STREAM_FID; ++ return -EAGAIN; ++ } ++ } ++ ++ /* ++ * Increase the sequence number regardless of any buffer states, so + * that discontinuous sequence numbers always indicate lost frames. + */ + if (stream->last_fid != fid) { +@@ -1157,50 +1205,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + meta_buf->state = UVC_BUF_STATE_ACTIVE; + } + +- /* Mark the buffer as done if we're at the beginning of a new frame. +- * End of frame detection is better implemented by checking the EOF +- * bit (FID bit toggling is delayed by one frame compared to the EOF +- * bit), but some devices don't set the bit at end of frame (and the +- * last payload can be lost anyway). We thus must check if the FID has +- * been toggled. +- * +- * stream->last_fid is initialized to -1, so the first isochronous +- * frame will never trigger an end of frame detection. +- * +- * Empty buffers (bytesused == 0) don't trigger end of frame detection +- * as it doesn't make sense to return an empty buffer. This also +- * avoids detecting end of frame conditions at FID toggling if the +- * previous payload had the EOF bit set. +- */ +- if (fid != stream->last_fid && buf->bytesused != 0) { +- uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit " +- "toggled).\n"); +- buf->state = UVC_BUF_STATE_READY; +- return -EAGAIN; +- } +- +- /* +- * Some cameras, when running two parallel streams (one MJPEG alongside +- * another non-MJPEG stream), are known to lose the EOF packet for a frame. +- * We can detect the end of a frame by checking for a new SOI marker, as +- * the SOI always lies on the packet boundary between two frames for +- * these devices. +- */ +- if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && +- (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || +- stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { +- const u8 *packet = data + header_len; +- +- if (len >= header_len + 2 && +- packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && +- buf->bytesused != 0) { +- buf->state = UVC_BUF_STATE_READY; +- buf->error = 1; +- stream->last_fid ^= UVC_STREAM_FID; +- return -EAGAIN; +- } +- } +- + stream->last_fid = fid; + + return header_len; +-- +2.53.0 + diff --git a/staging-5.10/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch b/staging-5.10/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch new file mode 100644 index 0000000000..d13ee63732 --- /dev/null +++ b/staging-5.10/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch @@ -0,0 +1,112 @@ +From 4d8e565ccc3264f67b21b575764713cd4d330391 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 10:43:19 +0000 +Subject: media: uvcvideo: Implement dual stream quirk to fix loss of usb + packets + +From: Isaac Scott + +commit c2eda35e675b6ea4a0a21a4b1167b121571a9036 upstream. + +Some cameras, such as the Sonix Technology Co. 292A, exhibit issues when +running two parallel streams, causing USB packets to be dropped when an +H.264 stream posts a keyframe while an MJPEG stream is running +simultaneously. This occasionally causes the driver to erroneously +output two consecutive JPEG images as a single frame. + +To fix this, we inspect the buffer, and trigger a new frame when we +find an SOI. + +Signed-off-by: Isaac Scott +Reviewed-by: Ricardo Ribalda +Link: https://lore.kernel.org/r/20241128145144.61475-2-isaac.scott@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +[Added JPEG_MARKER_SOI definition, jpeg header does not exist yet] +Signed-off-by: Ricardo Ribalda +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 28 +++++++++++++++++++++++++++- + drivers/media/usb/uvc/uvcvideo.h | 4 ++++ + 2 files changed, 31 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 1a8a89aa0c5c..7d462e346abd 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -21,6 +21,8 @@ + + #include "uvcvideo.h" + ++#define JPEG_MARKER_SOI 0xd8 ++ + /* ------------------------------------------------------------------------ + * UVC Controls + */ +@@ -1075,6 +1077,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + struct uvc_buffer *meta_buf, + const u8 *data, int len) + { ++ u8 header_len; + u8 fid; + + /* Sanity checks: +@@ -1087,6 +1090,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + return -EINVAL; + } + ++ header_len = data[0]; + fid = data[1] & UVC_STREAM_FID; + + /* Increase the sequence number regardless of any buffer states, so +@@ -1175,9 +1179,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + return -EAGAIN; + } + ++ /* ++ * Some cameras, when running two parallel streams (one MJPEG alongside ++ * another non-MJPEG stream), are known to lose the EOF packet for a frame. ++ * We can detect the end of a frame by checking for a new SOI marker, as ++ * the SOI always lies on the packet boundary between two frames for ++ * these devices. ++ */ ++ if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && ++ (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || ++ stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { ++ const u8 *packet = data + header_len; ++ ++ if (len >= header_len + 2 && ++ packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && ++ buf->bytesused != 0) { ++ buf->state = UVC_BUF_STATE_READY; ++ buf->error = 1; ++ stream->last_fid ^= UVC_STREAM_FID; ++ return -EAGAIN; ++ } ++ } ++ + stream->last_fid = fid; + +- return data[0]; ++ return header_len; + } + + /* +diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h +index a83995276170..4a1ff08453d7 100644 +--- a/drivers/media/usb/uvc/uvcvideo.h ++++ b/drivers/media/usb/uvc/uvcvideo.h +@@ -204,6 +204,10 @@ + #define UVC_QUIRK_FORCE_Y8 0x00000800 + #define UVC_QUIRK_FORCE_BPP 0x00001000 + #define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000 ++#define UVC_QUIRK_NO_RESET_RESUME 0x00004000 ++#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 ++#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 ++#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 + + /* Format flags */ + #define UVC_FMT_FLAG_COMPRESSED 0x00000001 +-- +2.53.0 + diff --git a/staging-5.10/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch b/staging-5.10/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch new file mode 100644 index 0000000000..5afca81301 --- /dev/null +++ b/staging-5.10/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch @@ -0,0 +1,74 @@ +From 006dbf7b421df18e7ca652dc22b48de48c0a5dee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:08:29 +0900 +Subject: net: mpls: initialize rtm_tos in mpls_getroute() + +From: Yehyeong Lee + +[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ] + +mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE +request by filling a struct rtmsg allocated from an skb whose data +area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every +field of the header except rtm_tos: + + r = nlmsg_data(nlh); + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; + r->rtm_protocol = rt->rt_protocol; + r->rtm_flags = 0; + +struct rtmsg has no padding, so the one uninitialised byte rtm_tos +(offset 3) is copied straight to user space on recvmsg(), leaking a +byte of uninitialised heap memory. This is in contrast to +mpls_dump_route(), which fills the very same header and does set +rtm_tos = 0. + +Initialize rtm_tos to 0, matching mpls_dump_route(). + +Reproduced with KMSAN by adding an MPLS route and issuing a +non-RTM_F_FIB_MATCH RTM_GETROUTE for its label: + + BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 + _copy_to_iter+0x36c/0x33f0 + __skb_datagram_iter+0x196/0x12c0 + skb_copy_datagram_iter+0x5b/0x210 + netlink_recvmsg+0x37b/0xef0 + ... + Uninit was created at: + __alloc_skb+0x8ca/0x10e0 + mpls_getroute+0x1280/0x3a40 + rtnetlink_rcv_msg+0x1138/0x15a0 + ... + Byte 19 of 64 is uninitialized + +(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos) + +Fixes: 397fc9e5cefe ("mpls: route get support") +Signed-off-by: Yehyeong Lee +Link: https://patch.msgid.link/20260723010830.289917-1-yhlee@isslab.korea.ac.kr +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/mpls/af_mpls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 66f498667ed8..5c80fb93bb7a 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -2492,6 +2492,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; ++ r->rtm_tos = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; +-- +2.53.0 + diff --git a/staging-5.10/series b/staging-5.10/series new file mode 100644 index 0000000000..a83ad165d1 --- /dev/null +++ b/staging-5.10/series @@ -0,0 +1,3 @@ +net-mpls-initialize-rtm_tos-in-mpls_getroute.patch +media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch +media-uvcvideo-fix-sequence-number-when-no-eof.patch diff --git a/staging-5.15/media-uvcvideo-fix-sequence-number-when-no-eof.patch b/staging-5.15/media-uvcvideo-fix-sequence-number-when-no-eof.patch new file mode 100644 index 0000000000..5201c59521 --- /dev/null +++ b/staging-5.15/media-uvcvideo-fix-sequence-number-when-no-eof.patch @@ -0,0 +1,157 @@ +From b60af3c20395afe4a364be38a954cb89a625a2e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 10:48:33 +0000 +Subject: media: uvcvideo: Fix sequence number when no EOF + +From: Ricardo Ribalda + +commit f078966ca1fb1b3865d8e6bbe2705cfd277fc637 upstream. + +If the driver could not detect the EOF, the sequence number is increased +twice: + 1) When we enter uvc_video_decode_start() with the old buffer and FID has + flipped => We return -EAGAIN and last_fid is not flipped + 2) When we enter uvc_video_decode_start() with the new buffer. + +Fix this issue by moving the new frame detection logic earlier in +uvc_video_decode_start(). + +This also has some nice side affects: + +- The error status from the new packet will no longer get propagated + to the previous frame-buffer. +- uvc_video_clock_decode() will no longer update the previous frame + buf->stf with info from the new packet. +- uvc_video_clock_decode() and uvc_video_stats_decode() will no longer + get called twice for the same packet. + +Cc: stable@kernel.org +Fixes: 650b95feee35 ("[media] uvcvideo: Generate discontinuous sequence numbers when frames are lost") +Reported-by: Hans de Goede +Closes: https://lore.kernel.org/linux-media/CANiDSCuj4cPuB5_v2xyvAagA5FjoN8V5scXiFFOeD3aKDMqkCg@mail.gmail.com/T/#me39fb134e8c2c085567a31548c3403eb639625e4 +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +Signed-off-by: Hans Verkuil +Signed-off-by: Ricardo Ribalda +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 94 ++++++++++++++++--------------- + 1 file changed, 49 insertions(+), 45 deletions(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 2a2c10daa07a..d0415ebe54d0 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1095,7 +1095,55 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + header_len = data[0]; + fid = data[1] & UVC_STREAM_FID; + +- /* Increase the sequence number regardless of any buffer states, so ++ /* ++ * Mark the buffer as done if we're at the beginning of a new frame. ++ * End of frame detection is better implemented by checking the EOF ++ * bit (FID bit toggling is delayed by one frame compared to the EOF ++ * bit), but some devices don't set the bit at end of frame (and the ++ * last payload can be lost anyway). We thus must check if the FID has ++ * been toggled. ++ * ++ * stream->last_fid is initialized to -1, and buf->bytesused to 0, ++ * so the first isochronous frame will never trigger an end of frame ++ * detection. ++ * ++ * Empty buffers (bytesused == 0) don't trigger end of frame detection ++ * as it doesn't make sense to return an empty buffer. This also ++ * avoids detecting end of frame conditions at FID toggling if the ++ * previous payload had the EOF bit set. ++ */ ++ if (fid != stream->last_fid && buf && buf->bytesused != 0) { ++ uvc_dbg(stream->dev, FRAME, ++ "Frame complete (FID bit toggled)\n"); ++ buf->state = UVC_BUF_STATE_READY; ++ ++ return -EAGAIN; ++ } ++ ++ /* ++ * Some cameras, when running two parallel streams (one MJPEG alongside ++ * another non-MJPEG stream), are known to lose the EOF packet for a frame. ++ * We can detect the end of a frame by checking for a new SOI marker, as ++ * the SOI always lies on the packet boundary between two frames for ++ * these devices. ++ */ ++ if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && ++ (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || ++ stream->cur_format->fcc == V4L2_PIX_FMT_JPEG) && ++ buf && buf->bytesused != 0) { ++ const u8 *packet = data + header_len; ++ ++ if (len >= header_len + 2 && ++ packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI) { ++ buf->state = UVC_BUF_STATE_READY; ++ buf->error = 1; ++ stream->last_fid ^= UVC_STREAM_FID; ++ return -EAGAIN; ++ } ++ } ++ ++ /* ++ * Increase the sequence number regardless of any buffer states, so + * that discontinuous sequence numbers always indicate lost frames. + */ + if (stream->last_fid != fid) { +@@ -1159,50 +1207,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + meta_buf->state = UVC_BUF_STATE_ACTIVE; + } + +- /* Mark the buffer as done if we're at the beginning of a new frame. +- * End of frame detection is better implemented by checking the EOF +- * bit (FID bit toggling is delayed by one frame compared to the EOF +- * bit), but some devices don't set the bit at end of frame (and the +- * last payload can be lost anyway). We thus must check if the FID has +- * been toggled. +- * +- * stream->last_fid is initialized to -1, so the first isochronous +- * frame will never trigger an end of frame detection. +- * +- * Empty buffers (bytesused == 0) don't trigger end of frame detection +- * as it doesn't make sense to return an empty buffer. This also +- * avoids detecting end of frame conditions at FID toggling if the +- * previous payload had the EOF bit set. +- */ +- if (fid != stream->last_fid && buf->bytesused != 0) { +- uvc_dbg(stream->dev, FRAME, +- "Frame complete (FID bit toggled)\n"); +- buf->state = UVC_BUF_STATE_READY; +- return -EAGAIN; +- } +- +- /* +- * Some cameras, when running two parallel streams (one MJPEG alongside +- * another non-MJPEG stream), are known to lose the EOF packet for a frame. +- * We can detect the end of a frame by checking for a new SOI marker, as +- * the SOI always lies on the packet boundary between two frames for +- * these devices. +- */ +- if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && +- (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || +- stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { +- const u8 *packet = data + header_len; +- +- if (len >= header_len + 2 && +- packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && +- buf->bytesused != 0) { +- buf->state = UVC_BUF_STATE_READY; +- buf->error = 1; +- stream->last_fid ^= UVC_STREAM_FID; +- return -EAGAIN; +- } +- } +- + stream->last_fid = fid; + + return header_len; +-- +2.53.0 + diff --git a/staging-5.15/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch b/staging-5.15/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch new file mode 100644 index 0000000000..30b8fc1f58 --- /dev/null +++ b/staging-5.15/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch @@ -0,0 +1,112 @@ +From 0c5a192d9c2389203f6f1e951c11829d9c2129f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 10:48:32 +0000 +Subject: media: uvcvideo: Implement dual stream quirk to fix loss of usb + packets + +From: Isaac Scott + +commit c2eda35e675b6ea4a0a21a4b1167b121571a9036 upstream. + +Some cameras, such as the Sonix Technology Co. 292A, exhibit issues when +running two parallel streams, causing USB packets to be dropped when an +H.264 stream posts a keyframe while an MJPEG stream is running +simultaneously. This occasionally causes the driver to erroneously +output two consecutive JPEG images as a single frame. + +To fix this, we inspect the buffer, and trigger a new frame when we +find an SOI. + +Signed-off-by: Isaac Scott +Reviewed-by: Ricardo Ribalda +Link: https://lore.kernel.org/r/20241128145144.61475-2-isaac.scott@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +[Added JPEG_MARKER_SOI definition, jpeg header does not exist yet] +Signed-off-by: Ricardo Ribalda +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 28 +++++++++++++++++++++++++++- + drivers/media/usb/uvc/uvcvideo.h | 4 ++++ + 2 files changed, 31 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 3184308e6896..2a2c10daa07a 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -24,6 +24,8 @@ + + #include "uvcvideo.h" + ++#define JPEG_MARKER_SOI 0xd8 ++ + /* ------------------------------------------------------------------------ + * UVC Controls + */ +@@ -1077,6 +1079,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + struct uvc_buffer *meta_buf, + const u8 *data, int len) + { ++ u8 header_len; + u8 fid; + + /* Sanity checks: +@@ -1089,6 +1092,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + return -EINVAL; + } + ++ header_len = data[0]; + fid = data[1] & UVC_STREAM_FID; + + /* Increase the sequence number regardless of any buffer states, so +@@ -1177,9 +1181,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + return -EAGAIN; + } + ++ /* ++ * Some cameras, when running two parallel streams (one MJPEG alongside ++ * another non-MJPEG stream), are known to lose the EOF packet for a frame. ++ * We can detect the end of a frame by checking for a new SOI marker, as ++ * the SOI always lies on the packet boundary between two frames for ++ * these devices. ++ */ ++ if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && ++ (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || ++ stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { ++ const u8 *packet = data + header_len; ++ ++ if (len >= header_len + 2 && ++ packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && ++ buf->bytesused != 0) { ++ buf->state = UVC_BUF_STATE_READY; ++ buf->error = 1; ++ stream->last_fid ^= UVC_STREAM_FID; ++ return -EAGAIN; ++ } ++ } ++ + stream->last_fid = fid; + +- return data[0]; ++ return header_len; + } + + static inline enum dma_data_direction uvc_stream_dir( +diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h +index be4b746d902c..2dd8d04589ab 100644 +--- a/drivers/media/usb/uvc/uvcvideo.h ++++ b/drivers/media/usb/uvc/uvcvideo.h +@@ -212,6 +212,10 @@ + #define UVC_QUIRK_FORCE_Y8 0x00000800 + #define UVC_QUIRK_FORCE_BPP 0x00001000 + #define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000 ++#define UVC_QUIRK_NO_RESET_RESUME 0x00004000 ++#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 ++#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 ++#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 + + /* Format flags */ + #define UVC_FMT_FLAG_COMPRESSED 0x00000001 +-- +2.53.0 + diff --git a/staging-5.15/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch b/staging-5.15/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch new file mode 100644 index 0000000000..67e5369e5f --- /dev/null +++ b/staging-5.15/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch @@ -0,0 +1,74 @@ +From 4044c7986bb3746f4f1b05bbda25088e0fdb8343 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:08:29 +0900 +Subject: net: mpls: initialize rtm_tos in mpls_getroute() + +From: Yehyeong Lee + +[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ] + +mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE +request by filling a struct rtmsg allocated from an skb whose data +area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every +field of the header except rtm_tos: + + r = nlmsg_data(nlh); + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; + r->rtm_protocol = rt->rt_protocol; + r->rtm_flags = 0; + +struct rtmsg has no padding, so the one uninitialised byte rtm_tos +(offset 3) is copied straight to user space on recvmsg(), leaking a +byte of uninitialised heap memory. This is in contrast to +mpls_dump_route(), which fills the very same header and does set +rtm_tos = 0. + +Initialize rtm_tos to 0, matching mpls_dump_route(). + +Reproduced with KMSAN by adding an MPLS route and issuing a +non-RTM_F_FIB_MATCH RTM_GETROUTE for its label: + + BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 + _copy_to_iter+0x36c/0x33f0 + __skb_datagram_iter+0x196/0x12c0 + skb_copy_datagram_iter+0x5b/0x210 + netlink_recvmsg+0x37b/0xef0 + ... + Uninit was created at: + __alloc_skb+0x8ca/0x10e0 + mpls_getroute+0x1280/0x3a40 + rtnetlink_rcv_msg+0x1138/0x15a0 + ... + Byte 19 of 64 is uninitialized + +(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos) + +Fixes: 397fc9e5cefe ("mpls: route get support") +Signed-off-by: Yehyeong Lee +Link: https://patch.msgid.link/20260723010830.289917-1-yhlee@isslab.korea.ac.kr +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/mpls/af_mpls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index bd84c9ddb006..d77e028aed23 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -2495,6 +2495,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; ++ r->rtm_tos = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; +-- +2.53.0 + diff --git a/staging-5.15/series b/staging-5.15/series new file mode 100644 index 0000000000..a83ad165d1 --- /dev/null +++ b/staging-5.15/series @@ -0,0 +1,3 @@ +net-mpls-initialize-rtm_tos-in-mpls_getroute.patch +media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch +media-uvcvideo-fix-sequence-number-when-no-eof.patch diff --git a/staging-6.1/media-uvcvideo-fix-sequence-number-when-no-eof.patch b/staging-6.1/media-uvcvideo-fix-sequence-number-when-no-eof.patch new file mode 100644 index 0000000000..4bb52ee733 --- /dev/null +++ b/staging-6.1/media-uvcvideo-fix-sequence-number-when-no-eof.patch @@ -0,0 +1,155 @@ +From 60635162af7211f55bcd12ded6e65ee47692448a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 10:52:23 +0000 +Subject: media: uvcvideo: Fix sequence number when no EOF + +From: Ricardo Ribalda + +commit f078966ca1fb1b3865d8e6bbe2705cfd277fc637 upstream. + +If the driver could not detect the EOF, the sequence number is increased +twice: + 1) When we enter uvc_video_decode_start() with the old buffer and FID has + flipped => We return -EAGAIN and last_fid is not flipped + 2) When we enter uvc_video_decode_start() with the new buffer. + +Fix this issue by moving the new frame detection logic earlier in +uvc_video_decode_start(). + +This also has some nice side affects: + +- The error status from the new packet will no longer get propagated + to the previous frame-buffer. +- uvc_video_clock_decode() will no longer update the previous frame + buf->stf with info from the new packet. +- uvc_video_clock_decode() and uvc_video_stats_decode() will no longer + get called twice for the same packet. + +Cc: stable@kernel.org +Fixes: 650b95feee35 ("[media] uvcvideo: Generate discontinuous sequence numbers when frames are lost") +Reported-by: Hans de Goede +Closes: https://lore.kernel.org/linux-media/CANiDSCuj4cPuB5_v2xyvAagA5FjoN8V5scXiFFOeD3aKDMqkCg@mail.gmail.com/T/#me39fb134e8c2c085567a31548c3403eb639625e4 +Signed-off-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +Signed-off-by: Hans Verkuil +Signed-off-by: Ricardo Ribalda +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 92 ++++++++++++++++--------------- + 1 file changed, 47 insertions(+), 45 deletions(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index 408be24fceea..2cc00f4be793 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -1108,6 +1108,53 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + header_len = data[0]; + fid = data[1] & UVC_STREAM_FID; + ++ /* ++ * Mark the buffer as done if we're at the beginning of a new frame. ++ * End of frame detection is better implemented by checking the EOF ++ * bit (FID bit toggling is delayed by one frame compared to the EOF ++ * bit), but some devices don't set the bit at end of frame (and the ++ * last payload can be lost anyway). We thus must check if the FID has ++ * been toggled. ++ * ++ * stream->last_fid is initialized to -1, and buf->bytesused to 0, ++ * so the first isochronous frame will never trigger an end of frame ++ * detection. ++ * ++ * Empty buffers (bytesused == 0) don't trigger end of frame detection ++ * as it doesn't make sense to return an empty buffer. This also ++ * avoids detecting end of frame conditions at FID toggling if the ++ * previous payload had the EOF bit set. ++ */ ++ if (fid != stream->last_fid && buf && buf->bytesused != 0) { ++ uvc_dbg(stream->dev, FRAME, ++ "Frame complete (FID bit toggled)\n"); ++ buf->state = UVC_BUF_STATE_READY; ++ ++ return -EAGAIN; ++ } ++ ++ /* ++ * Some cameras, when running two parallel streams (one MJPEG alongside ++ * another non-MJPEG stream), are known to lose the EOF packet for a frame. ++ * We can detect the end of a frame by checking for a new SOI marker, as ++ * the SOI always lies on the packet boundary between two frames for ++ * these devices. ++ */ ++ if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && ++ (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || ++ stream->cur_format->fcc == V4L2_PIX_FMT_JPEG) && ++ buf && buf->bytesused != 0) { ++ const u8 *packet = data + header_len; ++ ++ if (len >= header_len + 2 && ++ packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI) { ++ buf->state = UVC_BUF_STATE_READY; ++ buf->error = 1; ++ stream->last_fid ^= UVC_STREAM_FID; ++ return -EAGAIN; ++ } ++ } ++ + /* + * Increase the sequence number regardless of any buffer states, so + * that discontinuous sequence numbers always indicate lost frames. +@@ -1175,51 +1222,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + meta_buf->state = UVC_BUF_STATE_ACTIVE; + } + +- /* +- * Mark the buffer as done if we're at the beginning of a new frame. +- * End of frame detection is better implemented by checking the EOF +- * bit (FID bit toggling is delayed by one frame compared to the EOF +- * bit), but some devices don't set the bit at end of frame (and the +- * last payload can be lost anyway). We thus must check if the FID has +- * been toggled. +- * +- * stream->last_fid is initialized to -1, so the first isochronous +- * frame will never trigger an end of frame detection. +- * +- * Empty buffers (bytesused == 0) don't trigger end of frame detection +- * as it doesn't make sense to return an empty buffer. This also +- * avoids detecting end of frame conditions at FID toggling if the +- * previous payload had the EOF bit set. +- */ +- if (fid != stream->last_fid && buf->bytesused != 0) { +- uvc_dbg(stream->dev, FRAME, +- "Frame complete (FID bit toggled)\n"); +- buf->state = UVC_BUF_STATE_READY; +- return -EAGAIN; +- } +- +- /* +- * Some cameras, when running two parallel streams (one MJPEG alongside +- * another non-MJPEG stream), are known to lose the EOF packet for a frame. +- * We can detect the end of a frame by checking for a new SOI marker, as +- * the SOI always lies on the packet boundary between two frames for +- * these devices. +- */ +- if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && +- (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || +- stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { +- const u8 *packet = data + header_len; +- +- if (len >= header_len + 2 && +- packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && +- buf->bytesused != 0) { +- buf->state = UVC_BUF_STATE_READY; +- buf->error = 1; +- stream->last_fid ^= UVC_STREAM_FID; +- return -EAGAIN; +- } +- } +- + stream->last_fid = fid; + + return header_len; +-- +2.53.0 + diff --git a/staging-6.1/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch b/staging-6.1/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch new file mode 100644 index 0000000000..19cdb81b70 --- /dev/null +++ b/staging-6.1/media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch @@ -0,0 +1,112 @@ +From fad444426a785df6855987c7fbbc0a893ad1bdd1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 10:52:22 +0000 +Subject: media: uvcvideo: Implement dual stream quirk to fix loss of usb + packets + +From: Isaac Scott + +commit c2eda35e675b6ea4a0a21a4b1167b121571a9036 upstream. + +Some cameras, such as the Sonix Technology Co. 292A, exhibit issues when +running two parallel streams, causing USB packets to be dropped when an +H.264 stream posts a keyframe while an MJPEG stream is running +simultaneously. This occasionally causes the driver to erroneously +output two consecutive JPEG images as a single frame. + +To fix this, we inspect the buffer, and trigger a new frame when we +find an SOI. + +Signed-off-by: Isaac Scott +Reviewed-by: Ricardo Ribalda +Link: https://lore.kernel.org/r/20241128145144.61475-2-isaac.scott@ideasonboard.com +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +[Added JPEG_MARKER_SOI definition, jpeg header does not exist yet] +Signed-off-by: Ricardo Ribalda +Signed-off-by: Sasha Levin +--- + drivers/media/usb/uvc/uvc_video.c | 28 +++++++++++++++++++++++++++- + drivers/media/usb/uvc/uvcvideo.h | 4 ++++ + 2 files changed, 31 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c +index e33b9bedddda..408be24fceea 100644 +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -24,6 +24,8 @@ + + #include "uvcvideo.h" + ++#define JPEG_MARKER_SOI 0xd8 ++ + /* ------------------------------------------------------------------------ + * UVC Controls + */ +@@ -1089,6 +1091,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + struct uvc_buffer *meta_buf, + const u8 *data, int len) + { ++ u8 header_len; + u8 fid; + + /* +@@ -1102,6 +1105,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + return -EINVAL; + } + ++ header_len = data[0]; + fid = data[1] & UVC_STREAM_FID; + + /* +@@ -1194,9 +1198,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, + return -EAGAIN; + } + ++ /* ++ * Some cameras, when running two parallel streams (one MJPEG alongside ++ * another non-MJPEG stream), are known to lose the EOF packet for a frame. ++ * We can detect the end of a frame by checking for a new SOI marker, as ++ * the SOI always lies on the packet boundary between two frames for ++ * these devices. ++ */ ++ if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF && ++ (stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG || ++ stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) { ++ const u8 *packet = data + header_len; ++ ++ if (len >= header_len + 2 && ++ packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI && ++ buf->bytesused != 0) { ++ buf->state = UVC_BUF_STATE_READY; ++ buf->error = 1; ++ stream->last_fid ^= UVC_STREAM_FID; ++ return -EAGAIN; ++ } ++ } ++ + stream->last_fid = fid; + +- return data[0]; ++ return header_len; + } + + static inline enum dma_data_direction uvc_stream_dir( +diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h +index a7182305390b..8404814fa899 100644 +--- a/drivers/media/usb/uvc/uvcvideo.h ++++ b/drivers/media/usb/uvc/uvcvideo.h +@@ -77,6 +77,10 @@ + #define UVC_QUIRK_FORCE_Y8 0x00000800 + #define UVC_QUIRK_FORCE_BPP 0x00001000 + #define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000 ++#define UVC_QUIRK_NO_RESET_RESUME 0x00004000 ++#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 ++#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 ++#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 + + /* Format flags */ + #define UVC_FMT_FLAG_COMPRESSED 0x00000001 +-- +2.53.0 + diff --git a/staging-6.1/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch b/staging-6.1/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch new file mode 100644 index 0000000000..15ab868316 --- /dev/null +++ b/staging-6.1/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch @@ -0,0 +1,74 @@ +From e2784b54299ddcbc5b097aa122700eee428dfe1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:08:29 +0900 +Subject: net: mpls: initialize rtm_tos in mpls_getroute() + +From: Yehyeong Lee + +[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ] + +mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE +request by filling a struct rtmsg allocated from an skb whose data +area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every +field of the header except rtm_tos: + + r = nlmsg_data(nlh); + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; + r->rtm_protocol = rt->rt_protocol; + r->rtm_flags = 0; + +struct rtmsg has no padding, so the one uninitialised byte rtm_tos +(offset 3) is copied straight to user space on recvmsg(), leaking a +byte of uninitialised heap memory. This is in contrast to +mpls_dump_route(), which fills the very same header and does set +rtm_tos = 0. + +Initialize rtm_tos to 0, matching mpls_dump_route(). + +Reproduced with KMSAN by adding an MPLS route and issuing a +non-RTM_F_FIB_MATCH RTM_GETROUTE for its label: + + BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 + _copy_to_iter+0x36c/0x33f0 + __skb_datagram_iter+0x196/0x12c0 + skb_copy_datagram_iter+0x5b/0x210 + netlink_recvmsg+0x37b/0xef0 + ... + Uninit was created at: + __alloc_skb+0x8ca/0x10e0 + mpls_getroute+0x1280/0x3a40 + rtnetlink_rcv_msg+0x1138/0x15a0 + ... + Byte 19 of 64 is uninitialized + +(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos) + +Fixes: 397fc9e5cefe ("mpls: route get support") +Signed-off-by: Yehyeong Lee +Link: https://patch.msgid.link/20260723010830.289917-1-yhlee@isslab.korea.ac.kr +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/mpls/af_mpls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 6369ff87f4b9..11131f6a5a94 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -2483,6 +2483,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; ++ r->rtm_tos = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; +-- +2.53.0 + diff --git a/staging-6.1/netfilter-br_netfilter-reallocate-headroom-if-necess.patch b/staging-6.1/netfilter-br_netfilter-reallocate-headroom-if-necess.patch new file mode 100644 index 0000000000..2bcb6f6af6 --- /dev/null +++ b/staging-6.1/netfilter-br_netfilter-reallocate-headroom-if-necess.patch @@ -0,0 +1,142 @@ +From 212df0069a67885c08e01baedcf628a63ec24830 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 16:46:38 +0200 +Subject: netfilter: br_netfilter: Reallocate headroom if necessary in + neigh_hh_bridge() + +From: Lorenzo Bianconi + +[ Upstream commit b2870fc21601db9133bc70c48c603b487614fa3b ] + +neigh_hh_bridge() assumes the skb always has sufficient headroom to copy +the aligned L2 header. This assumption can trigger the crash reported +below using the following netfilter setup: + +$modprobe br_netfilter +$sysctl -w net.bridge.bridge-nf-call-iptables=1 + +$root@OpenWrt:~# nft list ruleset +table ip nat { + chain prerouting { + type nat hook prerouting priority dstnat; policy accept; + ip daddr 192.168.83.123 dnat to 192.168.83.120 + } +} + +- iperf3 client (192.168.83.119) --> bridge (192.168.83.118) --> iperf3 server (192.168.83.120) + +the iperf3 client is sending packet for 192.168.83.123 to the bridge device. + +[ 1579.036575] Unable to handle kernel write to read-only memory at virtual address ffffff8004d76ffe +[ 1579.045482] Mem abort info: +[ 1579.048273] ESR = 0x000000009600004f +[ 1579.052024] EC = 0x25: DABT (current EL), IL = 32 bits +[ 1579.057363] SET = 0, FnV = 0 +[ 1579.060417] EA = 0, S1PTW = 0 +[ 1579.063550] FSC = 0x0f: level 3 permission fault +[ 1579.068345] Data abort info: +[ 1579.071224] ISV = 0, ISS = 0x0000004f, ISS2 = 0x00000000 +[ 1579.076720] CM = 0, WnR = 1, TnD = 0, TagAccess = 0 +[ 1579.081770] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 1579.087092] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000080dc4000 +[ 1579.093794] [ffffff8004d76ffe] pgd=180000009ffff003, p4d=180000009ffff003, pud=180000009ffff003, pmd=180000009ffe3003, pte=0060000084d76787 +[ 1579.106343] Internal error: Oops: 000000009600004f [#1] SMP +[ 1579.193824] CPU: 0 UID: 0 PID: 235 Comm: napi/qdma_eth-3 Tainted: G O 6.12.57 #0 +[ 1579.202614] Tainted: [O]=OOT_MODULE +[ 1579.206102] Hardware name: Airoha AN7581 Evaluation Board (DT) +[ 1579.211929] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 1579.218889] pc : br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.225859] lr : br_nf_pre_routing_finish_bridge+0x18c/0xcc8 [br_netfilter] +[ 1579.232822] sp : ffffffc0817cba20 +[ 1579.236128] x29: ffffffc0817cba20 x28: 0000000000000000 x27: ffffff8002b89000 +[ 1579.243273] x26: ffffff8004d7700e x25: 0000000000000008 x24: 0000000000000000 +[ 1579.250416] x23: ffffffc08179d4c0 x22: 0000000000000000 x21: ffffffc08179d4c0 +[ 1579.257561] x20: ffffff8004d9b800 x19: ffffff8015010000 x18: 0000000000000014 +[ 1579.264704] x17: ffffffbf9e930000 x16: ffffffc0817c8000 x15: 0000000000000070 +[ 1579.271848] x14: 0000000000000080 x13: 0000000000000001 x12: 0000000000000000 +[ 1579.278993] x11: ffffffc0798caae0 x10: ffffff8014db6fd8 x9 : 0000000000000000 +[ 1579.286136] x8 : 0000000000000003 x7 : ffffffc08171f628 x6 : 000000001a3b83d3 +[ 1579.293281] x5 : 0000000000000000 x4 : 1beb76f22fee0000 x3 : ffffff8004d7700e +[ 1579.300425] x2 : 0000000000000000 x1 : ffffff8004d9b8bc x0 : ffffff80026ed000 +[ 1579.307570] Call trace: +[ 1579.310018] br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.316632] br_nf_hook_thresh+0xd4/0x14bc [br_netfilter] +[ 1579.322032] br_nf_hook_thresh+0x250/0x14bc [br_netfilter] +[ 1579.327517] br_nf_hook_thresh+0x76c/0x14bc [br_netfilter] +[ 1579.333003] br_handle_frame+0x180/0x480 +[ 1579.336935] __netif_receive_skb_core.constprop.0+0x540/0xf40 +[ 1579.342682] __netif_receive_skb_one_core+0x28/0x50 +[ 1579.347561] process_backlog+0x98/0x1e0 +[ 1579.351398] __napi_poll+0x34/0x1c4 +[ 1579.354887] net_rx_action+0x178/0x330 +[ 1579.358638] handle_softirqs+0x108/0x2d4 +[ 1579.362560] __do_softirq+0x10/0x18 +[ 1579.366051] ____do_softirq+0xc/0x20 +[ 1579.369627] call_on_irq_stack+0x30/0x4c +[ 1579.373550] do_softirq_own_stack+0x18/0x20 +[ 1579.377734] do_softirq+0x4c/0x60 +[ 1579.381050] __local_bh_enable_ip+0x88/0x98 +[ 1579.385234] napi_threaded_poll_loop+0x188/0x21c +[ 1579.389853] napi_threaded_poll+0x70/0x80 +[ 1579.393863] kthread+0xd8/0xdc +[ 1579.396918] ret_from_fork+0x10/0x20 +[ 1579.400499] Code: 88dffc22 3707ffc2 f9406663 f9406684 (f81f0064) +[ 1579.406589] ---[ end trace 0000000000000000 ]--- +[ 1579.411209] Kernel panic - not syncing: Oops: Fatal exception in interrupt +[ 1579.418083] SMP: stopping secondary CPUs +[ 1579.422012] Kernel Offset: disabled + +Fix the issue reallocating the skb headroom if necessary in neigh_hh_bridge routine. + +Fixes: e179e6322ac33 ("netfilter: bridge-netfilter: Fix MAC header handling with IP DNAT") +Reviewed-by: Ido Schimmel +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/neighbour.h | 8 ++++++-- + net/bridge/br_netfilter_hooks.c | 6 +++++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/include/net/neighbour.h b/include/net/neighbour.h +index 93aecfaa7628..b8b385a2a31c 100644 +--- a/include/net/neighbour.h ++++ b/include/net/neighbour.h +@@ -478,11 +478,15 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) + #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) + static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) + { +- unsigned int seq, hh_alen; ++ unsigned int seq, hh_alen = HH_DATA_ALIGN(ETH_HLEN); ++ int err; ++ ++ err = skb_cow_head(skb, hh_alen); ++ if (err) ++ return err; + + do { + seq = read_seqbegin(&hh->hh_lock); +- hh_alen = HH_DATA_ALIGN(ETH_HLEN); + memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); + } while (read_seqretry(&hh->hh_lock, seq)); + return 0; +diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c +index c4765691e781..ffd100a242a0 100644 +--- a/net/bridge/br_netfilter_hooks.c ++++ b/net/bridge/br_netfilter_hooks.c +@@ -292,7 +292,11 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_ + goto free_skb; + } + +- neigh_hh_bridge(&neigh->hh, skb); ++ if (neigh_hh_bridge(&neigh->hh, skb)) { ++ neigh_release(neigh); ++ goto free_skb; ++ } ++ + skb->dev = br_indev; + + ret = br_handle_frame_finish(net, sk, skb); +-- +2.53.0 + diff --git a/staging-6.1/series b/staging-6.1/series index 5d3a24c72c..ca65a4d42c 100644 --- a/staging-6.1/series +++ b/staging-6.1/series @@ -2,3 +2,7 @@ io_uring-rw-fix-missing-erestartsys-conversion-in-re.patch mm-damon-core-validate-ranges-in-damon_set_regions.patch mm-damon-core-disallow-overlapping-input-ranges-for-.patch netfilter-nf_conntrack_expect-restore-helper-propaga.patch +netfilter-br_netfilter-reallocate-headroom-if-necess.patch +net-mpls-initialize-rtm_tos-in-mpls_getroute.patch +media-uvcvideo-implement-dual-stream-quirk-to-fix-lo.patch +media-uvcvideo-fix-sequence-number-when-no-eof.patch diff --git a/staging-6.12/net-airoha-fix-register-index-for-tx-fwd-counter-con.patch b/staging-6.12/net-airoha-fix-register-index-for-tx-fwd-counter-con.patch new file mode 100644 index 0000000000..0b3477ee4f --- /dev/null +++ b/staging-6.12/net-airoha-fix-register-index-for-tx-fwd-counter-con.patch @@ -0,0 +1,45 @@ +From e1cc41fc264d103a19bfebc3fc7133019a7b49c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Jun 2026 07:09:13 +0800 +Subject: net: airoha: Fix register index for Tx-fwd counter configuration + +From: Wayen.Yan + +[ Upstream commit 1402ecccf5630a0b7fa4749d7d2e72abc3f3d73d ] + +In airoha_qdma_init_qos_stats(), the Tx-fwd counter configuration +register uses the same index (i << 1) as the Tx-cpu counter, which +overwrites the Tx-cpu configuration. The Tx-fwd counter value register +correctly uses (i << 1) + 1, so the configuration register should use +the same index. + +Fix the REG_CNTR_CFG index from (i << 1) to ((i << 1) + 1) so that +the Tx-fwd counter is properly configured instead of clobbering the +Tx-cpu counter config. + +Fixes: 20bf7d07c956 ("net: airoha: Add sched ETS offload support") +Signed-off-by: Wayen.Yan +Acked-by: Lorenzo Bianconi +Link: https://patch.msgid.link/6a2b40e7.4dd82583.3a5c46.e566@mx.google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/airoha/airoha_eth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c +index 58e5791e9cd4..9ebc9788ded7 100644 +--- a/drivers/net/ethernet/airoha/airoha_eth.c ++++ b/drivers/net/ethernet/airoha/airoha_eth.c +@@ -2022,7 +2022,7 @@ static void airoha_qdma_init_qos_stats(struct airoha_qdma *qdma) + FIELD_PREP(CNTR_CHAN_MASK, i)); + /* Tx-fwd transferred count */ + airoha_qdma_wr(qdma, REG_CNTR_VAL((i << 1) + 1), 0); +- airoha_qdma_wr(qdma, REG_CNTR_CFG(i << 1), ++ airoha_qdma_wr(qdma, REG_CNTR_CFG((i << 1) + 1), + CNTR_EN_MASK | CNTR_ALL_QUEUE_EN_MASK | + CNTR_ALL_DSCP_RING_EN_MASK | + FIELD_PREP(CNTR_SRC_MASK, 1) | +-- +2.53.0 + diff --git a/staging-6.12/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch b/staging-6.12/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch new file mode 100644 index 0000000000..6e8222829d --- /dev/null +++ b/staging-6.12/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch @@ -0,0 +1,74 @@ +From 936a49ce377e5e93e23df1ba275802a43312ae10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:08:29 +0900 +Subject: net: mpls: initialize rtm_tos in mpls_getroute() + +From: Yehyeong Lee + +[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ] + +mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE +request by filling a struct rtmsg allocated from an skb whose data +area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every +field of the header except rtm_tos: + + r = nlmsg_data(nlh); + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; + r->rtm_protocol = rt->rt_protocol; + r->rtm_flags = 0; + +struct rtmsg has no padding, so the one uninitialised byte rtm_tos +(offset 3) is copied straight to user space on recvmsg(), leaking a +byte of uninitialised heap memory. This is in contrast to +mpls_dump_route(), which fills the very same header and does set +rtm_tos = 0. + +Initialize rtm_tos to 0, matching mpls_dump_route(). + +Reproduced with KMSAN by adding an MPLS route and issuing a +non-RTM_F_FIB_MATCH RTM_GETROUTE for its label: + + BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 + _copy_to_iter+0x36c/0x33f0 + __skb_datagram_iter+0x196/0x12c0 + skb_copy_datagram_iter+0x5b/0x210 + netlink_recvmsg+0x37b/0xef0 + ... + Uninit was created at: + __alloc_skb+0x8ca/0x10e0 + mpls_getroute+0x1280/0x3a40 + rtnetlink_rcv_msg+0x1138/0x15a0 + ... + Byte 19 of 64 is uninitialized + +(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos) + +Fixes: 397fc9e5cefe ("mpls: route get support") +Signed-off-by: Yehyeong Lee +Link: https://patch.msgid.link/20260723010830.289917-1-yhlee@isslab.korea.ac.kr +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/mpls/af_mpls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 98816e51e01a..0379540d601a 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -2468,6 +2468,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; ++ r->rtm_tos = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; +-- +2.53.0 + diff --git a/staging-6.12/netfilter-br_netfilter-reallocate-headroom-if-necess.patch b/staging-6.12/netfilter-br_netfilter-reallocate-headroom-if-necess.patch new file mode 100644 index 0000000000..e213cba2f6 --- /dev/null +++ b/staging-6.12/netfilter-br_netfilter-reallocate-headroom-if-necess.patch @@ -0,0 +1,142 @@ +From 803fa2f613703f2af77704991ad23ea7ae7f1c26 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 16:46:38 +0200 +Subject: netfilter: br_netfilter: Reallocate headroom if necessary in + neigh_hh_bridge() + +From: Lorenzo Bianconi + +[ Upstream commit b2870fc21601db9133bc70c48c603b487614fa3b ] + +neigh_hh_bridge() assumes the skb always has sufficient headroom to copy +the aligned L2 header. This assumption can trigger the crash reported +below using the following netfilter setup: + +$modprobe br_netfilter +$sysctl -w net.bridge.bridge-nf-call-iptables=1 + +$root@OpenWrt:~# nft list ruleset +table ip nat { + chain prerouting { + type nat hook prerouting priority dstnat; policy accept; + ip daddr 192.168.83.123 dnat to 192.168.83.120 + } +} + +- iperf3 client (192.168.83.119) --> bridge (192.168.83.118) --> iperf3 server (192.168.83.120) + +the iperf3 client is sending packet for 192.168.83.123 to the bridge device. + +[ 1579.036575] Unable to handle kernel write to read-only memory at virtual address ffffff8004d76ffe +[ 1579.045482] Mem abort info: +[ 1579.048273] ESR = 0x000000009600004f +[ 1579.052024] EC = 0x25: DABT (current EL), IL = 32 bits +[ 1579.057363] SET = 0, FnV = 0 +[ 1579.060417] EA = 0, S1PTW = 0 +[ 1579.063550] FSC = 0x0f: level 3 permission fault +[ 1579.068345] Data abort info: +[ 1579.071224] ISV = 0, ISS = 0x0000004f, ISS2 = 0x00000000 +[ 1579.076720] CM = 0, WnR = 1, TnD = 0, TagAccess = 0 +[ 1579.081770] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 1579.087092] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000080dc4000 +[ 1579.093794] [ffffff8004d76ffe] pgd=180000009ffff003, p4d=180000009ffff003, pud=180000009ffff003, pmd=180000009ffe3003, pte=0060000084d76787 +[ 1579.106343] Internal error: Oops: 000000009600004f [#1] SMP +[ 1579.193824] CPU: 0 UID: 0 PID: 235 Comm: napi/qdma_eth-3 Tainted: G O 6.12.57 #0 +[ 1579.202614] Tainted: [O]=OOT_MODULE +[ 1579.206102] Hardware name: Airoha AN7581 Evaluation Board (DT) +[ 1579.211929] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 1579.218889] pc : br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.225859] lr : br_nf_pre_routing_finish_bridge+0x18c/0xcc8 [br_netfilter] +[ 1579.232822] sp : ffffffc0817cba20 +[ 1579.236128] x29: ffffffc0817cba20 x28: 0000000000000000 x27: ffffff8002b89000 +[ 1579.243273] x26: ffffff8004d7700e x25: 0000000000000008 x24: 0000000000000000 +[ 1579.250416] x23: ffffffc08179d4c0 x22: 0000000000000000 x21: ffffffc08179d4c0 +[ 1579.257561] x20: ffffff8004d9b800 x19: ffffff8015010000 x18: 0000000000000014 +[ 1579.264704] x17: ffffffbf9e930000 x16: ffffffc0817c8000 x15: 0000000000000070 +[ 1579.271848] x14: 0000000000000080 x13: 0000000000000001 x12: 0000000000000000 +[ 1579.278993] x11: ffffffc0798caae0 x10: ffffff8014db6fd8 x9 : 0000000000000000 +[ 1579.286136] x8 : 0000000000000003 x7 : ffffffc08171f628 x6 : 000000001a3b83d3 +[ 1579.293281] x5 : 0000000000000000 x4 : 1beb76f22fee0000 x3 : ffffff8004d7700e +[ 1579.300425] x2 : 0000000000000000 x1 : ffffff8004d9b8bc x0 : ffffff80026ed000 +[ 1579.307570] Call trace: +[ 1579.310018] br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.316632] br_nf_hook_thresh+0xd4/0x14bc [br_netfilter] +[ 1579.322032] br_nf_hook_thresh+0x250/0x14bc [br_netfilter] +[ 1579.327517] br_nf_hook_thresh+0x76c/0x14bc [br_netfilter] +[ 1579.333003] br_handle_frame+0x180/0x480 +[ 1579.336935] __netif_receive_skb_core.constprop.0+0x540/0xf40 +[ 1579.342682] __netif_receive_skb_one_core+0x28/0x50 +[ 1579.347561] process_backlog+0x98/0x1e0 +[ 1579.351398] __napi_poll+0x34/0x1c4 +[ 1579.354887] net_rx_action+0x178/0x330 +[ 1579.358638] handle_softirqs+0x108/0x2d4 +[ 1579.362560] __do_softirq+0x10/0x18 +[ 1579.366051] ____do_softirq+0xc/0x20 +[ 1579.369627] call_on_irq_stack+0x30/0x4c +[ 1579.373550] do_softirq_own_stack+0x18/0x20 +[ 1579.377734] do_softirq+0x4c/0x60 +[ 1579.381050] __local_bh_enable_ip+0x88/0x98 +[ 1579.385234] napi_threaded_poll_loop+0x188/0x21c +[ 1579.389853] napi_threaded_poll+0x70/0x80 +[ 1579.393863] kthread+0xd8/0xdc +[ 1579.396918] ret_from_fork+0x10/0x20 +[ 1579.400499] Code: 88dffc22 3707ffc2 f9406663 f9406684 (f81f0064) +[ 1579.406589] ---[ end trace 0000000000000000 ]--- +[ 1579.411209] Kernel panic - not syncing: Oops: Fatal exception in interrupt +[ 1579.418083] SMP: stopping secondary CPUs +[ 1579.422012] Kernel Offset: disabled + +Fix the issue reallocating the skb headroom if necessary in neigh_hh_bridge routine. + +Fixes: e179e6322ac33 ("netfilter: bridge-netfilter: Fix MAC header handling with IP DNAT") +Reviewed-by: Ido Schimmel +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/neighbour.h | 8 ++++++-- + net/bridge/br_netfilter_hooks.c | 6 +++++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/include/net/neighbour.h b/include/net/neighbour.h +index cb5f835a5d61..0272d0f0e89d 100644 +--- a/include/net/neighbour.h ++++ b/include/net/neighbour.h +@@ -476,11 +476,15 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) + #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) + static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) + { +- unsigned int seq, hh_alen; ++ unsigned int seq, hh_alen = HH_DATA_ALIGN(ETH_HLEN); ++ int err; ++ ++ err = skb_cow_head(skb, hh_alen); ++ if (err) ++ return err; + + do { + seq = read_seqbegin(&hh->hh_lock); +- hh_alen = HH_DATA_ALIGN(ETH_HLEN); + memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); + } while (read_seqretry(&hh->hh_lock, seq)); + return 0; +diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c +index 5ad3f3ef4ca7..c550907b92dd 100644 +--- a/net/bridge/br_netfilter_hooks.c ++++ b/net/bridge/br_netfilter_hooks.c +@@ -296,7 +296,11 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_ + goto free_skb; + } + +- neigh_hh_bridge(&neigh->hh, skb); ++ if (neigh_hh_bridge(&neigh->hh, skb)) { ++ neigh_release(neigh); ++ goto free_skb; ++ } ++ + skb->dev = br_indev; + + ret = br_handle_frame_finish(net, sk, skb); +-- +2.53.0 + diff --git a/staging-6.12/series b/staging-6.12/series index 8b36f5acf4..ab6e78e7a2 100644 --- a/staging-6.12/series +++ b/staging-6.12/series @@ -8,3 +8,6 @@ um-set-parent-death-signal-for-userspace-process.patch kunit-tool-terminate-kernel-under-test-on-sigint.patch kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch um-preserve-errno-within-signal-handler.patch +netfilter-br_netfilter-reallocate-headroom-if-necess.patch +net-airoha-fix-register-index-for-tx-fwd-counter-con.patch +net-mpls-initialize-rtm_tos-in-mpls_getroute.patch diff --git a/staging-6.18/drm-gpusvm-publish-dpagemap-early-to-avoid-device-ma.patch b/staging-6.18/drm-gpusvm-publish-dpagemap-early-to-avoid-device-ma.patch new file mode 100644 index 0000000000..fee34d5fa1 --- /dev/null +++ b/staging-6.18/drm-gpusvm-publish-dpagemap-early-to-avoid-device-ma.patch @@ -0,0 +1,70 @@ +From 081cb57de50473cb058ae07230a580f7d9bbb7ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Jul 2026 19:17:28 +0800 +Subject: drm/gpusvm: publish dpagemap early to avoid device mapping leak on + error + +From: Honglei Huang + +commit 7f708f51e3955bda0d77a0b67ab9bea6c97fea99 upstream. + +drm_gpusvm_get_pages() only stored the local dpagemap into +svm_pages->dpagemap on the success path. If a later page failed (e.g. +-EOPNOTSUPP when ctx->allow_mixed is false) and jumped to err_unmap, +svm_pages->dpagemap was still NULL, so __drm_gpusvm_unmap_pages() skipped +device_unmap() and leaked the device mappings already created. + +Assign svm_pages->dpagemap when the first device page is mapped so the +err_unmap path can device_unmap() those mappings. + +This issue was found by Sashiko AI review. + +Fixes: f70da6f99d4f ("drm/gpusvm: pull out drm_gpusvm_pages substructure") +Cc: stable@vger.kernel.org +Reviewed-by: Matthew Brost +Signed-off-by: Honglei Huang +Signed-off-by: Matthew Brost +Link: https://patch.msgid.link/20260701062800.409248-4-honghuan@amd.com +[ Adjusted for 6.18.y: drop drm_pagemap_get()/drm_pagemap_put() around the + svm_pages->dpagemap assignment; that reference counting is not present in + 6.18 where the field is not refcounted (unmap path only clears it). ] +Signed-off-by: Honglei Huang +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/drm_gpusvm.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c +index 781cd4e5b704..e5c7befe3108 100644 +--- a/drivers/gpu/drm/drm_gpusvm.c ++++ b/drivers/gpu/drm/drm_gpusvm.c +@@ -1390,6 +1390,14 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, + err = -EAGAIN; + goto err_unmap; + } ++ ++ /* ++ * Set the dpagemap as soon as the first ++ * device page is mapped so the err_unmap path ++ * can device_unmap() the device mappings that ++ * have already been created. ++ */ ++ svm_pages->dpagemap = dpagemap; + } + svm_pages->dma_addr[j] = + dpagemap->ops->device_map(dpagemap, +@@ -1432,10 +1440,8 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, + flags.has_dma_mapping = true; + } + +- if (pagemap) { ++ if (pagemap) + flags.has_devmem_pages = true; +- svm_pages->dpagemap = dpagemap; +- } + + /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */ + WRITE_ONCE(svm_pages->flags.__flags, flags.__flags); +-- +2.53.0 + diff --git a/staging-6.18/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch b/staging-6.18/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch new file mode 100644 index 0000000000..143608725b --- /dev/null +++ b/staging-6.18/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch @@ -0,0 +1,74 @@ +From 725d4c733423508d3690cb930ee44c9d168caa7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:08:29 +0900 +Subject: net: mpls: initialize rtm_tos in mpls_getroute() + +From: Yehyeong Lee + +[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ] + +mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE +request by filling a struct rtmsg allocated from an skb whose data +area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every +field of the header except rtm_tos: + + r = nlmsg_data(nlh); + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; + r->rtm_protocol = rt->rt_protocol; + r->rtm_flags = 0; + +struct rtmsg has no padding, so the one uninitialised byte rtm_tos +(offset 3) is copied straight to user space on recvmsg(), leaking a +byte of uninitialised heap memory. This is in contrast to +mpls_dump_route(), which fills the very same header and does set +rtm_tos = 0. + +Initialize rtm_tos to 0, matching mpls_dump_route(). + +Reproduced with KMSAN by adding an MPLS route and issuing a +non-RTM_F_FIB_MATCH RTM_GETROUTE for its label: + + BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 + _copy_to_iter+0x36c/0x33f0 + __skb_datagram_iter+0x196/0x12c0 + skb_copy_datagram_iter+0x5b/0x210 + netlink_recvmsg+0x37b/0xef0 + ... + Uninit was created at: + __alloc_skb+0x8ca/0x10e0 + mpls_getroute+0x1280/0x3a40 + rtnetlink_rcv_msg+0x1138/0x15a0 + ... + Byte 19 of 64 is uninitialized + +(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos) + +Fixes: 397fc9e5cefe ("mpls: route get support") +Signed-off-by: Yehyeong Lee +Link: https://patch.msgid.link/20260723010830.289917-1-yhlee@isslab.korea.ac.kr +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/mpls/af_mpls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index f7f60025d042..f9b8c4d0f049 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -2468,6 +2468,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; ++ r->rtm_tos = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; +-- +2.53.0 + diff --git a/staging-6.18/netfilter-br_netfilter-reallocate-headroom-if-necess.patch b/staging-6.18/netfilter-br_netfilter-reallocate-headroom-if-necess.patch new file mode 100644 index 0000000000..3f36b3221d --- /dev/null +++ b/staging-6.18/netfilter-br_netfilter-reallocate-headroom-if-necess.patch @@ -0,0 +1,142 @@ +From 55d3dc69df3c4c77d98127c4891fe31a2eb9d115 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 16:46:38 +0200 +Subject: netfilter: br_netfilter: Reallocate headroom if necessary in + neigh_hh_bridge() + +From: Lorenzo Bianconi + +[ Upstream commit b2870fc21601db9133bc70c48c603b487614fa3b ] + +neigh_hh_bridge() assumes the skb always has sufficient headroom to copy +the aligned L2 header. This assumption can trigger the crash reported +below using the following netfilter setup: + +$modprobe br_netfilter +$sysctl -w net.bridge.bridge-nf-call-iptables=1 + +$root@OpenWrt:~# nft list ruleset +table ip nat { + chain prerouting { + type nat hook prerouting priority dstnat; policy accept; + ip daddr 192.168.83.123 dnat to 192.168.83.120 + } +} + +- iperf3 client (192.168.83.119) --> bridge (192.168.83.118) --> iperf3 server (192.168.83.120) + +the iperf3 client is sending packet for 192.168.83.123 to the bridge device. + +[ 1579.036575] Unable to handle kernel write to read-only memory at virtual address ffffff8004d76ffe +[ 1579.045482] Mem abort info: +[ 1579.048273] ESR = 0x000000009600004f +[ 1579.052024] EC = 0x25: DABT (current EL), IL = 32 bits +[ 1579.057363] SET = 0, FnV = 0 +[ 1579.060417] EA = 0, S1PTW = 0 +[ 1579.063550] FSC = 0x0f: level 3 permission fault +[ 1579.068345] Data abort info: +[ 1579.071224] ISV = 0, ISS = 0x0000004f, ISS2 = 0x00000000 +[ 1579.076720] CM = 0, WnR = 1, TnD = 0, TagAccess = 0 +[ 1579.081770] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 1579.087092] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000080dc4000 +[ 1579.093794] [ffffff8004d76ffe] pgd=180000009ffff003, p4d=180000009ffff003, pud=180000009ffff003, pmd=180000009ffe3003, pte=0060000084d76787 +[ 1579.106343] Internal error: Oops: 000000009600004f [#1] SMP +[ 1579.193824] CPU: 0 UID: 0 PID: 235 Comm: napi/qdma_eth-3 Tainted: G O 6.12.57 #0 +[ 1579.202614] Tainted: [O]=OOT_MODULE +[ 1579.206102] Hardware name: Airoha AN7581 Evaluation Board (DT) +[ 1579.211929] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 1579.218889] pc : br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.225859] lr : br_nf_pre_routing_finish_bridge+0x18c/0xcc8 [br_netfilter] +[ 1579.232822] sp : ffffffc0817cba20 +[ 1579.236128] x29: ffffffc0817cba20 x28: 0000000000000000 x27: ffffff8002b89000 +[ 1579.243273] x26: ffffff8004d7700e x25: 0000000000000008 x24: 0000000000000000 +[ 1579.250416] x23: ffffffc08179d4c0 x22: 0000000000000000 x21: ffffffc08179d4c0 +[ 1579.257561] x20: ffffff8004d9b800 x19: ffffff8015010000 x18: 0000000000000014 +[ 1579.264704] x17: ffffffbf9e930000 x16: ffffffc0817c8000 x15: 0000000000000070 +[ 1579.271848] x14: 0000000000000080 x13: 0000000000000001 x12: 0000000000000000 +[ 1579.278993] x11: ffffffc0798caae0 x10: ffffff8014db6fd8 x9 : 0000000000000000 +[ 1579.286136] x8 : 0000000000000003 x7 : ffffffc08171f628 x6 : 000000001a3b83d3 +[ 1579.293281] x5 : 0000000000000000 x4 : 1beb76f22fee0000 x3 : ffffff8004d7700e +[ 1579.300425] x2 : 0000000000000000 x1 : ffffff8004d9b8bc x0 : ffffff80026ed000 +[ 1579.307570] Call trace: +[ 1579.310018] br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.316632] br_nf_hook_thresh+0xd4/0x14bc [br_netfilter] +[ 1579.322032] br_nf_hook_thresh+0x250/0x14bc [br_netfilter] +[ 1579.327517] br_nf_hook_thresh+0x76c/0x14bc [br_netfilter] +[ 1579.333003] br_handle_frame+0x180/0x480 +[ 1579.336935] __netif_receive_skb_core.constprop.0+0x540/0xf40 +[ 1579.342682] __netif_receive_skb_one_core+0x28/0x50 +[ 1579.347561] process_backlog+0x98/0x1e0 +[ 1579.351398] __napi_poll+0x34/0x1c4 +[ 1579.354887] net_rx_action+0x178/0x330 +[ 1579.358638] handle_softirqs+0x108/0x2d4 +[ 1579.362560] __do_softirq+0x10/0x18 +[ 1579.366051] ____do_softirq+0xc/0x20 +[ 1579.369627] call_on_irq_stack+0x30/0x4c +[ 1579.373550] do_softirq_own_stack+0x18/0x20 +[ 1579.377734] do_softirq+0x4c/0x60 +[ 1579.381050] __local_bh_enable_ip+0x88/0x98 +[ 1579.385234] napi_threaded_poll_loop+0x188/0x21c +[ 1579.389853] napi_threaded_poll+0x70/0x80 +[ 1579.393863] kthread+0xd8/0xdc +[ 1579.396918] ret_from_fork+0x10/0x20 +[ 1579.400499] Code: 88dffc22 3707ffc2 f9406663 f9406684 (f81f0064) +[ 1579.406589] ---[ end trace 0000000000000000 ]--- +[ 1579.411209] Kernel panic - not syncing: Oops: Fatal exception in interrupt +[ 1579.418083] SMP: stopping secondary CPUs +[ 1579.422012] Kernel Offset: disabled + +Fix the issue reallocating the skb headroom if necessary in neigh_hh_bridge routine. + +Fixes: e179e6322ac33 ("netfilter: bridge-netfilter: Fix MAC header handling with IP DNAT") +Reviewed-by: Ido Schimmel +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/neighbour.h | 8 ++++++-- + net/bridge/br_netfilter_hooks.c | 6 +++++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/include/net/neighbour.h b/include/net/neighbour.h +index 4a30bd458c5a..c13c758aca7e 100644 +--- a/include/net/neighbour.h ++++ b/include/net/neighbour.h +@@ -480,11 +480,15 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) + #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) + static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) + { +- unsigned int seq, hh_alen; ++ unsigned int seq, hh_alen = HH_DATA_ALIGN(ETH_HLEN); ++ int err; ++ ++ err = skb_cow_head(skb, hh_alen); ++ if (err) ++ return err; + + do { + seq = read_seqbegin(&hh->hh_lock); +- hh_alen = HH_DATA_ALIGN(ETH_HLEN); + memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); + } while (read_seqretry(&hh->hh_lock, seq)); + return 0; +diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c +index 083e2fe96441..6544c18febef 100644 +--- a/net/bridge/br_netfilter_hooks.c ++++ b/net/bridge/br_netfilter_hooks.c +@@ -296,7 +296,11 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_ + goto free_skb; + } + +- neigh_hh_bridge(&neigh->hh, skb); ++ if (neigh_hh_bridge(&neigh->hh, skb)) { ++ neigh_release(neigh); ++ goto free_skb; ++ } ++ + skb->dev = br_indev; + + ret = br_handle_frame_finish(net, sk, skb); +-- +2.53.0 + diff --git a/staging-6.18/series b/staging-6.18/series index e31db453cc..cc1362d923 100644 --- a/staging-6.18/series +++ b/staging-6.18/series @@ -1,3 +1,6 @@ netfilter-nf_conntrack_expect-restore-helper-propaga.patch kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch kunit-tool-terminate-kernel-under-test-on-sigint.patch +netfilter-br_netfilter-reallocate-headroom-if-necess.patch +net-mpls-initialize-rtm_tos-in-mpls_getroute.patch +drm-gpusvm-publish-dpagemap-early-to-avoid-device-ma.patch diff --git a/staging-6.6/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch b/staging-6.6/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch new file mode 100644 index 0000000000..87273df32f --- /dev/null +++ b/staging-6.6/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch @@ -0,0 +1,74 @@ +From af674c2145b8eec73f250be1433796e3af33aba1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:08:29 +0900 +Subject: net: mpls: initialize rtm_tos in mpls_getroute() + +From: Yehyeong Lee + +[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ] + +mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE +request by filling a struct rtmsg allocated from an skb whose data +area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every +field of the header except rtm_tos: + + r = nlmsg_data(nlh); + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; + r->rtm_protocol = rt->rt_protocol; + r->rtm_flags = 0; + +struct rtmsg has no padding, so the one uninitialised byte rtm_tos +(offset 3) is copied straight to user space on recvmsg(), leaking a +byte of uninitialised heap memory. This is in contrast to +mpls_dump_route(), which fills the very same header and does set +rtm_tos = 0. + +Initialize rtm_tos to 0, matching mpls_dump_route(). + +Reproduced with KMSAN by adding an MPLS route and issuing a +non-RTM_F_FIB_MATCH RTM_GETROUTE for its label: + + BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 + _copy_to_iter+0x36c/0x33f0 + __skb_datagram_iter+0x196/0x12c0 + skb_copy_datagram_iter+0x5b/0x210 + netlink_recvmsg+0x37b/0xef0 + ... + Uninit was created at: + __alloc_skb+0x8ca/0x10e0 + mpls_getroute+0x1280/0x3a40 + rtnetlink_rcv_msg+0x1138/0x15a0 + ... + Byte 19 of 64 is uninitialized + +(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos) + +Fixes: 397fc9e5cefe ("mpls: route get support") +Signed-off-by: Yehyeong Lee +Link: https://patch.msgid.link/20260723010830.289917-1-yhlee@isslab.korea.ac.kr +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/mpls/af_mpls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 2099ce095edc..cf5ae62ba898 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -2469,6 +2469,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; ++ r->rtm_tos = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; +-- +2.53.0 + diff --git a/staging-6.6/netfilter-br_netfilter-reallocate-headroom-if-necess.patch b/staging-6.6/netfilter-br_netfilter-reallocate-headroom-if-necess.patch new file mode 100644 index 0000000000..e6dc84f061 --- /dev/null +++ b/staging-6.6/netfilter-br_netfilter-reallocate-headroom-if-necess.patch @@ -0,0 +1,142 @@ +From 92da9a2759d37369e137570b018903ac0cccf9d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 May 2026 16:46:38 +0200 +Subject: netfilter: br_netfilter: Reallocate headroom if necessary in + neigh_hh_bridge() + +From: Lorenzo Bianconi + +[ Upstream commit b2870fc21601db9133bc70c48c603b487614fa3b ] + +neigh_hh_bridge() assumes the skb always has sufficient headroom to copy +the aligned L2 header. This assumption can trigger the crash reported +below using the following netfilter setup: + +$modprobe br_netfilter +$sysctl -w net.bridge.bridge-nf-call-iptables=1 + +$root@OpenWrt:~# nft list ruleset +table ip nat { + chain prerouting { + type nat hook prerouting priority dstnat; policy accept; + ip daddr 192.168.83.123 dnat to 192.168.83.120 + } +} + +- iperf3 client (192.168.83.119) --> bridge (192.168.83.118) --> iperf3 server (192.168.83.120) + +the iperf3 client is sending packet for 192.168.83.123 to the bridge device. + +[ 1579.036575] Unable to handle kernel write to read-only memory at virtual address ffffff8004d76ffe +[ 1579.045482] Mem abort info: +[ 1579.048273] ESR = 0x000000009600004f +[ 1579.052024] EC = 0x25: DABT (current EL), IL = 32 bits +[ 1579.057363] SET = 0, FnV = 0 +[ 1579.060417] EA = 0, S1PTW = 0 +[ 1579.063550] FSC = 0x0f: level 3 permission fault +[ 1579.068345] Data abort info: +[ 1579.071224] ISV = 0, ISS = 0x0000004f, ISS2 = 0x00000000 +[ 1579.076720] CM = 0, WnR = 1, TnD = 0, TagAccess = 0 +[ 1579.081770] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 +[ 1579.087092] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000080dc4000 +[ 1579.093794] [ffffff8004d76ffe] pgd=180000009ffff003, p4d=180000009ffff003, pud=180000009ffff003, pmd=180000009ffe3003, pte=0060000084d76787 +[ 1579.106343] Internal error: Oops: 000000009600004f [#1] SMP +[ 1579.193824] CPU: 0 UID: 0 PID: 235 Comm: napi/qdma_eth-3 Tainted: G O 6.12.57 #0 +[ 1579.202614] Tainted: [O]=OOT_MODULE +[ 1579.206102] Hardware name: Airoha AN7581 Evaluation Board (DT) +[ 1579.211929] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 1579.218889] pc : br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.225859] lr : br_nf_pre_routing_finish_bridge+0x18c/0xcc8 [br_netfilter] +[ 1579.232822] sp : ffffffc0817cba20 +[ 1579.236128] x29: ffffffc0817cba20 x28: 0000000000000000 x27: ffffff8002b89000 +[ 1579.243273] x26: ffffff8004d7700e x25: 0000000000000008 x24: 0000000000000000 +[ 1579.250416] x23: ffffffc08179d4c0 x22: 0000000000000000 x21: ffffffc08179d4c0 +[ 1579.257561] x20: ffffff8004d9b800 x19: ffffff8015010000 x18: 0000000000000014 +[ 1579.264704] x17: ffffffbf9e930000 x16: ffffffc0817c8000 x15: 0000000000000070 +[ 1579.271848] x14: 0000000000000080 x13: 0000000000000001 x12: 0000000000000000 +[ 1579.278993] x11: ffffffc0798caae0 x10: ffffff8014db6fd8 x9 : 0000000000000000 +[ 1579.286136] x8 : 0000000000000003 x7 : ffffffc08171f628 x6 : 000000001a3b83d3 +[ 1579.293281] x5 : 0000000000000000 x4 : 1beb76f22fee0000 x3 : ffffff8004d7700e +[ 1579.300425] x2 : 0000000000000000 x1 : ffffff8004d9b8bc x0 : ffffff80026ed000 +[ 1579.307570] Call trace: +[ 1579.310018] br_nf_pre_routing_finish_bridge+0x1ac/0xcc8 [br_netfilter] +[ 1579.316632] br_nf_hook_thresh+0xd4/0x14bc [br_netfilter] +[ 1579.322032] br_nf_hook_thresh+0x250/0x14bc [br_netfilter] +[ 1579.327517] br_nf_hook_thresh+0x76c/0x14bc [br_netfilter] +[ 1579.333003] br_handle_frame+0x180/0x480 +[ 1579.336935] __netif_receive_skb_core.constprop.0+0x540/0xf40 +[ 1579.342682] __netif_receive_skb_one_core+0x28/0x50 +[ 1579.347561] process_backlog+0x98/0x1e0 +[ 1579.351398] __napi_poll+0x34/0x1c4 +[ 1579.354887] net_rx_action+0x178/0x330 +[ 1579.358638] handle_softirqs+0x108/0x2d4 +[ 1579.362560] __do_softirq+0x10/0x18 +[ 1579.366051] ____do_softirq+0xc/0x20 +[ 1579.369627] call_on_irq_stack+0x30/0x4c +[ 1579.373550] do_softirq_own_stack+0x18/0x20 +[ 1579.377734] do_softirq+0x4c/0x60 +[ 1579.381050] __local_bh_enable_ip+0x88/0x98 +[ 1579.385234] napi_threaded_poll_loop+0x188/0x21c +[ 1579.389853] napi_threaded_poll+0x70/0x80 +[ 1579.393863] kthread+0xd8/0xdc +[ 1579.396918] ret_from_fork+0x10/0x20 +[ 1579.400499] Code: 88dffc22 3707ffc2 f9406663 f9406684 (f81f0064) +[ 1579.406589] ---[ end trace 0000000000000000 ]--- +[ 1579.411209] Kernel panic - not syncing: Oops: Fatal exception in interrupt +[ 1579.418083] SMP: stopping secondary CPUs +[ 1579.422012] Kernel Offset: disabled + +Fix the issue reallocating the skb headroom if necessary in neigh_hh_bridge routine. + +Fixes: e179e6322ac33 ("netfilter: bridge-netfilter: Fix MAC header handling with IP DNAT") +Reviewed-by: Ido Schimmel +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/neighbour.h | 8 ++++++-- + net/bridge/br_netfilter_hooks.c | 6 +++++- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/include/net/neighbour.h b/include/net/neighbour.h +index d775906a65c7..9ada7451fd2a 100644 +--- a/include/net/neighbour.h ++++ b/include/net/neighbour.h +@@ -476,11 +476,15 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) + #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) + static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) + { +- unsigned int seq, hh_alen; ++ unsigned int seq, hh_alen = HH_DATA_ALIGN(ETH_HLEN); ++ int err; ++ ++ err = skb_cow_head(skb, hh_alen); ++ if (err) ++ return err; + + do { + seq = read_seqbegin(&hh->hh_lock); +- hh_alen = HH_DATA_ALIGN(ETH_HLEN); + memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); + } while (read_seqretry(&hh->hh_lock, seq)); + return 0; +diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c +index e6962d693359..3fbcf1b7e93d 100644 +--- a/net/bridge/br_netfilter_hooks.c ++++ b/net/bridge/br_netfilter_hooks.c +@@ -292,7 +292,11 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_ + goto free_skb; + } + +- neigh_hh_bridge(&neigh->hh, skb); ++ if (neigh_hh_bridge(&neigh->hh, skb)) { ++ neigh_release(neigh); ++ goto free_skb; ++ } ++ + skb->dev = br_indev; + + ret = br_handle_frame_finish(net, sk, skb); +-- +2.53.0 + diff --git a/staging-6.6/series b/staging-6.6/series index 9de0fac578..7464fefac5 100644 --- a/staging-6.6/series +++ b/staging-6.6/series @@ -1 +1,3 @@ netfilter-nf_conntrack_expect-restore-helper-propaga.patch +netfilter-br_netfilter-reallocate-headroom-if-necess.patch +net-mpls-initialize-rtm_tos-in-mpls_getroute.patch diff --git a/staging-7.1/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch b/staging-7.1/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch new file mode 100644 index 0000000000..f3c4f04906 --- /dev/null +++ b/staging-7.1/net-mpls-initialize-rtm_tos-in-mpls_getroute.patch @@ -0,0 +1,74 @@ +From 7426b5daf78256a507e3d6bc16375a9ad27dc735 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jul 2026 10:08:29 +0900 +Subject: net: mpls: initialize rtm_tos in mpls_getroute() + +From: Yehyeong Lee + +[ Upstream commit 295dd295e2137e10e9a5b1891d97e0f08de76f03 ] + +mpls_getroute() builds the RTM_NEWROUTE reply to an RTM_GETROUTE +request by filling a struct rtmsg allocated from an skb whose data +area is not zeroed (alloc_skb(NLMSG_GOODSIZE, ...)). It sets every +field of the header except rtm_tos: + + r = nlmsg_data(nlh); + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; + r->rtm_protocol = rt->rt_protocol; + r->rtm_flags = 0; + +struct rtmsg has no padding, so the one uninitialised byte rtm_tos +(offset 3) is copied straight to user space on recvmsg(), leaking a +byte of uninitialised heap memory. This is in contrast to +mpls_dump_route(), which fills the very same header and does set +rtm_tos = 0. + +Initialize rtm_tos to 0, matching mpls_dump_route(). + +Reproduced with KMSAN by adding an MPLS route and issuing a +non-RTM_F_FIB_MATCH RTM_GETROUTE for its label: + + BUG: KMSAN: kernel-infoleak in _copy_to_iter+0x36c/0x33f0 + _copy_to_iter+0x36c/0x33f0 + __skb_datagram_iter+0x196/0x12c0 + skb_copy_datagram_iter+0x5b/0x210 + netlink_recvmsg+0x37b/0xef0 + ... + Uninit was created at: + __alloc_skb+0x8ca/0x10e0 + mpls_getroute+0x1280/0x3a40 + rtnetlink_rcv_msg+0x1138/0x15a0 + ... + Byte 19 of 64 is uninitialized + +(byte 19 = nlmsghdr(16) + rtmsg offset 3 = rtm_tos) + +Fixes: 397fc9e5cefe ("mpls: route get support") +Signed-off-by: Yehyeong Lee +Link: https://patch.msgid.link/20260723010830.289917-1-yhlee@isslab.korea.ac.kr +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/mpls/af_mpls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 35069183f59c..1ad5a2d9b6cd 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -2541,6 +2541,7 @@ static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh, + r->rtm_family = AF_MPLS; + r->rtm_dst_len = 20; + r->rtm_src_len = 0; ++ r->rtm_tos = 0; + r->rtm_table = RT_TABLE_MAIN; + r->rtm_type = RTN_UNICAST; + r->rtm_scope = RT_SCOPE_UNIVERSE; +-- +2.53.0 + diff --git a/staging-7.1/series b/staging-7.1/series new file mode 100644 index 0000000000..20e097a07d --- /dev/null +++ b/staging-7.1/series @@ -0,0 +1 @@ +net-mpls-initialize-rtm_tos-in-mpls_getroute.patch