]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.7
authorSasha Levin <sashal@kernel.org>
Tue, 23 Jun 2020 01:30:15 +0000 (21:30 -0400)
committerSasha Levin <sashal@kernel.org>
Tue, 23 Jun 2020 01:30:15 +0000 (21:30 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.7/f2fs-avoid-utf8_strncasecmp-with-unstable-name.patch [new file with mode: 0644]
queue-5.7/f2fs-split-f2fs_d_compare-from-f2fs_match_name.patch [new file with mode: 0644]
queue-5.7/net-mlx5-dr-fix-freeing-in-dr_create_rc_qp.patch [new file with mode: 0644]
queue-5.7/series

diff --git a/queue-5.7/f2fs-avoid-utf8_strncasecmp-with-unstable-name.patch b/queue-5.7/f2fs-avoid-utf8_strncasecmp-with-unstable-name.patch
new file mode 100644 (file)
index 0000000..413cab3
--- /dev/null
@@ -0,0 +1,66 @@
+From ef85a057b5ffa75faeb5ffc8aa9bcf0b96b65f59 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Jun 2020 13:08:05 -0700
+Subject: f2fs: avoid utf8_strncasecmp() with unstable name
+
+From: Eric Biggers <ebiggers@google.com>
+
+[ Upstream commit fc3bb095ab02b9e7d89a069ade2cead15c64c504 ]
+
+If the dentry name passed to ->d_compare() fits in dentry::d_iname, then
+it may be concurrently modified by a rename.  This can cause undefined
+behavior (possibly out-of-bounds memory accesses or crashes) in
+utf8_strncasecmp(), since fs/unicode/ isn't written to handle strings
+that may be concurrently modified.
+
+Fix this by first copying the filename to a stack buffer if needed.
+This way we get a stable snapshot of the filename.
+
+Fixes: 2c2eb7a300cd ("f2fs: Support case-insensitive file name lookups")
+Cc: <stable@vger.kernel.org> # v5.4+
+Cc: Al Viro <viro@zeniv.linux.org.uk>
+Cc: Daniel Rosenberg <drosen@google.com>
+Cc: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/dir.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
+index 44eb12a00cd0e..54e90dbb09e78 100644
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -1076,11 +1076,27 @@ static int f2fs_d_compare(const struct dentry *dentry, unsigned int len,
+       const struct inode *dir = READ_ONCE(parent->d_inode);
+       const struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
+       struct qstr entry = QSTR_INIT(str, len);
++      char strbuf[DNAME_INLINE_LEN];
+       int res;
+       if (!dir || !IS_CASEFOLDED(dir))
+               goto fallback;
++      /*
++       * If the dentry name is stored in-line, then it may be concurrently
++       * modified by a rename.  If this happens, the VFS will eventually retry
++       * the lookup, so it doesn't matter what ->d_compare() returns.
++       * However, it's unsafe to call utf8_strncasecmp() with an unstable
++       * string.  Therefore, we have to copy the name into a temporary buffer.
++       */
++      if (len <= DNAME_INLINE_LEN - 1) {
++              memcpy(strbuf, str, len);
++              strbuf[len] = 0;
++              entry.name = strbuf;
++              /* prevent compiler from optimizing out the temporary buffer */
++              barrier();
++      }
++
+       res = utf8_strncasecmp(sbi->s_encoding, name, &entry);
+       if (res >= 0)
+               return res;
+-- 
+2.25.1
+
diff --git a/queue-5.7/f2fs-split-f2fs_d_compare-from-f2fs_match_name.patch b/queue-5.7/f2fs-split-f2fs_d_compare-from-f2fs_match_name.patch
new file mode 100644 (file)
index 0000000..5b1c22e
--- /dev/null
@@ -0,0 +1,152 @@
+From c451a515920bdc58e07752bf901ffc02bc8594d9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 7 May 2020 00:59:03 -0700
+Subject: f2fs: split f2fs_d_compare() from f2fs_match_name()
+
+From: Eric Biggers <ebiggers@google.com>
+
+[ Upstream commit f874fa1c7c7905c1744a2037a11516558ed00a81 ]
+
+Sharing f2fs_ci_compare() between comparing cached dentries
+(f2fs_d_compare()) and comparing on-disk dentries (f2fs_match_name())
+doesn't work as well as intended, as these actions fundamentally differ
+in several ways (e.g. whether the task may sleep, whether the directory
+is stable, whether the casefolded name was precomputed, whether the
+dentry will need to be decrypted once we allow casefold+encrypt, etc.)
+
+Just make f2fs_d_compare() implement what it needs directly, and rework
+f2fs_ci_compare() to be specialized for f2fs_match_name().
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/dir.c  | 70 +++++++++++++++++++++++++-------------------------
+ fs/f2fs/f2fs.h |  5 ----
+ 2 files changed, 35 insertions(+), 40 deletions(-)
+
+diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
+index 44bfc464df787..44eb12a00cd0e 100644
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -107,36 +107,28 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
+ /*
+  * Test whether a case-insensitive directory entry matches the filename
+  * being searched for.
+- *
+- * Returns: 0 if the directory entry matches, more than 0 if it
+- * doesn't match or less than zero on error.
+  */
+-int f2fs_ci_compare(const struct inode *parent, const struct qstr *name,
+-                              const struct qstr *entry, bool quick)
++static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
++                             const struct qstr *entry, bool quick)
+ {
+-      const struct f2fs_sb_info *sbi = F2FS_SB(parent->i_sb);
++      const struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+       const struct unicode_map *um = sbi->s_encoding;
+-      int ret;
++      int res;
+       if (quick)
+-              ret = utf8_strncasecmp_folded(um, name, entry);
++              res = utf8_strncasecmp_folded(um, name, entry);
+       else
+-              ret = utf8_strncasecmp(um, name, entry);
+-
+-      if (ret < 0) {
+-              /* Handle invalid character sequence as either an error
+-               * or as an opaque byte sequence.
++              res = utf8_strncasecmp(um, name, entry);
++      if (res < 0) {
++              /*
++               * In strict mode, ignore invalid names.  In non-strict mode,
++               * fall back to treating them as opaque byte sequences.
+                */
+-              if (f2fs_has_strict_mode(sbi))
+-                      return -EINVAL;
+-
+-              if (name->len != entry->len)
+-                      return 1;
+-
+-              return !!memcmp(name->name, entry->name, name->len);
++              if (f2fs_has_strict_mode(sbi) || name->len != entry->len)
++                      return false;
++              return !memcmp(name->name, entry->name, name->len);
+       }
+-
+-      return ret;
++      return res == 0;
+ }
+ static void f2fs_fname_setup_ci_filename(struct inode *dir,
+@@ -188,10 +180,10 @@ static inline bool f2fs_match_name(struct f2fs_dentry_ptr *d,
+               if (cf_str->name) {
+                       struct qstr cf = {.name = cf_str->name,
+                                         .len = cf_str->len};
+-                      return !f2fs_ci_compare(parent, &cf, &entry, true);
++                      return f2fs_match_ci_name(parent, &cf, &entry, true);
+               }
+-              return !f2fs_ci_compare(parent, fname->usr_fname, &entry,
+-                                      false);
++              return f2fs_match_ci_name(parent, fname->usr_fname, &entry,
++                                        false);
+       }
+ #endif
+       if (fscrypt_match_name(fname, d->filename[bit_pos],
+@@ -1080,17 +1072,25 @@ const struct file_operations f2fs_dir_operations = {
+ static int f2fs_d_compare(const struct dentry *dentry, unsigned int len,
+                         const char *str, const struct qstr *name)
+ {
+-      struct qstr qstr = {.name = str, .len = len };
+       const struct dentry *parent = READ_ONCE(dentry->d_parent);
+-      const struct inode *inode = READ_ONCE(parent->d_inode);
+-
+-      if (!inode || !IS_CASEFOLDED(inode)) {
+-              if (len != name->len)
+-                      return -1;
+-              return memcmp(str, name->name, len);
+-      }
+-
+-      return f2fs_ci_compare(inode, name, &qstr, false);
++      const struct inode *dir = READ_ONCE(parent->d_inode);
++      const struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
++      struct qstr entry = QSTR_INIT(str, len);
++      int res;
++
++      if (!dir || !IS_CASEFOLDED(dir))
++              goto fallback;
++
++      res = utf8_strncasecmp(sbi->s_encoding, name, &entry);
++      if (res >= 0)
++              return res;
++
++      if (f2fs_has_strict_mode(sbi))
++              return -EINVAL;
++fallback:
++      if (len != name->len)
++              return 1;
++      return !!memcmp(str, name->name, len);
+ }
+ static int f2fs_d_hash(const struct dentry *dentry, struct qstr *str)
+diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
+index 555c84953ea81..5a0f95dfbac2b 100644
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -3101,11 +3101,6 @@ int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
+                                                       bool hot, bool set);
+ struct dentry *f2fs_get_parent(struct dentry *child);
+-extern int f2fs_ci_compare(const struct inode *parent,
+-                         const struct qstr *name,
+-                         const struct qstr *entry,
+-                         bool quick);
+-
+ /*
+  * dir.c
+  */
+-- 
+2.25.1
+
diff --git a/queue-5.7/net-mlx5-dr-fix-freeing-in-dr_create_rc_qp.patch b/queue-5.7/net-mlx5-dr-fix-freeing-in-dr_create_rc_qp.patch
new file mode 100644 (file)
index 0000000..b20e17e
--- /dev/null
@@ -0,0 +1,37 @@
+From 2dc42b46d9f30301a974d47aacce2bcfa8091a4e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Jun 2020 19:45:26 +0300
+Subject: net/mlx5: DR, Fix freeing in dr_create_rc_qp()
+
+From: Denis Efremov <efremov@linux.com>
+
+[ Upstream commit 47a357de2b6b706af3c9471d5042f9ba8907031e ]
+
+Variable "in" in dr_create_rc_qp() is allocated with kvzalloc() and
+should be freed with kvfree().
+
+Fixes: 297cccebdc5a ("net/mlx5: DR, Expose an internal API to issue RDMA operations")
+Cc: stable@vger.kernel.org
+Signed-off-by: Denis Efremov <efremov@linux.com>
+Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
+index 18719acb7e547..eff8bb64899d6 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
+@@ -181,7 +181,7 @@ static struct mlx5dr_qp *dr_create_rc_qp(struct mlx5_core_dev *mdev,
+                                                        in, pas));
+       err = mlx5_core_create_qp(mdev, &dr_qp->mqp, in, inlen);
+-      kfree(in);
++      kvfree(in);
+       if (err) {
+               mlx5_core_warn(mdev, " Can't create QP\n");
+-- 
+2.25.1
+
index 24184dd9922b81a362971517358c3461183b6dec..6405825ac83eb582c18bb2c8c5fcae46471c00fe 100644 (file)
@@ -436,3 +436,6 @@ io_uring-reap-poll-completions-while-waiting-for-refs-to-drop-on-exit.patch
 io_uring-fix-possible-race-condition-against-req_f_need_cleanup.patch
 ext4-avoid-race-conditions-when-remounting-with-opti.patch
 drm-dp_mst-increase-act-retry-timeout-to-3s.patch
+net-mlx5-dr-fix-freeing-in-dr_create_rc_qp.patch
+f2fs-split-f2fs_d_compare-from-f2fs_match_name.patch
+f2fs-avoid-utf8_strncasecmp-with-unstable-name.patch