From: Sasha Levin Date: Tue, 23 Jun 2020 01:30:15 +0000 (-0400) Subject: Fixes for 5.4 X-Git-Tag: v5.7.6~35 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=124342a66e9d3ce689b8fcc9d30c9f8956d49ed9;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.4 Signed-off-by: Sasha Levin --- diff --git a/queue-5.4/block-nr_sects_write-disable-preemption-on-seqcount-.patch b/queue-5.4/block-nr_sects_write-disable-preemption-on-seqcount-.patch new file mode 100644 index 00000000000..edf6c88df2b --- /dev/null +++ b/queue-5.4/block-nr_sects_write-disable-preemption-on-seqcount-.patch @@ -0,0 +1,48 @@ +From 1762b9dcce9e48f1edc777c1bfa1c562c0aa64a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jun 2020 16:49:48 +0200 +Subject: block: nr_sects_write(): Disable preemption on seqcount write + +From: Ahmed S. Darwish + +[ Upstream commit 15b81ce5abdc4b502aa31dff2d415b79d2349d2f ] + +For optimized block readers not holding a mutex, the "number of sectors" +64-bit value is protected from tearing on 32-bit architectures by a +sequence counter. + +Disable preemption before entering that sequence counter's write side +critical section. Otherwise, the read side can preempt the write side +section and spin for the entire scheduler tick. If the reader belongs to +a real-time scheduling class, it can spin forever and the kernel will +livelock. + +Fixes: c83f6bf98dc1 ("block: add partition resize function to blkpg ioctl") +Cc: +Signed-off-by: Ahmed S. Darwish +Reviewed-by: Sebastian Andrzej Siewior +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + include/linux/genhd.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/linux/genhd.h b/include/linux/genhd.h +index 8b5330dd5ac09..62a2ec9f17df8 100644 +--- a/include/linux/genhd.h ++++ b/include/linux/genhd.h +@@ -750,9 +750,11 @@ static inline sector_t part_nr_sects_read(struct hd_struct *part) + static inline void part_nr_sects_write(struct hd_struct *part, sector_t size) + { + #if BITS_PER_LONG==32 && defined(CONFIG_SMP) ++ preempt_disable(); + write_seqcount_begin(&part->nr_sects_seq); + part->nr_sects = size; + write_seqcount_end(&part->nr_sects_seq); ++ preempt_enable(); + #elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT) + preempt_disable(); + part->nr_sects = size; +-- +2.25.1 + diff --git a/queue-5.4/f2fs-avoid-utf8_strncasecmp-with-unstable-name.patch b/queue-5.4/f2fs-avoid-utf8_strncasecmp-with-unstable-name.patch new file mode 100644 index 00000000000..d36848324d5 --- /dev/null +++ b/queue-5.4/f2fs-avoid-utf8_strncasecmp-with-unstable-name.patch @@ -0,0 +1,66 @@ +From f23b0fd9ac38590ae89a6de9259a08fc5a066a82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2020 13:08:05 -0700 +Subject: f2fs: avoid utf8_strncasecmp() with unstable name + +From: Eric Biggers + +[ 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: # v5.4+ +Cc: Al Viro +Cc: Daniel Rosenberg +Cc: Gabriel Krisman Bertazi +Signed-off-by: Eric Biggers +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + fs/f2fs/dir.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c +index 594c9ad774d23..e9af46dc06f72 100644 +--- a/fs/f2fs/dir.c ++++ b/fs/f2fs/dir.c +@@ -1063,11 +1063,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.4/f2fs-split-f2fs_d_compare-from-f2fs_match_name.patch b/queue-5.4/f2fs-split-f2fs_d_compare-from-f2fs_match_name.patch new file mode 100644 index 00000000000..50e3c82cf9a --- /dev/null +++ b/queue-5.4/f2fs-split-f2fs_d_compare-from-f2fs_match_name.patch @@ -0,0 +1,152 @@ +From cca5692f9c4f4b9818c7d21055dc1a19b44a246b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2020 00:59:03 -0700 +Subject: f2fs: split f2fs_d_compare() from f2fs_match_name() + +From: Eric Biggers + +[ 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 +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Sasha Levin +--- + 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 84280ad3786c3..594c9ad774d23 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], +@@ -1067,17 +1059,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 c22ca7d867ee5..03693d6b1c104 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -2954,11 +2954,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.4/net-mlx5-dr-fix-freeing-in-dr_create_rc_qp.patch b/queue-5.4/net-mlx5-dr-fix-freeing-in-dr_create_rc_qp.patch new file mode 100644 index 00000000000..f4d67668d88 --- /dev/null +++ b/queue-5.4/net-mlx5-dr-fix-freeing-in-dr_create_rc_qp.patch @@ -0,0 +1,37 @@ +From 80e79b519b782c173b78cf9540f0822dde6f8b49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Jun 2020 19:45:26 +0300 +Subject: net/mlx5: DR, Fix freeing in dr_create_rc_qp() + +From: Denis Efremov + +[ 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 +Signed-off-by: Saeed Mahameed +Signed-off-by: Sasha Levin +--- + 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 7c77378accf04..f012aac83b10e 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 + diff --git a/queue-5.4/series b/queue-5.4/series index b1238c123d6..b73c3429f0b 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -290,3 +290,7 @@ ext4-avoid-race-conditions-when-remounting-with-opti.patch drm-dp_mst-increase-act-retry-timeout-to-3s.patch drm-amd-display-use-swap-where-appropriate.patch x86-boot-compressed-relax-sed-symbol-type-regex-for-.patch +block-nr_sects_write-disable-preemption-on-seqcount-.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