]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 30 May 2021 14:19:37 +0000 (16:19 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 30 May 2021 14:19:37 +0000 (16:19 +0200)
added patches:
bluetooth-cmtp-fix-file-refcount-when-cmtp_attach_device-fails.patch
net-mlx4-fix-eeprom-dump-support.patch
nfs-don-t-corrupt-the-value-of-pg_bytes_written-in-nfs_do_recoalesce.patch
nfs-fix-an-incorrect-limit-in-filelayout_decode_layout.patch
nfsv4-fix-v4.0-v4.1-seek_data-return-enotsupp-when-set-nfs_v4_2-config.patch
revert-net-tipc-fix-a-double-free-in-tipc_sk_mcast_rcv.patch
tipc-skb_linearize-the-head-skb-when-reassembling-msgs.patch

queue-4.9/bluetooth-cmtp-fix-file-refcount-when-cmtp_attach_device-fails.patch [new file with mode: 0644]
queue-4.9/net-mlx4-fix-eeprom-dump-support.patch [new file with mode: 0644]
queue-4.9/nfs-don-t-corrupt-the-value-of-pg_bytes_written-in-nfs_do_recoalesce.patch [new file with mode: 0644]
queue-4.9/nfs-fix-an-incorrect-limit-in-filelayout_decode_layout.patch [new file with mode: 0644]
queue-4.9/nfsv4-fix-v4.0-v4.1-seek_data-return-enotsupp-when-set-nfs_v4_2-config.patch [new file with mode: 0644]
queue-4.9/revert-net-tipc-fix-a-double-free-in-tipc_sk_mcast_rcv.patch [new file with mode: 0644]
queue-4.9/series
queue-4.9/tipc-skb_linearize-the-head-skb-when-reassembling-msgs.patch [new file with mode: 0644]

diff --git a/queue-4.9/bluetooth-cmtp-fix-file-refcount-when-cmtp_attach_device-fails.patch b/queue-4.9/bluetooth-cmtp-fix-file-refcount-when-cmtp_attach_device-fails.patch
new file mode 100644 (file)
index 0000000..530250a
--- /dev/null
@@ -0,0 +1,40 @@
+From 8da3a0b87f4f1c3a3bbc4bfb78cf68476e97d183 Mon Sep 17 00:00:00 2001
+From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
+Date: Tue, 13 Apr 2021 13:21:03 -0300
+Subject: Bluetooth: cmtp: fix file refcount when cmtp_attach_device fails
+
+From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
+
+commit 8da3a0b87f4f1c3a3bbc4bfb78cf68476e97d183 upstream.
+
+When cmtp_attach_device fails, cmtp_add_connection returns the error value
+which leads to the caller to doing fput through sockfd_put. But
+cmtp_session kthread, which is stopped in this path will also call fput,
+leading to a potential refcount underflow or a use-after-free.
+
+Add a refcount before we signal the kthread to stop. The kthread will try
+to grab the cmtp_session_sem mutex before doing the fput, which is held
+when get_file is called, so there should be no races there.
+
+Reported-by: Ryota Shiga
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
+Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/cmtp/core.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/net/bluetooth/cmtp/core.c
++++ b/net/bluetooth/cmtp/core.c
+@@ -391,6 +391,11 @@ int cmtp_add_connection(struct cmtp_conn
+       if (!(session->flags & BIT(CMTP_LOOPBACK))) {
+               err = cmtp_attach_device(session);
+               if (err < 0) {
++                      /* Caller will call fput in case of failure, and so
++                       * will cmtp_session kthread.
++                       */
++                      get_file(session->sock->file);
++
+                       atomic_inc(&session->terminate);
+                       wake_up_interruptible(sk_sleep(session->sock->sk));
+                       up_write(&cmtp_session_sem);
diff --git a/queue-4.9/net-mlx4-fix-eeprom-dump-support.patch b/queue-4.9/net-mlx4-fix-eeprom-dump-support.patch
new file mode 100644 (file)
index 0000000..7b5732e
--- /dev/null
@@ -0,0 +1,198 @@
+From db825feefc6868896fed5e361787ba3bee2fd906 Mon Sep 17 00:00:00 2001
+From: Vladyslav Tarasiuk <vladyslavt@nvidia.com>
+Date: Sun, 9 May 2021 09:43:18 +0300
+Subject: net/mlx4: Fix EEPROM dump support
+
+From: Vladyslav Tarasiuk <vladyslavt@nvidia.com>
+
+commit db825feefc6868896fed5e361787ba3bee2fd906 upstream.
+
+Fix SFP and QSFP* EEPROM queries by setting i2c_address, offset and page
+number correctly. For SFP set the following params:
+- I2C address for offsets 0-255 is 0x50. For 256-511 - 0x51.
+- Page number is zero.
+- Offset is 0-255.
+
+At the same time, QSFP* parameters are different:
+- I2C address is always 0x50.
+- Page number is not limited to zero.
+- Offset is 0-255 for page zero and 128-255 for others.
+
+To set parameters accordingly to cable used, implement function to query
+module ID and implement respective helper functions to set parameters
+correctly.
+
+Fixes: 135dd9594f12 ("net/mlx4_en: ethtool, Remove unsupported SFP EEPROM high pages query")
+Signed-off-by: Vladyslav Tarasiuk <vladyslavt@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/mellanox/mlx4/en_ethtool.c |    4 
+ drivers/net/ethernet/mellanox/mlx4/port.c       |  107 +++++++++++++++++++++++-
+ 2 files changed, 104 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
++++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+@@ -1931,8 +1931,6 @@ static int mlx4_en_set_tunable(struct ne
+       return ret;
+ }
+-#define MLX4_EEPROM_PAGE_LEN 256
+-
+ static int mlx4_en_get_module_info(struct net_device *dev,
+                                  struct ethtool_modinfo *modinfo)
+ {
+@@ -1967,7 +1965,7 @@ static int mlx4_en_get_module_info(struc
+               break;
+       case MLX4_MODULE_ID_SFP:
+               modinfo->type = ETH_MODULE_SFF_8472;
+-              modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN;
++              modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+               break;
+       default:
+               return -ENOSYS;
+--- a/drivers/net/ethernet/mellanox/mlx4/port.c
++++ b/drivers/net/ethernet/mellanox/mlx4/port.c
+@@ -1856,6 +1856,7 @@ EXPORT_SYMBOL(mlx4_get_roce_gid_from_sla
+ #define I2C_ADDR_LOW  0x50
+ #define I2C_ADDR_HIGH 0x51
+ #define I2C_PAGE_SIZE 256
++#define I2C_HIGH_PAGE_SIZE 128
+ /* Module Info Data */
+ struct mlx4_cable_info {
+@@ -1909,6 +1910,88 @@ static inline const char *cable_info_mad
+       return "Unknown Error";
+ }
++static int mlx4_get_module_id(struct mlx4_dev *dev, u8 port, u8 *module_id)
++{
++      struct mlx4_cmd_mailbox *inbox, *outbox;
++      struct mlx4_mad_ifc *inmad, *outmad;
++      struct mlx4_cable_info *cable_info;
++      int ret;
++
++      inbox = mlx4_alloc_cmd_mailbox(dev);
++      if (IS_ERR(inbox))
++              return PTR_ERR(inbox);
++
++      outbox = mlx4_alloc_cmd_mailbox(dev);
++      if (IS_ERR(outbox)) {
++              mlx4_free_cmd_mailbox(dev, inbox);
++              return PTR_ERR(outbox);
++      }
++
++      inmad = (struct mlx4_mad_ifc *)(inbox->buf);
++      outmad = (struct mlx4_mad_ifc *)(outbox->buf);
++
++      inmad->method = 0x1; /* Get */
++      inmad->class_version = 0x1;
++      inmad->mgmt_class = 0x1;
++      inmad->base_version = 0x1;
++      inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */
++
++      cable_info = (struct mlx4_cable_info *)inmad->data;
++      cable_info->dev_mem_address = 0;
++      cable_info->page_num = 0;
++      cable_info->i2c_addr = I2C_ADDR_LOW;
++      cable_info->size = cpu_to_be16(1);
++
++      ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3,
++                         MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C,
++                         MLX4_CMD_NATIVE);
++      if (ret)
++              goto out;
++
++      if (be16_to_cpu(outmad->status)) {
++              /* Mad returned with bad status */
++              ret = be16_to_cpu(outmad->status);
++              mlx4_warn(dev,
++                        "MLX4_CMD_MAD_IFC Get Module ID attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n",
++                        0xFF60, port, I2C_ADDR_LOW, 0, 1, ret,
++                        cable_info_mad_err_str(ret));
++              ret = -ret;
++              goto out;
++      }
++      cable_info = (struct mlx4_cable_info *)outmad->data;
++      *module_id = cable_info->data[0];
++out:
++      mlx4_free_cmd_mailbox(dev, inbox);
++      mlx4_free_cmd_mailbox(dev, outbox);
++      return ret;
++}
++
++static void mlx4_sfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
++{
++      *i2c_addr = I2C_ADDR_LOW;
++      *page_num = 0;
++
++      if (*offset < I2C_PAGE_SIZE)
++              return;
++
++      *i2c_addr = I2C_ADDR_HIGH;
++      *offset -= I2C_PAGE_SIZE;
++}
++
++static void mlx4_qsfp_eeprom_params_set(u8 *i2c_addr, u8 *page_num, u16 *offset)
++{
++      /* Offsets 0-255 belong to page 0.
++       * Offsets 256-639 belong to pages 01, 02, 03.
++       * For example, offset 400 is page 02: 1 + (400 - 256) / 128 = 2
++       */
++      if (*offset < I2C_PAGE_SIZE)
++              *page_num = 0;
++      else
++              *page_num = 1 + (*offset - I2C_PAGE_SIZE) / I2C_HIGH_PAGE_SIZE;
++      *i2c_addr = I2C_ADDR_LOW;
++      *offset -= *page_num * I2C_HIGH_PAGE_SIZE;
++}
++
+ /**
+  * mlx4_get_module_info - Read cable module eeprom data
+  * @dev: mlx4_dev.
+@@ -1928,12 +2011,30 @@ int mlx4_get_module_info(struct mlx4_dev
+       struct mlx4_cmd_mailbox *inbox, *outbox;
+       struct mlx4_mad_ifc *inmad, *outmad;
+       struct mlx4_cable_info *cable_info;
+-      u16 i2c_addr;
++      u8 module_id, i2c_addr, page_num;
+       int ret;
+       if (size > MODULE_INFO_MAX_READ)
+               size = MODULE_INFO_MAX_READ;
++      ret = mlx4_get_module_id(dev, port, &module_id);
++      if (ret)
++              return ret;
++
++      switch (module_id) {
++      case MLX4_MODULE_ID_SFP:
++              mlx4_sfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
++              break;
++      case MLX4_MODULE_ID_QSFP:
++      case MLX4_MODULE_ID_QSFP_PLUS:
++      case MLX4_MODULE_ID_QSFP28:
++              mlx4_qsfp_eeprom_params_set(&i2c_addr, &page_num, &offset);
++              break;
++      default:
++              mlx4_err(dev, "Module ID not recognized: %#x\n", module_id);
++              return -EINVAL;
++      }
++
+       inbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(inbox))
+               return PTR_ERR(inbox);
+@@ -1959,11 +2060,9 @@ int mlx4_get_module_info(struct mlx4_dev
+                */
+               size -= offset + size - I2C_PAGE_SIZE;
+-      i2c_addr = I2C_ADDR_LOW;
+-
+       cable_info = (struct mlx4_cable_info *)inmad->data;
+       cable_info->dev_mem_address = cpu_to_be16(offset);
+-      cable_info->page_num = 0;
++      cable_info->page_num = page_num;
+       cable_info->i2c_addr = i2c_addr;
+       cable_info->size = cpu_to_be16(size);
diff --git a/queue-4.9/nfs-don-t-corrupt-the-value-of-pg_bytes_written-in-nfs_do_recoalesce.patch b/queue-4.9/nfs-don-t-corrupt-the-value-of-pg_bytes_written-in-nfs_do_recoalesce.patch
new file mode 100644 (file)
index 0000000..8313ef5
--- /dev/null
@@ -0,0 +1,52 @@
+From 0d0ea309357dea0d85a82815f02157eb7fcda39f Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+Date: Tue, 25 May 2021 10:40:12 -0400
+Subject: NFS: Don't corrupt the value of pg_bytes_written in nfs_do_recoalesce()
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+commit 0d0ea309357dea0d85a82815f02157eb7fcda39f upstream.
+
+The value of mirror->pg_bytes_written should only be updated after a
+successful attempt to flush out the requests on the list.
+
+Fixes: a7d42ddb3099 ("nfs: add mirroring support to pgio layer")
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/pagelist.c |   12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+--- a/fs/nfs/pagelist.c
++++ b/fs/nfs/pagelist.c
+@@ -952,17 +952,16 @@ static void nfs_pageio_doio(struct nfs_p
+ {
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
+-
+       if (!list_empty(&mirror->pg_list)) {
+               int error = desc->pg_ops->pg_doio(desc);
+               if (error < 0)
+                       desc->pg_error = error;
+-              else
++              if (list_empty(&mirror->pg_list)) {
+                       mirror->pg_bytes_written += mirror->pg_count;
+-      }
+-      if (list_empty(&mirror->pg_list)) {
+-              mirror->pg_count = 0;
+-              mirror->pg_base = 0;
++                      mirror->pg_count = 0;
++                      mirror->pg_base = 0;
++                      mirror->pg_recoalesce = 0;
++              }
+       }
+ }
+@@ -1061,7 +1060,6 @@ static int nfs_do_recoalesce(struct nfs_
+       do {
+               list_splice_init(&mirror->pg_list, &head);
+-              mirror->pg_bytes_written -= mirror->pg_count;
+               mirror->pg_count = 0;
+               mirror->pg_base = 0;
+               mirror->pg_recoalesce = 0;
diff --git a/queue-4.9/nfs-fix-an-incorrect-limit-in-filelayout_decode_layout.patch b/queue-4.9/nfs-fix-an-incorrect-limit-in-filelayout_decode_layout.patch
new file mode 100644 (file)
index 0000000..770a4ac
--- /dev/null
@@ -0,0 +1,34 @@
+From 769b01ea68b6c49dc3cde6adf7e53927dacbd3a8 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Tue, 11 May 2021 11:49:42 +0300
+Subject: NFS: fix an incorrect limit in filelayout_decode_layout()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit 769b01ea68b6c49dc3cde6adf7e53927dacbd3a8 upstream.
+
+The "sizeof(struct nfs_fh)" is two bytes too large and could lead to
+memory corruption.  It should be NFS_MAXFHSIZE because that's the size
+of the ->data[] buffer.
+
+I reversed the size of the arguments to put the variable on the left.
+
+Fixes: 16b374ca439f ("NFSv4.1: pnfs: filelayout: add driver's LAYOUTGET and GETDEVICEINFO infrastructure")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/filelayout/filelayout.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/nfs/filelayout/filelayout.c
++++ b/fs/nfs/filelayout/filelayout.c
+@@ -726,7 +726,7 @@ filelayout_decode_layout(struct pnfs_lay
+               if (unlikely(!p))
+                       goto out_err;
+               fl->fh_array[i]->size = be32_to_cpup(p++);
+-              if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
++              if (fl->fh_array[i]->size > NFS_MAXFHSIZE) {
+                       printk(KERN_ERR "NFS: Too big fh %d received %d\n",
+                              i, fl->fh_array[i]->size);
+                       goto out_err;
diff --git a/queue-4.9/nfsv4-fix-v4.0-v4.1-seek_data-return-enotsupp-when-set-nfs_v4_2-config.patch b/queue-4.9/nfsv4-fix-v4.0-v4.1-seek_data-return-enotsupp-when-set-nfs_v4_2-config.patch
new file mode 100644 (file)
index 0000000..1e04342
--- /dev/null
@@ -0,0 +1,36 @@
+From e67afa7ee4a59584d7253e45d7f63b9528819a13 Mon Sep 17 00:00:00 2001
+From: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
+Date: Tue, 25 May 2021 23:32:35 -0400
+Subject: NFSv4: Fix v4.0/v4.1 SEEK_DATA return -ENOTSUPP when set NFS_V4_2 config
+
+From: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
+
+commit e67afa7ee4a59584d7253e45d7f63b9528819a13 upstream.
+
+Since commit bdcc2cd14e4e ("NFSv4.2: handle NFS-specific llseek errors"),
+nfs42_proc_llseek would return -EOPNOTSUPP rather than -ENOTSUPP when
+SEEK_DATA on NFSv4.0/v4.1.
+
+This will lead xfstests generic/285 not run on NFSv4.0/v4.1 when set the
+CONFIG_NFS_V4_2, rather than run failed.
+
+Fixes: bdcc2cd14e4e ("NFSv4.2: handle NFS-specific llseek errors")
+Cc: <stable.vger.kernel.org> # 4.2
+Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/nfs4file.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/nfs/nfs4file.c
++++ b/fs/nfs/nfs4file.c
+@@ -147,7 +147,7 @@ static loff_t nfs4_file_llseek(struct fi
+       case SEEK_HOLE:
+       case SEEK_DATA:
+               ret = nfs42_proc_llseek(filep, offset, whence);
+-              if (ret != -ENOTSUPP)
++              if (ret != -EOPNOTSUPP)
+                       return ret;
+       default:
+               return nfs_file_llseek(filep, offset, whence);
diff --git a/queue-4.9/revert-net-tipc-fix-a-double-free-in-tipc_sk_mcast_rcv.patch b/queue-4.9/revert-net-tipc-fix-a-double-free-in-tipc_sk_mcast_rcv.patch
new file mode 100644 (file)
index 0000000..e0c3ff1
--- /dev/null
@@ -0,0 +1,36 @@
+From 75016891357a628d2b8acc09e2b9b2576c18d318 Mon Sep 17 00:00:00 2001
+From: Hoang Le <hoang.h.le@dektech.com.au>
+Date: Fri, 14 May 2021 08:23:03 +0700
+Subject: Revert "net:tipc: Fix a double free in tipc_sk_mcast_rcv"
+
+From: Hoang Le <hoang.h.le@dektech.com.au>
+
+commit 75016891357a628d2b8acc09e2b9b2576c18d318 upstream.
+
+This reverts commit 6bf24dc0cc0cc43b29ba344b66d78590e687e046.
+Above fix is not correct and caused memory leak issue.
+
+Fixes: 6bf24dc0cc0c ("net:tipc: Fix a double free in tipc_sk_mcast_rcv")
+Acked-by: Jon Maloy <jmaloy@redhat.com>
+Acked-by: Tung Nguyen <tung.q.nguyen@dektech.com.au>
+Signed-off-by: Hoang Le <hoang.h.le@dektech.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/tipc/socket.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/net/tipc/socket.c
++++ b/net/tipc/socket.c
+@@ -741,7 +741,10 @@ void tipc_sk_mcast_rcv(struct net *net,
+               spin_lock_bh(&inputq->lock);
+               if (skb_peek(arrvq) == skb) {
+                       skb_queue_splice_tail_init(&tmpq, inputq);
+-                      __skb_dequeue(arrvq);
++                      /* Decrease the skb's refcnt as increasing in the
++                       * function tipc_skb_peek
++                       */
++                      kfree_skb(__skb_dequeue(arrvq));
+               }
+               spin_unlock_bh(&inputq->lock);
+               __skb_queue_purge(&tmpq);
index 4dc3d98fd5fa7db39bd61050456e52927a4e9629..a55cbb53fca5da05aa03108777c9e8048c2ff11f 100644 (file)
@@ -25,3 +25,10 @@ usb-serial-ftdi_sio-add-ids-for-ids-gmbh-products.patch
 usb-serial-pl2303-add-device-id-for-adlink-nd-6530-gc.patch
 net-usb-fix-memory-leak-in-smsc75xx_bind.patch
 spi-fix-use-after-free-with-devm_spi_alloc_.patch
+bluetooth-cmtp-fix-file-refcount-when-cmtp_attach_device-fails.patch
+nfs-fix-an-incorrect-limit-in-filelayout_decode_layout.patch
+nfs-don-t-corrupt-the-value-of-pg_bytes_written-in-nfs_do_recoalesce.patch
+nfsv4-fix-v4.0-v4.1-seek_data-return-enotsupp-when-set-nfs_v4_2-config.patch
+net-mlx4-fix-eeprom-dump-support.patch
+revert-net-tipc-fix-a-double-free-in-tipc_sk_mcast_rcv.patch
+tipc-skb_linearize-the-head-skb-when-reassembling-msgs.patch
diff --git a/queue-4.9/tipc-skb_linearize-the-head-skb-when-reassembling-msgs.patch b/queue-4.9/tipc-skb_linearize-the-head-skb-when-reassembling-msgs.patch
new file mode 100644 (file)
index 0000000..d7cb9af
--- /dev/null
@@ -0,0 +1,95 @@
+From b7df21cf1b79ab7026f545e7bf837bd5750ac026 Mon Sep 17 00:00:00 2001
+From: Xin Long <lucien.xin@gmail.com>
+Date: Sat, 8 May 2021 03:57:03 +0800
+Subject: tipc: skb_linearize the head skb when reassembling msgs
+
+From: Xin Long <lucien.xin@gmail.com>
+
+commit b7df21cf1b79ab7026f545e7bf837bd5750ac026 upstream.
+
+It's not a good idea to append the frag skb to a skb's frag_list if
+the frag_list already has skbs from elsewhere, such as this skb was
+created by pskb_copy() where the frag_list was cloned (all the skbs
+in it were skb_get'ed) and shared by multiple skbs.
+
+However, the new appended frag skb should have been only seen by the
+current skb. Otherwise, it will cause use after free crashes as this
+appended frag skb are seen by multiple skbs but it only got skb_get
+called once.
+
+The same thing happens with a skb updated by pskb_may_pull() with a
+skb_cloned skb. Li Shuang has reported quite a few crashes caused
+by this when doing testing over macvlan devices:
+
+  [] kernel BUG at net/core/skbuff.c:1970!
+  [] Call Trace:
+  []  skb_clone+0x4d/0xb0
+  []  macvlan_broadcast+0xd8/0x160 [macvlan]
+  []  macvlan_process_broadcast+0x148/0x150 [macvlan]
+  []  process_one_work+0x1a7/0x360
+  []  worker_thread+0x30/0x390
+
+  [] kernel BUG at mm/usercopy.c:102!
+  [] Call Trace:
+  []  __check_heap_object+0xd3/0x100
+  []  __check_object_size+0xff/0x16b
+  []  simple_copy_to_iter+0x1c/0x30
+  []  __skb_datagram_iter+0x7d/0x310
+  []  __skb_datagram_iter+0x2a5/0x310
+  []  skb_copy_datagram_iter+0x3b/0x90
+  []  tipc_recvmsg+0x14a/0x3a0 [tipc]
+  []  ____sys_recvmsg+0x91/0x150
+  []  ___sys_recvmsg+0x7b/0xc0
+
+  [] kernel BUG at mm/slub.c:305!
+  [] Call Trace:
+  []  <IRQ>
+  []  kmem_cache_free+0x3ff/0x400
+  []  __netif_receive_skb_core+0x12c/0xc40
+  []  ? kmem_cache_alloc+0x12e/0x270
+  []  netif_receive_skb_internal+0x3d/0xb0
+  []  ? get_rx_page_info+0x8e/0xa0 [be2net]
+  []  be_poll+0x6ef/0xd00 [be2net]
+  []  ? irq_exit+0x4f/0x100
+  []  net_rx_action+0x149/0x3b0
+
+  ...
+
+This patch is to fix it by linearizing the head skb if it has frag_list
+set in tipc_buf_append(). Note that we choose to do this before calling
+skb_unshare(), as __skb_linearize() will avoid skb_copy(). Also, we can
+not just drop the frag_list either as the early time.
+
+Fixes: 45c8b7b175ce ("tipc: allow non-linear first fragment buffer")
+Reported-by: Li Shuang <shuali@redhat.com>
+Signed-off-by: Xin Long <lucien.xin@gmail.com>
+Acked-by: Jon Maloy <jmaloy@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/tipc/msg.c |    9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/net/tipc/msg.c
++++ b/net/tipc/msg.c
+@@ -141,18 +141,13 @@ int tipc_buf_append(struct sk_buff **hea
+               if (unlikely(head))
+                       goto err;
+               *buf = NULL;
++              if (skb_has_frag_list(frag) && __skb_linearize(frag))
++                      goto err;
+               frag = skb_unshare(frag, GFP_ATOMIC);
+               if (unlikely(!frag))
+                       goto err;
+               head = *headbuf = frag;
+               TIPC_SKB_CB(head)->tail = NULL;
+-              if (skb_is_nonlinear(head)) {
+-                      skb_walk_frags(head, tail) {
+-                              TIPC_SKB_CB(head)->tail = tail;
+-                      }
+-              } else {
+-                      skb_frag_list_init(head);
+-              }
+               return 0;
+       }