This patch makes the super block reserve space for the KSA. It computes the
number of KSA LEBs and adds the ksa_lebs to on-medium superblock. The value is
read off the media. The decision to use a KSA is controlled by use_ubifsec
switch, also added to the superblock, ubifs_info, and is controlled as a mount
option.
This is tested by creating a drive and checking the mount debug output. The
number of LEBS assigned during create_default_filesystem was changed to ensure
that remounting does infact read the old value. When the use_ubifsec option
was not enabled, no LEBs were assigned. Integck was run and the drive was
filled to capacity. The LEBs in the KSA were not used when filled.
Signed-off-by: Joel Reardon <[email protected]>
---
fs/ubifs/sb.c | 29 ++++++++++++++++++++++++++---
fs/ubifs/super.c | 15 +++++++++++++++
fs/ubifs/ubifs-media.h | 8 ++++++--
fs/ubifs/ubifs.h | 23 ++++++++++++++++++++++-
4 files changed, 69 insertions(+), 6 deletions(-)
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index f98d284..5583f2e 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -82,6 +82,7 @@ static int create_default_filesystem(struct ubifs_info *c)
int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
int min_leb_cnt = UBIFS_MIN_LEB_CNT;
+ int ksa_lebs = 0, ksa_first;
long long tmp64, main_bytes;
__le64 tmp_le64;
@@ -138,7 +139,21 @@ static int create_default_filesystem(struct ubifs_info *c)
*/
orph_lebs += 1;
- main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
+ if (c->use_ubifsec) {
+ /*
+ * Compute the size of the key space area based on partition
+ * geometry. The following calculation is equivalant to:
+ * LEBS * LEB_SIZE / DATANODE_SIZE / KEYS_PER_KSA_LEB, because
+ * KEYS_PER_KSA_LEB = LEB_SIZE / KEY_SIZE.
+ */
+ ksa_lebs = (c->leb_cnt * UBIFS_CRYPTO_KEYSIZE)
+ >> UBIFS_BLOCK_SHIFT;
+ ksa_lebs += ksa_lebs >> UBIFS_KSA_LEBS_SCALE_SHIFT;
+ ksa_lebs += UBIFS_KSA_ADD_LEBS;
+ }
+
+ main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - log_lebs - ksa_lebs;
main_lebs -= orph_lebs;
lpt_first = UBIFS_LOG_LNUM + log_lebs;
@@ -153,6 +168,7 @@ static int create_default_filesystem(struct ubifs_info *c)
lpt_first + lpt_lebs - 1);
main_first = c->leb_cnt - main_lebs;
+ ksa_first = c->leb_cnt - main_lebs - ksa_lebs;
/* Create default superblock */
tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
@@ -173,6 +189,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt);
sup->max_bud_bytes = cpu_to_le64(tmp64);
sup->log_lebs = cpu_to_le32(log_lebs);
+ sup->ksa_lebs = cpu_to_le32(ksa_lebs);
sup->lpt_lebs = cpu_to_le32(lpt_lebs);
sup->orph_lebs = cpu_to_le32(orph_lebs);
sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT);
@@ -180,6 +197,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->lsave_cnt = cpu_to_le32(c->lsave_cnt);
sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION);
sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN);
+ sup->use_ubifsec = cpu_to_le32(c->use_ubifsec);
if (c->mount_opts.override_compr)
sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
else
@@ -444,7 +462,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
}
if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs +
- c->orph_lebs + c->main_lebs != c->leb_cnt) {
+ c->orph_lebs + c->main_lebs + c->ksa_lebs != c->leb_cnt) {
err = 12;
goto failed;
}
@@ -605,6 +623,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->max_leb_cnt = le32_to_cpu(sup->max_leb_cnt);
c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
c->log_lebs = le32_to_cpu(sup->log_lebs);
+ c->ksa_lebs = le32_to_cpu(sup->ksa_lebs);
c->lpt_lebs = le32_to_cpu(sup->lpt_lebs);
c->orph_lebs = le32_to_cpu(sup->orph_lebs);
c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
@@ -613,6 +632,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->rp_size = le64_to_cpu(sup->rp_size);
c->rp_uid = le32_to_cpu(sup->rp_uid);
c->rp_gid = le32_to_cpu(sup->rp_gid);
+ c->use_ubifsec = le32_to_cpu(sup->use_ubifsec);
sup_flags = le32_to_cpu(sup->flags);
if (!c->mount_opts.override_compr)
c->default_compr = le16_to_cpu(sup->default_compr);
@@ -646,8 +666,11 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
c->orph_first = c->lpt_last + 1;
c->orph_last = c->orph_first + c->orph_lebs - 1;
- c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+ c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - c->ksa_lebs;
c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+ c->ksa_first = c->leb_cnt - c->main_lebs - c->ksa_lebs;
+ c->ksa_last = c->ksa_first + c->ksa_lebs - 1;
c->main_first = c->leb_cnt - c->main_lebs;
err = validate_sb(c, sup);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index d2fd76f..879ecf5 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -438,6 +438,8 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
else if (c->mount_opts.chk_data_crc == 1)
seq_printf(s, ",no_chk_data_crc");
+ if (c->mount_opts.use_ubifsec)
+ seq_printf(s, ",use_ubifsec");
if (c->mount_opts.override_compr) {
seq_printf(s, ",compr=%s",
ubifs_compr_name(c->mount_opts.compr_type));
@@ -934,6 +936,7 @@ static int check_volume_empty(struct ubifs_info *c)
* Opt_chk_data_crc: check CRCs when reading data nodes
* Opt_no_chk_data_crc: do not check CRCs when reading data nodes
* Opt_override_compr: override default compressor
+ * Opt_use_ubifsec: use ubifsec secure deletion feature
* Opt_err: just end of array marker
*/
enum {
@@ -944,6 +947,7 @@ enum {
Opt_chk_data_crc,
Opt_no_chk_data_crc,
Opt_override_compr,
+ Opt_use_ubifsec,
Opt_err,
};
@@ -955,6 +959,7 @@ static const match_table_t tokens = {
{Opt_chk_data_crc, "chk_data_crc"},
{Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_override_compr, "compr=%s"},
+ {Opt_use_ubifsec, "use_ubifsec"},
{Opt_err, NULL},
};
@@ -1054,6 +1059,12 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->default_compr = c->mount_opts.compr_type;
break;
}
+ case Opt_use_ubifsec:
+ {
+ c->mount_opts.use_ubifsec = 1;
+ c->use_ubifsec = 1;
+ break;
+ }
default:
{
unsigned long flag;
@@ -1446,6 +1457,9 @@ static int mount_ubifs(struct ubifs_info *c)
c->lpt_lebs, c->lpt_first, c->lpt_last);
dbg_msg("orphan area LEBs: %d (%d - %d)",
c->orph_lebs, c->orph_first, c->orph_last);
+ if (c->ksa_lebs)
+ dbg_msg("KSA LEBs: %d (%d - %d)",
+ c->ksa_lebs, c->ksa_first, c->ksa_last);
dbg_msg("main area LEBs: %d (%d - %d)",
c->main_lebs, c->main_first, c->leb_cnt - 1);
dbg_msg("index LEBs: %d", c->lst.idx_lebs);
@@ -1483,6 +1497,7 @@ static int mount_ubifs(struct ubifs_info *c)
c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
dbg_msg("max. seq. number: %llu", c->max_sqnum);
dbg_msg("commit number: %llu", c->cmt_no);
+ dbg_msg("use ubifsec: %d", c->use_ubifsec);
return 0;
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 90f348c..905608b 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -618,10 +618,12 @@ struct ubifs_pad_node {
* @rp_uid: reserve pool UID
* @rp_gid: reserve pool GID
* @rp_size: size of the reserved pool in bytes
- * @padding2: reserved for future, zeroes
* @time_gran: time granularity in nanoseconds
* @uuid: UUID generated when the file system image was created
* @ro_compat_version: UBIFS R/O compatibility version
+ * @crypto_lebs: number of LEBS being used to store keys
+ * @use_ubifsec: whether the file system should use secure deletion
+ * @padding2: reserved for future, zeroes
*/
struct ubifs_sb_node {
struct ubifs_ch ch;
@@ -649,7 +651,9 @@ struct ubifs_sb_node {
__le32 time_gran;
__u8 uuid[16];
__le32 ro_compat_version;
- __u8 padding2[3968];
+ __le32 ksa_lebs;
+ __u8 use_ubifsec;
+ __u8 padding2[3963];
} __packed;
/**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index d7f639a..f34ab84 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -164,6 +164,16 @@
#define UBIFS_CRYPTO_KEYSIZE 16
/* AES in counter mode is the encryption algorithm */
#define UBIFS_CRYPTO_ALGORITHM "ctr(aes)"
+/*
+ * Constant number of KSA LEBS to add to computed value, ensuring two plus a
+ * checkpoint LEB.
+ */
+#define UBIFS_KSA_ADD_LEBS 3
+/*
+ * KSA LEBS is 1.125 * the computed min to allow unused keys when the drive is
+ * full. This shift is used to compute 0.125 * LEBS.
+ */
+#define UBIFS_KSA_LEBS_SCALE_SHIFT 3
/*
* Lockdep classes for UBIFS inode @ui_mutex.
@@ -934,6 +944,7 @@ struct ubifs_orphan {
* specified in @compr_type)
* @compr_type: compressor type to override the superblock compressor with
* (%UBIFS_COMPR_NONE, etc)
+ * @use_ubifsec: use ubifsec secure deletion feature
*/
struct ubifs_mount_opts {
unsigned int unmount_mode:2;
@@ -941,6 +952,7 @@ struct ubifs_mount_opts {
unsigned int chk_data_crc:2;
unsigned int override_compr:1;
unsigned int compr_type:2;
+ unsigned int use_ubifsec:1;
};
/**
@@ -1224,7 +1236,11 @@ struct ubifs_debug_info;
* @size_tree: inode size information for recovery
* @mount_opts: UBIFS-specific mount options
*
- * @keymap: cryptographic key store for secure deletion
+ * @km: cryptographic key store for secure deletion
+ * @ksa_lebs: number of LEBS assigned to the KSA
+ * @ksa_first: number of the first LEB assigned to the KSA
+ * @ksa_last: number of the last LEB assigned to the KSA
+ * @use_ubifsec: switch to enable/disable secure deletion for UBIFS
* @dbg: debugging-related information
*/
struct ubifs_info {
@@ -1454,6 +1470,11 @@ struct ubifs_info {
struct ubifs_mount_opts mount_opts;
struct ubifs_keymap *km;
+ int ksa_lebs;
+ int ksa_first;
+ int ksa_last;
+ int use_ubifsec;
+
struct ubifs_debug_info *dbg;
};
--
1.7.5.4
On Fri, 2012-05-25 at 15:10 +0200, Joel Reardon wrote:
> This patch makes the super block reserve space for the KSA. It computes the
> number of KSA LEBs and adds the ksa_lebs to on-medium superblock. The value is
> read off the media. The decision to use a KSA is controlled by use_ubifsec
> switch, also added to the superblock, ubifs_info, and is controlled as a mount
> option.
>
> This is tested by creating a drive and checking the mount debug output. The
> number of LEBS assigned during create_default_filesystem was changed to ensure
> that remounting does infact read the old value. When the use_ubifsec option
> was not enabled, no LEBs were assigned. Integck was run and the drive was
> filled to capacity. The LEBs in the KSA were not used when filled.
>
> Signed-off-by: Joel Reardon <[email protected]>
I do not have to time to review it now, but please, make sure that the
KSA size is according to 'max_leb_cnt' (see the --max-leb-cnt of the
mkfs.ubifs tool). Also, think about this use-case in general: you have
UBI volume of size X, then the volume is resized to Y > X, then mounted
- UBIFS should work and resize itself to Y, up to the 'max_leb_cnt'. If
Y > 'max_leb_cnt', we resize only to 'max_leb_cnt'.
> struct ubifs_sb_node {
> struct ubifs_ch ch;
> @@ -649,7 +651,9 @@ struct ubifs_sb_node {
> __le32 time_gran;
> __u8 uuid[16];
> __le32 ro_compat_version;
> - __u8 padding2[3968];
> + __le32 ksa_lebs;
> + __u8 use_ubifsec;
If it is only one bit, document that only one bit (LSB?) is used. In the
future someone can add more bits there, and rename it, theoretically
(unlikely though).
--
Best Regards,
Artem Bityutskiy
>
> I do not have to time to review it now, but please, make sure that the
> KSA size is according to 'max_leb_cnt' (see the --max-leb-cnt of the
> mkfs.ubifs tool).
Ahh, I see now I also need to add the min number of lebs to min_leb_cnt if
the feature is enabled.
> Also, think about this use-case in general: you have
> UBI volume of size X, then the volume is resized to Y > X, then mounted
> - UBIFS should work and resize itself to Y, up to the 'max_leb_cnt'. If
> Y > 'max_leb_cnt', we resize only to 'max_leb_cnt'.
For this case, it should be fine if the KSA is sized to maxlebcnt.
However, it will remain that size regardless of the real leb_cnt.
In general, removing KSA blocks is possible, but if datanodes are
encrypted with keys on those blocks, then they must be re-encrypted with a
different key on the smaller set (or somehow write the new last KSA block
containing all the used keys from the removed KSA blocks along with a
relocation table, but this seems like alot of coding if removing LEBs from
the KSA isn't that important.)
Adding LEBs to the KSA is very simple, just add a new entry on the list
and set all the key states to deleted--after purging will be random data;
but KSA LEBs are logically-sequential, so if it comes from used main LEBs
the data nodes need to be relocated. or some complicated code structure
involved in determining where a key for an out-of-range KSA block is
remapped.
Cheers,
Joel Reardon
BTW! While I remember this. You had a concern about bad blocks. I was
thinking that UBI can notify UBIFS every time it marks a block as bad
using the linux notifiers mechanism. UBI would tell UBIFS the volume id
and leb number. Then UBIFS could asynchronously do all the security
stuff which is required in the background thread, or by submitting a
work. I think this is doable, but certainly not a priority.
On Sat, 2012-05-26 at 13:21 +0200, Joel Reardon wrote:
> >
> > I do not have to time to review it now, but please, make sure that the
> > KSA size is according to 'max_leb_cnt' (see the --max-leb-cnt of the
> > mkfs.ubifs tool).
>
> Ahh, I see now I also need to add the min number of lebs to min_leb_cnt if
> the feature is enabled.
Not sure what you mean...
> > Also, think about this use-case in general: you have
> > UBI volume of size X, then the volume is resized to Y > X, then mounted
> > - UBIFS should work and resize itself to Y, up to the 'max_leb_cnt'. If
> > Y > 'max_leb_cnt', we resize only to 'max_leb_cnt'.
>
> For this case, it should be fine if the KSA is sized to maxlebcnt.
> However, it will remain that size regardless of the real leb_cnt.
Yes, that's the idea. The lprops area behaves the same. This area stores
a small object for each LEB, so the more LEBs we have, the larger lprops
area is. And 'max_leb_cnt' defines lprops size. We can easily resize up
to 'max_leb_cnt' but re-sizing more than that is currently impossible.
> In general, removing KSA blocks is possible, but if datanodes are
> encrypted with keys on those blocks, then they must be re-encrypted with a
> different key on the smaller set (or somehow write the new last KSA block
> containing all the used keys from the removed KSA blocks along with a
> relocation table, but this seems like alot of coding if removing LEBs from
> the KSA isn't that important.)
Sure, no need to remove. Create them according to 'max_leb_cnt' and
that's it.
--
Best Regards,
Artem Bityutskiy
This patch makes the super block reserve space for the KSA. It computes the
number of KSA LEBs and adds the ksa_lebs to on-medium superblock. The value is
read off the media. The decision to use a KSA is controlled by use_ubifsec
switch, also added to the superblock, ubifs_info, and is controlled as a mount
option. In create_default_filesystem, the value of leb_cnt is used; later
in the function max_leb_cnt is set to leb_cnt. Later, mkfs.ubifs, will use
the value max_leb_cnt when computing the KSA size.
This is tested by creating a drive and checking the mount debug output. The
number of LEBS assigned during create_default_filesystem was changed to ensure
that remounting does infact read the old value. When the use_ubifsec option
was not enabled, no LEBs were assigned. Integck was run and the drive was
filled to capacity. The LEBs in the KSA were not used when filled.
Signed-off-by: Joel Reardon <[email protected]>
---
fs/ubifs/sb.c | 31 ++++++++++++++++++++++++++++---
fs/ubifs/super.c | 15 +++++++++++++++
fs/ubifs/ubifs-media.h | 9 +++++++--
fs/ubifs/ubifs.h | 23 ++++++++++++++++++++++-
4 files changed, 72 insertions(+), 6 deletions(-)
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index f98d284..f2c9235 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -82,6 +82,7 @@ static int create_default_filesystem(struct ubifs_info *c)
int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
int min_leb_cnt = UBIFS_MIN_LEB_CNT;
+ int ksa_lebs = 0, ksa_first;
long long tmp64, main_bytes;
__le64 tmp_le64;
@@ -103,6 +104,20 @@ static int create_default_filesystem(struct ubifs_info *c)
if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL)
jnl_lebs = DEFAULT_MAX_JNL / c->leb_size;
+ if (c->use_ubifsec) {
+ /*
+ * Compute the size of the key space area based on partition
+ * geometry. The following calculation is equivalant to:
+ * LEBS * LEB_SIZE / DATANODE_SIZE / KEYS_PER_KSA_LEB, because
+ * KEYS_PER_KSA_LEB = LEB_SIZE / KEY_SIZE.
+ */
+ ksa_lebs = (c->leb_cnt * UBIFS_CRYPTO_KEYSIZE)
+ >> UBIFS_BLOCK_SHIFT;
+ ksa_lebs += ksa_lebs >> UBIFS_KSA_LEBS_SCALE_SHIFT;
+ ksa_lebs += UBIFS_KSA_ADD_LEBS;
+ min_leb_cnt += ksa_lebs;
+ }
+
/*
* The log should be large enough to fit reference nodes for all bud
* LEBs. Because buds do not have to start from the beginning of LEBs
@@ -138,7 +153,8 @@ static int create_default_filesystem(struct ubifs_info *c)
*/
orph_lebs += 1;
- main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
+ main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - log_lebs - ksa_lebs;
main_lebs -= orph_lebs;
lpt_first = UBIFS_LOG_LNUM + log_lebs;
@@ -153,6 +169,7 @@ static int create_default_filesystem(struct ubifs_info *c)
lpt_first + lpt_lebs - 1);
main_first = c->leb_cnt - main_lebs;
+ ksa_first = c->leb_cnt - main_lebs - ksa_lebs;
/* Create default superblock */
tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
@@ -173,6 +190,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt);
sup->max_bud_bytes = cpu_to_le64(tmp64);
sup->log_lebs = cpu_to_le32(log_lebs);
+ sup->ksa_lebs = cpu_to_le32(ksa_lebs);
sup->lpt_lebs = cpu_to_le32(lpt_lebs);
sup->orph_lebs = cpu_to_le32(orph_lebs);
sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT);
@@ -180,6 +198,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->lsave_cnt = cpu_to_le32(c->lsave_cnt);
sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION);
sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN);
+ sup->use_ubifsec = cpu_to_le32(c->use_ubifsec);
if (c->mount_opts.override_compr)
sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
else
@@ -389,6 +408,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
*/
min_leb_cnt = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs;
min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6;
+ min_leb_cnt += c->ksa_lebs;
if (c->leb_cnt < min_leb_cnt || c->leb_cnt > c->vi.size) {
ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, "
@@ -444,7 +464,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
}
if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs +
- c->orph_lebs + c->main_lebs != c->leb_cnt) {
+ c->orph_lebs + c->main_lebs + c->ksa_lebs != c->leb_cnt) {
err = 12;
goto failed;
}
@@ -605,6 +625,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->max_leb_cnt = le32_to_cpu(sup->max_leb_cnt);
c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
c->log_lebs = le32_to_cpu(sup->log_lebs);
+ c->ksa_lebs = le32_to_cpu(sup->ksa_lebs);
c->lpt_lebs = le32_to_cpu(sup->lpt_lebs);
c->orph_lebs = le32_to_cpu(sup->orph_lebs);
c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
@@ -613,6 +634,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->rp_size = le64_to_cpu(sup->rp_size);
c->rp_uid = le32_to_cpu(sup->rp_uid);
c->rp_gid = le32_to_cpu(sup->rp_gid);
+ c->use_ubifsec = le32_to_cpu(sup->use_ubifsec);
sup_flags = le32_to_cpu(sup->flags);
if (!c->mount_opts.override_compr)
c->default_compr = le16_to_cpu(sup->default_compr);
@@ -646,8 +668,11 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
c->orph_first = c->lpt_last + 1;
c->orph_last = c->orph_first + c->orph_lebs - 1;
- c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+ c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - c->ksa_lebs;
c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+ c->ksa_first = c->leb_cnt - c->main_lebs - c->ksa_lebs;
+ c->ksa_last = c->ksa_first + c->ksa_lebs - 1;
c->main_first = c->leb_cnt - c->main_lebs;
err = validate_sb(c, sup);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index d2fd76f..879ecf5 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -438,6 +438,8 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
else if (c->mount_opts.chk_data_crc == 1)
seq_printf(s, ",no_chk_data_crc");
+ if (c->mount_opts.use_ubifsec)
+ seq_printf(s, ",use_ubifsec");
if (c->mount_opts.override_compr) {
seq_printf(s, ",compr=%s",
ubifs_compr_name(c->mount_opts.compr_type));
@@ -934,6 +936,7 @@ static int check_volume_empty(struct ubifs_info *c)
* Opt_chk_data_crc: check CRCs when reading data nodes
* Opt_no_chk_data_crc: do not check CRCs when reading data nodes
* Opt_override_compr: override default compressor
+ * Opt_use_ubifsec: use ubifsec secure deletion feature
* Opt_err: just end of array marker
*/
enum {
@@ -944,6 +947,7 @@ enum {
Opt_chk_data_crc,
Opt_no_chk_data_crc,
Opt_override_compr,
+ Opt_use_ubifsec,
Opt_err,
};
@@ -955,6 +959,7 @@ static const match_table_t tokens = {
{Opt_chk_data_crc, "chk_data_crc"},
{Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_override_compr, "compr=%s"},
+ {Opt_use_ubifsec, "use_ubifsec"},
{Opt_err, NULL},
};
@@ -1054,6 +1059,12 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->default_compr = c->mount_opts.compr_type;
break;
}
+ case Opt_use_ubifsec:
+ {
+ c->mount_opts.use_ubifsec = 1;
+ c->use_ubifsec = 1;
+ break;
+ }
default:
{
unsigned long flag;
@@ -1446,6 +1457,9 @@ static int mount_ubifs(struct ubifs_info *c)
c->lpt_lebs, c->lpt_first, c->lpt_last);
dbg_msg("orphan area LEBs: %d (%d - %d)",
c->orph_lebs, c->orph_first, c->orph_last);
+ if (c->ksa_lebs)
+ dbg_msg("KSA LEBs: %d (%d - %d)",
+ c->ksa_lebs, c->ksa_first, c->ksa_last);
dbg_msg("main area LEBs: %d (%d - %d)",
c->main_lebs, c->main_first, c->leb_cnt - 1);
dbg_msg("index LEBs: %d", c->lst.idx_lebs);
@@ -1483,6 +1497,7 @@ static int mount_ubifs(struct ubifs_info *c)
c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
dbg_msg("max. seq. number: %llu", c->max_sqnum);
dbg_msg("commit number: %llu", c->cmt_no);
+ dbg_msg("use ubifsec: %d", c->use_ubifsec);
return 0;
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 90f348c..1dda25d 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -618,10 +618,13 @@ struct ubifs_pad_node {
* @rp_uid: reserve pool UID
* @rp_gid: reserve pool GID
* @rp_size: size of the reserved pool in bytes
- * @padding2: reserved for future, zeroes
* @time_gran: time granularity in nanoseconds
* @uuid: UUID generated when the file system image was created
* @ro_compat_version: UBIFS R/O compatibility version
+ * @crypto_lebs: number of LEBS being used to store keys
+ * @use_ubifsec: the LSB signifies whether the file system should use secure
+ * deletion
+ * @padding2: reserved for future, zeroes
*/
struct ubifs_sb_node {
struct ubifs_ch ch;
@@ -649,7 +652,9 @@ struct ubifs_sb_node {
__le32 time_gran;
__u8 uuid[16];
__le32 ro_compat_version;
- __u8 padding2[3968];
+ __le32 ksa_lebs;
+ __u8 use_ubifsec;
+ __u8 padding2[3963];
} __packed;
/**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index d7f639a..f34ab84 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -164,6 +164,16 @@
#define UBIFS_CRYPTO_KEYSIZE 16
/* AES in counter mode is the encryption algorithm */
#define UBIFS_CRYPTO_ALGORITHM "ctr(aes)"
+/*
+ * Constant number of KSA LEBS to add to computed value, ensuring two plus a
+ * checkpoint LEB.
+ */
+#define UBIFS_KSA_ADD_LEBS 3
+/*
+ * KSA LEBS is 1.125 * the computed min to allow unused keys when the drive is
+ * full. This shift is used to compute 0.125 * LEBS.
+ */
+#define UBIFS_KSA_LEBS_SCALE_SHIFT 3
/*
* Lockdep classes for UBIFS inode @ui_mutex.
@@ -934,6 +944,7 @@ struct ubifs_orphan {
* specified in @compr_type)
* @compr_type: compressor type to override the superblock compressor with
* (%UBIFS_COMPR_NONE, etc)
+ * @use_ubifsec: use ubifsec secure deletion feature
*/
struct ubifs_mount_opts {
unsigned int unmount_mode:2;
@@ -941,6 +952,7 @@ struct ubifs_mount_opts {
unsigned int chk_data_crc:2;
unsigned int override_compr:1;
unsigned int compr_type:2;
+ unsigned int use_ubifsec:1;
};
/**
@@ -1224,7 +1236,11 @@ struct ubifs_debug_info;
* @size_tree: inode size information for recovery
* @mount_opts: UBIFS-specific mount options
*
- * @keymap: cryptographic key store for secure deletion
+ * @km: cryptographic key store for secure deletion
+ * @ksa_lebs: number of LEBS assigned to the KSA
+ * @ksa_first: number of the first LEB assigned to the KSA
+ * @ksa_last: number of the last LEB assigned to the KSA
+ * @use_ubifsec: switch to enable/disable secure deletion for UBIFS
* @dbg: debugging-related information
*/
struct ubifs_info {
@@ -1454,6 +1470,11 @@ struct ubifs_info {
struct ubifs_mount_opts mount_opts;
struct ubifs_keymap *km;
+ int ksa_lebs;
+ int ksa_first;
+ int ksa_last;
+ int use_ubifsec;
+
struct ubifs_debug_info *dbg;
};
--
1.7.5.4
Hi,
On Wed, 2012-05-30 at 15:32 +0200, Joel Reardon wrote:
> @@ -389,6 +408,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
> */
> min_leb_cnt = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs;
> min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6;
> + min_leb_cnt += c->ksa_lebs;
You need to validate that:
1. if use_ubifsec is true, then ksa_lebs is not zero.
2. ksa_lebs is sane - not too small, not too large.
> diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
> index 90f348c..1dda25d 100644
> --- a/fs/ubifs/ubifs-media.h
> +++ b/fs/ubifs/ubifs-media.h
> @@ -618,10 +618,13 @@ struct ubifs_pad_node {
> * @rp_uid: reserve pool UID
> * @rp_gid: reserve pool GID
> * @rp_size: size of the reserved pool in bytes
> - * @padding2: reserved for future, zeroes
Do not remove this comment.
> * @time_gran: time granularity in nanoseconds
> * @uuid: UUID generated when the file system image was created
> * @ro_compat_version: UBIFS R/O compatibility version
> + * @crypto_lebs: number of LEBS being used to store keys
> + * @use_ubifsec: the LSB signifies whether the file system should use secure
> + * deletion
> + * @padding2: reserved for future, zeroes
> */
> struct ubifs_sb_node {
> struct ubifs_ch ch;
> @@ -649,7 +652,9 @@ struct ubifs_sb_node {
> __le32 time_gran;
> __u8 uuid[16];
> __le32 ro_compat_version;
> - __u8 padding2[3968];
> + __le32 ksa_lebs;
> + __u8 use_ubifsec;
> + __u8 padding2[3963];
> } __packed;
--
Best Regards,
Artem Bityutskiy
> You need to validate that:
>
> 1. if use_ubifsec is true, then ksa_lebs is not zero.
> 2. ksa_lebs is sane - not too small, not too large.
>
Will add an assert and a dbg check function.
> > diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
> > index 90f348c..1dda25d 100644
> > --- a/fs/ubifs/ubifs-media.h
> > +++ b/fs/ubifs/ubifs-media.h
> > @@ -618,10 +618,13 @@ struct ubifs_pad_node {
> > * @rp_uid: reserve pool UID
> > * @rp_gid: reserve pool GID
> > * @rp_size: size of the reserved pool in bytes
> > - * @padding2: reserved for future, zeroes
>
> Do not remove this comment.
>
I only moved it, new fields were added to the struct and it was not longer
in the correct place in the comment.
> > * @time_gran: time granularity in nanoseconds
> > * @uuid: UUID generated when the file system image was created
> > * @ro_compat_version: UBIFS R/O compatibility version
> > + * @crypto_lebs: number of LEBS being used to store keys
> > + * @use_ubifsec: the LSB signifies whether the file system should use secure
> > + * deletion
> > + * @padding2: reserved for future, zeroes
> > */
Cheers,
Joel Reardon
On Thu, 2012-05-31 at 12:12 +0200, Joel Reardon wrote:
> > You need to validate that:
> >
> > 1. if use_ubifsec is true, then ksa_lebs is not zero.
> > 2. ksa_lebs is sane - not too small, not too large.
> >
>
> Will add an assert and a dbg check function.
Why assert? The point is that if we read the superblock we should check
that it is sane. See teh validate_sb() function. If any of the above 2
checks fail - the superblock is insane and we should refuse mounting.
--
Best Regards,
Artem Bityutskiy
On Thu, 2012-05-31 at 13:19 +0300, Artem Bityutskiy wrote:
> Why assert? The point is that if we read the superblock we should check
> that it is sane. See teh validate_sb() function. If any of the above 2
> checks fail - the superblock is insane and we should refuse mounting.
Let me put it this way. You are reading the KSA-related fields from the
flash. You cannot assume they have reasonable values to prevent attacks.
This is the general UBI/UBIFS pattern - we validate everything we read
from the flash. We check the CRC and make sure all the fields we use
have reasonable values.
--
Best Regards,
Artem Bityutskiy
This patch makes the super block reserve space for the KSA. It computes the
number of KSA LEBs and adds the ksa_lebs to on-medium superblock. The value is
read off the media. The decision to use a KSA is controlled by use_ubifsec
switch, also added to the superblock, ubifs_info, and is controlled as a mount
option. Validate superblock also checks these values.
This is tested by creating a drive and checking the mount debug output. The
number of LEBS assigned during create_default_filesystem was changed to ensure
that remounting does infact read the old value. When the use_ubifsec option
was not enabled, no LEBs were assigned. Integck was run and the drive was
filled to capacity. The LEBs in the KSA were not used when filled. Invalid
value for ksa_lebs were used and then rejected by validate superblock.
Signed-off-by: Joel Reardon <[email protected]>
---
fs/ubifs/sb.c | 49 +++++++++++++++++++++++++++++++++++++++++++++--
fs/ubifs/super.c | 15 ++++++++++++++
fs/ubifs/ubifs-media.h | 9 ++++++-
fs/ubifs/ubifs.h | 23 +++++++++++++++++++++-
4 files changed, 90 insertions(+), 6 deletions(-)
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index f98d284..08551c0 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -82,6 +82,7 @@ static int create_default_filesystem(struct ubifs_info *c)
int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
int min_leb_cnt = UBIFS_MIN_LEB_CNT;
+ int ksa_lebs = 0, ksa_first;
long long tmp64, main_bytes;
__le64 tmp_le64;
@@ -103,6 +104,20 @@ static int create_default_filesystem(struct ubifs_info *c)
if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL)
jnl_lebs = DEFAULT_MAX_JNL / c->leb_size;
+ if (c->use_ubifsec) {
+ /*
+ * Compute the size of the key space area based on partition
+ * geometry. The following calculation is equivalant to:
+ * LEBS * LEB_SIZE / DATANODE_SIZE / KEYS_PER_KSA_LEB, because
+ * KEYS_PER_KSA_LEB = LEB_SIZE / KEY_SIZE.
+ */
+ ksa_lebs = (c->leb_cnt * UBIFS_CRYPTO_KEYSIZE)
+ >> UBIFS_BLOCK_SHIFT;
+ ksa_lebs += ksa_lebs >> UBIFS_KSA_LEBS_SCALE_SHIFT;
+ ksa_lebs += UBIFS_KSA_ADD_LEBS;
+ min_leb_cnt += ksa_lebs;
+ }
+
/*
* The log should be large enough to fit reference nodes for all bud
* LEBs. Because buds do not have to start from the beginning of LEBs
@@ -138,7 +153,8 @@ static int create_default_filesystem(struct ubifs_info *c)
*/
orph_lebs += 1;
- main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
+ main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - log_lebs - ksa_lebs;
main_lebs -= orph_lebs;
lpt_first = UBIFS_LOG_LNUM + log_lebs;
@@ -153,6 +169,7 @@ static int create_default_filesystem(struct ubifs_info *c)
lpt_first + lpt_lebs - 1);
main_first = c->leb_cnt - main_lebs;
+ ksa_first = c->leb_cnt - main_lebs - ksa_lebs;
/* Create default superblock */
tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
@@ -173,6 +190,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt);
sup->max_bud_bytes = cpu_to_le64(tmp64);
sup->log_lebs = cpu_to_le32(log_lebs);
+ sup->ksa_lebs = cpu_to_le32(ksa_lebs);
sup->lpt_lebs = cpu_to_le32(lpt_lebs);
sup->orph_lebs = cpu_to_le32(orph_lebs);
sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT);
@@ -180,6 +198,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->lsave_cnt = cpu_to_le32(c->lsave_cnt);
sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION);
sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN);
+ sup->use_ubifsec = cpu_to_le32(c->use_ubifsec);
if (c->mount_opts.override_compr)
sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
else
@@ -389,6 +408,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
*/
min_leb_cnt = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs;
min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6;
+ min_leb_cnt += c->ksa_lebs;
if (c->leb_cnt < min_leb_cnt || c->leb_cnt > c->vi.size) {
ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, "
@@ -444,7 +464,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
}
if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs +
- c->orph_lebs + c->main_lebs != c->leb_cnt) {
+ c->orph_lebs + c->main_lebs + c->ksa_lebs != c->leb_cnt) {
err = 12;
goto failed;
}
@@ -465,6 +485,24 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
goto failed;
}
+ if (c->use_ubifsec && c->ksa_lebs <
+ ((c->leb_cnt * UBIFS_CRYPTO_KEYSIZE) >> UBIFS_BLOCK_SHIFT) +
+ UBIFS_KSA_ADD_LEBS) {
+ err = 16;
+ goto failed;
+ }
+
+ if (c->use_ubifsec && c->ksa_lebs >
+ (((c->leb_cnt * UBIFS_CRYPTO_KEYSIZE) >> UBIFS_BLOCK_SHIFT) << 1) +
+ UBIFS_KSA_ADD_LEBS) {
+ err = 17;
+ goto failed;
+ }
+
+ if (!c->use_ubifsec && c->ksa_lebs != 0) {
+ err = 18;
+ goto failed;
+ }
return 0;
failed:
@@ -605,6 +643,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->max_leb_cnt = le32_to_cpu(sup->max_leb_cnt);
c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
c->log_lebs = le32_to_cpu(sup->log_lebs);
+ c->ksa_lebs = le32_to_cpu(sup->ksa_lebs);
c->lpt_lebs = le32_to_cpu(sup->lpt_lebs);
c->orph_lebs = le32_to_cpu(sup->orph_lebs);
c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
@@ -613,6 +652,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->rp_size = le64_to_cpu(sup->rp_size);
c->rp_uid = le32_to_cpu(sup->rp_uid);
c->rp_gid = le32_to_cpu(sup->rp_gid);
+ c->use_ubifsec = le32_to_cpu(sup->use_ubifsec);
sup_flags = le32_to_cpu(sup->flags);
if (!c->mount_opts.override_compr)
c->default_compr = le16_to_cpu(sup->default_compr);
@@ -646,8 +686,11 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
c->orph_first = c->lpt_last + 1;
c->orph_last = c->orph_first + c->orph_lebs - 1;
- c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+ c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - c->ksa_lebs;
c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+ c->ksa_first = c->leb_cnt - c->main_lebs - c->ksa_lebs;
+ c->ksa_last = c->ksa_first + c->ksa_lebs - 1;
c->main_first = c->leb_cnt - c->main_lebs;
err = validate_sb(c, sup);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index d2fd76f..879ecf5 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -438,6 +438,8 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
else if (c->mount_opts.chk_data_crc == 1)
seq_printf(s, ",no_chk_data_crc");
+ if (c->mount_opts.use_ubifsec)
+ seq_printf(s, ",use_ubifsec");
if (c->mount_opts.override_compr) {
seq_printf(s, ",compr=%s",
ubifs_compr_name(c->mount_opts.compr_type));
@@ -934,6 +936,7 @@ static int check_volume_empty(struct ubifs_info *c)
* Opt_chk_data_crc: check CRCs when reading data nodes
* Opt_no_chk_data_crc: do not check CRCs when reading data nodes
* Opt_override_compr: override default compressor
+ * Opt_use_ubifsec: use ubifsec secure deletion feature
* Opt_err: just end of array marker
*/
enum {
@@ -944,6 +947,7 @@ enum {
Opt_chk_data_crc,
Opt_no_chk_data_crc,
Opt_override_compr,
+ Opt_use_ubifsec,
Opt_err,
};
@@ -955,6 +959,7 @@ static const match_table_t tokens = {
{Opt_chk_data_crc, "chk_data_crc"},
{Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_override_compr, "compr=%s"},
+ {Opt_use_ubifsec, "use_ubifsec"},
{Opt_err, NULL},
};
@@ -1054,6 +1059,12 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->default_compr = c->mount_opts.compr_type;
break;
}
+ case Opt_use_ubifsec:
+ {
+ c->mount_opts.use_ubifsec = 1;
+ c->use_ubifsec = 1;
+ break;
+ }
default:
{
unsigned long flag;
@@ -1446,6 +1457,9 @@ static int mount_ubifs(struct ubifs_info *c)
c->lpt_lebs, c->lpt_first, c->lpt_last);
dbg_msg("orphan area LEBs: %d (%d - %d)",
c->orph_lebs, c->orph_first, c->orph_last);
+ if (c->ksa_lebs)
+ dbg_msg("KSA LEBs: %d (%d - %d)",
+ c->ksa_lebs, c->ksa_first, c->ksa_last);
dbg_msg("main area LEBs: %d (%d - %d)",
c->main_lebs, c->main_first, c->leb_cnt - 1);
dbg_msg("index LEBs: %d", c->lst.idx_lebs);
@@ -1483,6 +1497,7 @@ static int mount_ubifs(struct ubifs_info *c)
c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
dbg_msg("max. seq. number: %llu", c->max_sqnum);
dbg_msg("commit number: %llu", c->cmt_no);
+ dbg_msg("use ubifsec: %d", c->use_ubifsec);
return 0;
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 90f348c..1dda25d 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -618,10 +618,13 @@ struct ubifs_pad_node {
* @rp_uid: reserve pool UID
* @rp_gid: reserve pool GID
* @rp_size: size of the reserved pool in bytes
- * @padding2: reserved for future, zeroes
* @time_gran: time granularity in nanoseconds
* @uuid: UUID generated when the file system image was created
* @ro_compat_version: UBIFS R/O compatibility version
+ * @crypto_lebs: number of LEBS being used to store keys
+ * @use_ubifsec: the LSB signifies whether the file system should use secure
+ * deletion
+ * @padding2: reserved for future, zeroes
*/
struct ubifs_sb_node {
struct ubifs_ch ch;
@@ -649,7 +652,9 @@ struct ubifs_sb_node {
__le32 time_gran;
__u8 uuid[16];
__le32 ro_compat_version;
- __u8 padding2[3968];
+ __le32 ksa_lebs;
+ __u8 use_ubifsec;
+ __u8 padding2[3963];
} __packed;
/**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index d7f639a..f34ab84 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -164,6 +164,16 @@
#define UBIFS_CRYPTO_KEYSIZE 16
/* AES in counter mode is the encryption algorithm */
#define UBIFS_CRYPTO_ALGORITHM "ctr(aes)"
+/*
+ * Constant number of KSA LEBS to add to computed value, ensuring two plus a
+ * checkpoint LEB.
+ */
+#define UBIFS_KSA_ADD_LEBS 3
+/*
+ * KSA LEBS is 1.125 * the computed min to allow unused keys when the drive is
+ * full. This shift is used to compute 0.125 * LEBS.
+ */
+#define UBIFS_KSA_LEBS_SCALE_SHIFT 3
/*
* Lockdep classes for UBIFS inode @ui_mutex.
@@ -934,6 +944,7 @@ struct ubifs_orphan {
* specified in @compr_type)
* @compr_type: compressor type to override the superblock compressor with
* (%UBIFS_COMPR_NONE, etc)
+ * @use_ubifsec: use ubifsec secure deletion feature
*/
struct ubifs_mount_opts {
unsigned int unmount_mode:2;
@@ -941,6 +952,7 @@ struct ubifs_mount_opts {
unsigned int chk_data_crc:2;
unsigned int override_compr:1;
unsigned int compr_type:2;
+ unsigned int use_ubifsec:1;
};
/**
@@ -1224,7 +1236,11 @@ struct ubifs_debug_info;
* @size_tree: inode size information for recovery
* @mount_opts: UBIFS-specific mount options
*
- * @keymap: cryptographic key store for secure deletion
+ * @km: cryptographic key store for secure deletion
+ * @ksa_lebs: number of LEBS assigned to the KSA
+ * @ksa_first: number of the first LEB assigned to the KSA
+ * @ksa_last: number of the last LEB assigned to the KSA
+ * @use_ubifsec: switch to enable/disable secure deletion for UBIFS
* @dbg: debugging-related information
*/
struct ubifs_info {
@@ -1454,6 +1470,11 @@ struct ubifs_info {
struct ubifs_mount_opts mount_opts;
struct ubifs_keymap *km;
+ int ksa_lebs;
+ int ksa_first;
+ int ksa_last;
+ int use_ubifsec;
+
struct ubifs_debug_info *dbg;
};
--
1.7.5.4
Hi Joel,
still a couple of small requests.
On Wed, 2012-06-06 at 12:03 +0200, Joel Reardon wrote:
> + if (c->use_ubifsec && c->ksa_lebs <
> + ((c->leb_cnt * UBIFS_CRYPTO_KEYSIZE) >> UBIFS_BLOCK_SHIFT) +
Please, do something like this:
min_leb_cnt = (c->leb_cnt * UBIFS_CRYPTO_KEYSIZE) >> UBIFS_BLOCK_SHIFT;
if (c->use_ubifsec && c->ksa_lebs < min_leb_cnt)
bah;
min_leb_cnt += UBIFS_KSA_ADD_LEBS;
if ()
bah;
That would be more readable.
> struct ubifs_sb_node {
> struct ubifs_ch ch;
> @@ -649,7 +652,9 @@ struct ubifs_sb_node {
> __le32 time_gran;
> __u8 uuid[16];
> __le32 ro_compat_version;
> - __u8 padding2[3968];
> + __le32 ksa_lebs;
> + __u8 use_ubifsec;
> + __u8 padding2[3963];
> } __packed;
I've just noticed that we have the 'flags' field ane a set of flags like
"UBIFS_FLG_SPACE_FIXUP". For UBIFSEC, could you please add
"UBIFS_FLG_UBFSEC = 0x8" or you name it. This would be more consistent
way.
--
Best Regards,
Artem Bityutskiy
This patch makes the super block reserve space for the KSA. It computes the
number of KSA LEBs and adds the ksa_lebs to on-medium superblock. The value is
read off the media. The decision to use a KSA is controlled by use_ubifsec
switch, added as a flag to the superblock, ubifs_info, and is controlled as a mount
option. Validate superblock also checks these values.
This is tested by creating a drive and checking the mount debug output. The
number of LEBS assigned during create_default_filesystem was changed to ensure
that remounting does infact read the old value. When the use_ubifsec option
was not enabled, no LEBs were assigned. Integck was run and the drive was
filled to capacity. The LEBs in the KSA were not used when filled. Invalid
value for ksa_lebs were used and then rejected by validate superblock.
Signed-off-by: Joel Reardon <[email protected]>
---
fs/ubifs/sb.c | 54 ++++++++++++++++++++++++++++++++++++++++++++---
fs/ubifs/super.c | 15 +++++++++++++
fs/ubifs/ubifs-media.h | 8 +++++-
fs/ubifs/ubifs.h | 23 +++++++++++++++++++-
4 files changed, 93 insertions(+), 7 deletions(-)
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index f98d284..c1665ca 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -82,6 +82,7 @@ static int create_default_filesystem(struct ubifs_info *c)
int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
int min_leb_cnt = UBIFS_MIN_LEB_CNT;
+ int ksa_lebs = 0, ksa_first;
long long tmp64, main_bytes;
__le64 tmp_le64;
@@ -103,6 +104,20 @@ static int create_default_filesystem(struct ubifs_info *c)
if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL)
jnl_lebs = DEFAULT_MAX_JNL / c->leb_size;
+ if (c->use_ubifsec) {
+ /*
+ * Compute the size of the key space area based on partition
+ * geometry. The following calculation is equivalant to:
+ * LEBS * LEB_SIZE / DATANODE_SIZE / KEYS_PER_KSA_LEB, because
+ * KEYS_PER_KSA_LEB = LEB_SIZE / KEY_SIZE.
+ */
+ ksa_lebs = (c->leb_cnt * UBIFS_CRYPTO_KEYSIZE)
+ >> UBIFS_BLOCK_SHIFT;
+ ksa_lebs += ksa_lebs >> UBIFS_KSA_LEBS_SCALE_SHIFT;
+ ksa_lebs += UBIFS_KSA_ADD_LEBS;
+ min_leb_cnt += ksa_lebs;
+ }
+
/*
* The log should be large enough to fit reference nodes for all bud
* LEBs. Because buds do not have to start from the beginning of LEBs
@@ -138,7 +153,8 @@ static int create_default_filesystem(struct ubifs_info *c)
*/
orph_lebs += 1;
- main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
+ main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - log_lebs - ksa_lebs;
main_lebs -= orph_lebs;
lpt_first = UBIFS_LOG_LNUM + log_lebs;
@@ -153,6 +169,7 @@ static int create_default_filesystem(struct ubifs_info *c)
lpt_first + lpt_lebs - 1);
main_first = c->leb_cnt - main_lebs;
+ ksa_first = c->leb_cnt - main_lebs - ksa_lebs;
/* Create default superblock */
tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
@@ -163,6 +180,8 @@ static int create_default_filesystem(struct ubifs_info *c)
tmp64 = (long long)max_buds * c->leb_size;
if (big_lpt)
sup_flags |= UBIFS_FLG_BIGLPT;
+ if (c->use_ubifsec)
+ sup_flags |= UBIFS_FLG_UBFSEC;
sup->ch.node_type = UBIFS_SB_NODE;
sup->key_hash = UBIFS_KEY_HASH_R5;
@@ -173,6 +192,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt);
sup->max_bud_bytes = cpu_to_le64(tmp64);
sup->log_lebs = cpu_to_le32(log_lebs);
+ sup->ksa_lebs = cpu_to_le32(ksa_lebs);
sup->lpt_lebs = cpu_to_le32(lpt_lebs);
sup->orph_lebs = cpu_to_le32(orph_lebs);
sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT);
@@ -351,6 +371,8 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
{
long long max_bytes;
int err = 1, min_leb_cnt;
+ int max_ksa_leb_cnt;
+ int min_ksa_leb_cnt;
if (!c->key_hash) {
err = 2;
@@ -389,6 +411,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
*/
min_leb_cnt = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs;
min_leb_cnt += c->lpt_lebs + c->orph_lebs + c->jhead_cnt + 6;
+ min_leb_cnt += c->ksa_lebs;
if (c->leb_cnt < min_leb_cnt || c->leb_cnt > c->vi.size) {
ubifs_err("bad LEB count: %d in superblock, %d on UBI volume, "
@@ -444,7 +467,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
}
if (UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs +
- c->orph_lebs + c->main_lebs != c->leb_cnt) {
+ c->orph_lebs + c->main_lebs + c->ksa_lebs != c->leb_cnt) {
err = 12;
goto failed;
}
@@ -465,6 +488,25 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
goto failed;
}
+ min_ksa_leb_cnt = (c->leb_cnt * UBIFS_CRYPTO_KEYSIZE)
+ >> UBIFS_BLOCK_SHIFT;
+ max_ksa_leb_cnt = min_ksa_leb_cnt << 1;
+ min_ksa_leb_cnt += UBIFS_KSA_ADD_LEBS;
+ max_ksa_leb_cnt += UBIFS_KSA_ADD_LEBS;
+ if (c->use_ubifsec && c->ksa_lebs < min_ksa_leb_cnt) {
+ err = 16;
+ goto failed;
+ }
+
+ if (c->use_ubifsec && c->ksa_lebs > max_ksa_leb_cnt) {
+ err = 17;
+ goto failed;
+ }
+
+ if (!c->use_ubifsec && c->ksa_lebs != 0) {
+ err = 18;
+ goto failed;
+ }
return 0;
failed:
@@ -605,6 +647,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->max_leb_cnt = le32_to_cpu(sup->max_leb_cnt);
c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
c->log_lebs = le32_to_cpu(sup->log_lebs);
+ c->ksa_lebs = le32_to_cpu(sup->ksa_lebs);
c->lpt_lebs = le32_to_cpu(sup->lpt_lebs);
c->orph_lebs = le32_to_cpu(sup->orph_lebs);
c->jhead_cnt = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
@@ -616,11 +659,11 @@ int ubifs_read_superblock(struct ubifs_info *c)
sup_flags = le32_to_cpu(sup->flags);
if (!c->mount_opts.override_compr)
c->default_compr = le16_to_cpu(sup->default_compr);
-
c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
memcpy(&c->uuid, &sup->uuid, 16);
c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+ c->use_ubifsec = !!(sup_flags & UBIFS_FLG_UBFSEC);
/* Automatically increase file system size to the maximum size */
c->old_leb_cnt = c->leb_cnt;
@@ -646,8 +689,11 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
c->orph_first = c->lpt_last + 1;
c->orph_last = c->orph_first + c->orph_lebs - 1;
- c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+ c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS
+ - c->ksa_lebs;
c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+ c->ksa_first = c->leb_cnt - c->main_lebs - c->ksa_lebs;
+ c->ksa_last = c->ksa_first + c->ksa_lebs - 1;
c->main_first = c->leb_cnt - c->main_lebs;
err = validate_sb(c, sup);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index d2fd76f..879ecf5 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -438,6 +438,8 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root)
else if (c->mount_opts.chk_data_crc == 1)
seq_printf(s, ",no_chk_data_crc");
+ if (c->mount_opts.use_ubifsec)
+ seq_printf(s, ",use_ubifsec");
if (c->mount_opts.override_compr) {
seq_printf(s, ",compr=%s",
ubifs_compr_name(c->mount_opts.compr_type));
@@ -934,6 +936,7 @@ static int check_volume_empty(struct ubifs_info *c)
* Opt_chk_data_crc: check CRCs when reading data nodes
* Opt_no_chk_data_crc: do not check CRCs when reading data nodes
* Opt_override_compr: override default compressor
+ * Opt_use_ubifsec: use ubifsec secure deletion feature
* Opt_err: just end of array marker
*/
enum {
@@ -944,6 +947,7 @@ enum {
Opt_chk_data_crc,
Opt_no_chk_data_crc,
Opt_override_compr,
+ Opt_use_ubifsec,
Opt_err,
};
@@ -955,6 +959,7 @@ static const match_table_t tokens = {
{Opt_chk_data_crc, "chk_data_crc"},
{Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_override_compr, "compr=%s"},
+ {Opt_use_ubifsec, "use_ubifsec"},
{Opt_err, NULL},
};
@@ -1054,6 +1059,12 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->default_compr = c->mount_opts.compr_type;
break;
}
+ case Opt_use_ubifsec:
+ {
+ c->mount_opts.use_ubifsec = 1;
+ c->use_ubifsec = 1;
+ break;
+ }
default:
{
unsigned long flag;
@@ -1446,6 +1457,9 @@ static int mount_ubifs(struct ubifs_info *c)
c->lpt_lebs, c->lpt_first, c->lpt_last);
dbg_msg("orphan area LEBs: %d (%d - %d)",
c->orph_lebs, c->orph_first, c->orph_last);
+ if (c->ksa_lebs)
+ dbg_msg("KSA LEBs: %d (%d - %d)",
+ c->ksa_lebs, c->ksa_first, c->ksa_last);
dbg_msg("main area LEBs: %d (%d - %d)",
c->main_lebs, c->main_first, c->leb_cnt - 1);
dbg_msg("index LEBs: %d", c->lst.idx_lebs);
@@ -1483,6 +1497,7 @@ static int mount_ubifs(struct ubifs_info *c)
c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20);
dbg_msg("max. seq. number: %llu", c->max_sqnum);
dbg_msg("commit number: %llu", c->cmt_no);
+ dbg_msg("use ubifsec: %d", c->use_ubifsec);
return 0;
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 90f348c..556567b 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -402,10 +402,12 @@ enum {
*
* UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
* UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
+ * UBIFS_FLG_UBFSEC: use ubifs secure deletion enhancement
*/
enum {
UBIFS_FLG_BIGLPT = 0x02,
UBIFS_FLG_SPACE_FIXUP = 0x04,
+ UBIFS_FLG_UBFSEC = 0x08,
};
/**
@@ -618,10 +620,11 @@ struct ubifs_pad_node {
* @rp_uid: reserve pool UID
* @rp_gid: reserve pool GID
* @rp_size: size of the reserved pool in bytes
- * @padding2: reserved for future, zeroes
* @time_gran: time granularity in nanoseconds
* @uuid: UUID generated when the file system image was created
* @ro_compat_version: UBIFS R/O compatibility version
+ * @crypto_lebs: number of LEBS being used to store keys
+ * @padding2: reserved for future, zeroes
*/
struct ubifs_sb_node {
struct ubifs_ch ch;
@@ -649,7 +652,8 @@ struct ubifs_sb_node {
__le32 time_gran;
__u8 uuid[16];
__le32 ro_compat_version;
- __u8 padding2[3968];
+ __le32 ksa_lebs;
+ __u8 padding2[3964];
} __packed;
/**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index d7f639a..f34ab84 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -164,6 +164,16 @@
#define UBIFS_CRYPTO_KEYSIZE 16
/* AES in counter mode is the encryption algorithm */
#define UBIFS_CRYPTO_ALGORITHM "ctr(aes)"
+/*
+ * Constant number of KSA LEBS to add to computed value, ensuring two plus a
+ * checkpoint LEB.
+ */
+#define UBIFS_KSA_ADD_LEBS 3
+/*
+ * KSA LEBS is 1.125 * the computed min to allow unused keys when the drive is
+ * full. This shift is used to compute 0.125 * LEBS.
+ */
+#define UBIFS_KSA_LEBS_SCALE_SHIFT 3
/*
* Lockdep classes for UBIFS inode @ui_mutex.
@@ -934,6 +944,7 @@ struct ubifs_orphan {
* specified in @compr_type)
* @compr_type: compressor type to override the superblock compressor with
* (%UBIFS_COMPR_NONE, etc)
+ * @use_ubifsec: use ubifsec secure deletion feature
*/
struct ubifs_mount_opts {
unsigned int unmount_mode:2;
@@ -941,6 +952,7 @@ struct ubifs_mount_opts {
unsigned int chk_data_crc:2;
unsigned int override_compr:1;
unsigned int compr_type:2;
+ unsigned int use_ubifsec:1;
};
/**
@@ -1224,7 +1236,11 @@ struct ubifs_debug_info;
* @size_tree: inode size information for recovery
* @mount_opts: UBIFS-specific mount options
*
- * @keymap: cryptographic key store for secure deletion
+ * @km: cryptographic key store for secure deletion
+ * @ksa_lebs: number of LEBS assigned to the KSA
+ * @ksa_first: number of the first LEB assigned to the KSA
+ * @ksa_last: number of the last LEB assigned to the KSA
+ * @use_ubifsec: switch to enable/disable secure deletion for UBIFS
* @dbg: debugging-related information
*/
struct ubifs_info {
@@ -1454,6 +1470,11 @@ struct ubifs_info {
struct ubifs_mount_opts mount_opts;
struct ubifs_keymap *km;
+ int ksa_lebs;
+ int ksa_first;
+ int ksa_last;
+ int use_ubifsec;
+
struct ubifs_debug_info *dbg;
};
--
1.7.5.4
On Wed, 2012-06-06 at 20:52 +0200, Joel Reardon wrote:
> This patch makes the super block reserve space for the KSA. It computes the
> number of KSA LEBs and adds the ksa_lebs to on-medium superblock. The value is
> read off the media. The decision to use a KSA is controlled by use_ubifsec
> switch, added as a flag to the superblock, ubifs_info, and is controlled as a mount
> option. Validate superblock also checks these values.
>
> This is tested by creating a drive and checking the mount debug output. The
> number of LEBS assigned during create_default_filesystem was changed to ensure
> that remounting does infact read the old value. When the use_ubifsec option
> was not enabled, no LEBs were assigned. Integck was run and the drive was
> filled to capacity. The LEBs in the KSA were not used when filled. Invalid
> value for ksa_lebs were used and then rejected by validate superblock.
>
> Signed-off-by: Joel Reardon <[email protected]>
Thank Joel, but this patch has several major issues with the KSA size
calculation, I believe. I've pushed it anyway to the 'joel' branch, then
on top of it I've added several clean-ups and little improvements, and
then on top of it I've added a patch which adds several TODO comments
for you. Please, take a look. I've also sent the patches to you
separately.
--
Best Regards,
Artem Bityutskiy