From ad415e09f3dafa49dcb38b8f57fb0c102ba905fa Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Wed, 11 Aug 2021 20:06:31 +0300 Subject: [PATCH] Add fault injection with wrong storage capacity With error injection `errinj_wrong_capacity` filesystem reports a wrong storage capacity. Problem simulated with `errinj_wrong_capacity` may happen in real. For instance see a case described in SQLite documentation: "There are many fraudulent USB sticks in circulation that report to have a high capacity (ex: 8GB) but are really only capable of storing a much smaller amount (ex: 1GB). Attempts to write on these devices will often result in unrelated files being overwritten. Any use of a fraudulent flash memory device can easily lead to database corruption, therefore." 1. https://www.sqlite.org/howtocorrupt.html Closes #62 wrong --- README.md | 3 +++ unreliablefs.conf.5 | 2 ++ unreliablefs_errinj.c | 6 ++++++ unreliablefs_errinj.h | 1 + unreliablefs_ops.c | 8 ++++++++ 5 files changed, 20 insertions(+) diff --git a/README.md b/README.md index 50db83d..98cc919 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ Supported fault injections are: - `errinj_slowdown` - slowdown invoked file operation. - `errinj_1byte_read` - amount of data returned by `read()` call is always limited by a single byte. +- `errinj_wrong_capacity` - filesystem reports a wrong storage capacity. + Simulated error can happen in a wild, for instance see '4.2. Fake capacity USB + sticks' in [How To Corrupt An SQLite Database File](https://www.sqlite.org/howtocorrupt.html). ### Building diff --git a/unreliablefs.conf.5 b/unreliablefs.conf.5 index 20b828a..d4160c1 100644 --- a/unreliablefs.conf.5 +++ b/unreliablefs.conf.5 @@ -40,6 +40,8 @@ File operation slowdown for nanoseconds specified by duration parameter. Return exactly 1 byte on every .Xr read 2 operation. +.It Cm errinj_wrong_capacity +Report a wrong storage capacity. .El .Pp The options are: diff --git a/unreliablefs_errinj.c b/unreliablefs_errinj.c index 681de37..118cb81 100644 --- a/unreliablefs_errinj.c +++ b/unreliablefs_errinj.c @@ -22,6 +22,7 @@ const char *errinj_name[] = "errinj_noop", "errinj_slowdown", "errinj_1byte_read", + "errinj_wrong_capacity", }; typedef enum { @@ -30,6 +31,7 @@ typedef enum { ERRINJ_NOOP, ERRINJ_SLOWDOWN, ERRINJ_1BYTE_READ, + ERRINJ_WRONG_CAPACITY, } errinj_type; typedef struct errinj_conf errinj_conf; @@ -269,6 +271,10 @@ int error_inject(const char* path, fuse_op operation) if (strcmp(op_name, "read") == 0) rc = -ERRINJ_1BYTE_READ; break; + case ERRINJ_WRONG_CAPACITY: + if (strcmp(op_name, "statfs") == 0) + rc = -ERRNO_WRONG_CAPACITY; + break; } } diff --git a/unreliablefs_errinj.h b/unreliablefs_errinj.h index 4889de8..d790ffa 100644 --- a/unreliablefs_errinj.h +++ b/unreliablefs_errinj.h @@ -23,6 +23,7 @@ #define MAX_PROBABLITY 100 #define ERRNO_NOOP -999 #define ERRNO_1BYTE_READ -998 +#define ERRNO_WRONG_CAPACITY -997 #define DEFAULT_SIGNAL_NAME SIGKILL int error_inject(const char* path, fuse_op operation); diff --git a/unreliablefs_ops.c b/unreliablefs_ops.c index 2c20d7d..c834233 100644 --- a/unreliablefs_ops.c +++ b/unreliablefs_ops.c @@ -386,6 +386,14 @@ int unreliable_statfs(const char *path, struct statvfs *buf) int ret = error_inject(path, OP_STATFS); if (ret == -ERRNO_NOOP) { return 0; + } else if (ret == -ERRNO_WRONG_CAPACITY) { + /* wrong capacity */ + ret = statvfs(path, buf); + if (ret == -1) { + return -errno; + } + buf->f_bfree = buf->f_bfree + ( 5 / 100.0 ) * (uint64_t)buf->f_bfree; + return 0; } else if (ret) { return ret; }