From c005032a3ffe77437f6ebc704af377fc9bc46279 Mon Sep 17 00:00:00 2001 From: Ben Seri Date: Wed, 13 Sep 2017 14:04:32 +0530 Subject: Bluetooth: Properly check L2CAP config option output buffer length Validate the output buffer length for L2CAP config requests and responses to avoid overflowing the stack buffer used for building the option blocks. Bug 1989825 Change-Id: Id158ece2176c4ac339a7232dfde8c47ce2241122 Cc: stable@vger.kernel.org Signed-off-by: Ben Seri Signed-off-by: Marcel Holtmann Signed-off-by: Linus Torvalds Signed-off-by: Bibek Basu Reviewed-on: https://git-master.nvidia.com/r/1558952 GVS: Gerrit_Virtual_Submit --- 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 c11a28bae844..10d4bee2d8bc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -52,7 +52,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, @@ -1283,7 +1283,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++; } @@ -2941,12 +2941,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; @@ -2971,7 +2974,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; @@ -2999,7 +3002,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) @@ -3143,11 +3146,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); @@ -3172,7 +3176,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: @@ -3188,7 +3192,7 @@ done: 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: @@ -3208,21 +3212,21 @@ done: 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; @@ -3240,17 +3244,17 @@ done: 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; } @@ -3261,10 +3265,11 @@ done: 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; @@ -3366,7 +3371,7 @@ done: 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) { @@ -3379,7 +3384,7 @@ done: 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 && @@ -3393,7 +3398,7 @@ done: 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; @@ -3426,7 +3431,7 @@ done: 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; @@ -3440,7 +3445,7 @@ done: 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; @@ -3454,7 +3459,7 @@ done: 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; @@ -3476,10 +3481,11 @@ done: } 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 }; @@ -3497,13 +3503,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: @@ -3517,13 +3523,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: @@ -3536,7 +3542,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: @@ -3624,7 +3630,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++; } @@ -3828,7 +3834,7 @@ sendresp: 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++; } @@ -3908,7 +3914,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; @@ -4012,7 +4018,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; @@ -4046,7 +4052,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++; } @@ -4106,7 +4112,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; @@ -4136,7 +4142,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; @@ -4718,7 +4724,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++; } } @@ -6604,7 +6610,7 @@ int 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++; } -- cgit v1.2.3 From 3494ec4c7f2f6f0261cbf582ea6a605f9033cb7b Mon Sep 17 00:00:00 2001 From: Debarshi Dutta Date: Tue, 8 Aug 2017 15:34:57 +0530 Subject: Revert "gpu: nvgpu: Remove IOCTL FREE_OBJ_CTX" Bug 200336148 This reverts commit 2db040946ff8340485b2b33fe5a46f3166fa96f6. Change-Id: I8a80a7bd1bd8b1a949fba26b683ac1c9bebc0c04 Signed-off-by: Debarshi Dutta Reviewed-on: https://git-master.nvidia.com/r/1534941 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 14 +++++++++++++- drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 3 ++- drivers/gpu/nvgpu/gk20a/gr_gk20a.c | 28 +++++++++++++++++++++++++++- drivers/gpu/nvgpu/gk20a/gr_gk20a.h | 5 ++++- include/linux/nvhost_ioctl.h | 8 +++++++- 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 3065e8403559..947b1dc668bf 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -3,7 +3,7 @@ * * GK20A Graphics channel * - * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -2066,6 +2066,18 @@ long gk20a_channel_ioctl(struct file *filp, (struct nvhost_alloc_obj_ctx_args *)buf); gk20a_idle(dev); break; + case NVHOST_IOCTL_CHANNEL_FREE_OBJ_CTX: + err = gk20a_busy(dev); + if (err) { + dev_err(&dev->dev, + "%s: failed to host gk20a for ioctl cmd: 0x%x", + __func__, cmd); + return err; + } + err = gk20a_free_obj_ctx(ch, + (struct nvhost_free_obj_ctx_args *)buf); + gk20a_idle(dev); + break; case NVHOST_IOCTL_CHANNEL_ALLOC_GPFIFO: err = gk20a_busy(dev); if (err) { diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h index 831db0f4986a..547bb064fd63 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h @@ -3,7 +3,7 @@ * * GK20A graphics channel * - * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -98,6 +98,7 @@ struct channel_gk20a { u64 userd_iova; u64 userd_gpu_va; + s32 num_objects; u32 obj_class; /* we support only one obj per channel */ struct priv_cmd_queue priv_cmd_q; diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c index d5a3bbd34a78..9e032e03a153 100644 --- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c @@ -1,7 +1,7 @@ /* * GK20A Graphics * - * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -2697,6 +2697,7 @@ void gk20a_free_channel_ctx(struct channel_gk20a *c) memset(&c->ch_ctx, 0, sizeof(struct channel_ctx_gk20a)); + c->num_objects = 0; c->first_init = false; } @@ -2847,6 +2848,8 @@ int gk20a_alloc_obj_ctx(struct channel_gk20a *c, c->first_init = true; } + c->num_objects++; + gk20a_dbg_fn("done"); return 0; out: @@ -2858,6 +2861,29 @@ out: return err; } +int gk20a_free_obj_ctx(struct channel_gk20a *c, + struct nvhost_free_obj_ctx_args *args) +{ + unsigned long timeout = gk20a_get_gr_idle_timeout(c->g); + + gk20a_dbg_fn(""); + + if (c->num_objects == 0) + return 0; + + c->num_objects--; + + if (c->num_objects == 0) { + c->first_init = false; + gk20a_disable_channel(c, + !c->has_timedout, + timeout); + gr_gk20a_unmap_channel_patch_ctx(c); + } + + return 0; +} + static void gk20a_remove_gr_support(struct gr_gk20a *gr) { struct gk20a *g = gr->g; diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.h b/drivers/gpu/nvgpu/gk20a/gr_gk20a.h index 526eefb46b6f..2a31aa0b830f 100644 --- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.h @@ -1,7 +1,7 @@ /* * GK20A Graphics Engine * - * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -324,9 +324,12 @@ int gk20a_init_gr_channel(struct channel_gk20a *ch_gk20a); int gr_gk20a_init_ctx_vars(struct gk20a *g, struct gr_gk20a *gr); struct nvhost_alloc_obj_ctx_args; +struct nvhost_free_obj_ctx_args; int gk20a_alloc_obj_ctx(struct channel_gk20a *c, struct nvhost_alloc_obj_ctx_args *args); +int gk20a_free_obj_ctx(struct channel_gk20a *c, + struct nvhost_free_obj_ctx_args *args); void gk20a_free_channel_ctx(struct channel_gk20a *c); int gk20a_gr_isr(struct gk20a *g); diff --git a/include/linux/nvhost_ioctl.h b/include/linux/nvhost_ioctl.h index a1011e5a1daf..b060864ff1d1 100644 --- a/include/linux/nvhost_ioctl.h +++ b/include/linux/nvhost_ioctl.h @@ -3,7 +3,7 @@ * * Tegra graphics host driver * - * Copyright (c) 2009-2017, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2009-2014, NVIDIA Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -118,6 +118,10 @@ struct nvhost_alloc_obj_ctx_args { __u64 obj_id; /* output, used to free later */ }; +struct nvhost_free_obj_ctx_args { + __u64 obj_id; /* obj ctx to free */ +}; + struct nvhost_alloc_gpfifo_args { __u32 num_entries; #define NVHOST_ALLOC_GPFIFO_FLAGS_VPR_ENABLED (1 << 0) /* set owner channel of this gpfifo as a vpr channel */ @@ -386,6 +390,8 @@ struct nvhost_set_ctxswitch_args { _IOWR(NVHOST_IOCTL_MAGIC, 107, struct nvhost_submit_gpfifo_args) #define NVHOST_IOCTL_CHANNEL_ALLOC_OBJ_CTX \ _IOWR(NVHOST_IOCTL_MAGIC, 108, struct nvhost_alloc_obj_ctx_args) +#define NVHOST_IOCTL_CHANNEL_FREE_OBJ_CTX \ + _IOR(NVHOST_IOCTL_MAGIC, 109, struct nvhost_free_obj_ctx_args) #define NVHOST_IOCTL_CHANNEL_ZCULL_BIND \ _IOWR(NVHOST_IOCTL_MAGIC, 110, struct nvhost_zcull_bind_args) #define NVHOST_IOCTL_CHANNEL_SET_ERROR_NOTIFIER \ -- cgit v1.2.3 From ea1df6ecbe78c63b25a64ee28bb5dce0e31ca736 Mon Sep 17 00:00:00 2001 From: Jay Agarwal Date: Tue, 14 Oct 2014 11:32:07 +0530 Subject: pcie: host: tegra: WAR for RAW violations Some of reads transaction getting before write has completed resulting in RAW violation. This WAR avoids this situation. Bug 1345350 Change-Id: I56728d00326b193be26ccb4fe68787ebd8a2623d Signed-off-by: Jay Agarwal Reviewed-on: http://git-master/r/365301 (cherry picked from commit a706735e3c50a70dfee4a3d11378d3a1872a71d7) Reviewed-on: https://git-master.nvidia.com/r/1595945 Reviewed-by: Vidya Sagar Reviewed-by: Manikanta Maddireddy GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Mantravadi Karthik --- drivers/pci/host/pci-tegra.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 371dc91c4cf5..7c8b714be77d 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -178,6 +178,7 @@ #define RP_VEND_XP 0x00000F00 #define RP_VEND_XP_DL_UP (1 << 30) +#define RP_VEND_XP_UPDATE_FC_THRESHOLD (0xFF << 18) #define RP_LINK_CONTROL_STATUS 0x00000090 @@ -191,6 +192,13 @@ #define NV_PCIE2_RP_INTR_BCR 0x0000003C #define NV_PCIE2_RP_INTR_BCR_INTR_LINE (0xFF << 0) +#define NV_PCIE2_RP_PRIV_XP_DL 0x00000494 +#define PCIE2_RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD (0x1FF << 1) + +#define NV_PCIE2_RP_RX_HDR_LIMIT 0x00000E00 +#define PCIE2_RP_RX_HDR_LIMIT_PW_MASK (0xFF00) +#define PCIE2_RP_RX_HDR_LIMIT_PW (0x0E << 8) + #define NV_PCIE2_RP_PRIV_MISC 0x00000FE0 #define PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0) #define PCIE2_RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0) @@ -1486,6 +1494,19 @@ static void tegra_pcie_apply_sw_war(int index, bool enum_done) data = rp_readl(NV_PCIE2_RP_INTR_BCR, index); data |= NV_PCIE2_RP_INTR_BCR_INTR_LINE; rp_writel(data, NV_PCIE2_RP_INTR_BCR, index); + /* WAR for RAW violation on T124/T132 platforms */ + data = rp_readl(NV_PCIE2_RP_RX_HDR_LIMIT, index); + data &= ~PCIE2_RP_RX_HDR_LIMIT_PW_MASK; + data |= PCIE2_RP_RX_HDR_LIMIT_PW; + rp_writel(data, NV_PCIE2_RP_RX_HDR_LIMIT, index); + + data = rp_readl(NV_PCIE2_RP_PRIV_XP_DL, index); + data |= PCIE2_RP_PRIV_XP_DL_GEN2_UPD_FC_TSHOLD; + rp_writel(data, NV_PCIE2_RP_PRIV_XP_DL, index); + + data = rp_readl(RP_VEND_XP, index); + data |= RP_VEND_XP_UPDATE_FC_THRESHOLD; + rp_writel(data, RP_VEND_XP, index); } } -- cgit v1.2.3 From bc078fb62c6d3c80bcba2c63cb57ad06e8b419e4 Mon Sep 17 00:00:00 2001 From: Sri Krishna chowdary Date: Fri, 23 Jun 2017 11:56:03 +0530 Subject: mm: larger stack guard gap, between vmas commit 1be7107fbe18eed3e319a6c3e83c78254b693acb upstream. Stack guard page is a useful feature to reduce a risk of stack smashing into a different mapping. We have been using a single page gap which is sufficient to prevent having stack adjacent to a different mapping. But this seems to be insufficient in the light of the stack usage in userspace. E.g. glibc uses as large as 64kB alloca() in many commonly used functions. Others use constructs liks gid_t buffer[NGROUPS_MAX] which is 256kB or stack strings with MAX_ARG_STRLEN. This will become especially dangerous for suid binaries and the default no limit for the stack size limit because those applications can be tricked to consume a large portion of the stack and a single glibc call could jump over the guard page. These attacks are not theoretical, unfortunatelly. Make those attacks less probable by increasing the stack guard gap to 1MB (on systems with 4k pages; but make it depend on the page size because systems with larger base pages might cap stack allocations in the PAGE_SIZE units) which should cover larger alloca() and VLA stack allocations. It is obviously not a full fix because the problem is somehow inherent, but it should reduce attack space a lot. One could argue that the gap size should be configurable from userspace, but that can be done later when somebody finds that the new 1MB is wrong for some special case applications. For now, add a kernel command line option (stack_guard_gap) to specify the stack gap size (in page units). Implementation wise, first delete all the old code for stack guard page: because although we could get away with accounting one extra page in a stack vma, accounting a larger gap can break userspace - case in point, a program run with "ulimit -S -v 20000" failed when the 1MB gap was counted for RLIMIT_AS; similar problems could come with RLIMIT_MLOCK and strict non-overcommit mode. Instead of keeping gap inside the stack vma, maintain the stack guard gap as a gap between vmas: using vm_start_gap() in place of vm_start (or vm_end_gap() in place of vm_end if VM_GROWSUP) in just those few places which need to respect the gap - mainly arch_get_unmapped_area(), and and the vma tree's subtree_gap support for that. Bug 1946430 Change-Id: I9a66aabc34b687996fb971e01bb0ef30a3d4de7d Original-patch-by: Oleg Nesterov Original-patch-by: Michal Hocko Signed-off-by: Hugh Dickins Acked-by: Michal Hocko Tested-by: Helge Deller # parisc Signed-off-by: Linus Torvalds [wt: backport to 4.11: adjust context] [wt: backport to 4.9: adjust context ; kernel doc was not in admin-guide] [wt: backport to 4.4: adjust context ; drop ppc hugetlb_radix changes] Signed-off-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sri Krishna chowdary Reviewed-on: https://git-master.nvidia.com/r/1509390 GVS: Gerrit_Virtual_Submit Tested-by: Bibek Basu Reviewed-by: Bibek Basu --- Documentation/kernel-parameters.txt | 7 ++ arch/arm/mm/mmap.c | 4 +- fs/hugetlbfs/inode.c | 2 +- fs/proc/task_mmu.c | 4 -- include/linux/mm.h | 53 +++++++-------- mm/memory.c | 48 ------------- mm/mmap.c | 130 +++++++++++++++++++++++------------- 7 files changed, 120 insertions(+), 128 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1311a48a7367..951b7eedc44e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2884,6 +2884,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. spia_pedr= spia_peddr= + stack_guard_gap= [MM] + override the default stack gap protection. The value + is in page units and it defines how many pages prior + to (for stacks growing down) resp. after (for stacks + growing up) the main stack are reserved for no other + mapping. Default value is 256 pages. + stacktrace [FTRACE] Enabled the stack tracer on boot up. diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c index a5b1934e711b..86cda2e8ec19 100644 --- a/arch/arm/mm/mmap.c +++ b/arch/arm/mm/mmap.c @@ -90,7 +90,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } @@ -155,7 +155,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 4e5f332f15d9..db7d89cea2ce 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -169,7 +169,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma))) return addr; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index db17f98bc564..fb705f672960 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -329,11 +329,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) /* We don't show the stack guard page in /proc/maps */ start = vma->vm_start; - if (stack_guard_page_start(vma, start)) - start += PAGE_SIZE; end = vma->vm_end; - if (stack_guard_page_end(vma, end)) - end -= PAGE_SIZE; seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", start, diff --git a/include/linux/mm.h b/include/linux/mm.h index 03a60a38ec45..9d572d445e3e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1066,34 +1066,6 @@ int set_page_dirty(struct page *page); int set_page_dirty_lock(struct page *page); int clear_page_dirty_for_io(struct page *page); -/* Is the vma a continuation of the stack vma above it? */ -static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) -{ - return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); -} - -static inline int stack_guard_page_start(struct vm_area_struct *vma, - unsigned long addr) -{ - return (vma->vm_flags & VM_GROWSDOWN) && - (vma->vm_start == addr) && - !vma_growsdown(vma->vm_prev, addr); -} - -/* Is the vma a continuation of the stack vma below it? */ -static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr) -{ - return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP); -} - -static inline int stack_guard_page_end(struct vm_area_struct *vma, - unsigned long addr) -{ - return (vma->vm_flags & VM_GROWSUP) && - (vma->vm_end == addr) && - !vma_growsup(vma->vm_next, addr); -} - extern pid_t vm_is_stack(struct task_struct *task, struct vm_area_struct *vma, int in_group); @@ -1620,6 +1592,7 @@ unsigned long ra_submit(struct file_ra_state *ra, struct address_space *mapping, struct file *filp); +extern unsigned long stack_guard_gap; /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */ extern int expand_stack(struct vm_area_struct *vma, unsigned long address); @@ -1648,6 +1621,30 @@ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * m return vma; } +static inline unsigned long vm_start_gap(struct vm_area_struct *vma) +{ + unsigned long vm_start = vma->vm_start; + + if (vma->vm_flags & VM_GROWSDOWN) { + vm_start -= stack_guard_gap; + if (vm_start > vma->vm_start) + vm_start = 0; + } + return vm_start; +} + +static inline unsigned long vm_end_gap(struct vm_area_struct *vma) +{ + unsigned long vm_end = vma->vm_end; + + if (vma->vm_flags & VM_GROWSUP) { + vm_end += stack_guard_gap; + if (vm_end < vma->vm_end) + vm_end = -PAGE_SIZE; + } + return vm_end; +} + static inline unsigned long vma_pages(struct vm_area_struct *vma) { return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; diff --git a/mm/memory.c b/mm/memory.c index 6be9914ddc0d..17c9186c819a 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1659,12 +1659,6 @@ no_page_table: return page; } -static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) -{ - return stack_guard_page_start(vma, addr) || - stack_guard_page_end(vma, addr+PAGE_SIZE); -} - /** * replace_cma_page() - migrate page out of CMA page blocks * @page: source page to be migrated @@ -1875,10 +1869,6 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, fault_flags = FAULT_FLAG_NO_CMA; /* For mlock, just skip the stack guard page. */ - if (foll_flags & FOLL_MLOCK) { - if (stack_guard_page(vma, start)) - goto next_page; - } if (foll_flags & FOLL_WRITE) fault_flags |= FAULT_FLAG_WRITE; if (nonblocking) @@ -3171,40 +3161,6 @@ out_release: return ret; } -/* - * This is like a special single-page "expand_{down|up}wards()", - * except we must first make sure that 'address{-|+}PAGE_SIZE' - * doesn't hit another vma. - */ -static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned long address) -{ - address &= PAGE_MASK; - if ((vma->vm_flags & VM_GROWSDOWN) && address == vma->vm_start) { - struct vm_area_struct *prev = vma->vm_prev; - - /* - * Is there a mapping abutting this one below? - * - * That's only ok if it's the same stack mapping - * that has gotten split.. - */ - if (prev && prev->vm_end == address) - return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; - - expand_downwards(vma, address - PAGE_SIZE); - } - if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { - struct vm_area_struct *next = vma->vm_next; - - /* As VM_GROWSDOWN but s/below/above/ */ - if (next && next->vm_start == address + PAGE_SIZE) - return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; - - expand_upwards(vma, address + PAGE_SIZE); - } - return 0; -} - bool is_vma_temporary_stack(struct vm_area_struct *vma); /* * We enter with non-exclusive mmap_sem (to exclude vma changes, @@ -3221,10 +3177,6 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, pte_unmap(page_table); - /* Check if we need to add a guard page to the stack */ - if (check_stack_guard_page(vma, address) < 0) - return VM_FAULT_SIGBUS; - /* Use the zero-page for reads */ if (!(flags & FAULT_FLAG_WRITE)) { entry = pte_mkspecial(pfn_pte(my_zero_pfn(address), diff --git a/mm/mmap.c b/mm/mmap.c index e0a152e2dc10..a323e12f8a6d 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -264,6 +264,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) unsigned long rlim, retval; unsigned long newbrk, oldbrk; struct mm_struct *mm = current->mm; + struct vm_area_struct *next; unsigned long min_brk; bool populate; @@ -309,7 +310,8 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) } /* Check against existing mmap mappings. */ - if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) + next = find_vma(mm, oldbrk); + if (next && newbrk + PAGE_SIZE > vm_start_gap(next)) goto out; /* Ok, looks good - let it rip. */ @@ -332,10 +334,22 @@ out: static long vma_compute_subtree_gap(struct vm_area_struct *vma) { - unsigned long max, subtree_gap; - max = vma->vm_start; - if (vma->vm_prev) - max -= vma->vm_prev->vm_end; + unsigned long max, prev_end, subtree_gap; + + /* + * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we + * allow two stack_guard_gaps between them here, and when choosing + * an unmapped area; whereas when expanding we only require one. + * That's a little inconsistent, but keeps the code here simpler. + */ + max = vm_start_gap(vma); + if (vma->vm_prev) { + prev_end = vm_end_gap(vma->vm_prev); + if (max > prev_end) + max -= prev_end; + else + max = 0; + } if (vma->vm_rb.rb_left) { subtree_gap = rb_entry(vma->vm_rb.rb_left, struct vm_area_struct, vm_rb)->rb_subtree_gap; @@ -419,7 +433,7 @@ void validate_mm(struct mm_struct *mm) list_for_each_entry(avc, &vma->anon_vma_chain, same_vma) anon_vma_interval_tree_verify(avc); vma_unlock_anon_vma(vma); - highest_address = vma->vm_end; + highest_address = vm_end_gap(vma); vma = vma->vm_next; i++; } @@ -587,7 +601,7 @@ void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, if (vma->vm_next) vma_gap_update(vma->vm_next); else - mm->highest_vm_end = vma->vm_end; + mm->highest_vm_end = vm_end_gap(vma); /* * vma->vm_prev wasn't known when we followed the rbtree to find the @@ -836,7 +850,7 @@ again: remove_next = 1 + (end > next->vm_end); vma_gap_update(vma); if (end_changed) { if (!next) - mm->highest_vm_end = end; + mm->highest_vm_end = vm_end_gap(vma); else if (!adjust_next) vma_gap_update(next); } @@ -879,7 +893,7 @@ again: remove_next = 1 + (end > next->vm_end); else if (next) vma_gap_update(next); else - mm->highest_vm_end = end; + mm->highest_vm_end = vm_end_gap(vma); } if (insert && file) uprobe_mmap(insert); @@ -1679,7 +1693,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) while (true) { /* Visit left subtree if it looks promising */ - gap_end = vma->vm_start; + gap_end = vm_start_gap(vma); if (gap_end >= low_limit && vma->vm_rb.rb_left) { struct vm_area_struct *left = rb_entry(vma->vm_rb.rb_left, @@ -1690,7 +1704,7 @@ unsigned long unmapped_area(struct vm_unmapped_area_info *info) } } - gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; + gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; check_current: /* Check if current node has a suitable gap */ if (gap_start > high_limit) @@ -1717,8 +1731,8 @@ check_current: vma = rb_entry(rb_parent(prev), struct vm_area_struct, vm_rb); if (prev == vma->vm_rb.rb_left) { - gap_start = vma->vm_prev->vm_end; - gap_end = vma->vm_start; + gap_start = vm_end_gap(vma->vm_prev); + gap_end = vm_start_gap(vma); goto check_current; } } @@ -1782,7 +1796,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) while (true) { /* Visit right subtree if it looks promising */ - gap_start = vma->vm_prev ? vma->vm_prev->vm_end : 0; + gap_start = vma->vm_prev ? vm_end_gap(vma->vm_prev) : 0; if (gap_start <= high_limit && vma->vm_rb.rb_right) { struct vm_area_struct *right = rb_entry(vma->vm_rb.rb_right, @@ -1795,7 +1809,7 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) check_current: /* Check if current node has a suitable gap */ - gap_end = vma->vm_start; + gap_end = vm_start_gap(vma); if (gap_end < low_limit) return -ENOMEM; if (gap_start <= high_limit && gap_end - gap_start >= length) @@ -1821,7 +1835,7 @@ check_current: struct vm_area_struct, vm_rb); if (prev == vma->vm_rb.rb_right) { gap_start = vma->vm_prev ? - vma->vm_prev->vm_end : 0; + vm_end_gap(vma->vm_prev) : 0; goto check_current; } } @@ -1859,7 +1873,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; + struct vm_area_struct *vma, *prev; struct vm_unmapped_area_info info; if (len > TASK_SIZE - mmap_min_addr) @@ -1870,9 +1884,10 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, if (addr) { addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); + vma = find_vma_prev(mm, addr, &prev); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma)) && + (!prev || addr >= vm_end_gap(prev))) return addr; } @@ -1904,7 +1919,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, const unsigned long len, const unsigned long pgoff, const unsigned long flags) { - struct vm_area_struct *vma; + struct vm_area_struct *vma, *prev; struct mm_struct *mm = current->mm; unsigned long addr = addr0; struct vm_unmapped_area_info info; @@ -1919,9 +1934,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, /* requesting a specific address */ if (addr) { addr = PAGE_ALIGN(addr); - vma = find_vma(mm, addr); + vma = find_vma_prev(mm, addr, &prev); if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vma->vm_start)) + (!vma || addr + len <= vm_start_gap(vma)) && + (!prev || addr >= vm_end_gap(prev))) return addr; } @@ -2061,7 +2077,8 @@ find_vma_prev(struct mm_struct *mm, unsigned long addr, * update accounting. This is shared with both the * grow-up and grow-down cases. */ -static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, unsigned long grow) +static int acct_stack_growth(struct vm_area_struct *vma, + unsigned long size, unsigned long grow) { struct mm_struct *mm = vma->vm_mm; struct rlimit *rlim = current->signal->rlim; @@ -2114,6 +2131,8 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns int expand_upwards(struct vm_area_struct *vma, unsigned long address) { int error; + struct vm_area_struct *next; + unsigned long gap_addr; if (!(vma->vm_flags & VM_GROWSUP)) return -EFAULT; @@ -2124,8 +2143,19 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) */ if (unlikely(anon_vma_prepare(vma))) return -ENOMEM; - vma_lock_anon_vma(vma); + /* Enforce stack_guard_gap */ + gap_addr = address + stack_guard_gap; + if (gap_addr < address) + return -ENOMEM; + next = vma->vm_next; + if (next && next->vm_start < gap_addr) { + if (!(next->vm_flags & VM_GROWSUP)) + return -ENOMEM; + /* Check that both stack segments have the same anon_vma? */ + } + + vma_lock_anon_vma(vma); /* * vma->vm_start/vm_end cannot change under us because the caller * is required to hold the mmap_sem in read mode. We need the @@ -2169,7 +2199,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) if (vma->vm_next) vma_gap_update(vma->vm_next); else - vma->vm_mm->highest_vm_end = address; + vma->vm_mm->highest_vm_end = vm_end_gap(vma); spin_unlock(&vma->vm_mm->page_table_lock); perf_event_mmap(vma); @@ -2190,6 +2220,8 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) int expand_downwards(struct vm_area_struct *vma, unsigned long address) { + struct vm_area_struct *prev; + unsigned long gap_addr; int error; /* @@ -2204,6 +2236,17 @@ int expand_downwards(struct vm_area_struct *vma, if (error) return error; + /* Enforce stack_guard_gap */ + gap_addr = address - stack_guard_gap; + if (gap_addr > address) + return -ENOMEM; + prev = vma->vm_prev; + if (prev && prev->vm_end > gap_addr) { + if (!(prev->vm_flags & VM_GROWSDOWN)) + return -ENOMEM; + /* Check that both stack segments have the same anon_vma? */ + } + vma_lock_anon_vma(vma); /* @@ -2253,28 +2296,25 @@ int expand_downwards(struct vm_area_struct *vma, return error; } -/* - * Note how expand_stack() refuses to expand the stack all the way to - * abut the next virtual mapping, *unless* that mapping itself is also - * a stack mapping. We want to leave room for a guard page, after all - * (the guard page itself is not added here, that is done by the - * actual page faulting logic) - * - * This matches the behavior of the guard page logic (see mm/memory.c: - * check_stack_guard_page()), which only allows the guard page to be - * removed under these circumstances. - */ +/* enforced gap between the expanding stack and other mappings. */ +unsigned long stack_guard_gap = 256UL<algo, PTR_ERR(tfm)); + algo, PTR_ERR(tfm)); goto out_alloc; } req = ahash_request_alloc(tfm, GFP_KERNEL); if (!req) { pr_err("alg:hash:Failed to allocate request for %s\n", - sha_req->algo); + algo); goto out_noreq; } @@ -574,7 +581,14 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req) hash_buff = xbuf[0]; - memcpy(hash_buff, sha_req->plaintext, sha_req->plaintext_sz); + ret = copy_from_user((void *)hash_buff, + (void __user *)sha_req->plaintext, + sha_req->plaintext_sz); + if (ret) { + ret = -EFAULT; + pr_err("%s: copy_from_user failed (%d)\n", __func__, ret); + goto out; + } sg_init_one(&sg[0], hash_buff, sha_req->plaintext_sz); if (sha_req->keylen) { @@ -583,7 +597,7 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req) sha_req->keylen); if (ret) { pr_err("alg:hash:setkey failed on %s:ret=%d\n", - sha_req->algo, ret); + algo, ret); goto out; } @@ -594,21 +608,21 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req) ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_init(req)); if (ret) { pr_err("alg: hash: init failed for %s: ret=%d\n", - sha_req->algo, ret); + algo, ret); goto out; } ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_update(req)); if (ret) { pr_err("alg: hash: update failed for %s: ret=%d\n", - sha_req->algo, ret); + algo, ret); goto out; } ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_final(req)); if (ret) { pr_err("alg: hash: final failed for %s: ret=%d\n", - sha_req->algo, ret); + algo, ret); goto out; } @@ -617,7 +631,7 @@ static int tegra_crypto_sha(struct tegra_sha_req *sha_req) if (ret) { ret = -EFAULT; pr_err("alg: hash: copy_to_user failed (%d) for %s\n", - ret, sha_req->algo); + ret, algo); } out: -- cgit v1.2.3 From 0fd9a32f3a6796791b4fe93bfbc05df4d4bf646e Mon Sep 17 00:00:00 2001 From: Gagan Grover Date: Tue, 22 Nov 2016 15:43:19 +0530 Subject: video: tegra: host: use lock to get syncpt name Use sp->syncpt_mutex lock to get syncpt name in syncpt_name_show() Without the lock, it is possible for user to read syncpt name in corrupted state if user read coincides with syncpt free Bug 1838598 Bug 1883567 Change-Id: I69ca5c1d80adaca4b93a337fe4a5debeb78f34fc Reviewed-on: http://git-master/r/1252580 Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1258020 (cherry picked from commit 9a7d12e49ca6c627dff2dc4c15fa9ba153e9265d in rel-24) Reviewed-on: https://git-master.nvidia.com/r/1513005 Signed-off-by: Debarshi Dutta Reviewed-on: https://git-master.nvidia.com/r/1650064 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/video/tegra/host/nvhost_syncpt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c index b0af8a143bd2..4d431cc14890 100644 --- a/drivers/video/tegra/host/nvhost_syncpt.c +++ b/drivers/video/tegra/host/nvhost_syncpt.c @@ -3,7 +3,7 @@ * * Tegra Graphics Host Syncpoints * - * Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -650,13 +650,18 @@ static ssize_t syncpt_name_show(struct kobject *kobj, { struct nvhost_syncpt_attr *syncpt_attr = container_of(attr, struct nvhost_syncpt_attr, attr); + ssize_t count = 0; if (syncpt_attr->id < 0) return snprintf(buf, PAGE_SIZE, "\n"); - return snprintf(buf, PAGE_SIZE, "%s\n", + mutex_lock(&syncpt_attr->host->syncpt.syncpt_mutex); + count = snprintf(buf, PAGE_SIZE, "%s\n", nvhost_syncpt_get_name(syncpt_attr->host->dev, syncpt_attr->id)); + mutex_unlock(&syncpt_attr->host->syncpt.syncpt_mutex); + + return count; } static ssize_t syncpt_min_show(struct kobject *kobj, -- cgit v1.2.3 From a7e55a39cdd16f8170136f7ca18eb89bee20e885 Mon Sep 17 00:00:00 2001 From: Konduri Praveen Date: Fri, 20 Oct 2017 11:31:36 +0530 Subject: CRYPTO: disable crypto dev fot t124 disabling tegra SE crypto dev for t124 platform. Bug 1927682 Change-Id: I16a24009e8f528df4be40ec65aa621b4ac779e41 Signed-off-by: Konduri Praveen Reviewed-on: https://git-master.nvidia.com/r/1582395 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- arch/arm/configs/tegra12_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/tegra12_defconfig b/arch/arm/configs/tegra12_defconfig index 5e16975801fe..a0cb43fa35b6 100644 --- a/arch/arm/configs/tegra12_defconfig +++ b/arch/arm/configs/tegra12_defconfig @@ -195,7 +195,6 @@ CONFIG_AD525X_DPOT=y CONFIG_AD525X_DPOT_I2C=y CONFIG_APDS9802ALS=y CONFIG_SENSORS_NCT1008=y -CONFIG_TEGRA_CRYPTO_DEV=y CONFIG_THERM_EST=y CONFIG_FAN_THERM_EST=y CONFIG_EEPROM_AT24=y -- cgit v1.2.3 From 370b9f7a1dad9ccb7198bb0ffd30a8e7df112ab2 Mon Sep 17 00:00:00 2001 From: Srikar Srimath Tirumala Date: Tue, 12 Sep 2017 12:27:13 -0700 Subject: thermal: add boundary check to set_cur_state Prevent sysfs from setting a cur_state that exceeds the max cur_state of the cooling device. Bug 200334223 Bug 200331706 Bug 1968660 Bug 1968616 Change-Id: I935be6166a9e184683abfcdce70cb08cbe4a1350 Signed-off-by: Srikar Srimath Tirumala Reviewed-on: https://git-master.nvidia.com/r/1558407 (cherry picked from commit 142cf9d96ed221124ea2b778dc37cf5db8d5702c) Reviewed-on: https://git-master.nvidia.com/r/1661413 Reviewed-on: https://git-master.nvidia.com/r/1662626 GVS: Gerrit_Virtual_Submit Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- drivers/thermal/thermal_core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index ffb4b9c41a40..68e6e09fdb37 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -944,8 +944,8 @@ thermal_cooling_device_cur_state_store(struct device *dev, const char *buf, size_t count) { struct thermal_cooling_device *cdev = to_cooling_device(dev); - unsigned long state; - int result; + unsigned long state, max_state; + int result, ret; if (!sscanf(buf, "%ld\n", &state)) return -EINVAL; @@ -953,6 +953,13 @@ thermal_cooling_device_cur_state_store(struct device *dev, if ((long)state < 0) return -EINVAL; + ret = cdev->ops->get_max_state(cdev, &max_state); + if (ret) + return ret; + + if (state > max_state) + return -EINVAL; + result = cdev->ops->set_cur_state(cdev, state); if (result) return result; -- cgit v1.2.3 From 9d09b31470a2714817375f86d9e56ffb1b617739 Mon Sep 17 00:00:00 2001 From: Debarshi Dutta Date: Fri, 9 Mar 2018 12:41:55 +0530 Subject: gpu: nvgpu: Validate buffer_offset argument Validate the mapping_size argument in the VM mapping IOCTL before attempting to use the argument for anything. Manual Cherry pick - https://git-master.nvidia.com/r/1547046 Bug 1954931 Bug 1965443 Change-Id: I81b22dc566c6c6f89e5e62604ce996376b33a343 Signed-off-by: Alex Waterman Reviewed-on: https://git-master.nvidia.com/r/1547046 Signed-off-by: Debarshi Dutta (cherry picked from commit e68391690cfcc23b77c68aec3f9605badea226ed in dev-kernel) Reviewed-on: https://git-master.nvidia.com/r/1671883 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/gpu/nvgpu/gk20a/mm_gk20a.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c index 2a5bd760f82d..59dc3656f486 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c @@ -1330,6 +1330,12 @@ u64 gk20a_vm_map(struct vm_gk20a *vm, bfr.pgsz_idx = -1; mapping_size = mapping_size ? mapping_size : bfr.size; + if ((mapping_size > bfr.size) || + (buffer_offset > (bfr.size - mapping_size))) { + err = -EINVAL; + goto clean_up; + } + /* If FIX_OFFSET is set, pgsz is determined. Otherwise, select * page size according to memory alignment */ if (flags & NVHOST_AS_MAP_BUFFER_FLAGS_FIXED_OFFSET) { -- cgit v1.2.3 From 1357daf84c6e99b32c50ed39a524871d003d1886 Mon Sep 17 00:00:00 2001 From: David Pu Date: Tue, 26 Jan 2016 11:21:06 -0800 Subject: video: tegra: sor: set drive current for lane4 drive current for LANE4 was not set if configured as 24bpp lvds out. fix it by programming proper drive current register if using 24bpp out. Bug 1724122 Change-Id: Ie2ad71ace0b4f247e007e671be828230545b15f6 Signed-off-by: David Pu Reviewed-on: https://git-master.nvidia.com/r/1544691 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Wayne Wang (SW-TEGRA) GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/video/tegra/dc/sor.c | 6 +++++- drivers/video/tegra/dc/sor_regs.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/video/tegra/dc/sor.c b/drivers/video/tegra/dc/sor.c index e5fe66be55d0..f4992eced400 100644 --- a/drivers/video/tegra/dc/sor.c +++ b/drivers/video/tegra/dc/sor.c @@ -1,7 +1,7 @@ /* * drivers/video/tegra/dc/sor.c * - * Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -186,6 +186,7 @@ static int dbg_sor_show(struct seq_file *s, void *unused) DUMP_REG(NV_SOR_DC(0)); DUMP_REG(NV_SOR_DC(1)); DUMP_REG(NV_SOR_LANE_DRIVE_CURRENT(0)); + DUMP_REG(NV_SOR_LANE4_DRIVE_CURRENT(0)); DUMP_REG(NV_SOR_PR(0)); DUMP_REG(NV_SOR_LANE4_PREEMPHASIS(0)); DUMP_REG(NV_SOR_POSTCURSOR(0)); @@ -1230,6 +1231,9 @@ void tegra_dc_sor_enable_lvds(struct tegra_dc_sor_data *sor, tegra_sor_writel(sor, NV_SOR_LVDS, reg_val); tegra_sor_writel(sor, NV_SOR_LANE_DRIVE_CURRENT(sor->portnum), 0x40404040); + if (!conforming && (sor->dc->pdata->default_out->depth == 24)) + tegra_sor_writel(sor, NV_SOR_LANE4_DRIVE_CURRENT(sor->portnum), + 0x40); #if 0 tegra_sor_write_field(sor, NV_SOR_LVDS, diff --git a/drivers/video/tegra/dc/sor_regs.h b/drivers/video/tegra/dc/sor_regs.h index cbf4b94c1664..8080e2925d82 100644 --- a/drivers/video/tegra/dc/sor_regs.h +++ b/drivers/video/tegra/dc/sor_regs.h @@ -1,7 +1,7 @@ /* * drivers/video/tegra/dc/sor_regs.h * - * Copyright (c) 2011-2013, NVIDIA CORPORATION, All rights reserved. + * Copyright (c) 2011-2017, NVIDIA CORPORATION, All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -611,6 +611,7 @@ #define NV_SOR_DC_LANE0_DP_LANE2_P1_LEVEL2 (43) #define NV_SOR_DC_LANE0_DP_LANE2_P0_LEVEL3 (51) #define NV_SOR_LANE_DRIVE_CURRENT(i) (0x4e + (i)) +#define NV_SOR_LANE4_DRIVE_CURRENT(i) (0x50 + (i)) #define NV_SOR_PR(i) (0x52 + (i)) #define NV_SOR_PR_LANE3_DP_LANE3_SHIFT (24) #define NV_SOR_PR_LANE3_DP_LANE3_MASK (0xff << 24) -- cgit v1.2.3 From b6d6e5af1450ed5ccae042ab1125a6b799433b73 Mon Sep 17 00:00:00 2001 From: Ravindra Lokhande Date: Mon, 8 May 2017 14:42:48 +0530 Subject: ASoC: tegra: check ucode upper limit Check ucode size for upper limit. Bug 1901435 Bug 1954563 Bug 1917589 Signed-off-by: Ravindra Lokhande Signed-off-by: Xia Yang Change-Id: I2f455771147bb4466d154878d2461e472647c4fb Reviewed-on: https://git-master.nvidia.com/r/1575925 Reviewed-on: https://git-master.nvidia.com/r/1674399 GVS: Gerrit_Virtual_Submit Tested-by: Amulya Yarlagadda Tested-by: James Huang Reviewed-by: James Huang Reviewed-by: Winnie Hsu --- sound/soc/tegra/tegra30_avp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/tegra/tegra30_avp.c b/sound/soc/tegra/tegra30_avp.c index 44d954561f96..a074e25614d1 100644 --- a/sound/soc/tegra/tegra30_avp.c +++ b/sound/soc/tegra/tegra30_avp.c @@ -256,7 +256,7 @@ static int tegra30_avp_load_ucode(void) struct audio_engine_data *audio_engine; const struct firmware *ucode_fw; const struct tegra30_avp_ucode_desc *ucode_desc; - int ucode_size = 0, ucode_offset = 0, total_ucode_size = 0; + ssize_t ucode_size = 0, ucode_offset = 0, total_ucode_size = 0; int i, ret = 0; dev_vdbg(audio_avp->dev, "%s", __func__); @@ -296,13 +296,14 @@ static int tegra30_avp_load_ucode(void) } ucode_size = ucode_fw->size; - if (ucode_size <= 0) { + if (ucode_size <= 0 || + ucode_size > avp_ucode_desc[i].max_mem_size) { dev_err(audio_avp->dev, "Invalid ucode size."); ret = -EINVAL; release_firmware(ucode_fw); goto err_param_mem_free; } - dev_vdbg(audio_avp->dev, "%s ucode size = %d bytes", + dev_vdbg(audio_avp->dev, "%s ucode size = %zd bytes", ucode_desc->bin_name, ucode_size); /* Read ucode */ -- cgit v1.2.3 From 7b67aa2c06e6906c6c190aabb1fa9722fd3cfb36 Mon Sep 17 00:00:00 2001 From: Mallikarjun Kasoju Date: Fri, 16 Mar 2018 15:40:06 +0530 Subject: tegra-cryptodev:Avoid untrusted usrptr dereference In RSA operations use copy_from_user to get key data into local buffer before using it. This will avoid untrusted user pointer dereference. Coverity ID 24040 Bug 200192571 Bug 1932494 Change-Id: I9c8f3fd7cfc18121d9c2179127dfb28202f38cdb Signed-off-by: Mallikarjun Kasoju Reviewed-on: https://git-master.nvidia.com/r/1676570 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/misc/tegra-cryptodev.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/misc/tegra-cryptodev.c b/drivers/misc/tegra-cryptodev.c index d1fa004367b1..4dc6ca63226d 100644 --- a/drivers/misc/tegra-cryptodev.c +++ b/drivers/misc/tegra-cryptodev.c @@ -425,6 +425,33 @@ static int tegra_crypt_rsa(struct tegra_crypto_ctx *ctx, int ret = 0; unsigned long *xbuf[XBUFSIZE]; struct tegra_crypto_completion rsa_complete; + unsigned int total_key_len; + char *key_mem; + + if ((((rsa_req->keylen >> 16) & 0xFFFF) > + MAX_RSA_MSG_LEN) || + ((rsa_req->keylen & 0xFFFF) > + MAX_RSA_MSG_LEN)) { + pr_err("Invalid rsa key length\n"); + return -EINVAL; + } + + total_key_len = (((rsa_req->keylen >> 16) & 0xFFFF) + + (rsa_req->keylen & 0xFFFF)); + + key_mem = kzalloc(total_key_len, GFP_KERNEL); + if (!key_mem) + return -ENOMEM; + + ret = copy_from_user(key_mem, (void __user *)rsa_req->key, + total_key_len); + if (ret) { + pr_err("%s: copy_from_user fail(%d)\n", __func__, ret); + kfree(key_mem); + return -EINVAL; + } + + rsa_req->key = key_mem; switch (rsa_req->algo) { case TEGRA_RSA512: @@ -475,10 +502,8 @@ static int tegra_crypt_rsa(struct tegra_crypto_ctx *ctx, init_completion(&rsa_complete.restart); result = kzalloc(rsa_req->keylen >> 16, GFP_KERNEL); - if (!result) { - pr_err("\nresult alloc fail\n"); + if (!result) goto result_fail; - } hash_buff = xbuf[0]; @@ -528,6 +553,7 @@ result_fail: buf_fail: ahash_request_free(req); req_fail: + kfree(key_mem); return ret; } -- cgit v1.2.3 From 763ada650d0d24dde8d4ec90f665f16c8d7edab7 Mon Sep 17 00:00:00 2001 From: Alex Waterman Date: Thu, 13 Oct 2016 10:03:59 -0700 Subject: gpu: nvgpu: Add ref counting to channels Make sure that the VM owned by a channel lives for at least as long as that channel does. If the channel's VM is cleaned up before the channel then use-after-free bugs can occur. Bug: 31680980 NvBug 1825464 Bug: 1885921 Change-Id: I0711781492a764b643c2ed1da1b3ba87fda72744 Signed-off-by: Alex Waterman Reviewed-on: https://git-psac.nvidia.com/r/#/c/9261 Signed-off-by: Debarshi Dutta (cherry picked from commit e205f2720fcee61886e7979e9588602d691507ea) Reviewed-on: https://git-master.nvidia.com/r/1681801 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 5 +++-- drivers/gpu/nvgpu/gk20a/mm_gk20a.c | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 947b1dc668bf..0a48f6a551ae 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c @@ -669,7 +669,7 @@ void gk20a_free_channel(struct channel_gk20a *ch, bool finish) memset(&ch->ramfc, 0, sizeof(struct mem_desc_sub)); /* free gpfifo */ - if (ch->gpfifo.gpu_va) + if (ch->vm && ch->gpfifo.gpu_va) gk20a_gmmu_unmap(ch_vm, ch->gpfifo.gpu_va, ch->gpfifo.size, gk20a_mem_flag_none); if (ch->gpfifo.cpu_va) @@ -698,8 +698,9 @@ unbind: channel_gk20a_unbind(ch); channel_gk20a_free_inst(g, ch); - ch->vpr = false; + gk20a_vm_put(ch->vm); /* Don't use VM after this. */ ch->vm = NULL; + ch->vpr = false; WARN_ON(ch->sync); /* unlink all debug sessions */ diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c index 59dc3656f486..5a828d394bfc 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c @@ -2427,6 +2427,7 @@ int gk20a_vm_bind_channel(struct gk20a_as_share *as_share, gk20a_dbg_fn(""); + gk20a_vm_get(vm); ch->vm = vm; err = channel_gk20a_commit_va(ch); if (err) -- cgit v1.2.3 From aba332e1dc32edfed73448364f2a88457738a270 Mon Sep 17 00:00:00 2001 From: Jeetesh Burman Date: Wed, 14 Feb 2018 11:50:57 +0530 Subject: arm: define speculation barrier The instruction sequency "dsb sy" followed by "isb" functions as a speculation barrier, which prevents the instructions after that from being speculatively executed. bug 2039126 Change-Id: I898aab771ff82b26b08214a06814d2e6e78969a7 Signed-off-by: Bo Yan Reviewed-on: https://git-master.nvidia.com/r/1618222 Signed-off-by: James Huang Reviewed-on: https://git-master.nvidia.com/r/1650093 Signed-off-by: Jeetesh Burman (cherry picked from commit f125c60045878513902cac4a084fde9a516eb3e2) Reviewed-on: https://git-master.nvidia.com/r/1660771 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- arch/arm/include/asm/barrier.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h index b00ef075bc2e..6af46bfa9837 100644 --- a/arch/arm/include/asm/barrier.h +++ b/arch/arm/include/asm/barrier.h @@ -79,5 +79,9 @@ do { \ #define set_mb(var, value) do { var = value; smp_mb(); } while (0) +#define speculation_barrier() \ + asm volatile( "dsb sy\n" \ + "isb\n" : : : "memory") + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_BARRIER_H */ -- cgit v1.2.3 From 92779c767e5e7c750cdea0c392e3f31befc37921 Mon Sep 17 00:00:00 2001 From: Jeetesh Burman Date: Wed, 14 Feb 2018 16:18:40 +0530 Subject: drivers: speculative load before bound-check Data can be speculatively loaded from memory and stay in cache even when bound check fails. This can lead to unintended information disclosure via side-channel analysis. To mitigate this problem, insert speculation barrier. Bug 1964290 CVE-2017-5753 Change-Id: I7382dbcc6e9f352fafd457301beafe753925f3c4 Signed-off-by: Hien Goi Signed-off-by: James Huang Reviewed-on: https://git-master.nvidia.com/r/1650791 Signed-off-by: Jeetesh Burman (cherry picked from commit 5cabd53985a30aa818896abdb64564a74c09ab9c) Reviewed-on: https://git-master.nvidia.com/r/1660772 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/media/i2c/ad9389b.c | 4 ++++ drivers/media/i2c/adv7604.c | 4 ++++ drivers/media/i2c/ov7670.c | 4 ++++ drivers/media/i2c/ov9650.c | 3 +++ drivers/media/i2c/s5c73m3/s5c73m3-core.c | 7 +++++++ drivers/media/i2c/s5k6aa.c | 3 +++ drivers/media/v4l2-core/videobuf2-core.c | 3 +++ 7 files changed, 28 insertions(+) diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index 58344b6c3a55..436b9fd4775e 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -36,6 +36,7 @@ #include #include #include +#include static int debug; module_param(debug, int, 0644); @@ -627,6 +628,9 @@ static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi } if (edid->start_block >= state->edid.segments * 2) return -E2BIG; + + speculation_barrier(); + if (edid->blocks + edid->start_block >= state->edid.segments * 2) edid->blocks = state->edid.segments * 2 - edid->start_block; memcpy(edid->edid, &state->edid.data[edid->start_block * 128], diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 31a63c9324fe..84202010d7d8 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -40,6 +40,7 @@ #include #include #include +#include static int debug; module_param(debug, int, 0644); @@ -1593,6 +1594,9 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi return -EINVAL; if (edid->start_block >= state->edid_blocks) return -EINVAL; + + speculation_barrier(); + if (edid->start_block + edid->blocks > state->edid_blocks) edid->blocks = state->edid_blocks - edid->start_block; if (!edid->edid) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 617ad3fff4aa..7124145a210b 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -21,6 +21,7 @@ #include #include #include +#include MODULE_AUTHOR("Jonathan Corbet "); MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); @@ -1087,6 +1088,9 @@ static int ov7670_enum_frameintervals(struct v4l2_subdev *sd, { if (interval->index >= ARRAY_SIZE(ov7670_frame_rates)) return -EINVAL; + + speculation_barrier(); + interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; interval->discrete.numerator = 1; interval->discrete.denominator = ov7670_frame_rates[interval->index]; diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 1dbb8118a285..47902efae8d4 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -30,6 +30,7 @@ #include #include #include +#include static int debug; module_param(debug, int, 0644); @@ -1086,6 +1087,8 @@ static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd, if (fse->index > ARRAY_SIZE(ov965x_framesizes)) return -EINVAL; + speculation_barrier(); + while (--i) if (fse->code == ov965x_formats[i].code) break; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 9eac5310942f..a7078441e1e1 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "s5c73m3.h" @@ -959,6 +960,8 @@ static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd, if (fie->index >= ARRAY_SIZE(s5c73m3_intervals)) return -EINVAL; + speculation_barrier(); + mutex_lock(&state->lock); fi = &s5c73m3_intervals[fie->index]; if (fie->width > fi->size.width || fie->height > fi->size.height) @@ -1228,6 +1231,8 @@ static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= s5c73m3_resolutions_len[idx]) return -EINVAL; + speculation_barrier(); + fse->min_width = s5c73m3_resolutions[idx][fse->index].width; fse->max_width = fse->min_width; fse->max_height = s5c73m3_resolutions[idx][fse->index].height; @@ -1272,6 +1277,8 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= s5c73m3_resolutions_len[idx]) return -EINVAL; + speculation_barrier(); + fse->min_width = s5c73m3_resolutions[idx][fse->index].width; fse->max_width = fse->min_width; fse->max_height = s5c73m3_resolutions[idx][fse->index].height; diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index bdf5e3db31d1..aff91c3bcfde 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -29,6 +29,7 @@ #include #include #include +#include static int debug; module_param(debug, int, 0644); @@ -1006,6 +1007,8 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, if (fie->index > ARRAY_SIZE(s5k6aa_intervals)) return -EINVAL; + speculation_barrier(); + v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN, S5K6AA_WIN_WIDTH_MAX, 1, &fie->height, S5K6AA_WIN_HEIGHT_MIN, diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index e3bdc3be91e1..60ba606afc56 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -23,6 +23,7 @@ #include #include #include +#include static int debug; module_param(debug, int, 0644); @@ -1800,6 +1801,8 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) return -EINVAL; } + speculation_barrier(); + vb = q->bufs[eb->index]; if (eb->plane >= vb->num_planes) { -- cgit v1.2.3 From 5fea92e18248d450c16c897f95d295e8ecdea000 Mon Sep 17 00:00:00 2001 From: Jeetesh Burman Date: Thu, 15 Feb 2018 13:00:39 +0530 Subject: cryptodev: prevent speculative load related leak Data can be speculatively loaded from memory and stay in cache even when bound check fails. This can lead to unintended information disclosure via side-channel analysis. To mitigate this problem, insert speculation barrier. bug 2039126 CVE-2017-5753 Change-Id: Id85eb9c91932f358dd999b28dd53d7788b37ea04 Signed-off-by: David Gilhooley Reviewed-on: https://git-master.nvidia.com/r/1640356 Signed-off-by: James Huang Reviewed-on: https://git-master.nvidia.com/r/1650014 Signed-off-by: Jeetesh Burman (cherry picked from commit 25bd9436b11f41e23048c9515deae97900a46669) Reviewed-on: https://git-master.nvidia.com/r/1660780 Reviewed-by: Winnie Hsu Tested-by: Winnie Hsu --- drivers/misc/tegra-cryptodev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/misc/tegra-cryptodev.c b/drivers/misc/tegra-cryptodev.c index 4dc6ca63226d..2c0d3918100d 100644 --- a/drivers/misc/tegra-cryptodev.c +++ b/drivers/misc/tegra-cryptodev.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "tegra-cryptodev.h" @@ -282,6 +283,8 @@ static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_re const u8 *key = NULL; struct tegra_crypto_completion tcrypt_complete; + speculation_barrier(); + if (crypt_req->op & TEGRA_CRYPTO_ECB) { req = ablkcipher_request_alloc(ctx->ecb_tfm, GFP_KERNEL); tfm = ctx->ecb_tfm; @@ -930,6 +933,9 @@ rng_out: rsa_req.algo); return -EINVAL; } + + speculation_barrier(); + ret = tegra_crypt_rsa(ctx, &rsa_req); break; -- cgit v1.2.3 From 68bd404adda3b13e3a5a465696ec85647f08dbdf Mon Sep 17 00:00:00 2001 From: Jeetesh Burman Date: Thu, 15 Feb 2018 14:07:39 +0530 Subject: v4l2: prevent speculative load bug 2039126 Change-Id: Id1908c3058c9ecc0dfb4f2d85440a8d36db45db5 Signed-off-by: David Gilhooley Signed-off-by: James Huang Reviewed-on: https://git-master.nvidia.com/r/1650029 Signed-off-by: Jeetesh Burman (cherry picked from commit 7a0213eca150614fe88d197a09d461fff6168652) Reviewed-on: https://git-master.nvidia.com/r/1660781 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- drivers/media/v4l2-core/v4l2-ioctl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7658586fe5f4..80bef0e66683 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -28,6 +28,7 @@ #include #include #include +#include /* Zero out the end of the struct pointed to by p. Everything after, but * not including, the specified field is cleared. */ @@ -2119,6 +2120,7 @@ bool v4l2_is_known_ioctl(unsigned int cmd) { if (_IOC_NR(cmd) >= V4L2_IOCTLS) return false; + speculation_barrier(); return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd; } @@ -2128,6 +2130,7 @@ struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, unsigned cmd) return vdev->lock; if (test_bit(_IOC_NR(cmd), vdev->disable_locking)) return NULL; + speculation_barrier(); if (vdev->queue && vdev->queue->lock && (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE)) return vdev->queue->lock; -- cgit v1.2.3 From 946ad0dedcd475c32e4c455d21c5c6df12caa6f7 Mon Sep 17 00:00:00 2001 From: James Huang Date: Thu, 1 Feb 2018 13:01:50 +0800 Subject: arm64: define speculation barrier The instruction sequency "dsb sy" followed by "isb" functions as a speculation barrier, which prevents the instructions after that from being speculatively executed. bug 2039126 Change-Id: Ie3b7b873a12002617e60510ed8759bdaa7cd7057 Signed-off-by: Bo Yan Reviewed-on: https://git-master.nvidia.com/r/1618222 Signed-off-by: James Huang Reviewed-on: https://git-master.nvidia.com/r/1650093 Signed-off-by: Jeetesh Burman (cherry picked from commit f125c60045878513902cac4a084fde9a516eb3e2) Reviewed-on: https://git-master.nvidia.com/r/1660782 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu --- arch/arm64/include/asm/barrier.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 9269edba2c90..8059ead5f2d6 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -99,6 +99,10 @@ do { \ #define set_mb(var, value) do { var = value; smp_mb(); } while (0) #define nop() asm volatile("nop"); +#define speculation_barrier() \ + asm volatile( "dsb sy\n" \ + "isb\n" : : : "memory") + #endif /* __ASSEMBLY__ */ #endif /* __ASM_BARRIER_H */ -- cgit v1.2.3 From ff6dbd5dff104b4d6d4aeeeafe90493e377474e2 Mon Sep 17 00:00:00 2001 From: Gagan Grover Date: Fri, 25 Nov 2016 17:58:44 +0530 Subject: staging: ion: Fix ION subsystem privilege vulnerability A malicious application can take advantage of the ION kmalloc heap to create a specific memory chunk size to exercise a rowhammer attack on the physical hardware. The fix is designed to disable ION heap type. CVE-2016-6728: A-30400942 Bug 1823317 Change-Id: I6b6d891a85da0c175f88cc1a3e48875796db80d4 Signed-off-by: Gagan Grover Reviewed-on: https://git-master.nvidia.com/r/1690291 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- drivers/staging/android/ion/ion_heap.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 551fe2e0bc2d..ec1fb7913f4c 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -269,6 +269,8 @@ static int ion_heap_shrink(struct shrinker *shrinker, struct shrink_control *sc) { struct ion_heap *heap = container_of(shrinker, struct ion_heap, shrinker); + if (IS_ERR_OR_NULL(heap)) + return -EINVAL; int total = 0; int freed = 0; int to_scan = sc->nr_to_scan; @@ -309,8 +311,9 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) switch (heap_data->type) { case ION_HEAP_TYPE_SYSTEM_CONTIG: - heap = ion_system_contig_heap_create(heap_data); - break; + pr_err("%s: Heap type is disabled: %d\n", __func__, + heap_data->type); + return ERR_PTR(-EINVAL); case ION_HEAP_TYPE_SYSTEM: heap = ion_system_heap_create(heap_data); break; @@ -343,12 +346,13 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) void ion_heap_destroy(struct ion_heap *heap) { - if (!heap) + if (IS_ERR_OR_NULL(heap)) return; switch (heap->type) { case ION_HEAP_TYPE_SYSTEM_CONTIG: - ion_system_contig_heap_destroy(heap); + pr_err("%s: Heap type is disabled: %d\n", __func__, + heap->type); break; case ION_HEAP_TYPE_SYSTEM: ion_system_heap_destroy(heap); -- cgit v1.2.3 From ab6caaa6ab10ff7e3c6d536277dacf1e644c3cd2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 17 Aug 2016 05:56:26 -0700 Subject: tcp: fix use after free in tcp_xmit_retransmit_queue() When tcp_sendmsg() allocates a fresh and empty skb, it puts it at the tail of the write queue using tcp_add_write_queue_tail() Then it attempts to copy user data into this fresh skb. If the copy fails, we undo the work and remove the fresh skb. Unfortunately, this undo lacks the change done to tp->highest_sack and we can leave a dangling pointer (to a freed skb) Later, tcp_xmit_retransmit_queue() can dereference this pointer and access freed memory. For regular kernels where memory is not unmapped, this might cause SACK bugs because tcp_highest_sack_seq() is buggy, returning garbage instead of tp->snd_nxt, but with various debug features like CONFIG_DEBUG_PAGEALLOC, this can crash the kernel. This bug was found by Marco Grassi thanks to syzkaller. Bug 1823317 Bug 1935735 Change-Id: I9bf709b21e5637f338c34d894617f33d84f93ecc Reported-by: Marco Grassi Signed-off-by: Eric Dumazet Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1260003 (cherry picked from commit 0c20962647685008dfc6a15fb8a2169ed2abafe6) Reviewed-on: https://git-master.nvidia.com/r/1690290 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- include/net/tcp.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/net/tcp.h b/include/net/tcp.h index 13f12c10f03b..013daf1494ba 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1392,6 +1392,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli { if (sk->sk_send_head == skb_unlinked) sk->sk_send_head = NULL; + if (tcp_sk(sk)->highest_sack == skb_unlinked) + tcp_sk(sk)->highest_sack = NULL; } static inline void tcp_init_send_head(struct sock *sk) -- cgit v1.2.3 From aeea4acc3327edf231266bd8225e0af559dd5f79 Mon Sep 17 00:00:00 2001 From: Vladis Dronov Date: Thu, 31 Mar 2016 12:05:43 -0400 Subject: ALSA: usb-audio: Fix double-free in error paths after snd_usb_add_audio_stream() call create_fixed_stream_quirk(), snd_usb_parse_audio_interface() and create_uaxx_quirk() functions allocate the audioformat object by themselves and free it upon error before returning. However, once the object is linked to a stream, it's freed again in snd_usb_audio_pcm_free(), thus it'll be double-freed, eventually resulting in a memory corruption. This patch fixes these failures in the error paths by unlinking the audioformat object before freeing it. Based on a patch by Takashi Iwai [Note for stable backports: this patch requires the commit 902eb7fd1e4a ('ALSA: usb-audio: Minor code cleanup in create_fixed_stream_quirk()')] Bug 1823317 Bug 1935735 Change-Id: I4f65a902a19e7b21e8bc0fa21efd833c8360a3cf Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1283358 Reported-by: Ralf Spenneberg Cc: # see the note above Signed-off-by: Vladis Dronov Signed-off-by: Takashi Iwai Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1259999 (cherry picked from commit 14e09c3233fb7578c778b70ec3933ba5cadfccb6) Reviewed-on: https://git-master.nvidia.com/r/1690292 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- sound/usb/quirks.c | 17 +++++++++++------ sound/usb/stream.c | 6 +++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 3879eae7e874..a72bfeee6de2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -136,6 +136,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, snd_printk(KERN_ERR "cannot memdup\n"); return -ENOMEM; } + INIT_LIST_HEAD(&fp->list); if (fp->nr_rates > MAX_NR_RATES) { kfree(fp); return -EINVAL; @@ -154,15 +155,12 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { - kfree(fp); - kfree(rate_table); - return err; + goto error; } if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber || fp->altset_idx >= iface->num_altsetting) { - kfree(fp); - kfree(rate_table); - return -EINVAL; + err = -EINVAL; + goto error; } alts = &iface->altsetting[fp->altset_idx]; if (fp->datainterval == 0) @@ -173,6 +171,11 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, snd_usb_init_pitch(chip, fp->iface, alts, fp); snd_usb_init_sample_rate(chip, fp->iface, alts, fp, fp->rate_max); return 0; +error: + list_del(&fp->list); /* unlink for avoiding double-free */ + kfree(fp); + kfree(rate_table); + return err; } /* @@ -239,6 +242,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; fp->datainterval = 0; fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + INIT_LIST_HEAD(&fp->list); switch (fp->maxpacksize) { case 0x120: @@ -262,6 +266,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { + list_del(&fp->list); /* unlink for avoiding double-free */ kfree(fp); return err; } diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 5b6f7a027c6a..7ddf4a437e4a 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -307,7 +307,9 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, /* * add this endpoint to the chip instance. * if a stream with the same endpoint already exists, append to it. - * if not, create a new pcm stream. + * if not, create a new pcm stream. note, fp is added to the substream + * fmt_list and will be freed on the chip instance release. do not free + * fp or do remove it from the substream fmt_list to avoid double-free. */ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, int stream, @@ -755,6 +757,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); fp->clock = clock; fp->chmap = convert_chmap(num_channels, chconfig, protocol); + INIT_LIST_HEAD(&fp->list); /* some quirks for attributes here */ @@ -799,6 +802,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { + list_del(&fp->list); /* unlink for avoiding double-free */ kfree(fp->rate_table); kfree(fp->chmap); kfree(fp); -- cgit v1.2.3 From 47fcced74e05eeb30f586bde0db955b9ccdb60dc Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 29 Jul 2016 10:40:31 +0200 Subject: block: fix use-after-free in seq file I got a KASAN report of use-after-free: ================================================================== BUG: KASAN: use-after-free in klist_iter_exit+0x61/0x70 at addr ffff8800b6581508 Read of size 8 by task trinity-c1/315 ============================================================================= BUG kmalloc-32 (Not tainted): kasan: bad access detected ----------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Allocated in disk_seqf_start+0x66/0x110 age=144 cpu=1 pid=315 ___slab_alloc+0x4f1/0x520 __slab_alloc.isra.58+0x56/0x80 kmem_cache_alloc_trace+0x260/0x2a0 disk_seqf_start+0x66/0x110 traverse+0x176/0x860 seq_read+0x7e3/0x11a0 proc_reg_read+0xbc/0x180 do_loop_readv_writev+0x134/0x210 do_readv_writev+0x565/0x660 vfs_readv+0x67/0xa0 do_preadv+0x126/0x170 SyS_preadv+0xc/0x10 do_syscall_64+0x1a1/0x460 return_from_SYSCALL_64+0x0/0x6a INFO: Freed in disk_seqf_stop+0x42/0x50 age=160 cpu=1 pid=315 __slab_free+0x17a/0x2c0 kfree+0x20a/0x220 disk_seqf_stop+0x42/0x50 traverse+0x3b5/0x860 seq_read+0x7e3/0x11a0 proc_reg_read+0xbc/0x180 do_loop_readv_writev+0x134/0x210 do_readv_writev+0x565/0x660 vfs_readv+0x67/0xa0 do_preadv+0x126/0x170 SyS_preadv+0xc/0x10 do_syscall_64+0x1a1/0x460 return_from_SYSCALL_64+0x0/0x6a CPU: 1 PID: 315 Comm: trinity-c1 Tainted: G B 4.7.0+ #62 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 ffffea0002d96000 ffff880119b9f918 ffffffff81d6ce81 ffff88011a804480 ffff8800b6581500 ffff880119b9f948 ffffffff8146c7bd ffff88011a804480 ffffea0002d96000 ffff8800b6581500 fffffffffffffff4 ffff880119b9f970 Call Trace: [] dump_stack+0x65/0x84 [] print_trailer+0x10d/0x1a0 [] object_err+0x2f/0x40 [] kasan_report_error+0x221/0x520 [] __asan_report_load8_noabort+0x3e/0x40 [] klist_iter_exit+0x61/0x70 [] class_dev_iter_exit+0x9/0x10 [] disk_seqf_stop+0x3a/0x50 [] seq_read+0x4b2/0x11a0 [] proc_reg_read+0xbc/0x180 [] do_loop_readv_writev+0x134/0x210 [] do_readv_writev+0x565/0x660 [] vfs_readv+0x67/0xa0 [] do_preadv+0x126/0x170 [] SyS_preadv+0xc/0x10 This problem can occur in the following situation: open() - pread() - .seq_start() - iter = kmalloc() // succeeds - seqf->private = iter - .seq_stop() - kfree(seqf->private) - pread() - .seq_start() - iter = kmalloc() // fails - .seq_stop() - class_dev_iter_exit(seqf->private) // boom! old pointer As the comment in disk_seqf_stop() says, stop is called even if start failed, so we need to reinitialise the private pointer to NULL when seq iteration stops. An alternative would be to set the private pointer to NULL when the kmalloc() in disk_seqf_start() fails. Bug 1823317 Bug 1935735 Change-Id: Ic3f82ef82c570866b48c5ea8e195d8e504570d80 Cc: stable@vger.kernel.org Signed-off-by: Vegard Nossum Acked-by: Tejun Heo Signed-off-by: Jens Axboe Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1259961 (cherry picked from commit 9d4a4a8711e9570c3ead013b64ff6e8bad05afbc) Reviewed-on: https://git-master.nvidia.com/r/1690293 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- block/genhd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/genhd.c b/block/genhd.c index 6f612a747810..50d8e7ac4d69 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -828,6 +828,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v) if (iter) { class_dev_iter_exit(iter); kfree(iter); + seqf->private = NULL; } } -- cgit v1.2.3 From c402cacd260ca10bcdd12e068a55ca562666793b Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Fri, 1 Jul 2016 00:39:35 -0700 Subject: block: fix use-after-free in sys_ioprio_get() get_task_ioprio() accesses the task->io_context without holding the task lock and thus can race with exit_io_context(), leading to a use-after-free. The reproducer below hits this within a few seconds on my 4-core QEMU VM: int main(int argc, char **argv) { pid_t pid, child; long nproc, i; /* ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); */ syscall(SYS_ioprio_set, 1, 0, 0x6000); nproc = sysconf(_SC_NPROCESSORS_ONLN); for (i = 0; i < nproc; i++) { pid = fork(); assert(pid != -1); if (pid == 0) { for (;;) { pid = fork(); assert(pid != -1); if (pid == 0) { _exit(0); } else { child = wait(NULL); assert(child == pid); } } } pid = fork(); assert(pid != -1); if (pid == 0) { for (;;) { /* ioprio_get(IOPRIO_WHO_PGRP, 0); */ syscall(SYS_ioprio_get, 2, 0); } } } for (;;) { /* ioprio_get(IOPRIO_WHO_PGRP, 0); */ syscall(SYS_ioprio_get, 2, 0); } return 0; } This gets us KASAN dumps like this: [ 35.526914] ================================================================== [ 35.530009] BUG: KASAN: out-of-bounds in get_task_ioprio+0x7b/0x90 at addr ffff880066f34e6c [ 35.530009] Read of size 2 by task ioprio-gpf/363 [ 35.530009] ============================================================================= [ 35.530009] BUG blkdev_ioc (Not tainted): kasan: bad access detected [ 35.530009] ----------------------------------------------------------------------------- [ 35.530009] Disabling lock debugging due to kernel taint [ 35.530009] INFO: Allocated in create_task_io_context+0x2b/0x370 age=0 cpu=0 pid=360 [ 35.530009] ___slab_alloc+0x55d/0x5a0 [ 35.530009] __slab_alloc.isra.20+0x2b/0x40 [ 35.530009] kmem_cache_alloc_node+0x84/0x200 [ 35.530009] create_task_io_context+0x2b/0x370 [ 35.530009] get_task_io_context+0x92/0xb0 [ 35.530009] copy_process.part.8+0x5029/0x5660 [ 35.530009] _do_fork+0x155/0x7e0 [ 35.530009] SyS_clone+0x19/0x20 [ 35.530009] do_syscall_64+0x195/0x3a0 [ 35.530009] return_from_SYSCALL_64+0x0/0x6a [ 35.530009] INFO: Freed in put_io_context+0xe7/0x120 age=0 cpu=0 pid=1060 [ 35.530009] __slab_free+0x27b/0x3d0 [ 35.530009] kmem_cache_free+0x1fb/0x220 [ 35.530009] put_io_context+0xe7/0x120 [ 35.530009] put_io_context_active+0x238/0x380 [ 35.530009] exit_io_context+0x66/0x80 [ 35.530009] do_exit+0x158e/0x2b90 [ 35.530009] do_group_exit+0xe5/0x2b0 [ 35.530009] SyS_exit_group+0x1d/0x20 [ 35.530009] entry_SYSCALL_64_fastpath+0x1a/0xa4 [ 35.530009] INFO: Slab 0xffffea00019bcd00 objects=20 used=4 fp=0xffff880066f34ff0 flags=0x1fffe0000004080 [ 35.530009] INFO: Object 0xffff880066f34e58 @offset=3672 fp=0x0000000000000001 [ 35.530009] ================================================================== Fix it by grabbing the task lock while we poke at the io_context. Bug 1823317 Bug 1935735 Change-Id: If331a4574b63e9288d1019c45c28af82731e9abb Cc: stable@vger.kernel.org Reported-by: Dmitry Vyukov Signed-off-by: Omar Sandoval Signed-off-by: Jens Axboe Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1259972 (cherry picked from commit 15e376e5d8b1399d02814cf8b1481f7ac40dc483) Reviewed-on: https://git-master.nvidia.com/r/1690294 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- fs/ioprio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ioprio.c b/fs/ioprio.c index e50170ca7c33..46f0e24f43e9 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -149,8 +149,10 @@ static int get_task_ioprio(struct task_struct *p) if (ret) goto out; ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); + task_lock(p); if (p->io_context) ret = p->io_context->ioprio; + task_unlock(p); out: return ret; } -- cgit v1.2.3 From 0a84f61d56be62df02267668dc60a8220bf15472 Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Fri, 30 Oct 2015 16:57:00 -0700 Subject: sg: Fix double-free when drives detach during SG_IO In sg_common_write(), we free the block request and return -ENODEV if the device is detached in the middle of the SG_IO ioctl(). Unfortunately, sg_finish_rem_req() also tries to free srp->rq, so we end up freeing rq->cmd in the already free rq object, and then free the object itself out from under the current user. This ends up corrupting random memory via the list_head on the rq object. The most common crash trace I saw is this: ------------[ cut here ]------------ kernel BUG at block/blk-core.c:1420! Call Trace: [] blk_put_request+0x5b/0x80 [] sg_finish_rem_req+0x6b/0x120 [sg] [] sg_common_write.isra.14+0x459/0x5a0 [sg] [] ? selinux_file_alloc_security+0x48/0x70 [] sg_new_write.isra.17+0x195/0x2d0 [sg] [] sg_ioctl+0x644/0xdb0 [sg] [] do_vfs_ioctl+0x90/0x520 [] ? file_has_perm+0x97/0xb0 [] SyS_ioctl+0x91/0xb0 [] tracesys+0xdd/0xe2 RIP [] __blk_put_request+0x154/0x1a0 The solution is straightforward: just set srp->rq to NULL in the failure branch so that sg_finish_rem_req() doesn't attempt to re-free it. Additionally, since sg_rq_end_io() will never be called on the object when this happens, we need to free memory backing ->cmd if it isn't embedded in the object itself. KASAN was extremely helpful in finding the root cause of this bug. Bug 1823317 Bug 1935735 Change-Id: I883243dce583cd79e28facaa2cdd81157b293d74 Signed-off-by: Calvin Owens Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1259958 (cherry picked from commit b49da4529988ca02bddaed8091a7f5e91105970a) Reviewed-on: https://git-master.nvidia.com/r/1690295 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- drivers/scsi/sg.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index df5e961484e1..47eafb87e038 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -765,8 +765,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return k; /* probably out of space --> ENOMEM */ } if (sdp->detached) { - if (srp->bio) + if (srp->bio) { + if (srp->rq->cmd != srp->rq->__cmd) + kfree(srp->rq->cmd); + blk_end_request_all(srp->rq, -EIO); + srp->rq = NULL; + } + sg_finish_rem_req(srp); return -ENODEV; } -- cgit v1.2.3 From 781051311df5d2e155f0ff3f67aa0b2763c54ede Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Jan 2016 09:22:44 -0200 Subject: [media] xc2028: avoid use after free If struct xc2028_config is passed without a firmware name, the following trouble may happen: [11009.907205] xc2028 5-0061: type set to XCeive xc2028/xc3028 tuner [11009.907491] ================================================================== [11009.907750] BUG: KASAN: use-after-free in strcmp+0x96/0xb0 at addr ffff8803bd78ab40 [11009.907992] Read of size 1 by task modprobe/28992 [11009.907994] ============================================================================= [11009.907997] BUG kmalloc-16 (Tainted: G W ): kasan: bad access detected [11009.907999] ----------------------------------------------------------------------------- [11009.908008] INFO: Allocated in xhci_urb_enqueue+0x214/0x14c0 [xhci_hcd] age=0 cpu=3 pid=28992 [11009.908012] ___slab_alloc+0x581/0x5b0 [11009.908014] __slab_alloc+0x51/0x90 [11009.908017] __kmalloc+0x27b/0x350 [11009.908022] xhci_urb_enqueue+0x214/0x14c0 [xhci_hcd] [11009.908026] usb_hcd_submit_urb+0x1e8/0x1c60 [11009.908029] usb_submit_urb+0xb0e/0x1200 [11009.908032] usb_serial_generic_write_start+0xb6/0x4c0 [11009.908035] usb_serial_generic_write+0x92/0xc0 [11009.908039] usb_console_write+0x38a/0x560 [11009.908045] call_console_drivers.constprop.14+0x1ee/0x2c0 [11009.908051] console_unlock+0x40d/0x900 [11009.908056] vprintk_emit+0x4b4/0x830 [11009.908061] vprintk_default+0x1f/0x30 [11009.908064] printk+0x99/0xb5 [11009.908067] kasan_report_error+0x10a/0x550 [11009.908070] __asan_report_load1_noabort+0x43/0x50 [11009.908074] INFO: Freed in xc2028_set_config+0x90/0x630 [tuner_xc2028] age=1 cpu=3 pid=28992 [11009.908077] __slab_free+0x2ec/0x460 [11009.908080] kfree+0x266/0x280 [11009.908083] xc2028_set_config+0x90/0x630 [tuner_xc2028] [11009.908086] xc2028_attach+0x310/0x8a0 [tuner_xc2028] [11009.908090] em28xx_attach_xc3028.constprop.7+0x1f9/0x30d [em28xx_dvb] [11009.908094] em28xx_dvb_init.part.3+0x8e4/0x5cf4 [em28xx_dvb] [11009.908098] em28xx_dvb_init+0x81/0x8a [em28xx_dvb] [11009.908101] em28xx_register_extension+0xd9/0x190 [em28xx] [11009.908105] em28xx_dvb_register+0x10/0x1000 [em28xx_dvb] [11009.908108] do_one_initcall+0x141/0x300 [11009.908111] do_init_module+0x1d0/0x5ad [11009.908114] load_module+0x6666/0x9ba0 [11009.908117] SyS_finit_module+0x108/0x130 [11009.908120] entry_SYSCALL_64_fastpath+0x16/0x76 [11009.908123] INFO: Slab 0xffffea000ef5e280 objects=25 used=25 fp=0x (null) flags=0x2ffff8000004080 [11009.908126] INFO: Object 0xffff8803bd78ab40 @offset=2880 fp=0x0000000000000001 [11009.908130] Bytes b4 ffff8803bd78ab30: 01 00 00 00 2a 07 00 00 9d 28 00 00 01 00 00 00 ....*....(...... [11009.908133] Object ffff8803bd78ab40: 01 00 00 00 00 00 00 00 b0 1d c3 6a 00 88 ff ff ...........j.... [11009.908137] CPU: 3 PID: 28992 Comm: modprobe Tainted: G B W 4.5.0-rc1+ #43 [11009.908140] Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015 [11009.908142] ffff8803bd78a000 ffff8802c273f1b8 ffffffff81932007 ffff8803c6407a80 [11009.908148] ffff8802c273f1e8 ffffffff81556759 ffff8803c6407a80 ffffea000ef5e280 [11009.908153] ffff8803bd78ab40 dffffc0000000000 ffff8802c273f210 ffffffff8155ccb4 [11009.908158] Call Trace: [11009.908162] [] dump_stack+0x4b/0x64 [11009.908165] [] print_trailer+0xf9/0x150 [11009.908168] [] object_err+0x34/0x40 [11009.908171] [] kasan_report_error+0x230/0x550 [11009.908175] [] ? trace_hardirqs_off_caller+0x21/0x290 [11009.908179] [] ? kasan_unpoison_shadow+0x36/0x50 [11009.908182] [] __asan_report_load1_noabort+0x43/0x50 [11009.908185] [] ? __asan_register_globals+0x50/0xa0 [11009.908189] [] ? strcmp+0x96/0xb0 [11009.908192] [] strcmp+0x96/0xb0 [11009.908196] [] xc2028_set_config+0x15c/0x630 [tuner_xc2028] [11009.908200] [] xc2028_attach+0x310/0x8a0 [tuner_xc2028] [11009.908203] [] ? memset+0x28/0x30 [11009.908206] [] ? xc2028_set_config+0x630/0x630 [tuner_xc2028] [11009.908211] [] em28xx_attach_xc3028.constprop.7+0x1f9/0x30d [em28xx_dvb] [11009.908215] [] ? em28xx_dvb_init.part.3+0x37c/0x5cf4 [em28xx_dvb] [11009.908219] [] ? hauppauge_hvr930c_init+0x487/0x487 [em28xx_dvb] [11009.908222] [] ? lgdt330x_attach+0x1cc/0x370 [lgdt330x] [11009.908226] [] ? i2c_read_demod_bytes.isra.2+0x210/0x210 [lgdt330x] [11009.908230] [] ? ref_module.part.15+0x10/0x10 [11009.908233] [] ? module_assert_mutex_or_preempt+0x80/0x80 [11009.908238] [] em28xx_dvb_init.part.3+0x8e4/0x5cf4 [em28xx_dvb] [11009.908242] [] ? em28xx_attach_xc3028.constprop.7+0x30d/0x30d [em28xx_dvb] [11009.908245] [] ? string+0x14d/0x1f0 [11009.908249] [] ? symbol_string+0xff/0x1a0 [11009.908253] [] ? uuid_string+0x6f0/0x6f0 [11009.908257] [] ? __kernel_text_address+0x7e/0xa0 [11009.908260] [] ? print_context_stack+0x7f/0xf0 [11009.908264] [] ? __module_address+0xb6/0x360 [11009.908268] [] ? is_ftrace_trampoline+0x99/0xe0 [11009.908271] [] ? __kernel_text_address+0x7e/0xa0 [11009.908275] [] ? debug_check_no_locks_freed+0x290/0x290 [11009.908278] [] ? dump_trace+0x11b/0x300 [11009.908282] [] ? em28xx_register_extension+0x23/0x190 [em28xx] [11009.908285] [] ? trace_hardirqs_off_caller+0x21/0x290 [11009.908289] [] ? trace_hardirqs_on_caller+0x16/0x590 [11009.908292] [] ? trace_hardirqs_on+0xd/0x10 [11009.908296] [] ? em28xx_register_extension+0x23/0x190 [em28xx] [11009.908299] [] ? mutex_trylock+0x400/0x400 [11009.908302] [] ? do_one_initcall+0x131/0x300 [11009.908306] [] ? call_rcu_sched+0x17/0x20 [11009.908309] [] ? put_object+0x48/0x70 [11009.908314] [] em28xx_dvb_init+0x81/0x8a [em28xx_dvb] [11009.908317] [] em28xx_register_extension+0xd9/0x190 [em28xx] [11009.908320] [] ? 0xffffffffa0150000 [11009.908324] [] em28xx_dvb_register+0x10/0x1000 [em28xx_dvb] [11009.908327] [] do_one_initcall+0x141/0x300 [11009.908330] [] ? try_to_run_init_process+0x40/0x40 [11009.908333] [] ? trace_hardirqs_on_caller+0x16/0x590 [11009.908337] [] ? kasan_unpoison_shadow+0x36/0x50 [11009.908340] [] ? kasan_unpoison_shadow+0x36/0x50 [11009.908343] [] ? kasan_unpoison_shadow+0x36/0x50 [11009.908346] [] ? __asan_register_globals+0x87/0xa0 [11009.908350] [] do_init_module+0x1d0/0x5ad [11009.908353] [] load_module+0x6666/0x9ba0 [11009.908356] [] ? symbol_put_addr+0x50/0x50 [11009.908361] [] ? em28xx_dvb_init.part.3+0x5989/0x5cf4 [em28xx_dvb] [11009.908366] [] ? module_frob_arch_sections+0x20/0x20 [11009.908369] [] ? open_exec+0x50/0x50 [11009.908374] [] ? ns_capable+0x5b/0xd0 [11009.908377] [] SyS_finit_module+0x108/0x130 [11009.908379] [] ? SyS_init_module+0x1f0/0x1f0 [11009.908383] [] ? lockdep_sys_exit_thunk+0x12/0x14 [11009.908394] [] entry_SYSCALL_64_fastpath+0x16/0x76 [11009.908396] Memory state around the buggy address: [11009.908398] ffff8803bd78aa00: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc [11009.908401] ffff8803bd78aa80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [11009.908403] >ffff8803bd78ab00: fc fc fc fc fc fc fc fc 00 00 fc fc fc fc fc fc [11009.908405] ^ [11009.908407] ffff8803bd78ab80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [11009.908409] ffff8803bd78ac00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [11009.908411] ================================================================== In order to avoid it, let's set the cached value of the firmware name to NULL after freeing it. While here, return an error if the memory allocation fails. Bug 1823317 Bug 1935735 Change-Id: I1825fc7eb08bd458ed5413fea8b47de539c9b23f Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Gagan Grover Reviewed-on: https://git-master.nvidia.com/r/1690296 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- drivers/media/tuners/tuner-xc2028.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 9771cd83c06e..38afc54ef349 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -1385,11 +1385,12 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) * in order to avoid troubles during device release. */ kfree(priv->ctrl.fname); + priv->ctrl.fname = NULL; memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); if (p->fname) { priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); if (priv->ctrl.fname == NULL) - rc = -ENOMEM; + return -ENOMEM; } /* -- cgit v1.2.3 From 9616bef14596d892b6f9c1292c15fe4758c51873 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Tue, 19 Jul 2016 17:42:57 -0400 Subject: audit: fix a double fetch in audit_log_single_execve_arg() There is a double fetch problem in audit_log_single_execve_arg() where we first check the execve(2) argumnets for any "bad" characters which would require hex encoding and then re-fetch the arguments for logging in the audit record[1]. Of course this leaves a window of opportunity for an unsavory application to munge with the data. This patch reworks things by only fetching the argument data once[2] into a buffer where it is scanned and logged into the audit records(s). In addition to fixing the double fetch, this patch improves on the original code in a few other ways: better handling of large arguments which require encoding, stricter record length checking, and some performance improvements (completely unverified, but we got rid of some strlen() calls, that's got to be a good thing). As part of the development of this patch, I've also created a basic regression test for the audit-testsuite, the test can be tracked on GitHub at the following link: * https://github.com/linux-audit/audit-testsuite/issues/25 [1] If you pay careful attention, there is actually a triple fetch problem due to a strnlen_user() call at the top of the function. [2] This is a tiny white lie, we do make a call to strnlen_user() prior to fetching the argument data. I don't like it, but due to the way the audit record is structured we really have no choice unless we copy the entire argument at once (which would require a rather wasteful allocation). The good news is that with this patch the kernel no longer relies on this strnlen_user() value for anything beyond recording it in the log, we also update it with a trustworthy value whenever possible. Bug 1823317 Bug 1935735 Change-Id: I500834e1e699cb43d207333fa91292673de54933 Reported-by: Pengfei Wang Cc: Signed-off-by: Paul Moore Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1261377 (cherry picked from commit 1cc418b165a23b352e06aa5ab66a2d1e1a942a98) Reviewed-on: https://git-master.nvidia.com/r/1690297 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- kernel/auditsc.c | 341 +++++++++++++++++++++++++++---------------------------- 1 file changed, 169 insertions(+), 172 deletions(-) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 9845cb32b60a..04a257b4a2da 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -68,6 +68,7 @@ #include #include #include +#include #include "audit.h" @@ -76,7 +77,8 @@ #define AUDITSC_SUCCESS 1 #define AUDITSC_FAILURE 2 -/* no execve audit message should be longer than this (userspace limits) */ +/* no execve audit message should be longer than this (userspace limits), + * see the note near the top of audit_log_execve_info() about this value */ #define MAX_EXECVE_AUDIT_LEN 7500 /* number of audit rules */ @@ -1001,189 +1003,184 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid, return rc; } -/* - * to_send and len_sent accounting are very loose estimates. We aren't - * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being - * within about 500 bytes (next page boundary) - * - * why snprintf? an int is up to 12 digits long. if we just assumed when - * logging that a[%d]= was going to be 16 characters long we would be wasting - * space in every audit message. In one 7500 byte message we can log up to - * about 1000 min size arguments. That comes down to about 50% waste of space - * if we didn't do the snprintf to find out how long arg_num_len was. - */ -static int audit_log_single_execve_arg(struct audit_context *context, - struct audit_buffer **ab, - int arg_num, - size_t *len_sent, - const char __user *p, - char *buf) +static void audit_log_execve_info(struct audit_context *context, + struct audit_buffer **ab, + struct audit_aux_data_execve *axi) { - char arg_num_len_buf[12]; - const char __user *tmp_p = p; - /* how many digits are in arg_num? 5 is the length of ' a=""' */ - size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5; - size_t len, len_left, to_send; - size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN; - unsigned int i, has_cntl = 0, too_long = 0; - int ret; - - /* strnlen_user includes the null we don't want to send */ - len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1; + long len_max; + long len_rem; + long len_full; + long len_buf; + long len_abuf; + long len_tmp; + bool require_data; + bool encode; + unsigned int iter; + unsigned int arg; + char *buf_head; + char *buf; + const char __user *p; - /* - * We just created this mm, if we can't find the strings - * we just copied into it something is _very_ wrong. Similar - * for strings that are too long, we should not have created - * any. - */ - if (unlikely((len == -1) || len > MAX_ARG_STRLEN - 1)) { - WARN_ON(1); - send_sig(SIGKILL, current, 0); - return -1; + /* NOTE: this buffer needs to be large enough to hold all the non-arg + * data we put in the audit record for this argument (see the + * code below) ... at this point in time 96 is plenty */ + char abuf[96]; + + if (axi->mm != current->mm) + return; /* execve failed, no additional info */ + + p = (const char __user *)axi->mm->arg_start; + + /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the + * current value of 7500 is not as important as the fact that it + * is less than 8k, a setting of 7500 gives us plenty of wiggle + * room if we go over a little bit in the logging below */ + WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500); + len_max = MAX_EXECVE_AUDIT_LEN; + + /* scratch buffer to hold the userspace args */ + buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); + if (!buf_head) { + audit_panic("out of memory for argv string"); + return; } + buf = buf_head; + + audit_log_format(*ab, "argc=%d", axi->argc); - /* walk the whole argument looking for non-ascii chars */ + len_rem = len_max; + len_buf = 0; + len_full = 0; + require_data = true; + encode = false; + iter = 0; + arg = 0; do { - if (len_left > MAX_EXECVE_AUDIT_LEN) - to_send = MAX_EXECVE_AUDIT_LEN; - else - to_send = len_left; - ret = copy_from_user(buf, tmp_p, to_send); - /* - * There is no reason for this copy to be short. We just - * copied them here, and the mm hasn't been exposed to user- - * space yet. - */ - if (ret) { - WARN_ON(1); - send_sig(SIGKILL, current, 0); - return -1; - } - buf[to_send] = '\0'; - has_cntl = audit_string_contains_control(buf, to_send); - if (has_cntl) { - /* - * hex messages get logged as 2 bytes, so we can only - * send half as much in each message - */ - max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2; - break; - } - len_left -= to_send; - tmp_p += to_send; - } while (len_left > 0); - - len_left = len; - - if (len > max_execve_audit_len) - too_long = 1; - - /* rewalk the argument actually logging the message */ - for (i = 0; len_left > 0; i++) { - int room_left; - - if (len_left > max_execve_audit_len) - to_send = max_execve_audit_len; - else - to_send = len_left; - - /* do we have space left to send this argument in this ab? */ - room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent; - if (has_cntl) - room_left -= (to_send * 2); - else - room_left -= to_send; - if (room_left < 0) { - *len_sent = 0; - audit_log_end(*ab); - *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE); - if (!*ab) - return 0; - } + /* NOTE: we don't ever want to trust this value for anything + * serious, but the audit record format insists we + * provide an argument length for really long arguments, + * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but + * to use strncpy_from_user() to obtain this value for + * recording in the log, although we don't use it + * anywhere here to avoid a double-fetch problem */ + if (len_full == 0) + len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1; + + /* read more data from userspace */ + if (require_data) { + /* can we make more room in the buffer? */ + if (buf != buf_head) { + memmove(buf_head, buf, len_buf); + buf = buf_head; + } - /* - * first record needs to say how long the original string was - * so we can be sure nothing was lost. - */ - if ((i == 0) && (too_long)) - audit_log_format(*ab, " a%d_len=%zu", arg_num, - has_cntl ? 2*len : len); - - /* - * normally arguments are small enough to fit and we already - * filled buf above when we checked for control characters - * so don't bother with another copy_from_user - */ - if (len >= max_execve_audit_len) - ret = copy_from_user(buf, p, to_send); - else - ret = 0; - if (ret) { - WARN_ON(1); - send_sig(SIGKILL, current, 0); - return -1; - } - buf[to_send] = '\0'; - - /* actually log it */ - audit_log_format(*ab, " a%d", arg_num); - if (too_long) - audit_log_format(*ab, "[%d]", i); - audit_log_format(*ab, "="); - if (has_cntl) - audit_log_n_hex(*ab, buf, to_send); - else - audit_log_string(*ab, buf); - - p += to_send; - len_left -= to_send; - *len_sent += arg_num_len; - if (has_cntl) - *len_sent += to_send * 2; - else - *len_sent += to_send; - } - /* include the null we didn't log */ - return len + 1; -} + /* fetch as much as we can of the argument */ + len_tmp = strncpy_from_user(&buf_head[len_buf], p, + len_max - len_buf); + if (len_tmp == -EFAULT) { + /* unable to copy from userspace */ + send_sig(SIGKILL, current, 0); + goto out; + } else if (len_tmp == (len_max - len_buf)) { + /* buffer is not large enough */ + require_data = true; + /* NOTE: if we are going to span multiple + * buffers force the encoding so we stand + * a chance at a sane len_full value and + * consistent record encoding */ + encode = true; + len_full = len_full * 2; + p += len_tmp; + } else { + require_data = false; + if (!encode) + encode = audit_string_contains_control( + buf, len_tmp); + /* try to use a trusted value for len_full */ + if (len_full < len_max) + len_full = (encode ? + len_tmp * 2 : len_tmp); + p += len_tmp + 1; + } + len_buf += len_tmp; + buf_head[len_buf] = '\0'; -static void audit_log_execve_info(struct audit_context *context, - struct audit_buffer **ab, - struct audit_aux_data_execve *axi) -{ - int i, len; - size_t len_sent = 0; - const char __user *p; - char *buf; + /* length of the buffer in the audit record? */ + len_abuf = (encode ? len_buf * 2 : len_buf + 2); + } - if (axi->mm != current->mm) - return; /* execve failed, no additional info */ + /* write as much as we can to the audit log */ + if (len_buf > 0) { + /* NOTE: some magic numbers here - basically if we + * can't fit a reasonable amount of data into the + * existing audit buffer, flush it and start with + * a new buffer */ + if ((sizeof(abuf) + 8) > len_rem) { + len_rem = len_max; + audit_log_end(*ab); + *ab = audit_log_start(context, + GFP_KERNEL, AUDIT_EXECVE); + if (!*ab) + goto out; + } - p = (const char __user *)axi->mm->arg_start; + /* create the non-arg portion of the arg record */ + len_tmp = 0; + if (require_data || (iter > 0) || + ((len_abuf + sizeof(abuf)) > len_rem)) { + if (iter == 0) { + len_tmp += snprintf(&abuf[len_tmp], + sizeof(abuf) - len_tmp, + " a%d_len=%lu", + arg, len_full); + } + len_tmp += snprintf(&abuf[len_tmp], + sizeof(abuf) - len_tmp, + " a%d[%d]=", arg, iter++); + } else + len_tmp += snprintf(&abuf[len_tmp], + sizeof(abuf) - len_tmp, + " a%d=", arg); + WARN_ON(len_tmp >= sizeof(abuf)); + abuf[sizeof(abuf) - 1] = '\0'; + + /* log the arg in the audit record */ + audit_log_format(*ab, "%s", abuf); + len_rem -= len_tmp; + len_tmp = len_buf; + if (encode) { + if (len_abuf > len_rem) + len_tmp = len_rem / 2; /* encoding */ + audit_log_n_hex(*ab, buf, len_tmp); + len_rem -= len_tmp * 2; + len_abuf -= len_tmp * 2; + } else { + if (len_abuf > len_rem) + len_tmp = len_rem - 2; /* quotes */ + audit_log_n_string(*ab, buf, len_tmp); + len_rem -= len_tmp + 2; + /* don't subtract the "2" because we still need + * to add quotes to the remaining string */ + len_abuf -= len_tmp; + } + len_buf -= len_tmp; + buf += len_tmp; + } - audit_log_format(*ab, "argc=%d", axi->argc); + /* ready to move to the next argument? */ + if ((len_buf == 0) && !require_data) { + arg++; + iter = 0; + len_full = 0; + require_data = true; + encode = false; + } + } while (arg < axi->argc); - /* - * we need some kernel buffer to hold the userspace args. Just - * allocate one big one rather than allocating one of the right size - * for every single argument inside audit_log_single_execve_arg() - * should be <8k allocation so should be pretty safe. - */ - buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL); - if (!buf) { - audit_panic("out of memory for argv string\n"); - return; - } + /* NOTE: the caller handles the final audit_log_end() call */ - for (i = 0; i < axi->argc; i++) { - len = audit_log_single_execve_arg(context, ab, i, - &len_sent, p, buf); - if (len <= 0) - break; - p += len; - } - kfree(buf); +out: + kfree(buf_head); } static void show_special(struct audit_context *context, int *call_panic) -- cgit v1.2.3 From ba7727c3c66d5bd035ed8df69c74a613a6a7f9da Mon Sep 17 00:00:00 2001 From: Amulya Y Date: Thu, 5 Apr 2018 14:30:07 -0700 Subject: cgroup: Correct the address format specifier The format specifier %p can leak kernel addresses while not valuing the kptr_restrict system settings.The fix is designed to use %pK instead of %p, which also evaluates whether kptr_restrict is set. Bug 1823317 Bug 1935735 Change-Id: I19dc309e7f5341663add987f5d0b47ee32e1be50 Signed-off-by: Gagan Grover Signed-off-by: Amulya Yarlagadda Reviewed-on: http://git-master/r/1260110 (cherry picked from commit d018ef6518a7527562bedae1eab86838cfcc0570) Reviewed-on: https://git-master.nvidia.com/r/1690299 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: Winnie Hsu --- kernel/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 05b36e7b9e6b..1e2c3588b990 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -5449,7 +5449,7 @@ static int cgroup_css_links_read(struct cgroup *cont, struct css_set *cg = link->cg; struct task_struct *task; int count = 0; - seq_printf(seq, "css_set %p\n", cg); + seq_printf(seq, "css_set %pK\n", cg); list_for_each_entry(task, &cg->tasks, cg_list) { if (count++ > MAX_TASKS_SHOWN_PER_CSS) { seq_puts(seq, " ...\n"); -- cgit v1.2.3 From 1de99ac66623dc420140c8a1a6c0271a553fe515 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 27 Nov 2015 14:30:21 -0500 Subject: tty: Prevent ldisc drivers from re-using stale tty fields Line discipline drivers may mistakenly misuse ldisc-related fields when initializing. For example, a failure to initialize tty->receive_room in the N_GIGASET_M101 line discipline was recently found and fixed [1]. Now, the N_X25 line discipline has been discovered accessing the previous line discipline's already-freed private data [2]. Harden the ldisc interface against misuse by initializing revelant tty fields before instancing the new line discipline. [1] commit fd98e9419d8d622a4de91f76b306af6aa627aa9c Author: Tilman Schmidt Date: Tue Jul 14 00:37:13 2015 +0200 isdn/gigaset: reset tty->receive_room when attaching ser_gigaset [2] Report from Sasha Levin [ 634.336761] ================================================================== [ 634.338226] BUG: KASAN: use-after-free in x25_asy_open_tty+0x13d/0x490 at addr ffff8800a743efd0 [ 634.339558] Read of size 4 by task syzkaller_execu/8981 [ 634.340359] ============================================================================= [ 634.341598] BUG kmalloc-512 (Not tainted): kasan: bad access detected ... [ 634.405018] Call Trace: [ 634.405277] dump_stack (lib/dump_stack.c:52) [ 634.405775] print_trailer (mm/slub.c:655) [ 634.406361] object_err (mm/slub.c:662) [ 634.406824] kasan_report_error (mm/kasan/report.c:138 mm/kasan/report.c:236) [ 634.409581] __asan_report_load4_noabort (mm/kasan/report.c:279) [ 634.411355] x25_asy_open_tty (drivers/net/wan/x25_asy.c:559 (discriminator 1)) [ 634.413997] tty_ldisc_open.isra.2 (drivers/tty/tty_ldisc.c:447) [ 634.414549] tty_set_ldisc (drivers/tty/tty_ldisc.c:567) [ 634.415057] tty_ioctl (drivers/tty/tty_io.c:2646 drivers/tty/tty_io.c:2879) [ 634.423524] do_vfs_ioctl (fs/ioctl.c:43 fs/ioctl.c:607) [ 634.427491] SyS_ioctl (fs/ioctl.c:622 fs/ioctl.c:613) [ 634.427945] entry_SYSCALL_64_fastpath (arch/x86/entry/entry_64.S:188) Bug 1823317 Bug 1935735 Change-Id: Ica54faa9334c587594cc19bc9da007340fda672d Cc: Tilman Schmidt Cc: Sasha Levin Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman Signed-off-by: Gagan Grover Reviewed-on: http://git-master/r/1259925 (cherry picked from commit 2b1401855a2bdd31556a93feba50dd0dc0bb70e8) Reviewed-on: https://git-master.nvidia.com/r/1690300 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Amulya Yarlagadda Reviewed-by: Winnie Hsu --- drivers/tty/tty_ldisc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 1afe192bef6a..b5cbe12e2815 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -400,6 +400,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); * they are not on hot paths so a little discipline won't do * any harm. * + * The line discipline-related tty_struct fields are reset to + * prevent the ldisc driver from re-using stale information for + * the new ldisc instance. + * * Locking: takes termios_mutex */ @@ -408,6 +412,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) mutex_lock(&tty->termios_mutex); tty->termios.c_line = num; mutex_unlock(&tty->termios_mutex); + + tty->disc_data = NULL; + tty->receive_room = 0; } /** -- cgit v1.2.3 From c476b3908b73ae362945b9d14d620c0a09a8c539 Mon Sep 17 00:00:00 2001 From: Amulya Y Date: Thu, 5 Apr 2018 14:40:20 -0700 Subject: proc:prevent /proc/PID/environ access until ready If /proc//environ gets read before the envp[] array is fully set up in create_{aout,elf,elf_fdpic,flat}_tables(), we might end up trying to read more bytes than are actually written, as env_start will already be set but env_end will still be zero, making the range calculation underflow, allowing to read beyond the end of what has been written. Fix this as it is done for /proc//cmdline by testing env_end for zero. It is, apparently, intentionally set last in create_*_tables(). This bug was found by the PaX size_overflow plugin that detected the arithmetic underflow of 'this_len = env_end - (env_start + src)' when env_end is still zero. The expected consequence is that userland trying to access /proc//environ of a not yet fully set up process may get inconsistent data as we're in the middle of copying in the environment variables. Bug 1823317 Bug 1935735 Change-Id: I38356eb68ffd1294f1f1250fb328bd01a3b37158 Fixes: https://forums.grsecurity.net/viewtopic.php?f=3&t=4363 Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=116461 Signed-off-by: Mathias Krause Cc: Emese Revfy Cc: Pax Team Cc: Al Viro Cc: Mateusz Guzik Cc: Alexey Dobriyan Cc: Cyrill Gorcunov Cc: Jarod Wilson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Gagan Grover Signed-off-by: Amulya Yarlagadda Reviewed-on: http://git-master/r/1259930 (cherry picked from commit 78d40f25b8e090782ca6b0c6051020557d373c92) Reviewed-on: https://git-master.nvidia.com/r/1690302 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: Winnie Hsu --- fs/proc/base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 4823113f2584..464df13a1c19 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -46,7 +46,7 @@ * Paul Mundt : * Overall revision about smaps. * - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. */ #include @@ -857,7 +857,8 @@ static ssize_t environ_read(struct file *file, char __user *buf, int ret = 0; struct mm_struct *mm = file->private_data; - if (!mm) + /* Ensure the process spawned far enough to have an environment. */ + if (!mm || !mm->env_end) return 0; page = (char *)__get_free_page(GFP_TEMPORARY); -- cgit v1.2.3 From 6b8d6d331daaa7d2118fdd61eac514363e0625e7 Mon Sep 17 00:00:00 2001 From: Amulya Y Date: Thu, 5 Apr 2018 15:06:13 -0700 Subject: ext4:fix use after free in __ext4_journal_stop There is a use-after-free possibility in __ext4_journal_stop() in the case that we free the handle in the first jbd2_journal_stop() because we're referencing handle->h_err afterwards. This was introduced in 9705acd63b125dee8b15c705216d7186daea4625 and it is wrong. Fix it by storing the handle->h_err value beforehand and avoid referencing potentially freed handle. Bug 1823317 Change-Id: Ib6fe50ed8013943d5fc3459eb499ecda5533c6ef Fixes: 9705acd63b125dee8b15c705216d7186daea4625 Signed-off-by: Lukas Czerner Reviewed-by: Andreas Dilger Cc: stable@vger.kernel.org Signed-off-by: Gagan Grover Signed-off-by: Amulya Yarlagadda Reviewed-on: http://git-master/r/1259975 (cherry picked from commit 3c15c37dc613cb75339f8e0d546ab30643e65b84) Reviewed-on: https://git-master.nvidia.com/r/1690287 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: Winnie Hsu --- fs/ext4/ext4_jbd2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 1be3996b5942..3517d5af2574 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -75,8 +75,14 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) ext4_put_nojournal(handle); return 0; } - sb = handle->h_transaction->t_journal->j_private; + err = handle->h_err; + if (!handle->h_transaction) { + rc = jbd2_journal_stop(handle); + return err ? err : rc; + } + + sb = handle->h_transaction->t_journal->j_private; rc = jbd2_journal_stop(handle); if (!err) -- cgit v1.2.3 From ac43b10b632fac3412f18100e463e2129318bd3a Mon Sep 17 00:00:00 2001 From: Amulya Y Date: Fri, 6 Apr 2018 15:42:31 -0700 Subject: perf: Fix race in swevent hash There's a race on CPU unplug where we free the swevent hash array while it can still have events on. This will result in a use-after-free which is BAD. Simply do not free the hash array on unplug. This leaves the thing around and no use-after-free takes place. When the last swevent dies, we do a for_each_possible_cpu() iteration anyway to clean these up, at which time we'll free it, so no leakage will occur. Bug 1823317 But 1935735 Change-Id: I309528873f8576f96663afbe51ce2739934df16c Reported-by: Sasha Levin Tested-by: Sasha Levin Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Gagan Grover Signed-off-by: Amulya Yarlagadda Reviewed-on: http://git-master/r/1259934 (cherry picked from commit 5ea640855404df656d94bfa3990d8eba2b5f90f9) Reviewed-on: https://git-master.nvidia.com/r/1690284 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: Winnie Hsu --- kernel/events/core.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index f8eb2b154bdb..be3b4cc87eeb 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7450,13 +7450,7 @@ static void perf_event_exit_cpu_context(int cpu) static void perf_event_exit_cpu(int cpu) { - struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); - perf_event_exit_cpu_context(cpu); - - mutex_lock(&swhash->hlist_mutex); - swevent_hlist_release(swhash); - mutex_unlock(&swhash->hlist_mutex); } #else static inline void perf_event_exit_cpu(int cpu) { } -- cgit v1.2.3 From e592ed68b3c3c27d74d5592f99b423596755263a Mon Sep 17 00:00:00 2001 From: Amulya Y Date: Fri, 6 Apr 2018 15:48:49 -0700 Subject: HID: core: prevent out-of-bound readings Plugging a Logitech DJ receiver with KASAN activated raises a bunch of out-of-bound readings. The fields are allocated up to MAX_USAGE, meaning that potentially, we do not have enough fields to fit the incoming values. Add checks and silence KASAN. Bug 1823317 Bug 1935735 Change-Id: Ib3ba92572acbdd4c9ec265e54a45f92606107700 Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Gagan Grover Signed-off-by: Amulya Yarlagadda Reviewed-on: http://git-master/r/1259928 (cherry picked from commit fbc389a39540e177bfa4d49b9214dfe408ef2d4a) Reviewed-on: https://git-master.nvidia.com/r/1690285 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Reviewed-by: Winnie Hsu --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 46b7b12376f9..dcea21ed9cd6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1138,6 +1138,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, /* Ignore report if ErrorRollOver */ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && value[n] >= min && value[n] <= max && + value[n] - min < field->maxusage && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) goto exit; } @@ -1150,11 +1151,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, } if (field->value[n] >= min && field->value[n] <= max + && field->value[n] - min < field->maxusage && field->usage[field->value[n] - min].hid && search(value, field->value[n], count)) hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); if (value[n] >= min && value[n] <= max + && value[n] - min < field->maxusage && field->usage[value[n] - min].hid && search(field->value, value[n], count)) hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); -- cgit v1.2.3 From 3a956eb7d85eee8bc364545e371a5b2f6a683148 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 29 Jan 2018 17:02:22 -0800 Subject: array_index_nospec: Sanitize speculative array de-references Commit f3804203306e upstream. array_index_nospec() is proposed as a generic mechanism to mitigate against Spectre-variant-1 attacks, i.e. an attack that bypasses boundary checks via speculative execution. The array_index_nospec() implementation is expected to be safe for current generation CPUs across multiple architectures (ARM, x86). Based on an original implementation by Linus Torvalds, tweaked to remove speculative flows by Alexei Starovoitov, and tweaked again by Linus to introduce an x86 assembly implementation for the mask generation. Change-Id: I859161a289215b20bd25ef4006115c0268b30b83 Co-developed-by: Linus Torvalds Co-developed-by: Alexei Starovoitov Suggested-by: Cyril Novikov Signed-off-by: Dan Williams Signed-off-by: Thomas Gleixner Signed-off-by: Will Deacon Cc: linux-arch@vger.kernel.org Cc: kernel-hardening@lists.openwall.com Cc: Peter Zijlstra Cc: Catalin Marinas Cc: Will Deacon Cc: Russell King Cc: gregkh@linuxfoundation.org Cc: torvalds@linux-foundation.org Cc: alan@linux.intel.com Link: https://lkml.kernel.org/r/151727414229.33451.18411580953862676575.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1698396 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- include/linux/nospec.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 include/linux/nospec.h diff --git a/include/linux/nospec.h b/include/linux/nospec.h new file mode 100644 index 000000000000..b99bced39ac2 --- /dev/null +++ b/include/linux/nospec.h @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2018 Linus Torvalds. All rights reserved. +// Copyright(c) 2018 Alexei Starovoitov. All rights reserved. +// Copyright(c) 2018 Intel Corporation. All rights reserved. + +#ifndef _LINUX_NOSPEC_H +#define _LINUX_NOSPEC_H + +/** + * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise + * @index: array element index + * @size: number of elements in array + * + * When @index is out of bounds (@index >= @size), the sign bit will be + * set. Extend the sign bit to all bits and invert, giving a result of + * zero for an out of bounds index, or ~0 if within bounds [0, @size). + */ +#ifndef array_index_mask_nospec +static inline unsigned long array_index_mask_nospec(unsigned long index, + unsigned long size) +{ + /* + * Warn developers about inappropriate array_index_nospec() usage. + * + * Even if the CPU speculates past the WARN_ONCE branch, the + * sign bit of @index is taken into account when generating the + * mask. + * + * This warning is compiled out when the compiler can infer that + * @index and @size are less than LONG_MAX. + */ + if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX, + "array_index_nospec() limited to range of [0, LONG_MAX]\n")) + return 0; + + /* + * Always calculate and emit the mask even if the compiler + * thinks the mask is not needed. The compiler does not take + * into account the value of @index under speculation. + */ + OPTIMIZER_HIDE_VAR(index); + return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1); +} +#endif + +/* + * array_index_nospec - sanitize an array index after a bounds check + * + * For a code sequence like: + * + * if (index < size) { + * index = array_index_nospec(index, size); + * val = array[index]; + * } + * + * ...if the CPU speculates past the bounds check then + * array_index_nospec() will clamp the index within the range of [0, + * size). + */ +#define array_index_nospec(index, size) \ +({ \ + typeof(index) _i = (index); \ + typeof(size) _s = (size); \ + unsigned long _mask = array_index_mask_nospec(_i, _s); \ + \ + BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \ + BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \ + \ + _i &= _mask; \ + _i; \ +}) +#endif /* _LINUX_NOSPEC_H */ -- cgit v1.2.3 From 94606f27e4dfd95cf4c83dba8b7356de91e2859d Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 29 Jan 2018 17:02:16 -0800 Subject: Documentation: Document array_index_nospec Commit f84a56f73ddd upstream. Document the rationale and usage of the new array_index_nospec() helper. Change-Id: I4b804638bbe9811b82d34cd58314cbb1738d7d25 Signed-off-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Dan Williams Signed-off-by: Thomas Gleixner Reviewed-by: Kees Cook Cc: linux-arch@vger.kernel.org Cc: Jonathan Corbet Cc: Peter Zijlstra Cc: gregkh@linuxfoundation.org Cc: kernel-hardening@lists.openwall.com Cc: torvalds@linux-foundation.org Cc: alan@linux.intel.com Link: https://lkml.kernel.org/r/151727413645.33451.15878817161436755393.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1698397 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- Documentation/speculation.txt | 90 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 Documentation/speculation.txt diff --git a/Documentation/speculation.txt b/Documentation/speculation.txt new file mode 100644 index 000000000000..e9e6cbae2841 --- /dev/null +++ b/Documentation/speculation.txt @@ -0,0 +1,90 @@ +This document explains potential effects of speculation, and how undesirable +effects can be mitigated portably using common APIs. + +=========== +Speculation +=========== + +To improve performance and minimize average latencies, many contemporary CPUs +employ speculative execution techniques such as branch prediction, performing +work which may be discarded at a later stage. + +Typically speculative execution cannot be observed from architectural state, +such as the contents of registers. However, in some cases it is possible to +observe its impact on microarchitectural state, such as the presence or +absence of data in caches. Such state may form side-channels which can be +observed to extract secret information. + +For example, in the presence of branch prediction, it is possible for bounds +checks to be ignored by code which is speculatively executed. Consider the +following code: + + int load_array(int *array, unsigned int index) + { + if (index >= MAX_ARRAY_ELEMS) + return 0; + else + return array[index]; + } + +Which, on arm64, may be compiled to an assembly sequence such as: + + CMP , #MAX_ARRAY_ELEMS + B.LT less + MOV , #0 + RET + less: + LDR , [, ] + RET + +It is possible that a CPU mis-predicts the conditional branch, and +speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This +value will subsequently be discarded, but the speculated load may affect +microarchitectural state which can be subsequently measured. + +More complex sequences involving multiple dependent memory accesses may +result in sensitive information being leaked. Consider the following +code, building on the prior example: + + int load_dependent_arrays(int *arr1, int *arr2, int index) + { + int val1, val2, + + val1 = load_array(arr1, index); + val2 = load_array(arr2, val1); + + return val2; + } + +Under speculation, the first call to load_array() may return the value +of an out-of-bounds address, while the second call will influence +microarchitectural state dependent on this value. This may provide an +arbitrary read primitive. + +==================================== +Mitigating speculation side-channels +==================================== + +The kernel provides a generic API to ensure that bounds checks are +respected even under speculation. Architectures which are affected by +speculation-based side-channels are expected to implement these +primitives. + +The array_index_nospec() helper in can be used to +prevent information from being leaked via side-channels. + +A call to array_index_nospec(index, size) returns a sanitized index +value that is bounded to [0, size) even under cpu speculation +conditions. + +This can be used to protect the earlier load_array() example: + + int load_array(int *array, unsigned int index) + { + if (index >= MAX_ARRAY_ELEMS) + return 0; + else { + index = array_index_nospec(index, MAX_ARRAY_ELEMS); + return array[index]; + } + } -- cgit v1.2.3 From 9606849c487e3963e25a0cb632cbe44f8f0d5744 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 1 Feb 2018 11:07:36 +0000 Subject: arm: Add icache invalidation on switch_mm for Cortex-A15 ** Not yet queued for inclusion in mainline ** In order to avoid aliasing attacks against the branch predictor, Cortex-A15 require to invalidate the BTB when switching from one user context to another. The only way to do so on this CPU is to perform an ICIALLU, having set ACTLR[0] to 1 from secure mode. Change-Id: Ib0083803d75a4399b8225193349a4b490d1776a1 Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1698398 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- arch/arm/mm/proc-v7-2level.S | 12 +++++++++++- arch/arm/mm/proc-v7-3level.S | 10 ++++++++++ arch/arm/mm/proc-v7.S | 23 ++++++++++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S index a0cf0dc9f0d7..48db62324291 100644 --- a/arch/arm/mm/proc-v7-2level.S +++ b/arch/arm/mm/proc-v7-2level.S @@ -36,7 +36,16 @@ * * It is assumed that: * - we are not using split page tables - */ + * + * Cortex-A15 requires ACTLR[0] to be set from secure in order + * for the icache invalidation to also invalidate the BTB. + */ +ENTRY(cpu_v7_icinv_switch_mm) +#ifdef CONFIG_MMU + mcr p15, 0, r0, c7, c5, 0 @ ICIALLU + /* Fall through to switch_mm... */ +#endif + ENTRY(cpu_v7_switch_mm) #ifdef CONFIG_MMU mov r2, #0 @@ -61,6 +70,7 @@ ENTRY(cpu_v7_switch_mm) #endif mov pc, lr ENDPROC(cpu_v7_switch_mm) +ENDPROC(cpu_v7_icinv_switch_mm) /* * cpu_v7_set_pte_ext(ptep, pte) diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index e377cc4031b0..8ba8dfd0531e 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -53,6 +53,15 @@ * Set the translation table base pointer to be pgd_phys (physical address of * the new TTB). */ +ENTRY(cpu_v7_icinv_switch_mm) +#ifdef CONFIG_MMU + /* + * Cortex-A15 requires ACTLR[0] to be set from secure in order + * for the icache invalidation to also invalidate the BTB. + */ + mcr p15, 0, r0, c7, c5, 0 @ ICIALLU + /* Fall through to switch_mm... */ +#endif ENTRY(cpu_v7_switch_mm) #ifdef CONFIG_MMU mmid r2, r2 @ get mm->context.id @@ -64,6 +73,7 @@ ENTRY(cpu_v7_switch_mm) #endif mov pc, lr ENDPROC(cpu_v7_switch_mm) +ENDPROC(cpu_v7_icinv_switch_mm) /* * cpu_v7_set_pte_ext(ptep, pte) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index d1dea91517e0..aac1d85f9cd9 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -415,6 +415,26 @@ start_restore_wpt: ENDPROC(cpu_v7_do_resume) #endif +/* + * Cortex-A15 + */ + globl_equ cpu_ca15_proc_init, cpu_v7_proc_init + globl_equ cpu_ca15_proc_fin, cpu_v7_proc_fin + globl_equ cpu_ca15_reset, cpu_v7_reset + globl_equ cpu_ca15_do_idle, cpu_v7_do_idle + globl_equ cpu_ca15_dcache_clean_area, cpu_v7_dcache_clean_area + globl_equ cpu_ca15_set_pte_ext, cpu_v7_set_pte_ext + globl_equ cpu_ca15_suspend_size, cpu_v7_suspend_size +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR + globl_equ cpu_ca15_switch_mm, cpu_v7_icinv_switch_mm +#else + globl_equ cpu_ca15_switch_mm, cpu_v7_switch_mm +#endif +#ifdef CONFIG_ARM_CPU_SUSPEND + globl_equ cpu_ca15_do_suspend, cpu_v7_do_suspend + globl_equ cpu_ca15_do_resume, cpu_v7_do_resume +#endif + #ifdef CONFIG_CPU_PJ4B globl_equ cpu_pj4b_switch_mm, cpu_v7_switch_mm globl_equ cpu_pj4b_set_pte_ext, cpu_v7_set_pte_ext @@ -722,6 +742,7 @@ __v7_setup_stack: @ define struct processor (see and proc-macros.S) define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 + define_processor_functions ca15, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 #ifdef CONFIG_CPU_PJ4B define_processor_functions pj4b, dabort=v7_early_abort, pabort=v7_pabort, suspend=1 #endif @@ -818,7 +839,7 @@ __v7_ca15mp_r3_proc_info: __v7_ca15mp_proc_info: .long 0x410fc0f0 .long 0xff0ffff0 - __v7_proc __v7_ca15mp_setup + __v7_proc __v7_ca15mp_setup, proc_fns = ca15_processor_functions .size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info /* -- cgit v1.2.3 From de3110548b04b6a0b58b4c9d4235552388539ee0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 1 Feb 2018 11:07:34 +0000 Subject: arm: Invalidate BTB on prefetch abort outside of user mapping on Cortex A8, A9, A12 and A17 ** Not yet queued for inclusion in mainline ** In order to prevent aliasing attacks on the branch predictor, invalidate the BTB on CPUs that are known to be affected when taking a prefetch abort on a address that is outside of a user task limit. __ACCESS_CP15 and __ACCESS_CP15_64 added from below link: https://patchwork.kernel.org/patch/9234399/ Change-Id: Ib8c9807f5e787437e66b83ea0305d75cce4bbbdf Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1698399 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- arch/arm/include/asm/cp15.h | 23 +++++++++++++++ arch/arm/mm/fault.c | 19 +++++++++++++ arch/arm/mm/fsr-2level.c | 4 +-- arch/arm/mm/fsr-3level.c | 69 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h index 1f3262e99d81..43eddecc837d 100644 --- a/arch/arm/include/asm/cp15.h +++ b/arch/arm/include/asm/cp15.h @@ -42,8 +42,31 @@ #define vectors_high() (0) #endif +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) \ + "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32 +#define __ACCESS_CP15_64(Op1, CRm) \ + "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64 + +#define __read_sysreg(r, w, c, t) ({ \ + t __val; \ + asm volatile(r " " c : "=r" (__val)); \ + __val; \ +}) +#define read_sysreg(...) __read_sysreg(__VA_ARGS__) + +#define __write_sysreg(v, r, w, c, t) asm volatile(w " " c : : "r" ((t)(v))) +#define write_sysreg(v, ...) __write_sysreg(v, __VA_ARGS__) + #ifdef CONFIG_CPU_CP15 +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) \ + "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32 +#define __ACCESS_CP15_64(Op1, CRm) \ + "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64 + + +#define BPIALL __ACCESS_CP15(c7, 0, c5, 6) + extern unsigned long cr_no_alignment; /* defined in entry-armv.S */ extern unsigned long cr_alignment; /* defined in entry-armv.S */ diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 9820ad4b80c0..f18f94006fea 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -393,12 +394,30 @@ no_context: __do_kernel_fault(mm, addr, fsr, regs); return 0; } + +static int __maybe_unused +do_pabt_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR + if (addr > TASK_SIZE) { + switch (read_cpuid_part_number()) { + } + } +#endif + return do_page_fault(addr, fsr, regs); +} #else /* CONFIG_MMU */ static int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { return 0; } + +static int +do_pabt_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + return 0; +} #endif /* CONFIG_MMU */ /* diff --git a/arch/arm/mm/fsr-2level.c b/arch/arm/mm/fsr-2level.c index 18ca74c0f341..4cede9bc7722 100644 --- a/arch/arm/mm/fsr-2level.c +++ b/arch/arm/mm/fsr-2level.c @@ -50,7 +50,7 @@ static struct fsr_info ifsr_info[] = { { do_bad, SIGBUS, 0, "unknown 4" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" }, { do_bad, SIGSEGV, SEGV_ACCERR, "page access flag fault" }, - { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, + { do_pabt_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" }, { do_bad, SIGBUS, 0, "external abort on non-linefetch" }, { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" }, { do_bad, SIGBUS, 0, "unknown 10" }, @@ -58,7 +58,7 @@ static struct fsr_info ifsr_info[] = { { do_bad, SIGBUS, 0, "external abort on translation" }, { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" }, { do_bad, SIGBUS, 0, "external abort on translation" }, - { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" }, + { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" }, { do_bad, SIGBUS, 0, "unknown 16" }, { do_bad, SIGBUS, 0, "unknown 17" }, { do_bad, SIGBUS, 0, "unknown 18" }, diff --git a/arch/arm/mm/fsr-3level.c b/arch/arm/mm/fsr-3level.c index 47f4c6fb25ba..791ef0c66741 100644 --- a/arch/arm/mm/fsr-3level.c +++ b/arch/arm/mm/fsr-3level.c @@ -65,4 +65,73 @@ static struct fsr_info fsr_info[] = { { do_bad, SIGBUS, 0, "unknown 63" }, }; +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +static struct fsr_info ifsr_info[] = { + { do_bad, SIGBUS, 0, "unknown 0" }, + { do_bad, SIGBUS, 0, "unknown 1" }, + { do_bad, SIGBUS, 0, "unknown 2" }, + { do_bad, SIGBUS, 0, "unknown 3" }, + { do_bad, SIGBUS, 0, "reserved translation fault" }, + { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" }, + { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, + { do_pabt_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, + { do_bad, SIGBUS, 0, "reserved access flag fault" }, + { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, + { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, + { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, + { do_bad, SIGBUS, 0, "reserved permission fault" }, + { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, + { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" }, + { do_pabt_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, + { do_bad, SIGBUS, 0, "synchronous external abort" }, + { do_bad, SIGBUS, 0, "asynchronous external abort" }, + { do_bad, SIGBUS, 0, "unknown 18" }, + { do_bad, SIGBUS, 0, "unknown 19" }, + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, + { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, + { do_bad, SIGBUS, 0, "synchronous parity error" }, + { do_bad, SIGBUS, 0, "asynchronous parity error" }, + { do_bad, SIGBUS, 0, "unknown 26" }, + { do_bad, SIGBUS, 0, "unknown 27" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, + { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, + { do_bad, SIGBUS, 0, "unknown 32" }, + { do_bad, SIGBUS, BUS_ADRALN, "alignment fault" }, + { do_bad, SIGBUS, 0, "debug event" }, + { do_bad, SIGBUS, 0, "unknown 35" }, + { do_bad, SIGBUS, 0, "unknown 36" }, + { do_bad, SIGBUS, 0, "unknown 37" }, + { do_bad, SIGBUS, 0, "unknown 38" }, + { do_bad, SIGBUS, 0, "unknown 39" }, + { do_bad, SIGBUS, 0, "unknown 40" }, + { do_bad, SIGBUS, 0, "unknown 41" }, + { do_bad, SIGBUS, 0, "unknown 42" }, + { do_bad, SIGBUS, 0, "unknown 43" }, + { do_bad, SIGBUS, 0, "unknown 44" }, + { do_bad, SIGBUS, 0, "unknown 45" }, + { do_bad, SIGBUS, 0, "unknown 46" }, + { do_bad, SIGBUS, 0, "unknown 47" }, + { do_bad, SIGBUS, 0, "unknown 48" }, + { do_bad, SIGBUS, 0, "unknown 49" }, + { do_bad, SIGBUS, 0, "unknown 50" }, + { do_bad, SIGBUS, 0, "unknown 51" }, + { do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" }, + { do_bad, SIGBUS, 0, "unknown 53" }, + { do_bad, SIGBUS, 0, "unknown 54" }, + { do_bad, SIGBUS, 0, "unknown 55" }, + { do_bad, SIGBUS, 0, "unknown 56" }, + { do_bad, SIGBUS, 0, "unknown 57" }, + { do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" }, + { do_bad, SIGBUS, 0, "unknown 59" }, + { do_bad, SIGBUS, 0, "unknown 60" }, + { do_bad, SIGBUS, 0, "unknown 61" }, + { do_bad, SIGBUS, 0, "unknown 62" }, + { do_bad, SIGBUS, 0, "unknown 63" }, +}; +#else #define ifsr_info fsr_info ++#endif -- cgit v1.2.3 From 36591cfe15177a919d780b25cce5dfb304afaaa0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 1 Feb 2018 11:07:37 +0000 Subject: arm: Invalidate icache on prefetch abort outside of user mapping on Cortex-A15 ** Not yet queued for inclusion in mainline ** In order to prevent aliasing attacks on the branch predictor, invalidate the icache on Cortex-A15, which has the side effect of invalidating the BTB. This requires ACTLR[0] to be set to 1 (secure operation). Change-Id: I4bb8e3ec05853d739bebd8fb3c61657e252808c0 Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1698400 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- arch/arm/include/asm/cp15.h | 1 + arch/arm/mm/fault.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h index 43eddecc837d..d820fc5f043a 100644 --- a/arch/arm/include/asm/cp15.h +++ b/arch/arm/include/asm/cp15.h @@ -66,6 +66,7 @@ #define BPIALL __ACCESS_CP15(c7, 0, c5, 6) +#define ICIALLU __ACCESS_CP15(c7, 0, c5, 0) extern unsigned long cr_no_alignment; /* defined in entry-armv.S */ extern unsigned long cr_alignment; /* defined in entry-armv.S */ diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index f18f94006fea..e8f42821a206 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "fault.h" @@ -401,6 +402,9 @@ do_pabt_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR if (addr > TASK_SIZE) { switch (read_cpuid_part_number()) { + case ARM_CPU_PART_CORTEX_A15: + write_sysreg(0, ICIALLU); + break; } } #endif -- cgit v1.2.3 From 0eb5e1ea3339a378f8150cdf9592ece4193f3850 Mon Sep 17 00:00:00 2001 From: Jeetesh Burman Date: Thu, 19 Apr 2018 21:16:37 +0530 Subject: gpu: nvgpu: add speculative load barrier (ctrl IOCTLs) Data can be speculatively loaded from memory and stay in cache even when bound check fails. This can lead to unintended information disclosure via side-channel analysis. To mitigate this problem insert a speculation barrier. bug 2039126 CVE-2017-5753 Change-Id: Ib6c4b2f99b85af3119cce3882fe35ab47509c76f Signed-off-by: Alex Waterman Reviewed-on: https://git-master.nvidia.com/r/1640500 Signed-off-by: James Huang Reviewed-on: https://git-master.nvidia.com/r/1650050 (cherry picked from commit f293fa670fd2f4fbe170f1e372e9aa237283c67a) Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1682715 Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1698610 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- drivers/gpu/nvgpu/gk20a/gr_gk20a.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c index 9e032e03a153..db34cc0e85e9 100644 --- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "gk20a.h" #include "kind_gk20a.h" @@ -3594,6 +3595,7 @@ int gr_gk20a_add_zbc(struct gk20a *g, struct gr_gk20a *gr, mutex_lock(&gr->zbc_lock); switch (zbc_val->type) { case GK20A_ZBC_TYPE_COLOR: + speculation_barrier(); /* search existing tables */ for (i = 0; i < gr->max_used_color_index; i++) { @@ -3632,6 +3634,7 @@ int gr_gk20a_add_zbc(struct gk20a *g, struct gr_gk20a *gr, } break; case GK20A_ZBC_TYPE_DEPTH: + speculation_barrier(); /* search existing tables */ for (i = 0; i < gr->max_used_depth_index; i++) { -- cgit v1.2.3 From db28d5d9c87a31dd53716ab2bad7a1571212f7e8 Mon Sep 17 00:00:00 2001 From: Jeetesh Burman Date: Thu, 19 Apr 2018 21:27:20 +0530 Subject: host1x: prevent speculative load related leak Data can be speculatively loaded from memory and stay in cache even when bound check fails. This can lead to unintended information disclosure via side-channel analysis. To mitigate this problem, insert speculation barrier. bug 2039126 CVE-2017-5753 Change-Id: Ifc618c00cee497e6d84cac01a9b73fcecbe8f260 Signed-off-by: David Gilhooley Signed-off-by: James Huang Reviewed-on: https://git-master.nvidia.com/r/1650036 (cherry picked from commit 164f8684deb5b15a53c60a60c7d9b8e3bf5af5be) Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1682714 Signed-off-by: Jeetesh Burman Reviewed-on: https://git-master.nvidia.com/r/1698611 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- drivers/video/tegra/host/host1x/host1x.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/video/tegra/host/host1x/host1x.c b/drivers/video/tegra/host/host1x/host1x.c index 522219484286..6af16bab059c 100644 --- a/drivers/video/tegra/host/host1x/host1x.c +++ b/drivers/video/tegra/host/host1x/host1x.c @@ -33,6 +33,8 @@ #include #include +#include +#include #include "dev.h" #include @@ -267,6 +269,8 @@ static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx, args->lock > 1) return -EINVAL; + speculation_barrier(); + trace_nvhost_ioctl_ctrl_module_mutex(args->lock, args->id); if (args->lock && !ctx->mod_locks[args->id]) { if (args->id == 0) @@ -379,6 +383,7 @@ static int nvhost_ioctl_ctrl_syncpt_read_max(struct nvhost_ctrl_userctx *ctx, { if (args->id >= nvhost_syncpt_nb_pts(&ctx->dev->syncpt)) return -EINVAL; + speculation_barrier(); args->value = nvhost_syncpt_read_max(&ctx->dev->syncpt, args->id); return 0; } -- cgit v1.2.3 From e78bb38b883c42edf81766a1d557aed74458e08f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 1 Feb 2018 11:07:33 +0000 Subject: arm: Add BTB invalidation on switch_mm for Cortex-A9, A12 and A17 ** Not yet queued for inclusion in mainline ** In order to avoid aliasing attacks against the branch predictor, some implementations require to invalidate the BTB when switching from one user context to another. For this, we reuse the existing implementation for Cortex-A8, and apply it to A9, A12 and A17. Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon Change-Id: Ibbd99465a5dcf5eda6a29dd23a55f9b21b280e65 Reviewed-on: https://git-master.nvidia.com/r/1704129 GVS: Gerrit_Virtual_Submit Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- arch/arm/mm/Kconfig | 17 +++++++++++++++++ arch/arm/mm/proc-v7-3level.S | 5 +++++ arch/arm/mm/proc-v7.S | 20 ++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 2c7e308f8cab..07c3309b6288 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -947,3 +947,20 @@ config ARM_SAVE_DEBUG_CONTEXT_NO_LOCK the ARM debug registers across CPU powerdown. This option should not be selected unless you are actively debugging the context save/restore code. If unsure, say N. + +config HARDEN_BRANCH_PREDICTOR + bool "Harden the branch predictor against aliasing attacks" if EXPERT + default y + help + Speculation attacks against some high-performance processors rely on + being able to manipulate the branch predictor for a victim context by + executing aliasing branches in the attacker context. Such attacks + can be partially mitigated against by clearing internal branch + predictor state and limiting the prediction logic in some situations. + + This config option will take CPU-specific actions to harden the + branch predictor against aliasing attacks and may rely on specific + instruction sequences or control bits being set by the system + firmware. + + If unsure, say Y. diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index 8ba8dfd0531e..e2bb1ae55047 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -62,6 +62,10 @@ ENTRY(cpu_v7_icinv_switch_mm) mcr p15, 0, r0, c7, c5, 0 @ ICIALLU /* Fall through to switch_mm... */ #endif +ENTRY(cpu_v7_btbinv_switch_mm) +#ifdef CONFIG_MMU + mcr p15, 0, r0, c7, c5, 6 @ flush BTAC/BTB +#endif ENTRY(cpu_v7_switch_mm) #ifdef CONFIG_MMU mmid r2, r2 @ get mm->context.id @@ -73,6 +77,7 @@ ENTRY(cpu_v7_switch_mm) #endif mov pc, lr ENDPROC(cpu_v7_switch_mm) +ENDPROC(cpu_v7_btbinv_switch_mm) ENDPROC(cpu_v7_icinv_switch_mm) /* diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index aac1d85f9cd9..322ecf52c2a7 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -435,6 +435,26 @@ ENDPROC(cpu_v7_do_resume) globl_equ cpu_ca15_do_resume, cpu_v7_do_resume #endif +/* + * Cortex-A12/A17 + */ + globl_equ cpu_ca17_proc_init, cpu_v7_proc_init + globl_equ cpu_ca17_proc_fin, cpu_v7_proc_fin + globl_equ cpu_ca17_reset, cpu_v7_reset + globl_equ cpu_ca17_do_idle, cpu_v7_do_idle + globl_equ cpu_ca17_dcache_clean_area, cpu_v7_dcache_clean_area + globl_equ cpu_ca17_set_pte_ext, cpu_v7_set_pte_ext + globl_equ cpu_ca17_suspend_size, cpu_v7_suspend_size +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR + globl_equ cpu_ca17_switch_mm, cpu_v7_btbinv_switch_mm +#else + globl_equ cpu_ca17_switch_mm, cpu_v7_switch_mm +#endif +#ifdef CONFIG_ARM_CPU_SUSPEND + globl_equ cpu_ca17_do_suspend, cpu_v7_do_suspend + globl_equ cpu_ca17_do_resume, cpu_v7_do_resume +#endif + #ifdef CONFIG_CPU_PJ4B globl_equ cpu_pj4b_switch_mm, cpu_v7_switch_mm globl_equ cpu_pj4b_set_pte_ext, cpu_v7_set_pte_ext -- cgit v1.2.3