[PATCH] UBIFS: compute KSA size and store in superblock

From: Joel Reardon
Date: Fri May 25 2012 - 09:10:48 EST


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 <reardonj@xxxxxxxxxxx>
---
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


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/