From: Sasha Levin Date: Sun, 10 Apr 2022 23:23:07 +0000 (-0400) Subject: Fixes for 4.9 X-Git-Tag: v4.9.310~98 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=20feace1f23d3e317a754b9184a7f815c2db9b60;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 4.9 Signed-off-by: Sasha Levin --- diff --git a/queue-4.9/drbd-fix-five-use-after-free-bugs-in-get_initial_sta.patch b/queue-4.9/drbd-fix-five-use-after-free-bugs-in-get_initial_sta.patch new file mode 100644 index 00000000000..44186376bd1 --- /dev/null +++ b/queue-4.9/drbd-fix-five-use-after-free-bugs-in-get_initial_sta.patch @@ -0,0 +1,344 @@ +From 05ca8547f147e3d3f3ee9d7f9d8a4036f0b9af61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Apr 2022 21:04:43 +0200 +Subject: drbd: Fix five use after free bugs in get_initial_state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Lv Yunlong + +[ Upstream commit aadb22ba2f656581b2f733deb3a467c48cc618f6 ] + +In get_initial_state, it calls notify_initial_state_done(skb,..) if +cb->args[5]==1. If genlmsg_put() failed in notify_initial_state_done(), +the skb will be freed by nlmsg_free(skb). +Then get_initial_state will goto out and the freed skb will be used by +return value skb->len, which is a uaf bug. + +What's worse, the same problem goes even further: skb can also be +freed in the notify_*_state_change -> notify_*_state calls below. +Thus 4 additional uaf bugs happened. + +My patch lets the problem callee functions: notify_initial_state_done +and notify_*_state_change return an error code if errors happen. +So that the error codes could be propagated and the uaf bugs can be avoid. + +v2 reports a compilation warning. This v3 fixed this warning and built +successfully in my local environment with no additional warnings. +v2: https://lore.kernel.org/patchwork/patch/1435218/ + +Fixes: a29728463b254 ("drbd: Backport the "events2" command") +Signed-off-by: Lv Yunlong +Reviewed-by: Christoph Böhmwalder +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_int.h | 8 ++--- + drivers/block/drbd/drbd_nl.c | 41 ++++++++++++++++---------- + drivers/block/drbd/drbd_state.c | 18 +++++------ + drivers/block/drbd/drbd_state_change.h | 8 ++--- + 4 files changed, 42 insertions(+), 33 deletions(-) + +diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h +index 4cb8f21ff4ef..4a7be81e7de9 100644 +--- a/drivers/block/drbd/drbd_int.h ++++ b/drivers/block/drbd/drbd_int.h +@@ -1696,22 +1696,22 @@ struct sib_info { + }; + void drbd_bcast_event(struct drbd_device *device, const struct sib_info *sib); + +-extern void notify_resource_state(struct sk_buff *, ++extern int notify_resource_state(struct sk_buff *, + unsigned int, + struct drbd_resource *, + struct resource_info *, + enum drbd_notification_type); +-extern void notify_device_state(struct sk_buff *, ++extern int notify_device_state(struct sk_buff *, + unsigned int, + struct drbd_device *, + struct device_info *, + enum drbd_notification_type); +-extern void notify_connection_state(struct sk_buff *, ++extern int notify_connection_state(struct sk_buff *, + unsigned int, + struct drbd_connection *, + struct connection_info *, + enum drbd_notification_type); +-extern void notify_peer_device_state(struct sk_buff *, ++extern int notify_peer_device_state(struct sk_buff *, + unsigned int, + struct drbd_peer_device *, + struct peer_device_info *, +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index b809f325c2be..3c9cee9520ed 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -4611,7 +4611,7 @@ static int nla_put_notification_header(struct sk_buff *msg, + return drbd_notification_header_to_skb(msg, &nh, true); + } + +-void notify_resource_state(struct sk_buff *skb, ++int notify_resource_state(struct sk_buff *skb, + unsigned int seq, + struct drbd_resource *resource, + struct resource_info *resource_info, +@@ -4653,16 +4653,17 @@ void notify_resource_state(struct sk_buff *skb, + if (err && err != -ESRCH) + goto failed; + } +- return; ++ return 0; + + nla_put_failure: + nlmsg_free(skb); + failed: + drbd_err(resource, "Error %d while broadcasting event. Event seq:%u\n", + err, seq); ++ return err; + } + +-void notify_device_state(struct sk_buff *skb, ++int notify_device_state(struct sk_buff *skb, + unsigned int seq, + struct drbd_device *device, + struct device_info *device_info, +@@ -4702,16 +4703,17 @@ void notify_device_state(struct sk_buff *skb, + if (err && err != -ESRCH) + goto failed; + } +- return; ++ return 0; + + nla_put_failure: + nlmsg_free(skb); + failed: + drbd_err(device, "Error %d while broadcasting event. Event seq:%u\n", + err, seq); ++ return err; + } + +-void notify_connection_state(struct sk_buff *skb, ++int notify_connection_state(struct sk_buff *skb, + unsigned int seq, + struct drbd_connection *connection, + struct connection_info *connection_info, +@@ -4751,16 +4753,17 @@ void notify_connection_state(struct sk_buff *skb, + if (err && err != -ESRCH) + goto failed; + } +- return; ++ return 0; + + nla_put_failure: + nlmsg_free(skb); + failed: + drbd_err(connection, "Error %d while broadcasting event. Event seq:%u\n", + err, seq); ++ return err; + } + +-void notify_peer_device_state(struct sk_buff *skb, ++int notify_peer_device_state(struct sk_buff *skb, + unsigned int seq, + struct drbd_peer_device *peer_device, + struct peer_device_info *peer_device_info, +@@ -4801,13 +4804,14 @@ void notify_peer_device_state(struct sk_buff *skb, + if (err && err != -ESRCH) + goto failed; + } +- return; ++ return 0; + + nla_put_failure: + nlmsg_free(skb); + failed: + drbd_err(peer_device, "Error %d while broadcasting event. Event seq:%u\n", + err, seq); ++ return err; + } + + void notify_helper(enum drbd_notification_type type, +@@ -4858,7 +4862,7 @@ void notify_helper(enum drbd_notification_type type, + err, seq); + } + +-static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq) ++static int notify_initial_state_done(struct sk_buff *skb, unsigned int seq) + { + struct drbd_genlmsghdr *dh; + int err; +@@ -4872,11 +4876,12 @@ static void notify_initial_state_done(struct sk_buff *skb, unsigned int seq) + if (nla_put_notification_header(skb, NOTIFY_EXISTS)) + goto nla_put_failure; + genlmsg_end(skb, dh); +- return; ++ return 0; + + nla_put_failure: + nlmsg_free(skb); + pr_err("Error %d sending event. Event seq:%u\n", err, seq); ++ return err; + } + + static void free_state_changes(struct list_head *list) +@@ -4903,6 +4908,7 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) + unsigned int seq = cb->args[2]; + unsigned int n; + enum drbd_notification_type flags = 0; ++ int err = 0; + + /* There is no need for taking notification_mutex here: it doesn't + matter if the initial state events mix with later state chage +@@ -4911,32 +4917,32 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) + + cb->args[5]--; + if (cb->args[5] == 1) { +- notify_initial_state_done(skb, seq); ++ err = notify_initial_state_done(skb, seq); + goto out; + } + n = cb->args[4]++; + if (cb->args[4] < cb->args[3]) + flags |= NOTIFY_CONTINUES; + if (n < 1) { +- notify_resource_state_change(skb, seq, state_change->resource, ++ err = notify_resource_state_change(skb, seq, state_change->resource, + NOTIFY_EXISTS | flags); + goto next; + } + n--; + if (n < state_change->n_connections) { +- notify_connection_state_change(skb, seq, &state_change->connections[n], ++ err = notify_connection_state_change(skb, seq, &state_change->connections[n], + NOTIFY_EXISTS | flags); + goto next; + } + n -= state_change->n_connections; + if (n < state_change->n_devices) { +- notify_device_state_change(skb, seq, &state_change->devices[n], ++ err = notify_device_state_change(skb, seq, &state_change->devices[n], + NOTIFY_EXISTS | flags); + goto next; + } + n -= state_change->n_devices; + if (n < state_change->n_devices * state_change->n_connections) { +- notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n], ++ err = notify_peer_device_state_change(skb, seq, &state_change->peer_devices[n], + NOTIFY_EXISTS | flags); + goto next; + } +@@ -4951,7 +4957,10 @@ static int get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) + cb->args[4] = 0; + } + out: +- return skb->len; ++ if (err) ++ return err; ++ else ++ return skb->len; + } + + int drbd_adm_get_initial_state(struct sk_buff *skb, struct netlink_callback *cb) +diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c +index eea0c4aec978..b636d9c08c0e 100644 +--- a/drivers/block/drbd/drbd_state.c ++++ b/drivers/block/drbd/drbd_state.c +@@ -1505,7 +1505,7 @@ int drbd_bitmap_io_from_worker(struct drbd_device *device, + return rv; + } + +-void notify_resource_state_change(struct sk_buff *skb, ++int notify_resource_state_change(struct sk_buff *skb, + unsigned int seq, + struct drbd_resource_state_change *resource_state_change, + enum drbd_notification_type type) +@@ -1518,10 +1518,10 @@ void notify_resource_state_change(struct sk_buff *skb, + .res_susp_fen = resource_state_change->susp_fen[NEW], + }; + +- notify_resource_state(skb, seq, resource, &resource_info, type); ++ return notify_resource_state(skb, seq, resource, &resource_info, type); + } + +-void notify_connection_state_change(struct sk_buff *skb, ++int notify_connection_state_change(struct sk_buff *skb, + unsigned int seq, + struct drbd_connection_state_change *connection_state_change, + enum drbd_notification_type type) +@@ -1532,10 +1532,10 @@ void notify_connection_state_change(struct sk_buff *skb, + .conn_role = connection_state_change->peer_role[NEW], + }; + +- notify_connection_state(skb, seq, connection, &connection_info, type); ++ return notify_connection_state(skb, seq, connection, &connection_info, type); + } + +-void notify_device_state_change(struct sk_buff *skb, ++int notify_device_state_change(struct sk_buff *skb, + unsigned int seq, + struct drbd_device_state_change *device_state_change, + enum drbd_notification_type type) +@@ -1545,10 +1545,10 @@ void notify_device_state_change(struct sk_buff *skb, + .dev_disk_state = device_state_change->disk_state[NEW], + }; + +- notify_device_state(skb, seq, device, &device_info, type); ++ return notify_device_state(skb, seq, device, &device_info, type); + } + +-void notify_peer_device_state_change(struct sk_buff *skb, ++int notify_peer_device_state_change(struct sk_buff *skb, + unsigned int seq, + struct drbd_peer_device_state_change *p, + enum drbd_notification_type type) +@@ -1562,7 +1562,7 @@ void notify_peer_device_state_change(struct sk_buff *skb, + .peer_resync_susp_dependency = p->resync_susp_dependency[NEW], + }; + +- notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type); ++ return notify_peer_device_state(skb, seq, peer_device, &peer_device_info, type); + } + + static void broadcast_state_change(struct drbd_state_change *state_change) +@@ -1570,7 +1570,7 @@ static void broadcast_state_change(struct drbd_state_change *state_change) + struct drbd_resource_state_change *resource_state_change = &state_change->resource[0]; + bool resource_state_has_changed; + unsigned int n_device, n_connection, n_peer_device, n_peer_devices; +- void (*last_func)(struct sk_buff *, unsigned int, void *, ++ int (*last_func)(struct sk_buff *, unsigned int, void *, + enum drbd_notification_type) = NULL; + void *uninitialized_var(last_arg); + +diff --git a/drivers/block/drbd/drbd_state_change.h b/drivers/block/drbd/drbd_state_change.h +index 9e503a1a0bfb..e5a956d26866 100644 +--- a/drivers/block/drbd/drbd_state_change.h ++++ b/drivers/block/drbd/drbd_state_change.h +@@ -43,19 +43,19 @@ extern struct drbd_state_change *remember_old_state(struct drbd_resource *, gfp_ + extern void copy_old_to_new_state_change(struct drbd_state_change *); + extern void forget_state_change(struct drbd_state_change *); + +-extern void notify_resource_state_change(struct sk_buff *, ++extern int notify_resource_state_change(struct sk_buff *, + unsigned int, + struct drbd_resource_state_change *, + enum drbd_notification_type type); +-extern void notify_connection_state_change(struct sk_buff *, ++extern int notify_connection_state_change(struct sk_buff *, + unsigned int, + struct drbd_connection_state_change *, + enum drbd_notification_type type); +-extern void notify_device_state_change(struct sk_buff *, ++extern int notify_device_state_change(struct sk_buff *, + unsigned int, + struct drbd_device_state_change *, + enum drbd_notification_type type); +-extern void notify_peer_device_state_change(struct sk_buff *, ++extern int notify_peer_device_state_change(struct sk_buff *, + unsigned int, + struct drbd_peer_device_state_change *, + enum drbd_notification_type type); +-- +2.35.1 + diff --git a/queue-4.9/drm-imx-fix-memory-leak-in-imx_pd_connector_get_mode.patch b/queue-4.9/drm-imx-fix-memory-leak-in-imx_pd_connector_get_mode.patch new file mode 100644 index 00000000000..cc65bb395bf --- /dev/null +++ b/queue-4.9/drm-imx-fix-memory-leak-in-imx_pd_connector_get_mode.patch @@ -0,0 +1,44 @@ +From 4caeca0b3a290e02b9cbad1109fd570474614bee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 8 Jan 2022 17:52:30 +0100 +Subject: drm/imx: Fix memory leak in imx_pd_connector_get_modes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: José Expósito + +[ Upstream commit bce81feb03a20fca7bbdd1c4af16b4e9d5c0e1d3 ] + +Avoid leaking the display mode variable if of_get_drm_display_mode +fails. + +Fixes: 76ecd9c9fb24 ("drm/imx: parallel-display: check return code from of_get_drm_display_mode()") +Addresses-Coverity-ID: 1443943 ("Resource leak") +Signed-off-by: José Expósito +Signed-off-by: Philipp Zabel +Link: https://lore.kernel.org/r/20220108165230.44610-1-jose.exposito89@gmail.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/imx/parallel-display.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c +index d796ada2a47a..924a11232b84 100644 +--- a/drivers/gpu/drm/imx/parallel-display.c ++++ b/drivers/gpu/drm/imx/parallel-display.c +@@ -83,8 +83,10 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) + ret = of_get_drm_display_mode(np, &imxpd->mode, + &imxpd->bus_flags, + OF_USE_NATIVE_MODE); +- if (ret) ++ if (ret) { ++ drm_mode_destroy(connector->dev, mode); + return ret; ++ } + + drm_mode_copy(mode, &imxpd->mode); + mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +-- +2.35.1 + diff --git a/queue-4.9/net-stmmac-fix-unset-max_speed-difference-between-dt.patch b/queue-4.9/net-stmmac-fix-unset-max_speed-difference-between-dt.patch new file mode 100644 index 00000000000..04085b702d1 --- /dev/null +++ b/queue-4.9/net-stmmac-fix-unset-max_speed-difference-between-dt.patch @@ -0,0 +1,56 @@ +From a3534eee7629f0c9d6db57618428cd391769617b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 1 Apr 2022 02:48:32 +0800 +Subject: net: stmmac: Fix unset max_speed difference between DT and non-DT + platforms + +From: Chen-Yu Tsai + +[ Upstream commit c21cabb0fd0b54b8b54235fc1ecfe1195a23bcb2 ] + +In commit 9cbadf094d9d ("net: stmmac: support max-speed device tree +property"), when DT platforms don't set "max-speed", max_speed is set to +-1; for non-DT platforms, it stays the default 0. + +Prior to commit eeef2f6b9f6e ("net: stmmac: Start adding phylink support"), +the check for a valid max_speed setting was to check if it was greater +than zero. This commit got it right, but subsequent patches just checked +for non-zero, which is incorrect for DT platforms. + +In commit 92c3807b9ac3 ("net: stmmac: convert to phylink_get_linkmodes()") +the conversion switched completely to checking for non-zero value as a +valid value, which caused 1000base-T to stop getting advertised by +default. + +Instead of trying to fix all the checks, simply leave max_speed alone if +DT property parsing fails. + +Fixes: 9cbadf094d9d ("net: stmmac: support max-speed device tree property") +Fixes: 92c3807b9ac3 ("net: stmmac: convert to phylink_get_linkmodes()") +Signed-off-by: Chen-Yu Tsai +Acked-by: Russell King (Oracle) +Reviewed-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220331184832.16316-1-wens@kernel.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +index 2019e163e0e9..cbdd0deb7c56 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -221,8 +221,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) + plat->interface = of_get_phy_mode(np); + + /* Get max speed of operation from device tree */ +- if (of_property_read_u32(np, "max-speed", &plat->max_speed)) +- plat->max_speed = -1; ++ of_property_read_u32(np, "max-speed", &plat->max_speed); + + plat->bus_id = of_alias_get_id(np, "ethernet"); + if (plat->bus_id < 0) +-- +2.35.1 + diff --git a/queue-4.9/scsi-zorro7xx-fix-a-resource-leak-in-zorro7xx_remove.patch b/queue-4.9/scsi-zorro7xx-fix-a-resource-leak-in-zorro7xx_remove.patch new file mode 100644 index 00000000000..bd0968da8f0 --- /dev/null +++ b/queue-4.9/scsi-zorro7xx-fix-a-resource-leak-in-zorro7xx_remove.patch @@ -0,0 +1,40 @@ +From 8d5b7d66ec0011c1f73e28fd4c2bcf3f5de403a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Mar 2022 08:01:24 +0100 +Subject: scsi: zorro7xx: Fix a resource leak in zorro7xx_remove_one() + +From: Christophe JAILLET + +[ Upstream commit 16ed828b872d12ccba8f07bcc446ae89ba662f9c ] + +The error handling path of the probe releases a resource that is not freed +in the remove function. In some cases, a ioremap() must be undone. + +Add the missing iounmap() call in the remove function. + +Link: https://lore.kernel.org/r/247066a3104d25f9a05de8b3270fc3c848763bcc.1647673264.git.christophe.jaillet@wanadoo.fr +Fixes: 45804fbb00ee ("[SCSI] 53c700: Amiga Zorro NCR53c710 SCSI") +Reviewed-by: Geert Uytterhoeven +Signed-off-by: Christophe JAILLET +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/zorro7xx.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c +index aff31991aea9..ee6d97473853 100644 +--- a/drivers/scsi/zorro7xx.c ++++ b/drivers/scsi/zorro7xx.c +@@ -158,6 +158,8 @@ static void zorro7xx_remove_one(struct zorro_dev *z) + scsi_remove_host(host); + + NCR_700_release(host); ++ if (host->base > 0x01000000) ++ iounmap(hostdata->base); + kfree(hostdata); + free_irq(host->irq, host); + zorro_release_device(z); +-- +2.35.1 + diff --git a/queue-4.9/series b/queue-4.9/series index 3eab9e71e27..cf3520f0916 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -185,3 +185,7 @@ serial-samsung_tty-do-not-unlock-port-lock-for-uart_.patch virtio_console-eliminate-anonymous-module_init-modul.patch jfs-prevent-null-deref-in-difree.patch mm-fix-race-between-madv_free-reclaim-and-blkdev-dir.patch +scsi-zorro7xx-fix-a-resource-leak-in-zorro7xx_remove.patch +net-stmmac-fix-unset-max_speed-difference-between-dt.patch +drm-imx-fix-memory-leak-in-imx_pd_connector_get_mode.patch +drbd-fix-five-use-after-free-bugs-in-get_initial_sta.patch