From 9cd9a21ce070be8a918ffd3381468315a7a76ba6 Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Wed, 22 Feb 2017 17:15:21 +0100 Subject: [PATCH 1/7] ubi/upd: Always flush after prepared for an update In commit 6afaf8a484cb ("UBI: flush wl before clearing update marker") I managed to trigger and fix a similar bug. Now here is another version of which I assumed it wouldn't matter back then but it turns out UBI has a check for it and will error out like this: |ubi0 warning: validate_vid_hdr: inconsistent used_ebs |ubi0 error: validate_vid_hdr: inconsistent VID header at PEB 592 All you need to trigger this is? "ubiupdatevol /dev/ubi0_0 file" + a powercut in the middle of the operation. ubi_start_update() sets the update-marker and puts all EBs on the erase list. After that userland can proceed to write new data while the old EB aren't erased completely. A powercut at this point is usually not that much of a tragedy. UBI won't give read access to the static volume because it has the update marker. It will most likely set the corrupted flag because it misses some EBs. So we are all good. Unless the size of the image that has been written differs from the old image in the magnitude of at least one EB. In that case UBI will find two different values for `used_ebs' and refuse to attach the image with the error message mentioned above. So in order not to get in the situation, the patch will ensure that we wait until everything is removed before it tries to write any data. The alternative would be to detect such a case and remove all EBs at the attached time after we processed the volume-table and see the update-marker set. The patch looks bigger and I doubt it is worth it since usually the write() will wait from time to time for a new EB since usually there not that many spare EB that can be used. Cc: stable@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/upd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 0134ba32a057..39712560b4c1 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -148,11 +148,11 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, return err; } - if (bytes == 0) { - err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL); - if (err) - return err; + err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL); + if (err) + return err; + if (bytes == 0) { err = clear_update_marker(ubi, vol, 0); if (err) return err; From 63ed657362509b54635fe17af980fba722a008d8 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 10 Feb 2017 17:46:01 +0100 Subject: [PATCH 2/7] ubifs: Fix memory leak in error path in ubifs_mknod When fscrypt_setup_filename() fails we have to free dev. Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 30825d882aa9..51929be655c3 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1068,8 +1068,10 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, } err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); - if (err) + if (err) { + kfree(dev); goto out_budg; + } sz_change = CALC_DENT_SIZE(fname_len(&nm)); From b20e2d9999506bb445e9958efa407e84d1a579cc Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 15 Mar 2017 10:31:03 +0900 Subject: [PATCH 3/7] ubifs: Remove filename from debug messages in ubifs_readdir if filename is encrypted, filename could have no printable characters. so remove it. Signed-off-by: Hyunchul Lee Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 51929be655c3..87b04dc3a86e 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -606,8 +606,8 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) } while (1) { - dbg_gen("feed '%s', ino %llu, new f_pos %#x", - dent->name, (unsigned long long)le64_to_cpu(dent->inum), + dbg_gen("ino %llu, new f_pos %#x", + (unsigned long long)le64_to_cpu(dent->inum), key_hash_flash(c, &dent->key)); ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum); From e328379a18c5293c123bc56c32f19f9365384686 Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 15 Mar 2017 10:31:04 +0900 Subject: [PATCH 4/7] ubifs: Fix debug messages for an invalid filename in ubifs_dump_node if a character is not printable, print '?' instead of that. Signed-off-by: Hyunchul Lee Signed-off-by: Richard Weinberger --- fs/ubifs/debug.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 1e712a364680..b14c06f47a96 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "ubifs.h" static DEFINE_SPINLOCK(dbg_lock); @@ -464,7 +465,8 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) pr_err("(bad name length, not printing, bad or corrupted node)"); else { for (i = 0; i < nlen && dent->name[i]; i++) - pr_cont("%c", dent->name[i]); + pr_cont("%c", isprint(dent->name[i]) ? + dent->name[i] : '?'); } pr_cont("\n"); From 33fda9fa9fb081fae165348f32e3244414991fad Mon Sep 17 00:00:00 2001 From: Hyunchul Lee Date: Wed, 15 Mar 2017 10:31:05 +0900 Subject: [PATCH 5/7] ubifs: Fix debug messages for an invalid filename in ubifs_dump_inode instead of filenames, print inode numbers, file types, and length. Signed-off-by: Hyunchul Lee Signed-off-by: Richard Weinberger --- fs/ubifs/debug.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index b14c06f47a96..718b749fa11a 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -287,8 +287,10 @@ void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode) break; } - pr_err("\t%d: %s (%s)\n", - count++, dent->name, get_dent_type(dent->type)); + pr_err("\t%d: inode %llu, type %s, len %d\n", + count++, (unsigned long long) le64_to_cpu(dent->inum), + get_dent_type(dent->type), + le16_to_cpu(dent->nlen)); fname_name(&nm) = dent->name; fname_len(&nm) = le16_to_cpu(dent->nlen); From c3d9fda688742c06e89aa1f0f8fd943fc11468cb Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 6 Mar 2017 10:04:25 +0100 Subject: [PATCH 6/7] ubifs: Fix RENAME_WHITEOUT support Remove faulty leftover check in do_rename(), apparently introduced in a merge that combined whiteout support changes with commit f03b8ad8d386 ("fs: support RENAME_NOREPLACE for local filesystems") Fixes: f03b8ad8d386 ("fs: support RENAME_NOREPLACE for local filesystems") Fixes: 9e0a1fff8db5 ("ubifs: Implement RENAME_WHITEOUT") Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 87b04dc3a86e..0858213a4e63 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1318,9 +1318,6 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, unsigned int uninitialized_var(saved_nlink); struct fscrypt_name old_nm, new_nm; - if (flags & ~RENAME_NOREPLACE) - return -EINVAL; - /* * Budget request settings: deletion direntry, new direntry, removing * the old inode, and changing old and new parent directory inodes. From 32fe905c17f001c0eee13c59afddd0bf2eed509c Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Thu, 30 Mar 2017 10:50:49 +0200 Subject: [PATCH 7/7] ubifs: Fix O_TMPFILE corner case in ubifs_link() It is perfectly fine to link a tmpfile back using linkat(). Since tmpfiles are created with a link count of 0 they appear on the orphan list, upon re-linking the inode has to be removed from the orphan list again. Ralph faced a filesystem corruption in combination with overlayfs due to this bug. Cc: Cc: Ralph Sennhauser Cc: Amir Goldstein Reported-by: Ralph Sennhauser Tested-by: Ralph Sennhauser Reported-by: Amir Goldstein Fixes: 474b93704f321 ("ubifs: Implement O_TMPFILE") Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 0858213a4e63..b777bddaa1dd 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -748,6 +748,11 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, goto out_fname; lock_2_inodes(dir, inode); + + /* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */ + if (inode->i_nlink == 0) + ubifs_delete_orphan(c, inode->i_ino); + inc_nlink(inode); ihold(inode); inode->i_ctime = ubifs_current_time(inode); @@ -768,6 +773,8 @@ out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(inode); + if (inode->i_nlink == 0) + ubifs_add_orphan(c, inode->i_ino); unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); iput(inode);