Update to 4.12.13
This commit is contained in:
parent
bab2ab0e8d
commit
cb5ce6ce3b
|
@ -1,11 +1,33 @@
|
|||
linux (4.12.12-3) UNRELEASED; urgency=medium
|
||||
linux (4.12.13-1) UNRELEASED; urgency=medium
|
||||
|
||||
* New upstream stable update:
|
||||
https://www.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.12.13
|
||||
- mtd: nand: make Samsung SLC NAND usable again
|
||||
- mtd: nand: hynix: add support for 20nm NAND chips
|
||||
- [armhf] mtd: nand: mxc: Fix mxc_v1 ooblayout
|
||||
- nvme-fabrics: generate spec-compliant UUID NQNs
|
||||
- btrfs: resume qgroup rescan on rw remount
|
||||
- rtlwifi: btcoexist: Fix breakage of ant_sel for rtl8723be
|
||||
- radix-tree: must check __radix_tree_preload() return value
|
||||
- mm: kvfree the swap cluster info if the swap file is unsatisfactory
|
||||
- mm/swapfile.c: fix swapon frontswap_map memory leak on error
|
||||
- mm/memory.c: fix mem_cgroup_oom_disable() call missing
|
||||
- [i386] ALSA: msnd: Optimize / harden DSP and MIDI loops
|
||||
- [x86] KVM: SVM: Limit PFERR_NESTED_GUEST_PAGE error_code check to L1 guest
|
||||
- rt2800: fix TX_PIN_CFG setting for non MT7620 chips
|
||||
- Bluetooth: Properly check L2CAP config option output buffer length
|
||||
(CVE-2017-1000251) (Closes: #875881)
|
||||
- [arm64] dts: marvell: armada-37xx: Fix GIC maintenance interrupt
|
||||
- [armel,armhf] 8692/1: mm: abort uaccess retries upon fatal signal
|
||||
- NFS: Fix 2 use after free issues in the I/O code
|
||||
- NFS: Sync the correct byte range during synchronous writes
|
||||
- NFSv4: Fix up mirror allocation
|
||||
- xfs: XFS_IS_REALTIME_INODE() should be false if no rt device present
|
||||
(CVE-2017-14340)
|
||||
|
||||
[ Salvatore Bonaccorso ]
|
||||
* sctp: Avoid out-of-bounds reads from address storage (CVE-2017-7558)
|
||||
* scsi: qla2xxx: Fix an integer overflow in sysfs code (CVE-2017-14051)
|
||||
* xfs: XFS_IS_REALTIME_INODE() should be false if no rt device present
|
||||
(CVE-2017-14340)
|
||||
* Bluetooth: Properly check L2CAP config option output buffer length
|
||||
(CVE-2017-1000251) (Closes: #875881)
|
||||
* Add ABI reference for 4.12.0-2
|
||||
|
||||
-- Salvatore Bonaccorso <carnil@debian.org> Thu, 14 Sep 2017 06:25:04 +0200
|
||||
|
|
|
@ -1,359 +0,0 @@
|
|||
From: Ben Seri <ben@armis.com>
|
||||
Date: Sat, 9 Sep 2017 23:15:59 +0200
|
||||
Subject: Bluetooth: Properly check L2CAP config option output buffer length
|
||||
Origin: https://git.kernel.org/linus/e860d2c904d1a9f38a24eb44c9f34b8f915a6ea3
|
||||
Bug-Debian: https://bugs.debian.org/875881
|
||||
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-1000251
|
||||
|
||||
Validate the output buffer length for L2CAP config requests and responses
|
||||
to avoid overflowing the stack buffer used for building the option blocks.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Ben Seri <ben@armis.com>
|
||||
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
---
|
||||
net/bluetooth/l2cap_core.c | 80 +++++++++++++++++++++++++---------------------
|
||||
1 file changed, 43 insertions(+), 37 deletions(-)
|
||||
|
||||
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
|
||||
index 303c779bfe38..43ba91c440bc 100644
|
||||
--- a/net/bluetooth/l2cap_core.c
|
||||
+++ b/net/bluetooth/l2cap_core.c
|
||||
@@ -58,7 +58,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
|
||||
u8 code, u8 ident, u16 dlen, void *data);
|
||||
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
|
||||
void *data);
|
||||
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
|
||||
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size);
|
||||
static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
|
||||
|
||||
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
||||
@@ -1473,7 +1473,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
||||
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
- l2cap_build_conf_req(chan, buf), buf);
|
||||
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -2987,12 +2987,15 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
|
||||
return len;
|
||||
}
|
||||
|
||||
-static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
|
||||
+static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val, size_t size)
|
||||
{
|
||||
struct l2cap_conf_opt *opt = *ptr;
|
||||
|
||||
BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val);
|
||||
|
||||
+ if (size < L2CAP_CONF_OPT_SIZE + len)
|
||||
+ return;
|
||||
+
|
||||
opt->type = type;
|
||||
opt->len = len;
|
||||
|
||||
@@ -3017,7 +3020,7 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
|
||||
*ptr += L2CAP_CONF_OPT_SIZE + len;
|
||||
}
|
||||
|
||||
-static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
|
||||
+static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan, size_t size)
|
||||
{
|
||||
struct l2cap_conf_efs efs;
|
||||
|
||||
@@ -3045,7 +3048,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
|
||||
}
|
||||
|
||||
l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
|
||||
- (unsigned long) &efs);
|
||||
+ (unsigned long) &efs, size);
|
||||
}
|
||||
|
||||
static void l2cap_ack_timeout(struct work_struct *work)
|
||||
@@ -3191,11 +3194,12 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
|
||||
chan->ack_win = chan->tx_win;
|
||||
}
|
||||
|
||||
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
|
||||
{
|
||||
struct l2cap_conf_req *req = data;
|
||||
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
|
||||
void *ptr = req->data;
|
||||
+ void *endptr = data + data_size;
|
||||
u16 size;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
@@ -3220,7 +3224,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
|
||||
done:
|
||||
if (chan->imtu != L2CAP_DEFAULT_MTU)
|
||||
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
|
||||
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
|
||||
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
@@ -3239,7 +3243,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
rfc.max_pdu_size = 0;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
- (unsigned long) &rfc);
|
||||
+ (unsigned long) &rfc, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_MODE_ERTM:
|
||||
@@ -3259,21 +3263,21 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
L2CAP_DEFAULT_TX_WINDOW);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
- (unsigned long) &rfc);
|
||||
+ (unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
||||
- l2cap_add_opt_efs(&ptr, chan);
|
||||
+ l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
||||
- chan->tx_win);
|
||||
+ chan->tx_win, endptr - ptr);
|
||||
|
||||
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
||||
- chan->fcs);
|
||||
+ chan->fcs, endptr - ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3291,17 +3295,17 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
rfc.max_pdu_size = cpu_to_le16(size);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
- (unsigned long) &rfc);
|
||||
+ (unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
|
||||
- l2cap_add_opt_efs(&ptr, chan);
|
||||
+ l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
|
||||
|
||||
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
|
||||
if (chan->fcs == L2CAP_FCS_NONE ||
|
||||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
|
||||
chan->fcs = L2CAP_FCS_NONE;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
|
||||
- chan->fcs);
|
||||
+ chan->fcs, endptr - ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3312,10 +3316,11 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
|
||||
return ptr - data;
|
||||
}
|
||||
|
||||
-static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
+static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
|
||||
{
|
||||
struct l2cap_conf_rsp *rsp = data;
|
||||
void *ptr = rsp->data;
|
||||
+ void *endptr = data + data_size;
|
||||
void *req = chan->conf_req;
|
||||
int len = chan->conf_len;
|
||||
int type, hint, olen;
|
||||
@@ -3417,7 +3422,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
return -ECONNREFUSED;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
- (unsigned long) &rfc);
|
||||
+ (unsigned long) &rfc, endptr - ptr);
|
||||
}
|
||||
|
||||
if (result == L2CAP_CONF_SUCCESS) {
|
||||
@@ -3430,7 +3435,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
chan->omtu = mtu;
|
||||
set_bit(CONF_MTU_DONE, &chan->conf_state);
|
||||
}
|
||||
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
|
||||
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu, endptr - ptr);
|
||||
|
||||
if (remote_efs) {
|
||||
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
|
||||
@@ -3444,7 +3449,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
|
||||
sizeof(efs),
|
||||
- (unsigned long) &efs);
|
||||
+ (unsigned long) &efs, endptr - ptr);
|
||||
} else {
|
||||
/* Send PENDING Conf Rsp */
|
||||
result = L2CAP_CONF_PENDING;
|
||||
@@ -3477,7 +3482,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
set_bit(CONF_MODE_DONE, &chan->conf_state);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
|
||||
- sizeof(rfc), (unsigned long) &rfc);
|
||||
+ sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
|
||||
chan->remote_id = efs.id;
|
||||
@@ -3491,7 +3496,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
le32_to_cpu(efs.sdu_itime);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
|
||||
sizeof(efs),
|
||||
- (unsigned long) &efs);
|
||||
+ (unsigned long) &efs, endptr - ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3505,7 +3510,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
set_bit(CONF_MODE_DONE, &chan->conf_state);
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
|
||||
- (unsigned long) &rfc);
|
||||
+ (unsigned long) &rfc, endptr - ptr);
|
||||
|
||||
break;
|
||||
|
||||
@@ -3527,10 +3532,11 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
|
||||
}
|
||||
|
||||
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
- void *data, u16 *result)
|
||||
+ void *data, size_t size, u16 *result)
|
||||
{
|
||||
struct l2cap_conf_req *req = data;
|
||||
void *ptr = req->data;
|
||||
+ void *endptr = data + size;
|
||||
int type, olen;
|
||||
unsigned long val;
|
||||
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
|
||||
@@ -3548,13 +3554,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
|
||||
} else
|
||||
chan->imtu = val;
|
||||
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
|
||||
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_FLUSH_TO:
|
||||
chan->flush_to = val;
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
|
||||
- 2, chan->flush_to);
|
||||
+ 2, chan->flush_to, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_RFC:
|
||||
@@ -3568,13 +3574,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
chan->fcs = 0;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
|
||||
- sizeof(rfc), (unsigned long) &rfc);
|
||||
+ sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_EWS:
|
||||
chan->ack_win = min_t(u16, val, chan->ack_win);
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
|
||||
- chan->tx_win);
|
||||
+ chan->tx_win, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_EFS:
|
||||
@@ -3587,7 +3593,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
|
||||
return -ECONNREFUSED;
|
||||
|
||||
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
|
||||
- (unsigned long) &efs);
|
||||
+ (unsigned long) &efs, endptr - ptr);
|
||||
break;
|
||||
|
||||
case L2CAP_CONF_FCS:
|
||||
@@ -3692,7 +3698,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
|
||||
return;
|
||||
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
- l2cap_build_conf_req(chan, buf), buf);
|
||||
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -3900,7 +3906,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
|
||||
u8 buf[128];
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
- l2cap_build_conf_req(chan, buf), buf);
|
||||
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -3978,7 +3984,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
|
||||
break;
|
||||
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
- l2cap_build_conf_req(chan, req), req);
|
||||
+ l2cap_build_conf_req(chan, req, sizeof(req)), req);
|
||||
chan->num_conf_req++;
|
||||
break;
|
||||
|
||||
@@ -4090,7 +4096,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
||||
}
|
||||
|
||||
/* Complete config. */
|
||||
- len = l2cap_parse_conf_req(chan, rsp);
|
||||
+ len = l2cap_parse_conf_req(chan, rsp, sizeof(rsp));
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto unlock;
|
||||
@@ -4124,7 +4130,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
||||
if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
|
||||
u8 buf[64];
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
|
||||
- l2cap_build_conf_req(chan, buf), buf);
|
||||
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
|
||||
@@ -4184,7 +4190,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
||||
char buf[64];
|
||||
|
||||
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
||||
- buf, &result);
|
||||
+ buf, sizeof(buf), &result);
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
@@ -4214,7 +4220,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
||||
/* throw out any old stored conf requests */
|
||||
result = L2CAP_CONF_SUCCESS;
|
||||
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
|
||||
- req, &result);
|
||||
+ req, sizeof(req), &result);
|
||||
if (len < 0) {
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
goto done;
|
||||
@@ -4791,7 +4797,7 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn),
|
||||
L2CAP_CONF_REQ,
|
||||
- l2cap_build_conf_req(chan, buf), buf);
|
||||
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
}
|
||||
@@ -7465,7 +7471,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
||||
set_bit(CONF_REQ_SENT, &chan->conf_state);
|
||||
l2cap_send_cmd(conn, l2cap_get_ident(conn),
|
||||
L2CAP_CONF_REQ,
|
||||
- l2cap_build_conf_req(chan, buf),
|
||||
+ l2cap_build_conf_req(chan, buf, sizeof(buf)),
|
||||
buf);
|
||||
chan->num_conf_req++;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
From: Richard Wareing <rwareing@fb.com>
|
||||
Date: Wed, 13 Sep 2017 09:09:35 +1000
|
||||
Subject: xfs: XFS_IS_REALTIME_INODE() should be false if no rt device present
|
||||
Origin: https://git.kernel.org/linus/b31ff3cdf540110da4572e3e29bd172087af65cc
|
||||
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-14340
|
||||
|
||||
If using a kernel with CONFIG_XFS_RT=y and we set the RHINHERIT flag on
|
||||
a directory in a filesystem that does not have a realtime device and
|
||||
create a new file in that directory, it gets marked as a real time file.
|
||||
When data is written and a fsync is issued, the filesystem attempts to
|
||||
flush a non-existent rt device during the fsync process.
|
||||
|
||||
This results in a crash dereferencing a null buftarg pointer in
|
||||
xfs_blkdev_issue_flush():
|
||||
|
||||
BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
|
||||
IP: xfs_blkdev_issue_flush+0xd/0x20
|
||||
.....
|
||||
Call Trace:
|
||||
xfs_file_fsync+0x188/0x1c0
|
||||
vfs_fsync_range+0x3b/0xa0
|
||||
do_fsync+0x3d/0x70
|
||||
SyS_fsync+0x10/0x20
|
||||
do_syscall_64+0x4d/0xb0
|
||||
entry_SYSCALL64_slow_path+0x25/0x25
|
||||
|
||||
Setting RT inode flags does not require special privileges so any
|
||||
unprivileged user can cause this oops to occur. To reproduce, confirm
|
||||
kernel is compiled with CONFIG_XFS_RT=y and run:
|
||||
|
||||
# mkfs.xfs -f /dev/pmem0
|
||||
# mount /dev/pmem0 /mnt/test
|
||||
# mkdir /mnt/test/foo
|
||||
# xfs_io -c 'chattr +t' /mnt/test/foo
|
||||
# xfs_io -f -c 'pwrite 0 5m' -c fsync /mnt/test/foo/bar
|
||||
|
||||
Or just run xfstests with MKFS_OPTIONS="-d rtinherit=1" and wait.
|
||||
|
||||
Kernels built with CONFIG_XFS_RT=n are not exposed to this bug.
|
||||
|
||||
Fixes: f538d4da8d52 ("[XFS] write barrier support")
|
||||
Cc: <stable@vger.kernel.org>
|
||||
Signed-off-by: Richard Wareing <rwareing@fb.com>
|
||||
Signed-off-by: Dave Chinner <david@fromorbit.com>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
---
|
||||
fs/xfs/xfs_linux.h | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
|
||||
index 9301c5a6060b..dcd1292664b3 100644
|
||||
--- a/fs/xfs/xfs_linux.h
|
||||
+++ b/fs/xfs/xfs_linux.h
|
||||
@@ -270,7 +270,14 @@ static inline uint64_t howmany_64(uint64_t x, uint32_t y)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef CONFIG_XFS_RT
|
||||
-#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
|
||||
+
|
||||
+/*
|
||||
+ * make sure we ignore the inode flag if the filesystem doesn't have a
|
||||
+ * configured realtime device.
|
||||
+ */
|
||||
+#define XFS_IS_REALTIME_INODE(ip) \
|
||||
+ (((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) && \
|
||||
+ (ip)->i_mount->m_rtdev_targp)
|
||||
#else
|
||||
#define XFS_IS_REALTIME_INODE(ip) (0)
|
||||
#endif
|
||||
--
|
||||
2.11.0
|
||||
|
|
@ -122,8 +122,6 @@ features/all/lockdown/arm64-add-kernel-config-option-to-lock-down-when.patch
|
|||
debian/i386-686-pae-pci-set-pci-nobios-by-default.patch
|
||||
bugfix/all/sctp-Avoid-out-of-bounds-reads-from-address-storage.patch
|
||||
bugfix/all/scsi-qla2xxx-Fix-an-integer-overflow-in-sysfs-code.patch
|
||||
bugfix/all/xfs-XFS_IS_REALTIME_INODE-should-be-false-if-no-rt-d.patch
|
||||
bugfix/all/Bluetooth-Properly-check-L2CAP-config-option-output-.patch
|
||||
|
||||
# Fix exported symbol versions
|
||||
bugfix/alpha/alpha-restore-symbol-versions-for-symbols-exported-f.patch
|
||||
|
|
Loading…
Reference in New Issue