]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Mar 2021 08:32:21 +0000 (09:32 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Mar 2021 08:32:21 +0000 (09:32 +0100)
added patches:
scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch
scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch
scsi-iscsi-verify-lengths-on-passthrough-pdus.patch
swap-fix-swapfile-read-write-offset.patch
sysfs-add-sysfs_emit-and-sysfs_emit_at-to-format-sysfs-output.patch
xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch
xen-netback-respect-gnttab_map_refs-s-return-value.patch
zsmalloc-account-the-number-of-compacted-pages-correctly.patch

queue-5.4/scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch [new file with mode: 0644]
queue-5.4/scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch [new file with mode: 0644]
queue-5.4/scsi-iscsi-verify-lengths-on-passthrough-pdus.patch [new file with mode: 0644]
queue-5.4/series
queue-5.4/swap-fix-swapfile-read-write-offset.patch [new file with mode: 0644]
queue-5.4/sysfs-add-sysfs_emit-and-sysfs_emit_at-to-format-sysfs-output.patch [new file with mode: 0644]
queue-5.4/xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch [new file with mode: 0644]
queue-5.4/xen-netback-respect-gnttab_map_refs-s-return-value.patch [new file with mode: 0644]
queue-5.4/zsmalloc-account-the-number-of-compacted-pages-correctly.patch [new file with mode: 0644]

diff --git a/queue-5.4/scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch b/queue-5.4/scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch
new file mode 100644 (file)
index 0000000..67ac1d2
--- /dev/null
@@ -0,0 +1,438 @@
+From ec98ea7070e94cc25a422ec97d1421e28d97b7ee Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Tue, 23 Feb 2021 18:00:17 -0800
+Subject: scsi: iscsi: Ensure sysfs attributes are limited to PAGE_SIZE
+
+From: Chris Leech <cleech@redhat.com>
+
+commit ec98ea7070e94cc25a422ec97d1421e28d97b7ee upstream.
+
+As the iSCSI parameters are exported back through sysfs, it should be
+enforcing that they never are more than PAGE_SIZE (which should be more
+than enough) before accepting updates through netlink.
+
+Change all iSCSI sysfs attributes to use sysfs_emit().
+
+Cc: stable@vger.kernel.org
+Reported-by: Adam Nichols <adam@grimm-co.com>
+Reviewed-by: Lee Duncan <lduncan@suse.com>
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Reviewed-by: Mike Christie <michael.christie@oracle.com>
+Signed-off-by: Chris Leech <cleech@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/libiscsi.c             |  148 ++++++++++++++++++------------------
+ drivers/scsi/scsi_transport_iscsi.c |   23 +++--
+ 2 files changed, 89 insertions(+), 82 deletions(-)
+
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -3331,125 +3331,125 @@ int iscsi_session_get_param(struct iscsi
+       switch(param) {
+       case ISCSI_PARAM_FAST_ABORT:
+-              len = sprintf(buf, "%d\n", session->fast_abort);
++              len = sysfs_emit(buf, "%d\n", session->fast_abort);
+               break;
+       case ISCSI_PARAM_ABORT_TMO:
+-              len = sprintf(buf, "%d\n", session->abort_timeout);
++              len = sysfs_emit(buf, "%d\n", session->abort_timeout);
+               break;
+       case ISCSI_PARAM_LU_RESET_TMO:
+-              len = sprintf(buf, "%d\n", session->lu_reset_timeout);
++              len = sysfs_emit(buf, "%d\n", session->lu_reset_timeout);
+               break;
+       case ISCSI_PARAM_TGT_RESET_TMO:
+-              len = sprintf(buf, "%d\n", session->tgt_reset_timeout);
++              len = sysfs_emit(buf, "%d\n", session->tgt_reset_timeout);
+               break;
+       case ISCSI_PARAM_INITIAL_R2T_EN:
+-              len = sprintf(buf, "%d\n", session->initial_r2t_en);
++              len = sysfs_emit(buf, "%d\n", session->initial_r2t_en);
+               break;
+       case ISCSI_PARAM_MAX_R2T:
+-              len = sprintf(buf, "%hu\n", session->max_r2t);
++              len = sysfs_emit(buf, "%hu\n", session->max_r2t);
+               break;
+       case ISCSI_PARAM_IMM_DATA_EN:
+-              len = sprintf(buf, "%d\n", session->imm_data_en);
++              len = sysfs_emit(buf, "%d\n", session->imm_data_en);
+               break;
+       case ISCSI_PARAM_FIRST_BURST:
+-              len = sprintf(buf, "%u\n", session->first_burst);
++              len = sysfs_emit(buf, "%u\n", session->first_burst);
+               break;
+       case ISCSI_PARAM_MAX_BURST:
+-              len = sprintf(buf, "%u\n", session->max_burst);
++              len = sysfs_emit(buf, "%u\n", session->max_burst);
+               break;
+       case ISCSI_PARAM_PDU_INORDER_EN:
+-              len = sprintf(buf, "%d\n", session->pdu_inorder_en);
++              len = sysfs_emit(buf, "%d\n", session->pdu_inorder_en);
+               break;
+       case ISCSI_PARAM_DATASEQ_INORDER_EN:
+-              len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
++              len = sysfs_emit(buf, "%d\n", session->dataseq_inorder_en);
+               break;
+       case ISCSI_PARAM_DEF_TASKMGMT_TMO:
+-              len = sprintf(buf, "%d\n", session->def_taskmgmt_tmo);
++              len = sysfs_emit(buf, "%d\n", session->def_taskmgmt_tmo);
+               break;
+       case ISCSI_PARAM_ERL:
+-              len = sprintf(buf, "%d\n", session->erl);
++              len = sysfs_emit(buf, "%d\n", session->erl);
+               break;
+       case ISCSI_PARAM_TARGET_NAME:
+-              len = sprintf(buf, "%s\n", session->targetname);
++              len = sysfs_emit(buf, "%s\n", session->targetname);
+               break;
+       case ISCSI_PARAM_TARGET_ALIAS:
+-              len = sprintf(buf, "%s\n", session->targetalias);
++              len = sysfs_emit(buf, "%s\n", session->targetalias);
+               break;
+       case ISCSI_PARAM_TPGT:
+-              len = sprintf(buf, "%d\n", session->tpgt);
++              len = sysfs_emit(buf, "%d\n", session->tpgt);
+               break;
+       case ISCSI_PARAM_USERNAME:
+-              len = sprintf(buf, "%s\n", session->username);
++              len = sysfs_emit(buf, "%s\n", session->username);
+               break;
+       case ISCSI_PARAM_USERNAME_IN:
+-              len = sprintf(buf, "%s\n", session->username_in);
++              len = sysfs_emit(buf, "%s\n", session->username_in);
+               break;
+       case ISCSI_PARAM_PASSWORD:
+-              len = sprintf(buf, "%s\n", session->password);
++              len = sysfs_emit(buf, "%s\n", session->password);
+               break;
+       case ISCSI_PARAM_PASSWORD_IN:
+-              len = sprintf(buf, "%s\n", session->password_in);
++              len = sysfs_emit(buf, "%s\n", session->password_in);
+               break;
+       case ISCSI_PARAM_IFACE_NAME:
+-              len = sprintf(buf, "%s\n", session->ifacename);
++              len = sysfs_emit(buf, "%s\n", session->ifacename);
+               break;
+       case ISCSI_PARAM_INITIATOR_NAME:
+-              len = sprintf(buf, "%s\n", session->initiatorname);
++              len = sysfs_emit(buf, "%s\n", session->initiatorname);
+               break;
+       case ISCSI_PARAM_BOOT_ROOT:
+-              len = sprintf(buf, "%s\n", session->boot_root);
++              len = sysfs_emit(buf, "%s\n", session->boot_root);
+               break;
+       case ISCSI_PARAM_BOOT_NIC:
+-              len = sprintf(buf, "%s\n", session->boot_nic);
++              len = sysfs_emit(buf, "%s\n", session->boot_nic);
+               break;
+       case ISCSI_PARAM_BOOT_TARGET:
+-              len = sprintf(buf, "%s\n", session->boot_target);
++              len = sysfs_emit(buf, "%s\n", session->boot_target);
+               break;
+       case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
+-              len = sprintf(buf, "%u\n", session->auto_snd_tgt_disable);
++              len = sysfs_emit(buf, "%u\n", session->auto_snd_tgt_disable);
+               break;
+       case ISCSI_PARAM_DISCOVERY_SESS:
+-              len = sprintf(buf, "%u\n", session->discovery_sess);
++              len = sysfs_emit(buf, "%u\n", session->discovery_sess);
+               break;
+       case ISCSI_PARAM_PORTAL_TYPE:
+-              len = sprintf(buf, "%s\n", session->portal_type);
++              len = sysfs_emit(buf, "%s\n", session->portal_type);
+               break;
+       case ISCSI_PARAM_CHAP_AUTH_EN:
+-              len = sprintf(buf, "%u\n", session->chap_auth_en);
++              len = sysfs_emit(buf, "%u\n", session->chap_auth_en);
+               break;
+       case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
+-              len = sprintf(buf, "%u\n", session->discovery_logout_en);
++              len = sysfs_emit(buf, "%u\n", session->discovery_logout_en);
+               break;
+       case ISCSI_PARAM_BIDI_CHAP_EN:
+-              len = sprintf(buf, "%u\n", session->bidi_chap_en);
++              len = sysfs_emit(buf, "%u\n", session->bidi_chap_en);
+               break;
+       case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
+-              len = sprintf(buf, "%u\n", session->discovery_auth_optional);
++              len = sysfs_emit(buf, "%u\n", session->discovery_auth_optional);
+               break;
+       case ISCSI_PARAM_DEF_TIME2WAIT:
+-              len = sprintf(buf, "%d\n", session->time2wait);
++              len = sysfs_emit(buf, "%d\n", session->time2wait);
+               break;
+       case ISCSI_PARAM_DEF_TIME2RETAIN:
+-              len = sprintf(buf, "%d\n", session->time2retain);
++              len = sysfs_emit(buf, "%d\n", session->time2retain);
+               break;
+       case ISCSI_PARAM_TSID:
+-              len = sprintf(buf, "%u\n", session->tsid);
++              len = sysfs_emit(buf, "%u\n", session->tsid);
+               break;
+       case ISCSI_PARAM_ISID:
+-              len = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
++              len = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n",
+                             session->isid[0], session->isid[1],
+                             session->isid[2], session->isid[3],
+                             session->isid[4], session->isid[5]);
+               break;
+       case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
+-              len = sprintf(buf, "%u\n", session->discovery_parent_idx);
++              len = sysfs_emit(buf, "%u\n", session->discovery_parent_idx);
+               break;
+       case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
+               if (session->discovery_parent_type)
+-                      len = sprintf(buf, "%s\n",
++                      len = sysfs_emit(buf, "%s\n",
+                                     session->discovery_parent_type);
+               else
+-                      len = sprintf(buf, "\n");
++                      len = sysfs_emit(buf, "\n");
+               break;
+       default:
+               return -ENOSYS;
+@@ -3481,16 +3481,16 @@ int iscsi_conn_get_addr_param(struct soc
+       case ISCSI_PARAM_CONN_ADDRESS:
+       case ISCSI_HOST_PARAM_IPADDRESS:
+               if (sin)
+-                      len = sprintf(buf, "%pI4\n", &sin->sin_addr.s_addr);
++                      len = sysfs_emit(buf, "%pI4\n", &sin->sin_addr.s_addr);
+               else
+-                      len = sprintf(buf, "%pI6\n", &sin6->sin6_addr);
++                      len = sysfs_emit(buf, "%pI6\n", &sin6->sin6_addr);
+               break;
+       case ISCSI_PARAM_CONN_PORT:
+       case ISCSI_PARAM_LOCAL_PORT:
+               if (sin)
+-                      len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port));
++                      len = sysfs_emit(buf, "%hu\n", be16_to_cpu(sin->sin_port));
+               else
+-                      len = sprintf(buf, "%hu\n",
++                      len = sysfs_emit(buf, "%hu\n",
+                                     be16_to_cpu(sin6->sin6_port));
+               break;
+       default:
+@@ -3509,88 +3509,88 @@ int iscsi_conn_get_param(struct iscsi_cl
+       switch(param) {
+       case ISCSI_PARAM_PING_TMO:
+-              len = sprintf(buf, "%u\n", conn->ping_timeout);
++              len = sysfs_emit(buf, "%u\n", conn->ping_timeout);
+               break;
+       case ISCSI_PARAM_RECV_TMO:
+-              len = sprintf(buf, "%u\n", conn->recv_timeout);
++              len = sysfs_emit(buf, "%u\n", conn->recv_timeout);
+               break;
+       case ISCSI_PARAM_MAX_RECV_DLENGTH:
+-              len = sprintf(buf, "%u\n", conn->max_recv_dlength);
++              len = sysfs_emit(buf, "%u\n", conn->max_recv_dlength);
+               break;
+       case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+-              len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
++              len = sysfs_emit(buf, "%u\n", conn->max_xmit_dlength);
+               break;
+       case ISCSI_PARAM_HDRDGST_EN:
+-              len = sprintf(buf, "%d\n", conn->hdrdgst_en);
++              len = sysfs_emit(buf, "%d\n", conn->hdrdgst_en);
+               break;
+       case ISCSI_PARAM_DATADGST_EN:
+-              len = sprintf(buf, "%d\n", conn->datadgst_en);
++              len = sysfs_emit(buf, "%d\n", conn->datadgst_en);
+               break;
+       case ISCSI_PARAM_IFMARKER_EN:
+-              len = sprintf(buf, "%d\n", conn->ifmarker_en);
++              len = sysfs_emit(buf, "%d\n", conn->ifmarker_en);
+               break;
+       case ISCSI_PARAM_OFMARKER_EN:
+-              len = sprintf(buf, "%d\n", conn->ofmarker_en);
++              len = sysfs_emit(buf, "%d\n", conn->ofmarker_en);
+               break;
+       case ISCSI_PARAM_EXP_STATSN:
+-              len = sprintf(buf, "%u\n", conn->exp_statsn);
++              len = sysfs_emit(buf, "%u\n", conn->exp_statsn);
+               break;
+       case ISCSI_PARAM_PERSISTENT_PORT:
+-              len = sprintf(buf, "%d\n", conn->persistent_port);
++              len = sysfs_emit(buf, "%d\n", conn->persistent_port);
+               break;
+       case ISCSI_PARAM_PERSISTENT_ADDRESS:
+-              len = sprintf(buf, "%s\n", conn->persistent_address);
++              len = sysfs_emit(buf, "%s\n", conn->persistent_address);
+               break;
+       case ISCSI_PARAM_STATSN:
+-              len = sprintf(buf, "%u\n", conn->statsn);
++              len = sysfs_emit(buf, "%u\n", conn->statsn);
+               break;
+       case ISCSI_PARAM_MAX_SEGMENT_SIZE:
+-              len = sprintf(buf, "%u\n", conn->max_segment_size);
++              len = sysfs_emit(buf, "%u\n", conn->max_segment_size);
+               break;
+       case ISCSI_PARAM_KEEPALIVE_TMO:
+-              len = sprintf(buf, "%u\n", conn->keepalive_tmo);
++              len = sysfs_emit(buf, "%u\n", conn->keepalive_tmo);
+               break;
+       case ISCSI_PARAM_LOCAL_PORT:
+-              len = sprintf(buf, "%u\n", conn->local_port);
++              len = sysfs_emit(buf, "%u\n", conn->local_port);
+               break;
+       case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
+-              len = sprintf(buf, "%u\n", conn->tcp_timestamp_stat);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_stat);
+               break;
+       case ISCSI_PARAM_TCP_NAGLE_DISABLE:
+-              len = sprintf(buf, "%u\n", conn->tcp_nagle_disable);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_nagle_disable);
+               break;
+       case ISCSI_PARAM_TCP_WSF_DISABLE:
+-              len = sprintf(buf, "%u\n", conn->tcp_wsf_disable);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_wsf_disable);
+               break;
+       case ISCSI_PARAM_TCP_TIMER_SCALE:
+-              len = sprintf(buf, "%u\n", conn->tcp_timer_scale);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_timer_scale);
+               break;
+       case ISCSI_PARAM_TCP_TIMESTAMP_EN:
+-              len = sprintf(buf, "%u\n", conn->tcp_timestamp_en);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_en);
+               break;
+       case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
+-              len = sprintf(buf, "%u\n", conn->fragment_disable);
++              len = sysfs_emit(buf, "%u\n", conn->fragment_disable);
+               break;
+       case ISCSI_PARAM_IPV4_TOS:
+-              len = sprintf(buf, "%u\n", conn->ipv4_tos);
++              len = sysfs_emit(buf, "%u\n", conn->ipv4_tos);
+               break;
+       case ISCSI_PARAM_IPV6_TC:
+-              len = sprintf(buf, "%u\n", conn->ipv6_traffic_class);
++              len = sysfs_emit(buf, "%u\n", conn->ipv6_traffic_class);
+               break;
+       case ISCSI_PARAM_IPV6_FLOW_LABEL:
+-              len = sprintf(buf, "%u\n", conn->ipv6_flow_label);
++              len = sysfs_emit(buf, "%u\n", conn->ipv6_flow_label);
+               break;
+       case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
+-              len = sprintf(buf, "%u\n", conn->is_fw_assigned_ipv6);
++              len = sysfs_emit(buf, "%u\n", conn->is_fw_assigned_ipv6);
+               break;
+       case ISCSI_PARAM_TCP_XMIT_WSF:
+-              len = sprintf(buf, "%u\n", conn->tcp_xmit_wsf);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_xmit_wsf);
+               break;
+       case ISCSI_PARAM_TCP_RECV_WSF:
+-              len = sprintf(buf, "%u\n", conn->tcp_recv_wsf);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_recv_wsf);
+               break;
+       case ISCSI_PARAM_LOCAL_IPADDR:
+-              len = sprintf(buf, "%s\n", conn->local_ipaddr);
++              len = sysfs_emit(buf, "%s\n", conn->local_ipaddr);
+               break;
+       default:
+               return -ENOSYS;
+@@ -3608,13 +3608,13 @@ int iscsi_host_get_param(struct Scsi_Hos
+       switch (param) {
+       case ISCSI_HOST_PARAM_NETDEV_NAME:
+-              len = sprintf(buf, "%s\n", ihost->netdev);
++              len = sysfs_emit(buf, "%s\n", ihost->netdev);
+               break;
+       case ISCSI_HOST_PARAM_HWADDRESS:
+-              len = sprintf(buf, "%s\n", ihost->hwaddress);
++              len = sysfs_emit(buf, "%s\n", ihost->hwaddress);
+               break;
+       case ISCSI_HOST_PARAM_INITIATOR_NAME:
+-              len = sprintf(buf, "%s\n", ihost->initiatorname);
++              len = sysfs_emit(buf, "%s\n", ihost->initiatorname);
+               break;
+       default:
+               return -ENOSYS;
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -127,7 +127,8 @@ show_transport_handle(struct device *dev
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+-      return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
++      return sysfs_emit(buf, "%llu\n",
++                (unsigned long long)iscsi_handle(priv->iscsi_transport));
+ }
+ static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
+@@ -137,7 +138,7 @@ show_transport_##name(struct device *dev
+                     struct device_attribute *attr,char *buf)          \
+ {                                                                     \
+       struct iscsi_internal *priv = dev_to_iscsi_internal(dev);       \
+-      return sprintf(buf, format"\n", priv->iscsi_transport->name);   \
++      return sysfs_emit(buf, format"\n", priv->iscsi_transport->name);\
+ }                                                                     \
+ static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
+@@ -178,7 +179,7 @@ static ssize_t
+ show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+       struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+-      return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
++      return sysfs_emit(buf, "%llu\n", (unsigned long long) ep->id);
+ }
+ static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
+@@ -2768,6 +2769,9 @@ iscsi_set_param(struct iscsi_transport *
+       struct iscsi_cls_session *session;
+       int err = 0, value = 0;
++      if (ev->u.set_param.len > PAGE_SIZE)
++              return -EINVAL;
++
+       session = iscsi_session_lookup(ev->u.set_param.sid);
+       conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
+       if (!conn || !session)
+@@ -2915,6 +2919,9 @@ iscsi_set_host_param(struct iscsi_transp
+       if (!transport->set_host_param)
+               return -ENOSYS;
++      if (ev->u.set_host_param.len > PAGE_SIZE)
++              return -EINVAL;
++
+       shost = scsi_host_lookup(ev->u.set_host_param.host_no);
+       if (!shost) {
+               printk(KERN_ERR "set_host_param could not find host no %u\n",
+@@ -4025,7 +4032,7 @@ show_priv_session_state(struct device *d
+                       char *buf)
+ {
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+-      return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
++      return sysfs_emit(buf, "%s\n", iscsi_session_state_name(session->state));
+ }
+ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
+                       NULL);
+@@ -4034,7 +4041,7 @@ show_priv_session_creator(struct device
+                       char *buf)
+ {
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+-      return sprintf(buf, "%d\n", session->creator);
++      return sysfs_emit(buf, "%d\n", session->creator);
+ }
+ static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator,
+                       NULL);
+@@ -4043,7 +4050,7 @@ show_priv_session_target_id(struct devic
+                           char *buf)
+ {
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+-      return sprintf(buf, "%d\n", session->target_id);
++      return sysfs_emit(buf, "%d\n", session->target_id);
+ }
+ static ISCSI_CLASS_ATTR(priv_sess, target_id, S_IRUGO,
+                       show_priv_session_target_id, NULL);
+@@ -4056,8 +4063,8 @@ show_priv_session_##field(struct device
+       struct iscsi_cls_session *session =                             \
+                       iscsi_dev_to_session(dev->parent);              \
+       if (session->field == -1)                                       \
+-              return sprintf(buf, "off\n");                           \
+-      return sprintf(buf, format"\n", session->field);                \
++              return sysfs_emit(buf, "off\n");                        \
++      return sysfs_emit(buf, format"\n", session->field);             \
+ }
+ #define iscsi_priv_session_attr_store(field)                          \
diff --git a/queue-5.4/scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch b/queue-5.4/scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch
new file mode 100644 (file)
index 0000000..ffece65
--- /dev/null
@@ -0,0 +1,47 @@
+From 688e8128b7a92df982709a4137ea4588d16f24aa Mon Sep 17 00:00:00 2001
+From: Lee Duncan <lduncan@suse.com>
+Date: Tue, 23 Feb 2021 13:06:24 -0800
+Subject: scsi: iscsi: Restrict sessions and handles to admin capabilities
+
+From: Lee Duncan <lduncan@suse.com>
+
+commit 688e8128b7a92df982709a4137ea4588d16f24aa upstream.
+
+Protect the iSCSI transport handle, available in sysfs, by requiring
+CAP_SYS_ADMIN to read it. Also protect the netlink socket by restricting
+reception of messages to ones sent with CAP_SYS_ADMIN. This disables
+normal users from being able to end arbitrary iSCSI sessions.
+
+Cc: stable@vger.kernel.org
+Reported-by: Adam Nichols <adam@grimm-co.com>
+Reviewed-by: Chris Leech <cleech@redhat.com>
+Reviewed-by: Mike Christie <michael.christie@oracle.com>
+Signed-off-by: Lee Duncan <lduncan@suse.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/scsi_transport_iscsi.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -124,6 +124,9 @@ show_transport_handle(struct device *dev
+                     char *buf)
+ {
+       struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
++
++      if (!capable(CAP_SYS_ADMIN))
++              return -EACCES;
+       return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
+ }
+ static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
+@@ -3506,6 +3509,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, s
+       struct iscsi_cls_conn *conn;
+       struct iscsi_endpoint *ep = NULL;
++      if (!netlink_capable(skb, CAP_SYS_ADMIN))
++              return -EPERM;
++
+       if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
+               *group = ISCSI_NL_GRP_UIP;
+       else
diff --git a/queue-5.4/scsi-iscsi-verify-lengths-on-passthrough-pdus.patch b/queue-5.4/scsi-iscsi-verify-lengths-on-passthrough-pdus.patch
new file mode 100644 (file)
index 0000000..234477c
--- /dev/null
@@ -0,0 +1,49 @@
+From f9dbdf97a5bd92b1a49cee3d591b55b11fd7a6d5 Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Tue, 23 Feb 2021 21:39:01 -0800
+Subject: scsi: iscsi: Verify lengths on passthrough PDUs
+
+From: Chris Leech <cleech@redhat.com>
+
+commit f9dbdf97a5bd92b1a49cee3d591b55b11fd7a6d5 upstream.
+
+Open-iSCSI sends passthrough PDUs over netlink, but the kernel should be
+verifying that the provided PDU header and data lengths fall within the
+netlink message to prevent accessing beyond that in memory.
+
+Cc: stable@vger.kernel.org
+Reported-by: Adam Nichols <adam@grimm-co.com>
+Reviewed-by: Lee Duncan <lduncan@suse.com>
+Reviewed-by: Mike Christie <michael.christie@oracle.com>
+Signed-off-by: Chris Leech <cleech@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/scsi_transport_iscsi.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -3509,6 +3509,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, s
+ {
+       int err = 0;
+       u32 portid;
++      u32 pdu_len;
+       struct iscsi_uevent *ev = nlmsg_data(nlh);
+       struct iscsi_transport *transport = NULL;
+       struct iscsi_internal *priv;
+@@ -3626,6 +3627,14 @@ iscsi_if_recv_msg(struct sk_buff *skb, s
+                       err = -EINVAL;
+               break;
+       case ISCSI_UEVENT_SEND_PDU:
++              pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev);
++
++              if ((ev->u.send_pdu.hdr_size > pdu_len) ||
++                  (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) {
++                      err = -EINVAL;
++                      break;
++              }
++
+               conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
+               if (conn)
+                       ev->r.retcode = transport->send_pdu(conn,
index e85feb600494763258a7f53abc139cad6422f3b2..bdb441dda69fd0187787476fc130f3b8c12c72d4 100644 (file)
@@ -58,3 +58,11 @@ asoc-intel-bytcr_rt5640-add-quirk-for-the-estar-beau.patch
 asoc-intel-bytcr_rt5640-add-quirk-for-the-voyo-winpa.patch
 asoc-intel-bytcr_rt5651-add-quirk-for-the-jumper-ezp.patch
 asoc-intel-bytcr_rt5640-add-quirk-for-the-acer-one-s.patch
+scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch
+sysfs-add-sysfs_emit-and-sysfs_emit_at-to-format-sysfs-output.patch
+scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch
+scsi-iscsi-verify-lengths-on-passthrough-pdus.patch
+xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch
+xen-netback-respect-gnttab_map_refs-s-return-value.patch
+zsmalloc-account-the-number-of-compacted-pages-correctly.patch
+swap-fix-swapfile-read-write-offset.patch
diff --git a/queue-5.4/swap-fix-swapfile-read-write-offset.patch b/queue-5.4/swap-fix-swapfile-read-write-offset.patch
new file mode 100644 (file)
index 0000000..447d00c
--- /dev/null
@@ -0,0 +1,69 @@
+From caf6912f3f4af7232340d500a4a2008f81b93f14 Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Tue, 2 Mar 2021 14:53:21 -0700
+Subject: swap: fix swapfile read/write offset
+
+From: Jens Axboe <axboe@kernel.dk>
+
+commit caf6912f3f4af7232340d500a4a2008f81b93f14 upstream.
+
+We're not factoring in the start of the file for where to write and
+read the swapfile, which leads to very unfortunate side effects of
+writing where we should not be...
+
+Fixes: dd6bd0d9c7db ("swap: use bdev_read_page() / bdev_write_page()")
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Cc: Anthony Iliopoulos <ailiop@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/swap.h |    1 +
+ mm/page_io.c         |    5 -----
+ mm/swapfile.c        |   13 +++++++++++++
+ 3 files changed, 14 insertions(+), 5 deletions(-)
+
+--- a/include/linux/swap.h
++++ b/include/linux/swap.h
+@@ -473,6 +473,7 @@ struct backing_dev_info;
+ extern int init_swap_address_space(unsigned int type, unsigned long nr_pages);
+ extern void exit_swap_address_space(unsigned int type);
+ extern struct swap_info_struct *get_swap_device(swp_entry_t entry);
++sector_t swap_page_sector(struct page *page);
+ static inline void put_swap_device(struct swap_info_struct *si)
+ {
+--- a/mm/page_io.c
++++ b/mm/page_io.c
+@@ -260,11 +260,6 @@ out:
+       return ret;
+ }
+-static sector_t swap_page_sector(struct page *page)
+-{
+-      return (sector_t)__page_file_index(page) << (PAGE_SHIFT - 9);
+-}
+-
+ static inline void count_swpout_vm_event(struct page *page)
+ {
+ #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+--- a/mm/swapfile.c
++++ b/mm/swapfile.c
+@@ -221,6 +221,19 @@ offset_to_swap_extent(struct swap_info_s
+       BUG();
+ }
++sector_t swap_page_sector(struct page *page)
++{
++      struct swap_info_struct *sis = page_swap_info(page);
++      struct swap_extent *se;
++      sector_t sector;
++      pgoff_t offset;
++
++      offset = __page_file_index(page);
++      se = offset_to_swap_extent(sis, offset);
++      sector = se->start_block + (offset - se->start_page);
++      return sector << (PAGE_SHIFT - 9);
++}
++
+ /*
+  * swap allocation tell device that a cluster of swap can now be discarded,
+  * to allow the swap device to optimize its wear-levelling.
diff --git a/queue-5.4/sysfs-add-sysfs_emit-and-sysfs_emit_at-to-format-sysfs-output.patch b/queue-5.4/sysfs-add-sysfs_emit-and-sysfs_emit_at-to-format-sysfs-output.patch
new file mode 100644 (file)
index 0000000..79fa578
--- /dev/null
@@ -0,0 +1,151 @@
+From 2efc459d06f1630001e3984854848a5647086232 Mon Sep 17 00:00:00 2001
+From: Joe Perches <joe@perches.com>
+Date: Wed, 16 Sep 2020 13:40:38 -0700
+Subject: sysfs: Add sysfs_emit and sysfs_emit_at to format sysfs output
+
+From: Joe Perches <joe@perches.com>
+
+commit 2efc459d06f1630001e3984854848a5647086232 upstream.
+
+Output defects can exist in sysfs content using sprintf and snprintf.
+
+sprintf does not know the PAGE_SIZE maximum of the temporary buffer
+used for outputting sysfs content and it's possible to overrun the
+PAGE_SIZE buffer length.
+
+Add a generic sysfs_emit function that knows that the size of the
+temporary buffer and ensures that no overrun is done.
+
+Add a generic sysfs_emit_at function that can be used in multiple
+call situations that also ensures that no overrun is done.
+
+Validate the output buffer argument to be page aligned.
+Validate the offset len argument to be within the PAGE_SIZE buf.
+
+Signed-off-by: Joe Perches <joe@perches.com>
+Link: https://lore.kernel.org/r/884235202216d464d61ee975f7465332c86f76b2.1600285923.git.joe@perches.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/filesystems/sysfs.txt |    8 +----
+ fs/sysfs/file.c                     |   55 ++++++++++++++++++++++++++++++++++++
+ include/linux/sysfs.h               |   16 ++++++++++
+ 3 files changed, 74 insertions(+), 5 deletions(-)
+
+--- a/Documentation/filesystems/sysfs.txt
++++ b/Documentation/filesystems/sysfs.txt
+@@ -232,12 +232,10 @@ Other notes:
+   is 4096. 
+ - show() methods should return the number of bytes printed into the
+-  buffer. This is the return value of scnprintf().
++  buffer.
+-- show() must not use snprintf() when formatting the value to be
+-  returned to user space. If you can guarantee that an overflow
+-  will never happen you can use sprintf() otherwise you must use
+-  scnprintf().
++- show() should only use sysfs_emit() or sysfs_emit_at() when formatting
++  the value to be returned to user space.
+ - store() should return the number of bytes used from the buffer. If the
+   entire buffer has been used, just return the count argument.
+--- a/fs/sysfs/file.c
++++ b/fs/sysfs/file.c
+@@ -15,6 +15,7 @@
+ #include <linux/list.h>
+ #include <linux/mutex.h>
+ #include <linux/seq_file.h>
++#include <linux/mm.h>
+ #include "sysfs.h"
+@@ -558,3 +559,57 @@ void sysfs_remove_bin_file(struct kobjec
+       kernfs_remove_by_name(kobj->sd, attr->attr.name);
+ }
+ EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
++
++/**
++ *    sysfs_emit - scnprintf equivalent, aware of PAGE_SIZE buffer.
++ *    @buf:   start of PAGE_SIZE buffer.
++ *    @fmt:   format
++ *    @...:   optional arguments to @format
++ *
++ *
++ * Returns number of characters written to @buf.
++ */
++int sysfs_emit(char *buf, const char *fmt, ...)
++{
++      va_list args;
++      int len;
++
++      if (WARN(!buf || offset_in_page(buf),
++               "invalid sysfs_emit: buf:%p\n", buf))
++              return 0;
++
++      va_start(args, fmt);
++      len = vscnprintf(buf, PAGE_SIZE, fmt, args);
++      va_end(args);
++
++      return len;
++}
++EXPORT_SYMBOL_GPL(sysfs_emit);
++
++/**
++ *    sysfs_emit_at - scnprintf equivalent, aware of PAGE_SIZE buffer.
++ *    @buf:   start of PAGE_SIZE buffer.
++ *    @at:    offset in @buf to start write in bytes
++ *            @at must be >= 0 && < PAGE_SIZE
++ *    @fmt:   format
++ *    @...:   optional arguments to @fmt
++ *
++ *
++ * Returns number of characters written starting at &@buf[@at].
++ */
++int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
++{
++      va_list args;
++      int len;
++
++      if (WARN(!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE,
++               "invalid sysfs_emit_at: buf:%p at:%d\n", buf, at))
++              return 0;
++
++      va_start(args, fmt);
++      len = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
++      va_end(args);
++
++      return len;
++}
++EXPORT_SYMBOL_GPL(sysfs_emit_at);
+--- a/include/linux/sysfs.h
++++ b/include/linux/sysfs.h
+@@ -310,6 +310,11 @@ static inline void sysfs_enable_ns(struc
+       return kernfs_enable_ns(kn);
+ }
++__printf(2, 3)
++int sysfs_emit(char *buf, const char *fmt, ...);
++__printf(3, 4)
++int sysfs_emit_at(char *buf, int at, const char *fmt, ...);
++
+ #else /* CONFIG_SYSFS */
+ static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
+@@ -522,6 +527,17 @@ static inline void sysfs_enable_ns(struc
+ {
+ }
++__printf(2, 3)
++static inline int sysfs_emit(char *buf, const char *fmt, ...)
++{
++      return 0;
++}
++
++__printf(3, 4)
++static inline int sysfs_emit_at(char *buf, int at, const char *fmt, ...)
++{
++      return 0;
++}
+ #endif /* CONFIG_SYSFS */
+ static inline int __must_check sysfs_create_file(struct kobject *kobj,
diff --git a/queue-5.4/xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch b/queue-5.4/xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch
new file mode 100644 (file)
index 0000000..94013ba
--- /dev/null
@@ -0,0 +1,143 @@
+From 8310b77b48c5558c140e7a57a702e7819e62f04e Mon Sep 17 00:00:00 2001
+From: Jan Beulich <jbeulich@suse.com>
+Date: Thu, 25 Feb 2021 16:34:43 +0100
+Subject: Xen/gnttab: handle p2m update errors on a per-slot basis
+
+From: Jan Beulich <jbeulich@suse.com>
+
+commit 8310b77b48c5558c140e7a57a702e7819e62f04e upstream.
+
+Bailing immediately from set_foreign_p2m_mapping() upon a p2m updating
+error leaves the full batch in an ambiguous state as far as the caller
+is concerned. Instead flags respective slots as bad, unmapping what
+was mapped there right away.
+
+HYPERVISOR_grant_table_op()'s return value and the individual unmap
+slots' status fields get used only for a one-time - there's not much we
+can do in case of a failure.
+
+Note that there's no GNTST_enomem or alike, so GNTST_general_error gets
+used.
+
+The map ops' handle fields get overwritten just to be on the safe side.
+
+This is part of XSA-367.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Link: https://lore.kernel.org/r/96cccf5d-e756-5f53-b91a-ea269bfb9be0@suse.com
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/xen/p2m.c |   35 +++++++++++++++++++++++++++++++----
+ arch/x86/xen/p2m.c |   44 +++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 72 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/xen/p2m.c
++++ b/arch/arm/xen/p2m.c
+@@ -93,12 +93,39 @@ int set_foreign_p2m_mapping(struct gntta
+       int i;
+       for (i = 0; i < count; i++) {
++              struct gnttab_unmap_grant_ref unmap;
++              int rc;
++
+               if (map_ops[i].status)
+                       continue;
+-              if (unlikely(!set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
+-                                  map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT))) {
+-                      return -ENOMEM;
+-              }
++              if (likely(set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
++                                  map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT)))
++                      continue;
++
++              /*
++               * Signal an error for this slot. This in turn requires
++               * immediate unmapping.
++               */
++              map_ops[i].status = GNTST_general_error;
++              unmap.host_addr = map_ops[i].host_addr,
++              unmap.handle = map_ops[i].handle;
++              map_ops[i].handle = ~0;
++              if (map_ops[i].flags & GNTMAP_device_map)
++                      unmap.dev_bus_addr = map_ops[i].dev_bus_addr;
++              else
++                      unmap.dev_bus_addr = 0;
++
++              /*
++               * Pre-populate the status field, to be recognizable in
++               * the log message below.
++               */
++              unmap.status = 1;
++
++              rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
++                                             &unmap, 1);
++              if (rc || unmap.status != GNTST_okay)
++                      pr_err_once("gnttab unmap failed: rc=%d st=%d\n",
++                                  rc, unmap.status);
+       }
+       return 0;
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -714,6 +714,8 @@ int set_foreign_p2m_mapping(struct gntta
+       for (i = 0; i < count; i++) {
+               unsigned long mfn, pfn;
++              struct gnttab_unmap_grant_ref unmap[2];
++              int rc;
+               /* Do not add to override if the map failed. */
+               if (map_ops[i].status != GNTST_okay ||
+@@ -731,10 +733,46 @@ int set_foreign_p2m_mapping(struct gntta
+               WARN(pfn_to_mfn(pfn) != INVALID_P2M_ENTRY, "page must be ballooned");
+-              if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) {
+-                      ret = -ENOMEM;
+-                      goto out;
++              if (likely(set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
++                      continue;
++
++              /*
++               * Signal an error for this slot. This in turn requires
++               * immediate unmapping.
++               */
++              map_ops[i].status = GNTST_general_error;
++              unmap[0].host_addr = map_ops[i].host_addr,
++              unmap[0].handle = map_ops[i].handle;
++              map_ops[i].handle = ~0;
++              if (map_ops[i].flags & GNTMAP_device_map)
++                      unmap[0].dev_bus_addr = map_ops[i].dev_bus_addr;
++              else
++                      unmap[0].dev_bus_addr = 0;
++
++              if (kmap_ops) {
++                      kmap_ops[i].status = GNTST_general_error;
++                      unmap[1].host_addr = kmap_ops[i].host_addr,
++                      unmap[1].handle = kmap_ops[i].handle;
++                      kmap_ops[i].handle = ~0;
++                      if (kmap_ops[i].flags & GNTMAP_device_map)
++                              unmap[1].dev_bus_addr = kmap_ops[i].dev_bus_addr;
++                      else
++                              unmap[1].dev_bus_addr = 0;
+               }
++
++              /*
++               * Pre-populate both status fields, to be recognizable in
++               * the log message below.
++               */
++              unmap[0].status = 1;
++              unmap[1].status = 1;
++
++              rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
++                                             unmap, 1 + !!kmap_ops);
++              if (rc || unmap[0].status != GNTST_okay ||
++                  unmap[1].status != GNTST_okay)
++                      pr_err_once("gnttab unmap failed: rc=%d st0=%d st1=%d\n",
++                                  rc, unmap[0].status, unmap[1].status);
+       }
+ out:
diff --git a/queue-5.4/xen-netback-respect-gnttab_map_refs-s-return-value.patch b/queue-5.4/xen-netback-respect-gnttab_map_refs-s-return-value.patch
new file mode 100644 (file)
index 0000000..27bd6e6
--- /dev/null
@@ -0,0 +1,53 @@
+From 2991397d23ec597405b116d96de3813420bdcbc3 Mon Sep 17 00:00:00 2001
+From: Jan Beulich <jbeulich@suse.com>
+Date: Thu, 25 Feb 2021 16:35:15 +0100
+Subject: xen-netback: respect gnttab_map_refs()'s return value
+
+From: Jan Beulich <jbeulich@suse.com>
+
+commit 2991397d23ec597405b116d96de3813420bdcbc3 upstream.
+
+Commit 3194a1746e8a ("xen-netback: don't "handle" error by BUG()")
+dropped respective a BUG_ON() without noticing that with this the
+variable's value wouldn't be consumed anymore. With gnttab_set_map_op()
+setting all status fields to a non-zero value, in case of an error no
+slot should have a status of GNTST_okay (zero).
+
+This is part of XSA-367.
+
+Cc: <stable@vger.kernel.org>
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Link: https://lore.kernel.org/r/d933f495-619a-0086-5fb4-1ec3cf81a8fc@suse.com
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/xen-netback/netback.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -1335,11 +1335,21 @@ int xenvif_tx_action(struct xenvif_queue
+               return 0;
+       gnttab_batch_copy(queue->tx_copy_ops, nr_cops);
+-      if (nr_mops != 0)
++      if (nr_mops != 0) {
+               ret = gnttab_map_refs(queue->tx_map_ops,
+                                     NULL,
+                                     queue->pages_to_map,
+                                     nr_mops);
++              if (ret) {
++                      unsigned int i;
++
++                      netdev_err(queue->vif->dev, "Map fail: nr %u ret %d\n",
++                                 nr_mops, ret);
++                      for (i = 0; i < nr_mops; ++i)
++                              WARN_ON_ONCE(queue->tx_map_ops[i].status ==
++                                           GNTST_okay);
++              }
++      }
+       work_done = xenvif_tx_submit(queue);
diff --git a/queue-5.4/zsmalloc-account-the-number-of-compacted-pages-correctly.patch b/queue-5.4/zsmalloc-account-the-number-of-compacted-pages-correctly.patch
new file mode 100644 (file)
index 0000000..1b801d6
--- /dev/null
@@ -0,0 +1,134 @@
+From 2395928158059b8f9858365fce7713ce7fef62e4 Mon Sep 17 00:00:00 2001
+From: Rokudo Yan <wu-yan@tcl.com>
+Date: Thu, 25 Feb 2021 17:18:31 -0800
+Subject: zsmalloc: account the number of compacted pages correctly
+
+From: Rokudo Yan <wu-yan@tcl.com>
+
+commit 2395928158059b8f9858365fce7713ce7fef62e4 upstream.
+
+There exists multiple path may do zram compaction concurrently.
+1. auto-compaction triggered during memory reclaim
+2. userspace utils write zram<id>/compaction node
+
+So, multiple threads may call zs_shrinker_scan/zs_compact concurrently.
+But pages_compacted is a per zsmalloc pool variable and modification
+of the variable is not serialized(through under class->lock).
+There are two issues here:
+1. the pages_compacted may not equal to total number of pages
+freed(due to concurrently add).
+2. zs_shrinker_scan may not return the correct number of pages
+freed(issued by current shrinker).
+
+The fix is simple:
+1. account the number of pages freed in zs_compact locally.
+2. use actomic variable pages_compacted to accumulate total number.
+
+Link: https://lkml.kernel.org/r/20210202122235.26885-1-wu-yan@tcl.com
+Fixes: 860c707dca155a56 ("zsmalloc: account the number of compacted pages")
+Signed-off-by: Rokudo Yan <wu-yan@tcl.com>
+Cc: Minchan Kim <minchan@kernel.org>
+Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/block/zram/zram_drv.c |    2 +-
+ include/linux/zsmalloc.h      |    2 +-
+ mm/zsmalloc.c                 |   17 +++++++++++------
+ 3 files changed, 13 insertions(+), 8 deletions(-)
+
+--- a/drivers/block/zram/zram_drv.c
++++ b/drivers/block/zram/zram_drv.c
+@@ -1072,7 +1072,7 @@ static ssize_t mm_stat_show(struct devic
+                       zram->limit_pages << PAGE_SHIFT,
+                       max_used << PAGE_SHIFT,
+                       (u64)atomic64_read(&zram->stats.same_pages),
+-                      pool_stats.pages_compacted,
++                      atomic_long_read(&pool_stats.pages_compacted),
+                       (u64)atomic64_read(&zram->stats.huge_pages));
+       up_read(&zram->init_lock);
+--- a/include/linux/zsmalloc.h
++++ b/include/linux/zsmalloc.h
+@@ -35,7 +35,7 @@ enum zs_mapmode {
+ struct zs_pool_stats {
+       /* How many pages were migrated (freed) */
+-      unsigned long pages_compacted;
++      atomic_long_t pages_compacted;
+ };
+ struct zs_pool;
+--- a/mm/zsmalloc.c
++++ b/mm/zsmalloc.c
+@@ -2216,11 +2216,13 @@ static unsigned long zs_can_compact(stru
+       return obj_wasted * class->pages_per_zspage;
+ }
+-static void __zs_compact(struct zs_pool *pool, struct size_class *class)
++static unsigned long __zs_compact(struct zs_pool *pool,
++                                struct size_class *class)
+ {
+       struct zs_compact_control cc;
+       struct zspage *src_zspage;
+       struct zspage *dst_zspage = NULL;
++      unsigned long pages_freed = 0;
+       spin_lock(&class->lock);
+       while ((src_zspage = isolate_zspage(class, true))) {
+@@ -2250,7 +2252,7 @@ static void __zs_compact(struct zs_pool
+               putback_zspage(class, dst_zspage);
+               if (putback_zspage(class, src_zspage) == ZS_EMPTY) {
+                       free_zspage(pool, class, src_zspage);
+-                      pool->stats.pages_compacted += class->pages_per_zspage;
++                      pages_freed += class->pages_per_zspage;
+               }
+               spin_unlock(&class->lock);
+               cond_resched();
+@@ -2261,12 +2263,15 @@ static void __zs_compact(struct zs_pool
+               putback_zspage(class, src_zspage);
+       spin_unlock(&class->lock);
++
++      return pages_freed;
+ }
+ unsigned long zs_compact(struct zs_pool *pool)
+ {
+       int i;
+       struct size_class *class;
++      unsigned long pages_freed = 0;
+       for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) {
+               class = pool->size_class[i];
+@@ -2274,10 +2279,11 @@ unsigned long zs_compact(struct zs_pool
+                       continue;
+               if (class->index != i)
+                       continue;
+-              __zs_compact(pool, class);
++              pages_freed += __zs_compact(pool, class);
+       }
++      atomic_long_add(pages_freed, &pool->stats.pages_compacted);
+-      return pool->stats.pages_compacted;
++      return pages_freed;
+ }
+ EXPORT_SYMBOL_GPL(zs_compact);
+@@ -2294,13 +2300,12 @@ static unsigned long zs_shrinker_scan(st
+       struct zs_pool *pool = container_of(shrinker, struct zs_pool,
+                       shrinker);
+-      pages_freed = pool->stats.pages_compacted;
+       /*
+        * Compact classes and calculate compaction delta.
+        * Can run concurrently with a manually triggered
+        * (by user) compaction.
+        */
+-      pages_freed = zs_compact(pool) - pages_freed;
++      pages_freed = zs_compact(pool);
+       return pages_freed ? pages_freed : SHRINK_STOP;
+ }