From 0e26546cc485f20998908ff40dde851c814ac079 Mon Sep 17 00:00:00 2001 From: ZhaoLong Wang Date: Mon, 25 Dec 2023 20:11:33 +0800 Subject: [PATCH 1/5] ubi: Use the fault injection framework to enhance the fault injection capability hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8QZWQ CVE: NA ----------------------------------------- To make debug parameters configurable at run time, use the fault injection framework to reconstruct the debugfs interface, and retain the legacy fault injection interface. Now, the file emulate_failures and fault_attr files control whether to enable fault emmulation. The file emulate_failures receives a mask that controls type and process of fault injection. Generally, for ease of use, you can directly enter a mask with all 1s. echo 0xffff > /sys/kernel/debug/ubi/ubi0/emulate_failures And you need to configure other fault-injection capabilities for testing purpose: echo 100 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/probability echo 15 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/space echo 2 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/verbose echo -1 > /sys/kernel/debug/ubi/fault_inject/emulate_power_cut/times The CONFIG_MTD_UBI_FAULT_INJECTION to enable the Fault Injection is added to kconfig. Signed-off-by: ZhaoLong Wang Reviewed-by: Zhihao Cheng --- drivers/mtd/ubi/Kconfig | 9 +++ drivers/mtd/ubi/debug.c | 69 +++++++++++++++++-- drivers/mtd/ubi/debug.h | 142 +++++++++++++++++++++++++++++++++------- drivers/mtd/ubi/io.c | 10 ++- drivers/mtd/ubi/ubi.h | 15 ++--- 5 files changed, 203 insertions(+), 42 deletions(-) diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index 2ed77b7b3fcb..7499a540121e 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -104,4 +104,13 @@ config MTD_UBI_BLOCK If in doubt, say "N". +config MTD_UBI_FAULT_INJECTION + bool "Fault injection capability of UBI device" + default n + depends on FAULT_INJECTION_DEBUG_FS + help + This option enables fault-injection support for UBI devices for + testing purposes. + + If in doubt, say "N". endif # MTD_UBI diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 27168f511d6d..98325911cd7e 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -10,7 +10,23 @@ #include #include #include +#include +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION +static DECLARE_FAULT_ATTR(fault_bitflips_attr); +static DECLARE_FAULT_ATTR(fault_io_failures_attr); +static DECLARE_FAULT_ATTR(fault_power_cut_attr); + +#define FAIL_ACTION(name, fault_attr) \ +bool should_fail_##name(void) \ +{ \ + return should_fail(&fault_attr, 1); \ +} + +FAIL_ACTION(bitflips, fault_bitflips_attr) +FAIL_ACTION(io_failures, fault_io_failures_attr) +FAIL_ACTION(power_cut, fault_power_cut_attr) +#endif /** * ubi_dump_flash - dump a region of flash. @@ -212,6 +228,31 @@ void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req) */ static struct dentry *dfs_rootdir; +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION +static void dfs_create_fault_entry(struct dentry *parent) +{ + struct dentry *dir; + + dir = debugfs_create_dir("fault_inject", parent); + if (IS_ERR_OR_NULL(dir)) { + int err = dir ? PTR_ERR(dir) : -ENODEV; + + pr_warn("UBI error: cannot create \"fault_inject\"" + "debugfs directory, error %d\n", err); + return; + } + + fault_create_debugfs_attr("emulate_bitflips", dir, + &fault_bitflips_attr); + + fault_create_debugfs_attr("emulate_io_failures", dir, + &fault_io_failures_attr); + + fault_create_debugfs_attr("emulate_power_cut", dir, + &fault_power_cut_attr); +} +#endif + /** * ubi_debugfs_init - create UBI debugfs directory. * @@ -232,6 +273,10 @@ int ubi_debugfs_init(void) return err; } +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION + dfs_create_fault_entry(dfs_rootdir); +#endif + return 0; } @@ -272,7 +317,12 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf, val = d->emulate_bitflips; else if (dent == d->dfs_emulate_io_failures) val = d->emulate_io_failures; - else if (dent == d->dfs_emulate_power_cut) { + else if (dent == d->dfs_emulate_failures) { + snprintf(buf, sizeof(buf), "0x%04x\n", d->emulate_failures); + count = simple_read_from_buffer(user_buf, count, ppos, + buf, strlen(buf)); + goto out; + } else if (dent == d->dfs_emulate_power_cut) { snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut); count = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); @@ -287,8 +337,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf, count = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); goto out; - } - else { + } else { count = -EINVAL; goto out; } @@ -330,7 +379,11 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, goto out; } - if (dent == d->dfs_power_cut_min) { + if (dent == d->dfs_emulate_failures) { + if (kstrtouint(buf, 0, &d->emulate_failures) != 0) + count = -EINVAL; + goto out; + } else if (dent == d->dfs_power_cut_min) { if (kstrtouint(buf, 0, &d->power_cut_min) != 0) count = -EINVAL; goto out; @@ -559,6 +612,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir, (void *)ubi_num, &eraseblk_count_fops); +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION + d->dfs_emulate_failures = debugfs_create_file("emulate_failures", + mode, d->dfs_dir, + (void *)ubi_num, + &dfs_fops); +#endif return 0; } @@ -600,7 +659,5 @@ int ubi_dbg_power_cut(struct ubi_device *ubi, int caller) if (ubi->dbg.power_cut_counter) return 0; - ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX"); - ubi_ro_mode(ubi); return 1; } diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 23676f32b681..f2f499feff49 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -53,56 +53,153 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi); void ubi_debugfs_exit_dev(struct ubi_device *ubi); /** - * ubi_dbg_is_bgt_disabled - if the background thread is disabled. + * The following function is a legacy implementation of UBI fault-injection + * hook. When using more powerful fault injection capabilities, the legacy + * fault injection interface should be retained. + */ +int ubi_dbg_power_cut(struct ubi_device *ubi, int caller); + +static inline int ubi_dbg_bitflip(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_bitflips) + return !get_random_u32_below(200); + return 0; +} + +static inline int ubi_dbg_write_failure(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_io_failures) + return !get_random_u32_below(500); + return 0; +} + +static inline int ubi_dbg_erase_failure(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_io_failures) + return !get_random_u32_below(400); + return 0; +} + +/** + * MASK_XXX: Mask for emulate_failures in ubi_debug_info.The mask is used to + * precisely control the type and process of fault injection. + */ +/* Emulate a power cut when writing EC/VID header */ +#define MASK_POWER_CUT_EC (1 << 0) +#define MASK_POWER_CUT_VID (1 << 1) + +#ifdef CONFIG_MTD_UBI_FAULT_INJECTION +/* Emulate bit-flips */ +#define MASK_BITFLIPS (1 << 2) +/* Emulates -EIO during write/erase */ +#define MASK_IO_FAILURE (1 << 3) + +extern bool should_fail_bitflips(void); +extern bool should_fail_io_failures(void); +extern bool should_fail_power_cut(void); + +static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_BITFLIPS) + return should_fail_bitflips(); + return false; +} + +static inline bool ubi_dbg_fail_write(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) + return should_fail_io_failures(); + return false; +} + +static inline bool ubi_dbg_fail_erase(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) + return should_fail_io_failures(); + return false; +} + +static inline bool ubi_dbg_fail_power_cut(const struct ubi_device *ubi, + unsigned int caller) +{ + if (ubi->dbg.emulate_failures & caller) + return should_fail_power_cut(); + return false; +} + +#else /* CONFIG_MTD_UBI_FAULT_INJECTION */ + +#define ubi_dbg_fail_bitflip(u) false +#define ubi_dbg_fail_write(u) false +#define ubi_dbg_fail_erase(u) false +#define ubi_dbg_fail_power_cut(u, c) false +#endif + +/** + * ubi_dbg_is_power_cut - if it is time to emulate power cut. * @ubi: UBI device description object * - * Returns non-zero if the UBI background thread is disabled for testing - * purposes. + * Returns true if power cut should be emulated, otherwise returns false. */ -static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_power_cut(struct ubi_device *ubi, + unsigned int caller) { - return ubi->dbg.disable_bgt; + if (ubi_dbg_power_cut(ubi, caller)) + return true; + return ubi_dbg_fail_power_cut(ubi, caller); } /** * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip. * @ubi: UBI device description object * - * Returns non-zero if a bit-flip should be emulated, otherwise returns zero. + * Returns true if a bit-flip should be emulated, otherwise returns false. */ -static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_bitflip(const struct ubi_device *ubi) { - if (ubi->dbg.emulate_bitflips) - return !get_random_u32_below(200); - return 0; + if (ubi_dbg_bitflip(ubi)) + return true; + return ubi_dbg_fail_bitflip(ubi); } /** * ubi_dbg_is_write_failure - if it is time to emulate a write failure. * @ubi: UBI device description object * - * Returns non-zero if a write failure should be emulated, otherwise returns - * zero. + * Returns true if a write failure should be emulated, otherwise returns + * false. */ -static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_write_failure(const struct ubi_device *ubi) { - if (ubi->dbg.emulate_io_failures) - return !get_random_u32_below(500); - return 0; + if (ubi_dbg_write_failure(ubi)) + return true; + return ubi_dbg_fail_write(ubi); } /** * ubi_dbg_is_erase_failure - if its time to emulate an erase failure. * @ubi: UBI device description object * - * Returns non-zero if an erase failure should be emulated, otherwise returns - * zero. + * Returns true if an erase failure should be emulated, otherwise returns + * false. */ -static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi) +static inline bool ubi_dbg_is_erase_failure(const struct ubi_device *ubi) { - if (ubi->dbg.emulate_io_failures) - return !get_random_u32_below(400); - return 0; + if (ubi_dbg_erase_failure(ubi)) + return true; + return ubi_dbg_fail_erase(ubi); +} + +/** + * ubi_dbg_is_bgt_disabled - if the background thread is disabled. + * @ubi: UBI device description object + * + * Returns non-zero if the UBI background thread is disabled for testing + * purposes. + */ +static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) +{ + return ubi->dbg.disable_bgt; } static inline int ubi_dbg_chk_io(const struct ubi_device *ubi) @@ -125,5 +222,4 @@ static inline void ubi_enable_dbg_chk_fastmap(struct ubi_device *ubi) ubi->dbg.chk_fastmap = 1; } -int ubi_dbg_power_cut(struct ubi_device *ubi, int caller); #endif /* !__UBI_DEBUG_H__ */ diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 01b644861253..fb70f5227f18 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -821,8 +821,11 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, if (err) return err; - if (ubi_dbg_power_cut(ubi, POWER_CUT_EC_WRITE)) + if (ubi_dbg_is_power_cut(ubi, MASK_POWER_CUT_EC)) { + ubi_warn(ubi, "emulating a power cut when writing EC header"); + ubi_ro_mode(ubi); return -EROFS; + } err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize); return err; @@ -1071,8 +1074,11 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, if (err) return err; - if (ubi_dbg_power_cut(ubi, POWER_CUT_VID_WRITE)) + if (ubi_dbg_is_power_cut(ubi, MASK_POWER_CUT_VID)) { + ubi_warn(ubi, "emulating a power cut when writing VID header"); + ubi_ro_mode(ubi); return -EROFS; + } err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index c8f1bd4fa100..41f57d5717b2 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -142,17 +142,6 @@ enum { UBI_BAD_FASTMAP, }; -/* - * Flags for emulate_power_cut in ubi_debug_info - * - * POWER_CUT_EC_WRITE: Emulate a power cut when writing an EC header - * POWER_CUT_VID_WRITE: Emulate a power cut when writing a VID header - */ -enum { - POWER_CUT_EC_WRITE = 0x01, - POWER_CUT_VID_WRITE = 0x02, -}; - /** * struct ubi_vid_io_buf - VID buffer used to read/write VID info to/from the * flash. @@ -401,6 +390,7 @@ struct ubi_volume_desc { * @power_cut_counter: count down for writes left until emulated power cut * @power_cut_min: minimum number of writes before emulating a power cut * @power_cut_max: maximum number of writes until emulating a power cut + * @emulate_failures: emulate failures for testing purposes * @dfs_dir_name: name of debugfs directory containing files of this UBI device * @dfs_dir: direntry object of the UBI device debugfs directory * @dfs_chk_gen: debugfs knob to enable UBI general extra checks @@ -412,6 +402,7 @@ struct ubi_volume_desc { * @dfs_emulate_power_cut: debugfs knob to emulate power cuts * @dfs_power_cut_min: debugfs knob for minimum writes before power cut * @dfs_power_cut_max: debugfs knob for maximum writes until power cut + * @dfs_emulate_failures: debugfs entry to control the fault injection type */ struct ubi_debug_info { unsigned int chk_gen:1; @@ -424,6 +415,7 @@ struct ubi_debug_info { unsigned int power_cut_counter; unsigned int power_cut_min; unsigned int power_cut_max; + unsigned int emulate_failures; char dfs_dir_name[UBI_DFS_DIR_LEN + 1]; struct dentry *dfs_dir; struct dentry *dfs_chk_gen; @@ -435,6 +427,7 @@ struct ubi_debug_info { struct dentry *dfs_emulate_power_cut; struct dentry *dfs_power_cut_min; struct dentry *dfs_power_cut_max; + struct dentry *dfs_emulate_failures; }; /** -- Gitee From d5e7bb4eab8679f798a2fd81f4bdf765dc30500a Mon Sep 17 00:00:00 2001 From: ZhaoLong Wang Date: Mon, 25 Dec 2023 20:11:34 +0800 Subject: [PATCH 2/5] ubi: Split io_failures into write_failure and erase_failure hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8QZWQ CVE: NA ----------------------------------------- The emulate_io_failures debugfs entry controls both write failure and erase failure. This patch split io_failures to write_failure and erase_failure. Signed-off-by: ZhaoLong Wang Reviewed-by: Zhihao Cheng --- drivers/mtd/ubi/debug.c | 13 +++++++++---- drivers/mtd/ubi/debug.h | 14 ++++++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 98325911cd7e..e0ab7040bc2f 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -14,7 +14,8 @@ #ifdef CONFIG_MTD_UBI_FAULT_INJECTION static DECLARE_FAULT_ATTR(fault_bitflips_attr); -static DECLARE_FAULT_ATTR(fault_io_failures_attr); +static DECLARE_FAULT_ATTR(fault_write_failure_attr); +static DECLARE_FAULT_ATTR(fault_erase_failure_attr); static DECLARE_FAULT_ATTR(fault_power_cut_attr); #define FAIL_ACTION(name, fault_attr) \ @@ -24,7 +25,8 @@ bool should_fail_##name(void) \ } FAIL_ACTION(bitflips, fault_bitflips_attr) -FAIL_ACTION(io_failures, fault_io_failures_attr) +FAIL_ACTION(write_failure, fault_write_failure_attr) +FAIL_ACTION(erase_failure, fault_erase_failure_attr) FAIL_ACTION(power_cut, fault_power_cut_attr) #endif @@ -245,8 +247,11 @@ static void dfs_create_fault_entry(struct dentry *parent) fault_create_debugfs_attr("emulate_bitflips", dir, &fault_bitflips_attr); - fault_create_debugfs_attr("emulate_io_failures", dir, - &fault_io_failures_attr); + fault_create_debugfs_attr("emulate_write_failure", dir, + &fault_write_failure_attr); + + fault_create_debugfs_attr("emulate_erase_failure", dir, + &fault_erase_failure_attr); fault_create_debugfs_attr("emulate_power_cut", dir, &fault_power_cut_attr); diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index f2f499feff49..8cdd25eee013 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -92,10 +92,12 @@ static inline int ubi_dbg_erase_failure(const struct ubi_device *ubi) /* Emulate bit-flips */ #define MASK_BITFLIPS (1 << 2) /* Emulates -EIO during write/erase */ -#define MASK_IO_FAILURE (1 << 3) +#define MASK_WRITE_FAILURE (1 << 3) +#define MASK_ERASE_FAILURE (1 << 4) extern bool should_fail_bitflips(void); -extern bool should_fail_io_failures(void); +extern bool should_fail_write_failure(void); +extern bool should_fail_erase_failure(void); extern bool should_fail_power_cut(void); static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi) @@ -107,15 +109,15 @@ static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi) static inline bool ubi_dbg_fail_write(const struct ubi_device *ubi) { - if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) - return should_fail_io_failures(); + if (ubi->dbg.emulate_failures & MASK_WRITE_FAILURE) + return should_fail_write_failure(); return false; } static inline bool ubi_dbg_fail_erase(const struct ubi_device *ubi) { - if (ubi->dbg.emulate_failures & MASK_IO_FAILURE) - return should_fail_io_failures(); + if (ubi->dbg.emulate_failures & MASK_ERASE_FAILURE) + return should_fail_erase_failure(); return false; } -- Gitee From fccb33365ec5d413258b83a20e72950b19cdc2cc Mon Sep 17 00:00:00 2001 From: ZhaoLong Wang Date: Mon, 25 Dec 2023 20:11:35 +0800 Subject: [PATCH 3/5] ubi: Add six fault injection type for testing hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8QZWQ CVE: NA ----------------------------------------- This commit adds six fault injection type for testing to cover the abnormal path of the UBI driver. Inject the following faults when the UBI reads the LEB: +----------------------------+-----------------------------------+ | Interface name | emulate behavior | +----------------------------+-----------------------------------+ | emulate_eccerr | ECC error | +----------------------------+-----------------------------------+ | emulate_read_failure | read failure | |----------------------------+-----------------------------------+ | emulate_io_ff | read content as all FF | |----------------------------+-----------------------------------+ | emulate_io_ff_bitflips | content FF with MTD err reported | +----------------------------+-----------------------------------+ | emulate_bad_hdr | bad leb header | |----------------------------+-----------------------------------+ | emulate_bad_hdr_ebadmsg | bad header with ECC err | +----------------------------+-----------------------------------+ Signed-off-by: ZhaoLong Wang Reviewed-by: Zhihao Cheng --- drivers/mtd/ubi/debug.c | 30 +++++++ drivers/mtd/ubi/debug.h | 172 ++++++++++++++++++++++++++++++++++++++-- drivers/mtd/ubi/io.c | 76 +++++++++++++++++- drivers/mtd/ubi/ubi.h | 30 ++++--- 4 files changed, 287 insertions(+), 21 deletions(-) diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index e0ab7040bc2f..3f1ee0b07c36 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -13,10 +13,16 @@ #include #ifdef CONFIG_MTD_UBI_FAULT_INJECTION +static DECLARE_FAULT_ATTR(fault_eccerr_attr); static DECLARE_FAULT_ATTR(fault_bitflips_attr); +static DECLARE_FAULT_ATTR(fault_read_failure_attr); static DECLARE_FAULT_ATTR(fault_write_failure_attr); static DECLARE_FAULT_ATTR(fault_erase_failure_attr); static DECLARE_FAULT_ATTR(fault_power_cut_attr); +static DECLARE_FAULT_ATTR(fault_io_ff_attr); +static DECLARE_FAULT_ATTR(fault_io_ff_bitflips_attr); +static DECLARE_FAULT_ATTR(fault_bad_hdr_attr); +static DECLARE_FAULT_ATTR(fault_bad_hdr_ebadmsg_attr); #define FAIL_ACTION(name, fault_attr) \ bool should_fail_##name(void) \ @@ -24,10 +30,16 @@ bool should_fail_##name(void) \ return should_fail(&fault_attr, 1); \ } +FAIL_ACTION(eccerr, fault_eccerr_attr) FAIL_ACTION(bitflips, fault_bitflips_attr) +FAIL_ACTION(read_failure, fault_read_failure_attr) FAIL_ACTION(write_failure, fault_write_failure_attr) FAIL_ACTION(erase_failure, fault_erase_failure_attr) FAIL_ACTION(power_cut, fault_power_cut_attr) +FAIL_ACTION(io_ff, fault_io_ff_attr) +FAIL_ACTION(io_ff_bitflips, fault_io_ff_bitflips_attr) +FAIL_ACTION(bad_hdr, fault_bad_hdr_attr) +FAIL_ACTION(bad_hdr_ebadmsg, fault_bad_hdr_ebadmsg_attr) #endif /** @@ -244,6 +256,12 @@ static void dfs_create_fault_entry(struct dentry *parent) return; } + fault_create_debugfs_attr("emulate_eccerr", dir, + &fault_eccerr_attr); + + fault_create_debugfs_attr("emulate_read_failure", dir, + &fault_read_failure_attr); + fault_create_debugfs_attr("emulate_bitflips", dir, &fault_bitflips_attr); @@ -255,6 +273,18 @@ static void dfs_create_fault_entry(struct dentry *parent) fault_create_debugfs_attr("emulate_power_cut", dir, &fault_power_cut_attr); + + fault_create_debugfs_attr("emulate_io_ff", dir, + &fault_io_ff_attr); + + fault_create_debugfs_attr("emulate_io_ff_bitflips", dir, + &fault_io_ff_bitflips_attr); + + fault_create_debugfs_attr("emulate_bad_hdr", dir, + &fault_bad_hdr_attr); + + fault_create_debugfs_attr("emulate_bad_hdr_ebadmsg", dir, + &fault_bad_hdr_ebadmsg_attr); } #endif diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 8cdd25eee013..0e89a1ee88e5 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -87,18 +87,45 @@ static inline int ubi_dbg_erase_failure(const struct ubi_device *ubi) /* Emulate a power cut when writing EC/VID header */ #define MASK_POWER_CUT_EC (1 << 0) #define MASK_POWER_CUT_VID (1 << 1) +/* Emulate a power cut when writing data*/ +#define MASK_POWER_CUT_DATA (1 << 2) +/* Emulate bit-flips */ +#define MASK_BITFLIPS (1 << 3) +/* Emulate ecc error */ +#define MASK_ECCERR (1 << 4) +/* Emulates -EIO during data read */ +#define MASK_READ_FAILURE (1 << 5) +#define MASK_READ_FAILURE_EC (1 << 6) +#define MASK_READ_FAILURE_VID (1 << 7) +/* Emulates -EIO during data write */ +#define MASK_WRITE_FAILURE (1 << 8) +/* Emulates -EIO during erase a PEB*/ +#define MASK_ERASE_FAILURE (1 << 9) +/* Return UBI_IO_FF when reading EC/VID header */ +#define MASK_IO_FF_EC (1 << 10) +#define MASK_IO_FF_VID (1 << 11) +/* Return UBI_IO_FF_BITFLIPS when reading EC/VID header */ +#define MASK_IO_FF_BITFLIPS_EC (1 << 12) +#define MASK_IO_FF_BITFLIPS_VID (1 << 13) +/* Return UBI_IO_BAD_HDR when reading EC/VID header */ +#define MASK_BAD_HDR_EC (1 << 14) +#define MASK_BAD_HDR_VID (1 << 15) +/* Return UBI_IO_BAD_HDR_EBADMSG when reading EC/VID header */ +#define MASK_BAD_HDR_EBADMSG_EC (1 << 16) +#define MASK_BAD_HDR_EBADMSG_VID (1 << 17) #ifdef CONFIG_MTD_UBI_FAULT_INJECTION -/* Emulate bit-flips */ -#define MASK_BITFLIPS (1 << 2) -/* Emulates -EIO during write/erase */ -#define MASK_WRITE_FAILURE (1 << 3) -#define MASK_ERASE_FAILURE (1 << 4) +extern bool should_fail_eccerr(void); extern bool should_fail_bitflips(void); +extern bool should_fail_read_failure(void); extern bool should_fail_write_failure(void); extern bool should_fail_erase_failure(void); extern bool should_fail_power_cut(void); +extern bool should_fail_io_ff(void); +extern bool should_fail_io_ff_bitflips(void); +extern bool should_fail_bad_hdr(void); +extern bool should_fail_bad_hdr_ebadmsg(void); static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi) { @@ -122,19 +149,72 @@ static inline bool ubi_dbg_fail_erase(const struct ubi_device *ubi) } static inline bool ubi_dbg_fail_power_cut(const struct ubi_device *ubi, - unsigned int caller) + unsigned int caller) { if (ubi->dbg.emulate_failures & caller) return should_fail_power_cut(); return false; } +static inline bool ubi_dbg_fail_read(const struct ubi_device *ubi, + unsigned int caller) +{ + if (ubi->dbg.emulate_failures & caller) + return should_fail_read_failure(); + return false; +} + +static inline bool ubi_dbg_fail_eccerr(const struct ubi_device *ubi) +{ + if (ubi->dbg.emulate_failures & MASK_ECCERR) + return should_fail_eccerr(); + return false; +} + +static inline bool ubi_dbg_fail_ff(const struct ubi_device *ubi, + unsigned int caller) +{ + if (ubi->dbg.emulate_failures & caller) + return should_fail_io_ff(); + return false; +} + +static inline bool ubi_dbg_fail_ff_bitflips(const struct ubi_device *ubi, + unsigned int caller) +{ + if (ubi->dbg.emulate_failures & caller) + return should_fail_io_ff_bitflips(); + return false; +} + +static inline bool ubi_dbg_fail_bad_hdr(const struct ubi_device *ubi, + unsigned int caller) +{ + if (ubi->dbg.emulate_failures & caller) + return should_fail_bad_hdr(); + return false; +} + +static inline bool ubi_dbg_fail_bad_hdr_ebadmsg(const struct ubi_device *ubi, + unsigned int caller) +{ + if (ubi->dbg.emulate_failures & caller) + return should_fail_bad_hdr_ebadmsg(); + return false; +} #else /* CONFIG_MTD_UBI_FAULT_INJECTION */ #define ubi_dbg_fail_bitflip(u) false #define ubi_dbg_fail_write(u) false #define ubi_dbg_fail_erase(u) false #define ubi_dbg_fail_power_cut(u, c) false +#define ubi_dbg_fail_read(u, c) false +#define ubi_dbg_fail_eccerr(u) false +#define ubi_dbg_fail_ff(u, c) false +#define ubi_dbg_fail_ff_bitflips(u, v) false +#define ubi_dbg_fail_bad_hdr(u, c) false +#define ubi_dbg_fail_bad_hdr_ebadmsg(u, c) false + #endif /** @@ -192,6 +272,86 @@ static inline bool ubi_dbg_is_erase_failure(const struct ubi_device *ubi) return ubi_dbg_fail_erase(ubi); } +/** + * ubi_dbg_is_eccerr - if it is time to emulate ECC error. + * @ubi: UBI device description object + * + * Returns true if a ECC error should be emulated, otherwise returns false. + */ +static inline bool ubi_dbg_is_eccerr(const struct ubi_device *ubi) +{ + return ubi_dbg_fail_eccerr(ubi); +} + +/** + * ubi_dbg_is_read_failure - if it is time to emulate a read failure. + * @ubi: UBI device description object + * + * Returns true if a read failure should be emulated, otherwise returns + * false. + */ +static inline bool ubi_dbg_is_read_failure(const struct ubi_device *ubi, + unsigned int caller) +{ + return ubi_dbg_fail_read(ubi, caller); +} + +/** + * ubi_dbg_is_ff - if it is time to emulate that read region is only 0xFF. + * @ubi: UBI device description object + * + * Returns true if read region should be emulated 0xFF, otherwise + * returns false. + */ +static inline bool ubi_dbg_is_ff(const struct ubi_device *ubi, + unsigned int caller) +{ + return ubi_dbg_fail_ff(ubi, caller); +} + +/** + * ubi_dbg_is_ff_bitflips - if it is time to emulate that read region is only 0xFF + * with error reported by the MTD driver + * + * @ubi: UBI device description object + * + * Returns true if read region should be emulated 0xFF and error + * reported by the MTD driver, otherwise returns false. + */ +static inline bool ubi_dbg_is_ff_bitflips(const struct ubi_device *ubi, + unsigned int caller) +{ + return ubi_dbg_fail_ff_bitflips(ubi, caller); +} + +/** + * ubi_dbg_is_bad_hdr - if it is time to emulate a bad header + * @ubi: UBI device description object + * + * Returns true if a bad header error should be emulated, otherwise + * returns false. + */ +static inline bool ubi_dbg_is_bad_hdr(const struct ubi_device *ubi, + unsigned int caller) +{ + return ubi_dbg_fail_bad_hdr(ubi, caller); +} + +/** + * ubi_dbg_is_bad_hdr_ebadmsg - if it is time to emulate a bad header with + * ECC error. + * + * @ubi: UBI device description object + * + * Returns true if a bad header with ECC error should be emulated, otherwise + * returns false. + */ +static inline bool ubi_dbg_is_bad_hdr_ebadmsg(const struct ubi_device *ubi, + unsigned int caller) +{ + return ubi_dbg_fail_bad_hdr_ebadmsg(ubi, caller); +} + /** * ubi_dbg_is_bgt_disabled - if the background thread is disabled. * @ubi: UBI device description object diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index fb70f5227f18..a4999bce435f 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -195,7 +195,19 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, if (ubi_dbg_is_bitflip(ubi)) { dbg_gen("bit-flip (emulated)"); - err = UBI_IO_BITFLIPS; + return UBI_IO_BITFLIPS; + } + + if (ubi_dbg_is_read_failure(ubi, MASK_READ_FAILURE)) { + ubi_warn(ubi, "cannot read %d bytes from PEB %d:%d (emulated)", + len, pnum, offset); + return -EIO; + } + + if (ubi_dbg_is_eccerr(ubi)) { + ubi_warn(ubi, "ECC error (emulated) while reading %d bytes from PEB %d:%d, read %zd bytes", + len, pnum, offset, read); + return -EBADMSG; } } @@ -782,7 +794,36 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, * If there was %-EBADMSG, but the header CRC is still OK, report about * a bit-flip to force scrubbing on this PEB. */ - return read_err ? UBI_IO_BITFLIPS : 0; + if (read_err) + return UBI_IO_BITFLIPS; + + if (ubi_dbg_is_read_failure(ubi, MASK_READ_FAILURE_EC)) { + ubi_warn(ubi, "cannot read EC header from PEB %d (emulated)", + pnum); + return -EIO; + } + + if (ubi_dbg_is_ff(ubi, MASK_IO_FF_EC)) { + ubi_warn(ubi, "bit-all-ff (emulated)"); + return UBI_IO_FF; + } + + if (ubi_dbg_is_ff_bitflips(ubi, MASK_IO_FF_BITFLIPS_EC)) { + ubi_warn(ubi, "bit-all-ff with error reported by MTD driver (emulated)"); + return UBI_IO_FF_BITFLIPS; + } + + if (ubi_dbg_is_bad_hdr(ubi, MASK_BAD_HDR_EC)) { + ubi_warn(ubi, "bad_hdr (emulated)"); + return UBI_IO_BAD_HDR; + } + + if (ubi_dbg_is_bad_hdr_ebadmsg(ubi, MASK_BAD_HDR_EBADMSG_EC)) { + ubi_warn(ubi, "bad_hdr with ECC error (emulated)"); + return UBI_IO_BAD_HDR_EBADMSG; + } + + return 0; } /** @@ -1032,7 +1073,36 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, return -EINVAL; } - return read_err ? UBI_IO_BITFLIPS : 0; + if (read_err) + return UBI_IO_BITFLIPS; + + if (ubi_dbg_is_read_failure(ubi, MASK_READ_FAILURE_VID)) { + ubi_warn(ubi, "cannot read VID header from PEB %d (emulated)", + pnum); + return -EIO; + } + + if (ubi_dbg_is_ff(ubi, MASK_IO_FF_VID)) { + ubi_warn(ubi, "bit-all-ff (emulated)"); + return UBI_IO_FF; + } + + if (ubi_dbg_is_ff_bitflips(ubi, MASK_IO_FF_BITFLIPS_VID)) { + ubi_warn(ubi, "bit-all-ff with error reported by MTD driver (emulated)"); + return UBI_IO_FF_BITFLIPS; + } + + if (ubi_dbg_is_bad_hdr(ubi, MASK_BAD_HDR_VID)) { + ubi_warn(ubi, "bad_hdr (emulated)"); + return UBI_IO_BAD_HDR; + } + + if (ubi_dbg_is_bad_hdr_ebadmsg(ubi, MASK_BAD_HDR_EBADMSG_VID)) { + ubi_warn(ubi, "bad_hdr with ECC error (emulated)"); + return UBI_IO_BAD_HDR_EBADMSG; + } + + return 0; } /** diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 41f57d5717b2..e4b547514504 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -1117,6 +1117,19 @@ static inline struct ubi_vid_hdr *ubi_get_vid_hdr(struct ubi_vid_io_buf *vidb) return vidb->hdr; } +/** + * ubi_ro_mode - switch to read-only mode. + * @ubi: UBI device description object + */ +static inline void ubi_ro_mode(struct ubi_device *ubi) +{ + if (!ubi->ro_mode) { + ubi->ro_mode = 1; + ubi_warn(ubi, "switch to read-only mode"); + dump_stack(); + } +} + /* * This function is equivalent to 'ubi_io_read()', but @offset is relative to * the beginning of the logical eraseblock, not to the beginning of the @@ -1138,20 +1151,13 @@ static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf, int pnum, int offset, int len) { ubi_assert(offset >= 0); - return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len); -} -/** - * ubi_ro_mode - switch to read-only mode. - * @ubi: UBI device description object - */ -static inline void ubi_ro_mode(struct ubi_device *ubi) -{ - if (!ubi->ro_mode) { - ubi->ro_mode = 1; - ubi_warn(ubi, "switch to read-only mode"); - dump_stack(); + if (ubi_dbg_power_cut(ubi, MASK_POWER_CUT_DATA)) { + ubi_warn(ubi, "XXXXX emulating a power cut when writing data XXXXX"); + ubi_ro_mode(ubi); + return -EROFS; } + return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len); } /** -- Gitee From 7f016b94fee07eff5ccc84dead3a9c3203bb1780 Mon Sep 17 00:00:00 2001 From: ZhaoLong Wang Date: Mon, 25 Dec 2023 20:11:36 +0800 Subject: [PATCH 4/5] ubi: Reserve sufficient buffer length for the input mask hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8QZWQ CVE: NA ----------------------------------------- Because the mask received by the emulate_failures interface is a 32-bit unsigned integer, ensure that there is sufficient buffer length to receive and display this value. Signed-off-by: ZhaoLong Wang Reviewed-by: Zhihao Cheng --- drivers/mtd/ubi/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 3f1ee0b07c36..1172823cbf5b 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -332,7 +332,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf, struct dentry *dent = file->f_path.dentry; struct ubi_device *ubi; struct ubi_debug_info *d; - char buf[8]; + char buf[16]; int val; ubi = ubi_get_device(ubi_num); @@ -400,7 +400,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, struct ubi_device *ubi; struct ubi_debug_info *d; size_t buf_size; - char buf[8] = {0}; + char buf[16] = {0}; int val; ubi = ubi_get_device(ubi_num); -- Gitee From 3d7bbab242a175ab05fae9f78348effcf67221c2 Mon Sep 17 00:00:00 2001 From: ZhaoLong Wang Date: Mon, 25 Dec 2023 20:11:37 +0800 Subject: [PATCH 5/5] mtd: Add several functions to the fail_function list hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8QZWQ CVE: NA ----------------------------------------- add mtd_read(), mtd_write(), mtd_erase(), mtd_block_markbad() to fail_function list for testing purpose - Specify the function to inject the fault echo mtd_read > /sys/kernel/debug/fail_function/inject - Specifies the return value of the function to inject the fault printf %#x -12 > /sys/kernel/debug/fail_function/mtd_read/retval - Specify other fault injection configuration parameters. echo -1 > /sys/kernel/debug/fail_function/times echo 100 > /sys/kernel/debug/fail_function/probability echo 15 > /sys/kernel/debug/fail_function/space Signed-off-by: ZhaoLong Wang Reviewed-by: Zhihao Cheng --- drivers/mtd/mtdcore.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 9bd661be3ae9..12d997278b2d 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -1411,6 +1412,7 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) return ret; } EXPORT_SYMBOL_GPL(mtd_erase); +ALLOW_ERROR_INJECTION(mtd_erase, ERRNO); /* * This stuff for eXecute-In-Place. phys is optional and may be set to NULL. @@ -1508,6 +1510,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, return ret; } EXPORT_SYMBOL_GPL(mtd_read); +ALLOW_ERROR_INJECTION(mtd_read, ERRNO); int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) @@ -1524,6 +1527,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, return ret; } EXPORT_SYMBOL_GPL(mtd_write); +ALLOW_ERROR_INJECTION(mtd_write, ERRNO); /* * In blackbox flight recorder like scenarios we want to make successful writes @@ -2344,6 +2348,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) return 0; } EXPORT_SYMBOL_GPL(mtd_block_markbad); +ALLOW_ERROR_INJECTION(mtd_block_markbad, ERRNO); /* * default_mtd_writev - the default writev method -- Gitee