FAILED: patch "[PATCH] ubifs: Fix read out-of-bounds in ubifs_wbuf_write_nolock()" failed to apply to 4.14-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 4f2262a334641e05f645364d5ade1f565c85f20b Mon Sep 17 00:00:00 2001
From: Zhihao Cheng <[email protected]>
Date: Mon, 27 Dec 2021 11:22:40 +0800
Subject: [PATCH] ubifs: Fix read out-of-bounds in ubifs_wbuf_write_nolock()
Function ubifs_wbuf_write_nolock() may access buf out of bounds in following process:
ubifs_wbuf_write_nolock():
aligned_len = ALIGN(len, 8); // Assume len = 4089, aligned_len = 4096
if (aligned_len <= wbuf->avail) ... // Not satisfy
if (wbuf->used) {
ubifs_leb_write() // Fill some data in avail wbuf
len -= wbuf->avail; // len is still not 8-bytes aligned
aligned_len -= wbuf->avail;
}
n = aligned_len >> c->max_write_shift;
if (n) {
n <<= c->max_write_shift;
err = ubifs_leb_write(c, wbuf->lnum, buf + written,
wbuf->offs, n);
// n > len, read out of bounds less than 8(n-len) bytes}
, which can be catched by KASAN:
=========================================================
BUG: KASAN: slab-out-of-bounds in ecc_sw_hamming_calculate+0x1dc/0x7d0
Read of size 4 at addr ffff888105594ff8 by task kworker/u8:4/128
Workqueue: writeback wb_workfn (flush-ubifs_0_0)
Call Trace:
kasan_report.cold+0x81/0x165
nand_write_page_swecc+0xa9/0x160
ubifs_leb_write+0xf2/0x1b0 [ubifs]
ubifs_wbuf_write_nolock+0x421/0x12c0 [ubifs]
write_head+0xdc/0x1c0 [ubifs]
ubifs_jnl_write_inode+0x627/0x960 [ubifs]
wb_workfn+0x8af/0xb80Function ubifs_wbuf_write_nolock() accepts that parameter 'len' is not 8 bytes aligned, the 'len' represents the true length of buf (which is allocated in 'ubifs_jnl_xxx', eg. ubifs_jnl_write_inode), so ubifs_wbuf_write_nolock() must handle the length read from 'buf' carefully to write leb safely.
Fetch a reproducer in [Link].
fs/ubifs/io.c +30 -4
@@ -854,16 +854,42 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)*/ n = aligned_len >> c->max_write_shift;if (n) { - n <<= c->max_write_shift; +int m = n -1 ; +dbg_io ("write %d bytes to LEB %d:%d" , n, wbuf->lnum, wbuf->offs); - err =ubifs_leb_write (c, wbuf->lnum, buf + written, - wbuf->offs, n); + +if (m) { +/* '(n-1)<<c->max_write_shift < len' is always true. */ + m <<= c->max_write_shift; + err =ubifs_leb_write (c, wbuf->lnum, buf + written, + wbuf->offs, m); +if (err) + goto out; + wbuf->offs += m; + aligned_len -= m; + len -= m; + written += m; + } + +/* +* The non-written len of buf may be less than 'n' because +* parameter 'len' is not 8 bytes aligned, so here we read +* min(len, n) bytes from buf. +*/ + n =1 << c->max_write_shift; +memcpy (wbuf->buf, buf + written,min (len, n)); +if (n > len) { +ubifs_assert (c, n - len <8 ); +ubifs_pad (c, wbuf->buf + len, n - len); + } + + err =ubifs_leb_write (c, wbuf->lnum, wbuf->buf, wbuf->offs, n);if (err) goto out; wbuf->offs += n; aligned_len -= n; - len -= n; + len -=min (len, n); written += n; }