Patchwork Adding Secure Deletion to UBIFS

login
register
mail settings
Submitter Joel Reardon
Date Feb. 9, 2012, 3:24 p.m.
Message ID <alpine.DEB.2.00.1202091615540.26924@eristoteles.iwoars.net>
Download mbox | patch
Permalink /patch/140397/
State New
Headers show

Comments

Joel Reardon - Feb. 9, 2012, 3:24 p.m.
This patch provides efficient secure deletion for UBIFS.

The general problem of secure deletion on flash memory is the disparity between 
I/O size and erase block size---the inability to perform in-place updates means 
that simply overwriting data with a new value is insufficient. Moreover, 
forcing the garbage collection of every erase block that contains some deleted 
entry is woefully inefficient and reduces the lifetime of the flash memory.
Multiply overwriting deleted pages with zeros (but not erasing it) technically 
works but it is outside the specification, can cause data errors in other 
pages, and does not work with modern, larger MLC types of memory.

The solution here is to encrypt every data node with a different encryption 
key, and colocate the keys in a small (0.5-1 %) key storage area (KSA). The 
erase blocks of the KSA are frequently purged to remove deleted keys---each 
block of the old KSA is replaced with a new block, where all the used keys 
remain in the same position in the block, but all the unused and deleted keys 
are replaced with fresh, random data. This is done with UBI's atomic update, so 
it is not possible to lose any needed keys during this update, and the actual 
addition wear caused by more frequent erasure is evenly levelled over the 
device.

Each data nodes includes a reference to a key in the KSA. This key is read and 
used to decrypt the data. When a new data node is written, an unused key is 
selected from the KSA and used to encrypt the data node. The reference to the 
key is then included with the node. The keys in the KSA are written before 
actually being used to encrypt data. To securely delete a data node, we simply 
mark the corresponding key position as deleted, and during the next purging 
operation the KSA erase block that contains the key is then updated to a 
version that does not contain the key.

The data of data node is encrypted/decrypted in the compression/decompression 
functions respectively. A key parameter is passed in---if this is NULL, then no 
cryption is performed. If it points to a buffer, then it is interpreted as a 
128bit AES key. Counter mode is used with an IV of 0. Since each data block is 
encrypted with a unique key---each key only encrypts one item only once and 
sequentially---we do not need to worry about storing and generating IVs.

Key state is managed entirely in the TNC. When nodes are added to the TNC, they 
include a reference to a logical position in the key state map (KSA logical 
block number, offset). The TNC adding nodes will mark the key as used, removing 
a node will mark it as deleted, updating a node marks old as deleted and new as 
used. After purging, all deleted keys are replaced with new data and their key 
positions are marked as unused. Additionally, a checkpoint of the key state map 
is commited. When mounting the most recent checkpoint is loaded and then, if 
the journal is non-empty, the uncommited entries are replayed---thus updating 
the TNC and therefore correcting the key state map. The znode now includes the 
position in the KSA.

If power is lost during a commiting/purging of the key state map, then some KSA 
erase blocks will be updated and others will not be. However, in all possible 
failures, remounting the device guarantees the following three properties 
(which refer to the correctness of the key state map and are critical to the 
security of the system:
- every unused key must not decrypt any data node---either valid or invalid
- every used key must have exactly one data node it can decrypt and this data 
node must be valid according to the index
- every deleted key must not decrypt any data node that is valid according to 
the index.

I have a paper with lots more details and a proper treatment on power failure 
are examined.

Summary of changes to UBIFS

Mounting
mount the file system
  - allocate and initialize the keymap
  - deallocate keymap if an error occurs
  - read the size of the KSA from the master node
unmount the file system
- deallocate the keymap
create default file system
- use storage medium's geometry to compute the
   required KSA size
- store this information in the master node
- call keymap's initialize KSA routine

Commit
- call the keymap's purging routine

Input/Output
write data
- obtain an unused key position from the keymap - store the key's position in 
the data node's header - use the keymap and key position to look up the actual 
key - provide the key to the compress function recompute data after truncation
- obtain the original key, decrypt the data
- obtain a new key, encrypt the data with it after truncating
read data
- use the keymap and data node's key position to look up the actual key - 
provide the key to the decompress function

Tree Node Cache
add/update the TNC
- provide a key position when adding data nodes
- store the key position inside TNC entries
- mark key position as used
- if also updating, mark the old key position as deleted before storing the new 
position
delete/truncate the TNC
- when removing a data node from the TNC, mark the stored key position as 
deleted committing the TNC
- read and write key position to stored tree nodes

Testing was done using integck in mtd-utils for both drive mounted with the 
enhancement and without, where nandsim was used as the test flash device. Power 
cut testing was also performed. Manual testing of mounting and use was 
performed for both secure deletion and without. A suit of unit tests for the 
new keymap component exist but are not included. (What should I do with them?)

Things still to address:
- a consistency check for the three properties on the correctness of the key 
state map, along with the resulting ability to recover from a missing 
checkpoint by recomputing the key state map
- a change to an on-flash data structure renders it incompatible with older 
version, so this needs to be fixed

Joel Reardon

--------------------------------------------------
Signed-off-by: Joel Reardon <reardonj@inf.ethz.ch>
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/commit.c linux-3.2.1-ubifsec/fs/ubifs/commit.c
--- linux-3.2.1-vanilla/fs/ubifs/commit.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/commit.c	2012-02-08 16:54:49.097506842 
+0100
@@ -114,7 +114,11 @@ static int do_commit(struct ubifs_info *

  	dbg_cmt("start");
  	ubifs_assert(!c->ro_media && !c->ro_mount);
-
+	if (c->use_ubifsec) {
+		struct timeval tv;
+		do_gettimeofday(&tv);
+		c->next_commit = tv.tv_sec + c->commit_interval;
+	}
  	if (c->ro_error) {
  		err = -EROFS;
  		goto out_up;
@@ -134,6 +138,11 @@ static int do_commit(struct ubifs_info *
  	}

  	c->cmt_no += 1;
+	if (c->use_ubifsec) {
+		err = keymap_purge(c);
+		if (err)
+			goto out_up;
+	}
  	err = ubifs_gc_start_commit(c);
  	if (err)
  		goto out_up;
@@ -304,6 +313,16 @@ int ubifs_bg_thread(void *info)
  		if (try_to_freeze())
  			continue;

+		if (UBIFSEC_COMMIT_INTERVAL(c)) {
+			struct timeval tv;
+			do_gettimeofday(&tv);
+			if (c->next_commit < tv.tv_sec) {
+				c->next_commit = tv.tv_sec + 
c->commit_interval;
+				c->cmt_state = COMMIT_REQUIRED;
+				c->need_bgt = 1;
+			}
+		}
+
  		set_current_state(TASK_INTERRUPTIBLE);
  		/* Check if there is something to do */
  		if (!c->need_bgt) {
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/compress.c linux-3.2.1-ubifsec/fs/ubifs/compress.c
--- linux-3.2.1-vanilla/fs/ubifs/compress.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/compress.c	2012-02-08 16:54:49.097506842 
+0100
@@ -27,9 +27,11 @@
   * decompression.
   */

-#include <linux/crypto.h>
  #include "ubifs.h"

+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+
  /* Fake description object for the "none" compressor */
  static struct ubifs_compressor none_compr = {
  	.compr_type = UBIFS_COMPR_NONE,
@@ -74,6 +76,40 @@ static struct ubifs_compressor zlib_comp
  /* All UBIFS compressors */
  struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];

+int ubifs_aes_crypt(u8 *str, int len, u8 *key, int keylen, u8 *iv, int ivlen)
+{
+	struct crypto_blkcipher *tfm;
+	struct blkcipher_desc desc;
+	struct scatterlist sg;
+	int err = 0;
+	tfm = crypto_alloc_blkcipher(UBIFSEC_CRYPTO_ALGORITHM, 0, 0);
+
+	if (IS_ERR(tfm)) {
+		ubifs_err("failed to load transform for aes: %ld",
+			  PTR_ERR(tfm));
+		return err;
+	}
+
+	err = crypto_blkcipher_setkey(tfm, key, keylen);
+	desc.tfm = tfm;
+	desc.flags = 0;
+	if (err) {
+		ubifs_err("setkey() failed  flags=%x",
+			  crypto_blkcipher_get_flags(tfm));
+		return err;
+	}
+	memset(&sg, 0, sizeof(struct scatterlist));
+
+	sg_set_buf(&sg, str, len);
+	desc.info = iv;
+	err = crypto_blkcipher_encrypt(&desc, &sg, &sg, len);
+	crypto_free_blkcipher(tfm);
+	if (err)
+		return err;
+	return 0;
+}
+
+
  /**
   * ubifs_compress - compress data.
   * @in_buf: data to compress
@@ -93,7 +129,7 @@ struct ubifs_compressor *ubifs_compresso
   * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
   */
  void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int 
*out_len,
-		    int *compr_type)
+		    int *compr_type, u8* key)
  {
  	int err;
  	struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
@@ -115,7 +151,7 @@ void ubifs_compress(const void *in_buf,
  		ubifs_warn("cannot compress %d bytes, compressor %s, "
  			   "error %d, leave data uncompressed",
  			   in_len, compr->name, err);
-		 goto no_compr;
+		goto no_compr;
  	}

  	/*
@@ -124,13 +160,20 @@ void ubifs_compress(const void *in_buf,
  	 */
  	if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
  		goto no_compr;
-
-	return;
+	goto encrypt;

  no_compr:
  	memcpy(out_buf, in_buf, in_len);
  	*out_len = in_len;
  	*compr_type = UBIFS_COMPR_NONE;
+	goto encrypt;
+encrypt:
+	if (key) {
+		u8 iv[AES_KEYSIZE_128];
+		memset(iv, 0, AES_KEYSIZE_128);
+		ubifs_aes_crypt(out_buf, *out_len, key, AES_KEYSIZE_128,
+				iv, AES_KEYSIZE_128);
+	}
  }

  /**
@@ -145,8 +188,9 @@ no_compr:
   * The length of the uncompressed data is returned in @out_len. This functions
   * returns %0 on success or a negative error code on failure.
   */
-int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
-		     int *out_len, int compr_type)
+int ubifs_decompress(void *in_buf, int in_len, void *out_buf,
+		     int *out_len, int compr_type, u8* key)
+
  {
  	int err;
  	struct ubifs_compressor *compr;
@@ -163,6 +207,12 @@ int ubifs_decompress(const void *in_buf,
  		return -EINVAL;
  	}

+	if (key) {
+		u8 iv[AES_KEYSIZE_128];
+		memset(iv, 0, AES_KEYSIZE_128);
+		ubifs_aes_crypt(in_buf, in_len, key, AES_KEYSIZE_128,
+				iv, AES_KEYSIZE_128);
+	}
  	if (compr_type == UBIFS_COMPR_NONE) {
  		memcpy(out_buf, in_buf, in_len);
  		*out_len = in_len;
  	struct ubifs_znode *znode;
@@ -2181,11 +2184,20 @@ int ubifs_tnc_add(struct ubifs_info *c,
  		zbr.lnum = lnum;
  		zbr.offs = offs;
  		zbr.len = len;
+		if (c->use_ubifsec && key_type(c, key) == UBIFS_DATA_KEY) {
+			zbr.crypto_lookup = crypto_lookup;
+			keymap_mark_used(c, zbr.crypto_lookup);
+		}
  		key_copy(c, key, &zbr.key);
  		err = tnc_insert(c, znode, &zbr, n + 1);
  	} else if (found == 1) {
  		struct ubifs_zbranch *zbr = &znode->zbranch[n];

+		if (c->use_ubifsec && key_type(c, key) == UBIFS_DATA_KEY) {
+			keymap_mark_deleted(c, zbr->crypto_lookup);
+			zbr->crypto_lookup = crypto_lookup;
+			keymap_mark_used(c, zbr->crypto_lookup);
+		}
  		lnc_free(zbr);
  		err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
  		zbr->lnum = lnum;
@@ -2200,6 +2212,13 @@ int ubifs_tnc_add(struct ubifs_info *c,
  	return err;
  }

+int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+		  int offs, int len) {
+	if (c->use_ubifsec && key_type(c, key) == UBIFS_DATA_KEY)
+		ubifs_assert(c->use_ubifsec == 0);
+	return ubifs_tnc_add_with_crypto_lookup(c, key, lnum, offs, len, 0);
+}
+
  /**
   * ubifs_tnc_replace - replace a node in the TNC only if the old node is 
found.
   * @c: UBIFS file-system description object
@@ -2215,7 +2234,8 @@ int ubifs_tnc_add(struct ubifs_info *c,
   * Returns %0 on success or negative error code on failure.
   */
  int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
-		      int old_lnum, int old_offs, int lnum, int offs, int len)
+		      int old_lnum, int old_offs, int lnum, int offs, int len,
+		      u64 crypto_lookup)
  {
  	int found, n, err = 0;
  	struct ubifs_znode *znode;
@@ -2234,6 +2254,15 @@ int ubifs_tnc_replace(struct ubifs_info

  		found = 0;
  		if (zbr->lnum == old_lnum && zbr->offs == old_offs) {
+			if (c->use_ubifsec &&
+			    key_type(c, key) == UBIFS_DATA_KEY) {
+				if (zbr->crypto_lookup != crypto_lookup) {
+					keymap_mark_deleted(
+						c, zbr->crypto_lookup);
+					zbr->crypto_lookup = crypto_lookup;
+					keymap_mark_used(c, 
zbr->crypto_lookup);
+				}
+			}
  			lnc_free(zbr);
  			err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
  			if (err)
@@ -2401,6 +2430,8 @@ static int tnc_delete(struct ubifs_info
  	dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));

  	zbr = &znode->zbranch[n];
+	if (c->use_ubifsec && key_type(c, &(zbr->key)) == UBIFS_DATA_KEY)
+		keymap_mark_deleted(c, zbr->crypto_lookup);
  	lnc_free(zbr);

  	err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
@@ -2478,6 +2509,7 @@ static int tnc_delete(struct ubifs_info
  			c->zroot.lnum = zbr->lnum;
  			c->zroot.offs = zbr->offs;
  			c->zroot.len = zbr->len;
+			c->zroot.crypto_lookup = zbr->crypto_lookup;
  			c->zroot.znode = znode;
  			ubifs_assert(!ubifs_zn_obsolete(zp));
  			ubifs_assert(ubifs_zn_dirty(zp));
@@ -2647,6 +2679,7 @@ int ubifs_tnc_remove_range(struct ubifs_
  			key = &znode->zbranch[i].key;
  			if (!key_in_range(c, key, from_key, to_key))
  				break;
+			keymap_mark_deleted(c, 
znode->zbranch[i].crypto_lookup);
  			lnc_free(&znode->zbranch[i]);
  			err = ubifs_add_dirt(c, znode->zbranch[i].lnum,
  					     znode->zbranch[i].len);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/tnc_commit.c 
linux-3.2.1-ubifsec/fs/ubifs/tnc_commit.c
--- linux-3.2.1-vanilla/fs/ubifs/tnc_commit.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/tnc_commit.c	2012-02-08 16:54:49.149506844 
+0100
@@ -51,6 +51,8 @@ static int make_idx_node(struct ubifs_in
  		key_write_idx(c, &zbr->key, &br->key);
  		br->lnum = cpu_to_le32(zbr->lnum);
  		br->offs = cpu_to_le32(zbr->offs);
+		if (key_type(c, &zbr->key) == UBIFS_DATA_KEY)
+			br->crypto_lookup = cpu_to_le64(zbr->crypto_lookup);
  		br->len = cpu_to_le32(zbr->len);
  		if (!zbr->lnum || !zbr->len) {
  			ubifs_err("bad ref in znode");
@@ -859,6 +861,10 @@ static int write_index(struct ubifs_info
  			struct ubifs_zbranch *zbr = &znode->zbranch[i];

  			key_write_idx(c, &zbr->key, &br->key);
+			if (key_type(c, &zbr->key) == UBIFS_DATA_KEY) {
+				br->crypto_lookup =
+					cpu_to_le64(zbr->crypto_lookup);
+			}
  			br->lnum = cpu_to_le32(zbr->lnum);
  			br->offs = cpu_to_le32(zbr->offs);
  			br->len = cpu_to_le32(zbr->len);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/tnc_misc.c linux-3.2.1-ubifsec/fs/ubifs/tnc_misc.c
--- linux-3.2.1-vanilla/fs/ubifs/tnc_misc.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/tnc_misc.c	2012-02-08 16:54:49.149506844 
+0100
@@ -309,6 +309,7 @@ static int read_znode(struct ubifs_info
  		zbr->lnum = le32_to_cpu(br->lnum);
  		zbr->offs = le32_to_cpu(br->offs);
  		zbr->len  = le32_to_cpu(br->len);
+		zbr->crypto_lookup = 0;
  		zbr->znode = NULL;

  		/* Validate branch */
@@ -323,10 +324,12 @@ static int read_znode(struct ubifs_info

  		switch (key_type(c, &zbr->key)) {
  		case UBIFS_INO_KEY:
-		case UBIFS_DATA_KEY:
  		case UBIFS_DENT_KEY:
  		case UBIFS_XENT_KEY:
  			break;
+		case UBIFS_DATA_KEY:
+			zbr->crypto_lookup = le64_to_cpu(br->crypto_lookup);
+			break;
  		default:
  			dbg_msg("bad key type at slot %d: %s", i,
  				DBGKEY(&zbr->key));
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/ubifs.h linux-3.2.1-ubifsec/fs/ubifs/ubifs.h
--- linux-3.2.1-vanilla/fs/ubifs/ubifs.h	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/ubifs.h	2012-02-08 16:54:51.969506980 
+0100
@@ -163,6 +163,19 @@
  /* Maximum number of data nodes to bulk-read */
  #define UBIFS_MAX_BULK_READ 32

+/* Size of 128 bits in bytes */
+#define AES_KEYSIZE_128 16
+
+/* Key size in bytes for UBIFSEC */
+#define UBIFSEC_KEYSIZE AES_KEYSIZE_128
+#define UBIFSEC_CRYPTO_ALGORITHM "ctr(aes)"
+#define UBIFSEC_CRYPTO_LEBS_SCALE_SHIFT 4
+#define UBIFSEC_CRYPTO_LEBS_MIN 3
+#define UBIFSEC_COMMIT_INTERVAL(c)					\
+	((c)->use_ubifsec && (c)->commit_interval != -1)
+
+#define POISON_KEY(p) memset(p, 0xff, UBIFSEC_KEYSIZE)
+
  /*
   * Lockdep classes for UBIFS inode @ui_mutex.
   */
@@ -749,6 +762,7 @@ struct ubifs_zbranch {
  	int lnum;
  	int offs;
  	int len;
+	unsigned long long crypto_lookup;
  };

  /**
@@ -930,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;
@@ -937,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;
  };

  /**
@@ -974,6 +990,7 @@ struct ubifs_budg_info {
  };

  struct ubifs_debug_info;
+struct ubifs_keymap;

  /**
   * struct ubifs_info - UBIFS file-system description data structure
@@ -1218,6 +1235,13 @@ struct ubifs_debug_info;
   *                  FS to R/W mode
   * @size_tree: inode size information for recovery
   * @mount_opts: UBIFS-specific mount options
+ * @km: the keymap data structure for ubifsec
+ * @crypto_lebs: the number of LEBS assigned to store keys for the keymap
+ * @crypto_first: the number of the first LEB assigned to store keys
+ * @use_ubifsec: the switch to enable/disable UBIFSec
+ * @commit_interval: the number of seconds between forced commiting to purge
+ *                   the key storage area of deleted keys
+ * @next_commit: the time at which the next commit will occur
   *
   * @dbg: debugging-related information
   */
@@ -1450,6 +1474,13 @@ struct ubifs_info {
  #ifdef CONFIG_UBIFS_FS_DEBUG
  	struct ubifs_debug_info *dbg;
  #endif
+
+	struct ubifs_keymap *km;
+	int crypto_lebs;
+	int crypto_first;
+	unsigned int use_ubifsec;
+	long commit_interval;
+	unsigned long long next_commit;
  };

  extern struct list_head ubifs_infos;
@@ -1489,6 +1520,7 @@ int ubifs_write_node(struct ubifs_info *
  		     int offs, int dtype);
  int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
  		     int offs, int quiet, int must_chk_crc);
+void ubifs_set_datanode_crc(void *node);
  void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
  void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
  int ubifs_io_init(struct ubifs_info *c);
@@ -1579,8 +1611,12 @@ int ubifs_tnc_locate(struct ubifs_info *
  		     void *node, int *lnum, int *offs);
  int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
  		  int offs, int len);
+int ubifs_tnc_add_with_crypto_lookup(
+	struct ubifs_info *c, const union ubifs_key *key,
+	int lnum, int offs, int len, unsigned long long crypto_lookup);
  int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
-		      int old_lnum, int old_offs, int lnum, int offs, int len);
+		      int old_lnum, int old_offs, int lnum, int offs,
+		      int len, u64 crypto_lookup);
  int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
  		     int lnum, int offs, int len, const struct qstr *nm);
  int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
@@ -1775,9 +1811,26 @@ long ubifs_compat_ioctl(struct file *fil
  int __init ubifs_compressors_init(void);
  void ubifs_compressors_exit(void);
  void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int 
*out_len,
-		    int *compr_type);
-int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
-		     int compr_type);
+		    int *compr_type, u8* key);
+int ubifs_decompress(void *buf, int len, void *out, int *out_len,
+		     int compr_type, u8 *key);
+int ubifs_aes_crypt(u8 *str, int len, u8 *key, int keylen, u8 *iv, int ivlen);
+
+/* keymap.c */
+int keymap_purge(struct ubifs_info *c);
+int keymap_init(struct ubifs_info *c, int read_only, int use_ubifsec);
+void keymap_free(struct ubifs_info *c);
+int keymap_free_key(struct ubifs_info *c, u64 *pos, u8 *key);
+int keymap_read_key(struct ubifs_info *c, u64 pos, u8 *buf);
+void keymap_mark_used(struct ubifs_info *c, u64 pos);
+void keymap_mark_deleted(struct ubifs_info *c, u64 pos);
+int keymap_assign_lebs(struct ubifs_info *c);
+int keymap_keys_per_eb(struct ubifs_info *c);
+int keymap_promote_key(struct ubifs_info *c, u64 old_pos, u64 *new_pos,
+		       u8 *key);
+int keymap_gc_should_promote(struct ubifs_info *c, u64 pos);
+int keymap_swap_encryption_key(struct ubifs_info *c,
+			       struct ubifs_data_node *dn);

  #include "debug.h"
  #include "misc.h"
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/ubifs-media.h 
linux-3.2.1-ubifsec/fs/ubifs/ubifs-media.h
--- linux-3.2.1-vanilla/fs/ubifs/ubifs-media.h	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/ubifs-media.h	2012-02-08 16:54:51.969506980 
+0100
@@ -550,9 +550,14 @@ struct ubifs_dent_node {
   * Note, do not forget to amend 'zero_data_node_unused()' function when
   * changing the padding fields.
   */
+/* TODO(reardon): sorry about lifting these 8 unused bytes from @key to
+ * use for @crypto_lookup. Can someone reviewing this give me a more elegant
+ * and maintable way of preserving the size of data in a data node?
+ */
  struct ubifs_data_node {
  	struct ubifs_ch ch;
-	__u8 key[UBIFS_MAX_KEY_LEN];
+	__u8 key[UBIFS_MAX_KEY_LEN/2];
+	__u64 crypto_lookup;
  	__le32 size;
  	__le16 compr_type;
  	__u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
@@ -614,10 +619,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 ubifsec secure deletio
+ * @padding2: reserved for future, zeroes
   */
  struct ubifs_sb_node {
  	struct ubifs_ch ch;
@@ -645,7 +652,9 @@ struct ubifs_sb_node {
  	__le32 time_gran;
  	__u8 uuid[16];
  	__le32 ro_compat_version;
-	__u8 padding2[3968];
+	__le32 crypto_lebs;
+	__u8 use_ubifsec;
+	__u8 padding2[3963];
  } __packed;

  /**
@@ -742,6 +751,7 @@ struct ubifs_branch {
  	__le32 lnum;
  	__le32 offs;
  	__le32 len;
+	__le64 crypto_lookup;
  	__u8 key[];
  } __packed;
Artem Bityutskiy - Feb. 13, 2012, 4:54 p.m.
Hi, I will try to get into more details soon, but to keep you busy - the
first thing to start is to introduce new on-flash format version -
because you need more space in 'struct ubifs_branch'

On Thu, 2012-02-09 at 16:24 +0100, Joel Reardon wrote:
> @@ -742,6 +751,7 @@ struct ubifs_branch {
>   	__le32 lnum;
>   	__le32 offs;
>   	__le32 len;
> +	__le64 crypto_lookup;
>   	__u8 key[];
>   } __packed;

Could you make a separate patch which adds new on-flash format and make
sure that new ubifs binaries can mount the old formats and work with
them. And that old ubifs binaries gracefully reject the new format.
Joel Reardon - Feb. 20, 2012, 8:15 p.m.
This patch moves the computation of CRCs for data nodes from 
within ubifs_prepare_node to a separate function ubifs_set_datanode_crc, 
which takes a data node, and computes and sets the CRC. This is to avoid 
duplication of the CRC computation code in other places where it may be 
needed.

Signed-off-by: Joel Reardon <reardonj@inf.ethz.ch>
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/io.c linux-3.2.1-ubifsec/fs/ubifs/io.c
--- linux-3.2.1-vanilla/fs/ubifs/io.c   2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/io.c   2012-02-20 20:17:48.796684293 
+0100
@@ -367,6 +367,18 @@ static unsigned long long next_sqnum(str
  }

  /**
+ * ubifs_set_datanode_crc - writes the crc for a data node to the common
+ * header.
+ * @node: the data node
+ */
+void ubifs_set_datanode_crc(void *node)
+{
+       struct ubifs_ch *ch = (struct ubifs_ch *) node;
+       int len = le32_to_cpu(ch->len);
+       ch->crc = cpu_to_le32(crc32(UBIFS_CRC32_INIT, node + 8, len - 8));
+}
+
+/**
   * ubifs_prepare_node - prepare node to be written to flash.
   * @c: UBIFS file-system description object
   * @node: the node to pad
@@ -379,7 +391,6 @@ static unsigned long long next_sqnum(str
   */
  void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int 
pad)
  {
-       uint32_t crc;
         struct ubifs_ch *ch = node;
         unsigned long long sqnum = next_sqnum(c);

@@ -390,8 +401,7 @@ void ubifs_prepare_node(struct ubifs_inf
         ch->group_type = UBIFS_NO_NODE_GROUP;
         ch->sqnum = cpu_to_le64(sqnum);
         ch->padding[0] = ch->padding[1] = 0;
-       crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
-       ch->crc = cpu_to_le32(crc);
+       ubifs_set_datanode_crc(node);

         if (pad) {
                 len = ALIGN(len, 8);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/ubifs.h linux-3.2.1-ubifsec/fs/ubifs/ubifs.h
--- linux-3.2.1-vanilla/fs/ubifs/ubifs.h        2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/ubifs.h        2012-02-20 
20:18:17.368685674 +0100
@@ -1489,6 +1489,7 @@ int ubifs_write_node(struct ubifs_info *
                      int offs, int dtype);
  int ubifs_check_node(const struct ubifs_info *c, const void *buf, int 
lnum,
                      int offs, int quiet, int must_chk_crc);
+void ubifs_set_datanode_crc(void *node);
  void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int 
pad);
  void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int 
last);
  int ubifs_io_init(struct ubifs_info *c);
Joel Reardon - Feb. 23, 2012, 2:59 p.m.
>
> Could you make a separate patch which adds new on-flash format and make
> sure that new ubifs binaries can mount the old formats and work with
> them. And that old ubifs binaries gracefully reject the new format.
>

This patch provides a new version of two on-flash data structures for 
UBIFS:
ubifs_branch and ubifs_data_node have been grown by 8 bytes to include a 
64-bit reference
to a key position, which is needed by a proposed ubifs secure deletion 
addition. This patch is generated
against linux-3.2.1.

Because both data structures use C99 flexible arrays, it is not possible 
to add the new field as
the last member of the structure. Thus, it was added one before last, the 
last was renamed, and in a
handful of places where it was used, a macro accessor is used to get the 
version-correct position.

The new/modified macros are the following:
FMT_VERSION_DATA_NODE_HAS_CRYPTO_LOOKUP(c)
FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP(c)
These take the ubifs_context and return true if the version defined in 
fmt_version has a crypto_lookup field.

FMT_VERSION_BRANCH_POS_KEY(c, br)
FMT_VERSION_DATA_NODE_POS_DATA(c, dn)
These take the ubifs_context and the data_node / branch and return the 
address of the key / data field
that is correct for the version defined in fmt_version. key and data are 
renamed to __key / __data to
prevent any accidental version incapible usage.

UBIFS_DATA_NODE_SZ(c)
UBIFS_BRANCH_SZ(c)
These now take the ubifs_context and return the data structure's size 
according to the format version.

In create_default_filesystem, the fmt_version is set earlier so these 
macros behave correctly.


This was tested as follows:
1) A vanilla and modified module were both created. An empty drive was 
mounted under the vanilla
module to create a version 4 drive. Data was written to it
and integck was run (always a hundred times followed by powercut tests).
2) The module was switched to modified and it was mounted again. The data 
was read correctly and the
integck was run.
3) New data was written and it was mounted again under the vanilla 
modules. Both data was read again
and integck was run.
4) Finally, it was remounted under version 5 and the data correctly read 
and integck was run.

Additionally, an empty drive was mounted under the modified modules to 
create a version 5 drive.
1) Data was written to it and integck was run.
2) It was attempted to be mounted under the vanilla driver, but it did not 
succeed. Dmesg reports
version mismatch as the reason. A mounting attempted as read-only 
continued, but it failed when trying to read
the superblock.
3) It was remounted under the modified module where the data was correctly 
read back.


----------

Signed-off-by: Joel Reardon <reardonj@inf.ethz.ch>
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/commit.c 
linux-3.2.1-ubifsec/fs/ubifs/commit.c
--- linux-3.2.1-vanilla/fs/ubifs/commit.c	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/commit.c	2012-02-23 
15:06:49.107957279 +0100
@@ -650,7 +650,7 @@ int dbg_check_old_index(struct ubifs_inf
  		/* Check key range */
  		key_read(c, ubifs_idx_key(c, idx), &l_key);
  		br = ubifs_idx_branch(c, idx, child_cnt - 1);
-		key_read(c, &br->key, &u_key);
+		key_read(c, FMT_VERSION_BRANCH_POS_KEY(c, br), &u_key);
  		if (keys_cmp(c, &lower_key, &l_key) > 0) {
  			err = 5;
  			goto out_dump;
@@ -699,10 +699,11 @@ int dbg_check_old_index(struct ubifs_inf
  		lnum = le32_to_cpu(br->lnum);
  		offs = le32_to_cpu(br->offs);
  		len = le32_to_cpu(br->len);
-		key_read(c, &br->key, &lower_key);
+		key_read(c, FMT_VERSION_BRANCH_POS_KEY(c, br), 
&lower_key);
  		if (iip + 1 < le16_to_cpu(idx->child_cnt)) {
  			br = ubifs_idx_branch(c, idx, iip + 1);
-			key_read(c, &br->key, &upper_key);
+			key_read(c, FMT_VERSION_BRANCH_POS_KEY(c, br),
+				 &upper_key);
  		} else
  			key_copy(c, &i->upper_key, &upper_key);
  	}
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/debug.c linux-3.2.1-ubifsec/fs/ubifs/debug.c
--- linux-3.2.1-vanilla/fs/ubifs/debug.c	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/debug.c	2012-02-21 
22:27:01.222462655 +0100
@@ -538,7 +538,7 @@ void dbg_dump_node(const struct ubifs_in
  	case UBIFS_DATA_NODE:
  	{
  		const struct ubifs_data_node *dn = node;
-		int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
+		int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ(c);

  		key_read(c, &dn->key, &key);
  		printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
@@ -550,7 +550,7 @@ void dbg_dump_node(const struct ubifs_in
  		       dlen);
  		printk(KERN_DEBUG "\tdata:\n");
  		print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 
1,
-			       (void *)&dn->data, dlen, 0);
+			       FMT_VERSION_DATA_NODE_POS_DATA(c, dn), 
dlen, 0);
  		break;
  	}
  	case UBIFS_TRUN_NODE:
@@ -579,7 +579,7 @@ void dbg_dump_node(const struct ubifs_in
  			const struct ubifs_branch *br;

  			br = ubifs_idx_branch(c, idx, i);
-			key_read(c, &br->key, &key);
+			key_read(c, FMT_VERSION_BRANCH_POS_KEY(c, br), 
&key);
  			printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key 
%s\n",
  			       i, le32_to_cpu(br->lnum), 
le32_to_cpu(br->offs),
  			       le32_to_cpu(br->len), DBGKEY(&key));
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/file.c linux-3.2.1-ubifsec/fs/ubifs/file.c
--- linux-3.2.1-vanilla/fs/ubifs/file.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/file.c	2012-02-23 15:07:01.695957886 
+0100
@@ -77,10 +77,12 @@ static int read_block(struct inode *inod
  	if (len <= 0 || len > UBIFS_BLOCK_SIZE)
  		goto dump;

-	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
+	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ(c);
  	out_len = UBIFS_BLOCK_SIZE;
-	err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
-			       le16_to_cpu(dn->compr_type));
+	err = ubifs_decompress(FMT_VERSION_DATA_NODE_POS_DATA(c, dn), 
dlen,
+			       addr, &out_len, 
le16_to_cpu(dn->compr_type));
+	if (FMT_VERSION_DATA_NODE_HAS_CRYPTO_LOOKUP(c))
+		ubifs_assert(le64_to_cpu(dn->crypto_lookup) == 0);
  	if (err || len != out_len)
  		goto dump;

@@ -646,10 +648,13 @@ static int populate_page(struct ubifs_in
  			if (len <= 0 || len > UBIFS_BLOCK_SIZE)
  				goto out_err;

-			dlen = le32_to_cpu(dn->ch.len) - 
UBIFS_DATA_NODE_SZ;
+			dlen = le32_to_cpu(dn->ch.len) - 
UBIFS_DATA_NODE_SZ(c);
  			out_len = UBIFS_BLOCK_SIZE;
-			err = ubifs_decompress(&dn->data, dlen, addr, 
&out_len,
- 
le16_to_cpu(dn->compr_type));
+			err =
+			ubifs_decompress(
+				FMT_VERSION_DATA_NODE_POS_DATA(c, dn),
+				dlen, addr, &out_len,
+				le16_to_cpu(dn->compr_type));
  			if (err || len != out_len)
  				goto out_err;

diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/journal.c 
linux-3.2.1-ubifsec/fs/ubifs/journal.c
--- linux-3.2.1-vanilla/fs/ubifs/journal.c	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/journal.c	2012-02-23 
15:07:31.835959345 +0100
@@ -720,6 +720,8 @@ int ubifs_jnl_write_data(struct ubifs_in
  	key_write(c, key, &data->key);
  	data->size = cpu_to_le32(len);
  	zero_data_node_unused(data);
+	if (FMT_VERSION_DATA_NODE_HAS_CRYPTO_LOOKUP(c))
+		data->crypto_lookup = cpu_to_le64(0);

  	if (!(ui->flags & UBIFS_COMPR_FL))
  		/* Compression is disabled for this inode */
@@ -727,11 +729,12 @@ int ubifs_jnl_write_data(struct ubifs_in
  	else
  		compr_type = ui->compr_type;

-	out_len = dlen - UBIFS_DATA_NODE_SZ;
-	ubifs_compress(buf, len, &data->data, &out_len, &compr_type);
+	out_len = dlen - UBIFS_DATA_NODE_SZ(c);
+	ubifs_compress(buf, len, FMT_VERSION_DATA_NODE_POS_DATA(c, data),
+		       &out_len, &compr_type);
  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);

-	dlen = UBIFS_DATA_NODE_SZ + out_len;
+	dlen = UBIFS_DATA_NODE_SZ(c) + out_len;
  	data->compr_type = cpu_to_le16(compr_type);

  	/* Make reservation before allocating sequence numbers */
@@ -1093,13 +1096,16 @@ out_free:

  /**
   * recomp_data_node - re-compress a truncated data node.
+ * @c: UBIFS file-system description object
   * @dn: data node to re-compress
   * @new_len: new length
   *
   * This function is used when an inode is truncated and the last data 
node of
   * the inode has to be re-compressed and re-written.
   */
-static int recomp_data_node(struct ubifs_data_node *dn, int *new_len)
+static int recomp_data_node(struct ubifs_info *c,
+			    struct ubifs_data_node *dn,
+			    int *new_len)
  {
  	void *buf;
  	int err, len, compr_type, out_len;
@@ -1109,17 +1115,20 @@ static int recomp_data_node(struct ubifs
  	if (!buf)
  		return -ENOMEM;

-	len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
+	len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ(c);
  	compr_type = le16_to_cpu(dn->compr_type);
-	err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type);
+	err = ubifs_decompress(FMT_VERSION_DATA_NODE_POS_DATA(c, dn),
+			       len, buf, &out_len, compr_type);
  	if (err)
  		goto out;

-	ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type);
+	ubifs_compress(buf, *new_len, FMT_VERSION_DATA_NODE_POS_DATA(c, 
dn),
+		       &out_len, &compr_type);
+
  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
  	dn->compr_type = cpu_to_le16(compr_type);
  	dn->size = cpu_to_le32(*new_len);
-	*new_len = UBIFS_DATA_NODE_SZ + out_len;
+	*new_len = UBIFS_DATA_NODE_SZ(c) + out_len;
  out:
  	kfree(buf);
  	return err;
@@ -1190,12 +1199,12 @@ int ubifs_jnl_truncate(struct ubifs_info
  				int compr_type = 
le16_to_cpu(dn->compr_type);

  				if (compr_type != UBIFS_COMPR_NONE) {
-					err = recomp_data_node(dn, &dlen);
+					err = recomp_data_node(c, dn, 
&dlen);
  					if (err)
  						goto out_free;
  				} else {
  					dn->size = cpu_to_le32(dlen);
-					dlen += UBIFS_DATA_NODE_SZ;
+					dlen += UBIFS_DATA_NODE_SZ(c);
  				}
  				zero_data_node_unused(dn);
  			}
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/misc.h linux-3.2.1-ubifsec/fs/ubifs/misc.h
--- linux-3.2.1-vanilla/fs/ubifs/misc.h	2012-02-20 19:36:00.670753551 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/misc.h	2012-02-23 15:09:47.899965933 
+0100
@@ -200,7 +200,8 @@ static inline int ubifs_return_leb(struc
   */
  static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int 
child_cnt)
  {
-	return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * 
child_cnt;
+	return UBIFS_IDX_NODE_SZ
+	       + (UBIFS_BRANCH_SZ(c) + c->key_len) * child_cnt;
  }

  /**
@@ -214,8 +215,9 @@ struct ubifs_branch *ubifs_idx_branch(co
  				      const struct ubifs_idx_node *idx,
  				      int bnum)
  {
-	return (struct ubifs_branch *)((void *)idx->branches +
-				       (UBIFS_BRANCH_SZ + c->key_len) * 
bnum);
+	return (struct ubifs_branch *)
+		((void *)idx->branches + (UBIFS_BRANCH_SZ(c) + c->key_len)
+		* bnum);
  }

  /**
@@ -226,7 +228,8 @@ struct ubifs_branch *ubifs_idx_branch(co
  static inline void *ubifs_idx_key(const struct ubifs_info *c,
  				  const struct ubifs_idx_node *idx)
  {
-	return (void *)((struct ubifs_branch *)idx->branches)->key;
+	return (void *) FMT_VERSION_BRANCH_POS_KEY(
+		c, (struct ubifs_branch *)idx->branches);
  }

  /**
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/sb.c linux-3.2.1-ubifsec/fs/ubifs/sb.c
--- linux-3.2.1-vanilla/fs/ubifs/sb.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/sb.c	2012-02-22 11:39:51.480718000 
+0100
@@ -84,7 +84,7 @@ static int create_default_filesystem(str
  	int min_leb_cnt = UBIFS_MIN_LEB_CNT;
  	long long tmp64, main_bytes;
  	__le64 tmp_le64;
-
+	c->fmt_version = UBIFS_FORMAT_VERSION;
  	/* Some functions called from here depend on the @c->key_len filed 
*/
  	c->key_len = UBIFS_SK_LEN;

@@ -175,6 +175,7 @@ static int create_default_filesystem(str
  	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->crypto_lebs   = cpu_to_le32(0);
  	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);
@@ -182,6 +183,7 @@ static int create_default_filesystem(str
  	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(0);
  	if (c->mount_opts.override_compr)
  		sup->default_compr = 
cpu_to_le16(c->mount_opts.compr_type);
  	else
@@ -279,7 +281,7 @@ static int create_default_filesystem(str
  	idx->child_cnt = cpu_to_le16(1);
  	ino_key_init(c, &key, UBIFS_ROOT_INO);
  	br = ubifs_idx_branch(c, idx, 0);
-	key_write_idx(c, &key, &br->key);
+	key_write_idx(c, &key, FMT_VERSION_BRANCH_POS_KEY(c, br));
  	br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB);
  	br->len  = cpu_to_le32(UBIFS_INO_NODE_SZ);
  	err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 
0,
@@ -610,6 +612,10 @@ int ubifs_read_superblock(struct ubifs_i
  	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);
+	if (c->fmt_version > 4) {
+		ubifs_assert(le32_to_cpu(sup->crypto_lebs) == 0);
+		ubifs_assert(le32_to_cpu(sup->use_ubifsec) == 0);
+	}
  	sup_flags        = le32_to_cpu(sup->flags);
  	if (!c->mount_opts.override_compr)
  		c->default_compr = le16_to_cpu(sup->default_compr);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/super.c linux-3.2.1-ubifsec/fs/ubifs/super.c
--- linux-3.2.1-vanilla/fs/ubifs/super.c	2012-02-20 
19:36:03.478753687 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/super.c	2012-02-21 
22:20:04.478442495 +0100
@@ -585,13 +585,14 @@ static int init_constants_early(struct u
  	c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ;
  	c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ;
  	c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ;
-	c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ;
+	c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_VMIN_SZ;
  	c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ;
  	/*
  	 * Minimum indexing node size is amended later when superblock is
  	 * read and the key length is known.
  	 */
-	c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + 
UBIFS_BRANCH_SZ;
+	c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ +
+					    UBIFS_BRANCH_SZ(c);
  	/*
  	 * Maximum indexing node size is amended later when superblock is
  	 * read and the fanout is known.
@@ -1463,7 +1464,7 @@ static int mount_ubifs(struct ubifs_info
  	dbg_msg("max. znode size      %d", c->max_znode_sz);
  	dbg_msg("max. index node size %d", c->max_idx_node_sz);
  	dbg_msg("node sizes:          data %zu, inode %zu, dentry %zu",
-		UBIFS_DATA_NODE_SZ, UBIFS_INO_NODE_SZ, 
UBIFS_DENT_NODE_SZ);
+		UBIFS_DATA_NODE_SZ(c), UBIFS_INO_NODE_SZ, 
UBIFS_DENT_NODE_SZ);
  	dbg_msg("node sizes:          trun %zu, sb %zu, master %zu",
  		UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
  	dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
@@ -2213,7 +2214,8 @@ static int __init ubifs_init(void)
  	BUILD_BUG_ON(UBIFS_INO_NODE_SZ  & 7);
  	BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7);
  	BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7);
-	BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7);
+	BUILD_BUG_ON(UBIFS_DATA_NODE_V4_SZ & 7);
+	BUILD_BUG_ON(UBIFS_DATA_NODE_V5_SZ & 7);
  	BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7);
  	BUILD_BUG_ON(UBIFS_SB_NODE_SZ   & 7);
  	BUILD_BUG_ON(UBIFS_MST_NODE_SZ  & 7);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/tnc_commit.c 
linux-3.2.1-ubifsec/fs/ubifs/tnc_commit.c
--- linux-3.2.1-vanilla/fs/ubifs/tnc_commit.c	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/tnc_commit.c	2012-02-23 
15:09:27.295964938 +0100
@@ -48,9 +48,13 @@ static int make_idx_node(struct ubifs_in
  		struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
  		struct ubifs_zbranch *zbr = &znode->zbranch[i];

-		key_write_idx(c, &zbr->key, &br->key);
+		key_write_idx(c, &zbr->key, FMT_VERSION_BRANCH_POS_KEY(c, 
br));
  		br->lnum = cpu_to_le32(zbr->lnum);
  		br->offs = cpu_to_le32(zbr->offs);
+		if (key_type(c, &zbr->key) == UBIFS_DATA_KEY) {
+			if (FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP(c))
+				br->crypto_lookup = cpu_to_le64(0);
+		}
  		br->len = cpu_to_le32(zbr->len);
  		if (!zbr->lnum || !zbr->len) {
  			ubifs_err("bad ref in znode");
@@ -858,7 +862,12 @@ static int write_index(struct ubifs_info
  			struct ubifs_branch *br = ubifs_idx_branch(c, idx, 
i);
  			struct ubifs_zbranch *zbr = &znode->zbranch[i];

-			key_write_idx(c, &zbr->key, &br->key);
+			key_write_idx(c, &zbr->key,
+				      FMT_VERSION_BRANCH_POS_KEY(c, br));
+			if (key_type(c, &zbr->key) == UBIFS_DATA_KEY) {
+				if 
(FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP(c))
+					br->crypto_lookup = 
cpu_to_le64(0);
+			}
  			br->lnum = cpu_to_le32(zbr->lnum);
  			br->offs = cpu_to_le32(zbr->offs);
  			br->len = cpu_to_le32(zbr->len);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/tnc_misc.c 
linux-3.2.1-ubifsec/fs/ubifs/tnc_misc.c
--- linux-3.2.1-vanilla/fs/ubifs/tnc_misc.c	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/tnc_misc.c	2012-02-21 
13:13:01.775280827 +0100
@@ -305,7 +305,7 @@ static int read_znode(struct ubifs_info
  		const struct ubifs_branch *br = ubifs_idx_branch(c, idx, 
i);
  		struct ubifs_zbranch *zbr = &znode->zbranch[i];

-		key_read(c, &br->key, &zbr->key);
+		key_read(c, FMT_VERSION_BRANCH_POS_KEY(c, br), &zbr->key);
  		zbr->lnum = le32_to_cpu(br->lnum);
  		zbr->offs = le32_to_cpu(br->offs);
  		zbr->len  = le32_to_cpu(br->len);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/ubifs.h linux-3.2.1-ubifsec/fs/ubifs/ubifs.h
--- linux-3.2.1-vanilla/fs/ubifs/ubifs.h	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/ubifs.h	2012-02-21 
22:07:55.582407209 +0100
@@ -73,7 +73,7 @@
  #define MIN_INDEX_LEBS 2

  /* Minimum amount of data UBIFS writes to the flash */
-#define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
+#define MIN_WRITE_SZ (UBIFS_DATA_NODE_VMIN_SZ + 8)

  /*
   * Currently we do not support inode number overlapping and re-using, so 
this
@@ -155,7 +155,7 @@
   * How much memory is needed for a buffer where we comress a data node.
   */
  #define COMPRESSED_DATA_NODE_BUF_SZ \
-	(UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
+	(UBIFS_DATA_NODE_VMAX_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)

  /* Maximum expected tree height for use by bottom_up_buf */
  #define BOTTOM_UP_HEIGHT 64
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/ubifs-media.h 
linux-3.2.1-ubifsec/fs/ubifs/ubifs-media.h
--- linux-3.2.1-vanilla/fs/ubifs/ubifs-media.h	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/ubifs-media.h	2012-02-23 
15:12:45.971974550 +0100
@@ -44,9 +44,23 @@
   * a new feature.
   *
   * UBIFS went into mainline kernel with format version 4. The older 
formats
- * were development formats.
- */
-#define UBIFS_FORMAT_VERSION 4
+ * were development formats.  Version 5 is then used for secure deletion
+ * enhancement. N.B.: when adding new versions that also have this field,
+ * include the version in the data_struct_has_field defines below.
+ */
+#define UBIFS_FORMAT_VERSION 5
+#define FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP(c) ((c)->fmt_version == 5)
+#define FMT_VERSION_DATA_NODE_HAS_CRYPTO_LOOKUP(c) ((c)->fmt_version == 
5)
+#define FMT_VERSION_DATA_NODE_POS_DATA(c, dn)				\
+	(FMT_VERSION_DATA_NODE_HAS_CRYPTO_LOOKUP(c) ?			\
+	((void *) (&((dn)->__data))) :					\
+	((void *) (&((dn)->crypto_lookup))))
+
+#define FMT_VERSION_BRANCH_POS_KEY(c, br)				\
+	(FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP(c) ?			\
+	((void *) (&((br)->__key))) :					\
+	((void *) (&((br)->crypto_lookup))))
+

  /*
   * Read-only compatibility version. If the UBIFS format is changed, older 
UBIFS
@@ -274,25 +288,33 @@ enum {
  			   UBIFS_MIN_ORPH_LEBS + UBIFS_MIN_MAIN_LEBS)

  /* Node sizes (N.B. these are guaranteed to be multiples of 8) */
-#define UBIFS_CH_SZ        sizeof(struct ubifs_ch)
-#define UBIFS_INO_NODE_SZ  sizeof(struct ubifs_ino_node)
-#define UBIFS_DATA_NODE_SZ sizeof(struct ubifs_data_node)
-#define UBIFS_DENT_NODE_SZ sizeof(struct ubifs_dent_node)
-#define UBIFS_TRUN_NODE_SZ sizeof(struct ubifs_trun_node)
-#define UBIFS_PAD_NODE_SZ  sizeof(struct ubifs_pad_node)
-#define UBIFS_SB_NODE_SZ   sizeof(struct ubifs_sb_node)
-#define UBIFS_MST_NODE_SZ  sizeof(struct ubifs_mst_node)
-#define UBIFS_REF_NODE_SZ  sizeof(struct ubifs_ref_node)
-#define UBIFS_IDX_NODE_SZ  sizeof(struct ubifs_idx_node)
-#define UBIFS_CS_NODE_SZ   sizeof(struct ubifs_cs_node)
-#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node)
+#define UBIFS_CH_SZ            sizeof(struct ubifs_ch)
+#define UBIFS_INO_NODE_SZ      sizeof(struct ubifs_ino_node)
+#define UBIFS_DATA_NODE_SZ(c)   (sizeof(struct ubifs_data_node) \
+	- (FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP(c) ? 0 : sizeof(__u64)))
+/* The min and max data node header size across all version */
+#define UBIFS_DATA_NODE_V4_SZ (sizeof(struct ubifs_data_node) - 
sizeof(__u64))
+#define UBIFS_DATA_NODE_V5_SZ (sizeof(struct ubifs_data_node))
+#define UBIFS_DATA_NODE_VMIN_SZ UBIFS_DATA_NODE_V4_SZ
+#define UBIFS_DATA_NODE_VMAX_SZ UBIFS_DATA_NODE_V5_SZ
+
+#define UBIFS_DENT_NODE_SZ     sizeof(struct ubifs_dent_node)
+#define UBIFS_TRUN_NODE_SZ     sizeof(struct ubifs_trun_node)
+#define UBIFS_PAD_NODE_SZ      sizeof(struct ubifs_pad_node)
+#define UBIFS_SB_NODE_SZ       sizeof(struct ubifs_sb_node)
+#define UBIFS_MST_NODE_SZ      sizeof(struct ubifs_mst_node)
+#define UBIFS_REF_NODE_SZ      sizeof(struct ubifs_ref_node)
+#define UBIFS_IDX_NODE_SZ      sizeof(struct ubifs_idx_node)
+#define UBIFS_CS_NODE_SZ       sizeof(struct ubifs_cs_node)
+#define UBIFS_ORPH_NODE_SZ     sizeof(struct ubifs_orph_node)
  /* Extended attribute entry nodes are identical to directory entry nodes 
*/
  #define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
  /* Only this does not have to be multiple of 8 bytes */
-#define UBIFS_BRANCH_SZ    sizeof(struct ubifs_branch)
+#define UBIFS_BRANCH_SZ(c)    (sizeof(struct ubifs_branch)  \
+	- (FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP(c) ? 0 : sizeof(__u64)))

  /* Maximum node sizes (N.B. these are guaranteed to be multiples of 8) */
-#define UBIFS_MAX_DATA_NODE_SZ  (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE)
+#define UBIFS_MAX_DATA_NODE_SZ  (UBIFS_DATA_NODE_VMAX_SZ + 
UBIFS_BLOCK_SIZE)
  #define UBIFS_MAX_INO_NODE_SZ   (UBIFS_INO_NODE_SZ + UBIFS_MAX_INO_DATA)
  #define UBIFS_MAX_DENT_NODE_SZ  (UBIFS_DENT_NODE_SZ + UBIFS_MAX_NLEN + 1)
  #define UBIFS_MAX_XENT_NODE_SZ  UBIFS_MAX_DENT_NODE_SZ
@@ -549,6 +571,18 @@ struct ubifs_dent_node {
   *
   * Note, do not forget to amend 'zero_data_node_unused()' function when
   * changing the padding fields.
+ *
+ * This data structure format is version 5, which includes the 
@crypto_lookup
+ * field. Since @data is unbounded, the new field must be before it.
+ * Compatibility macros:
+ * FMT_VERSION_DATA_NODE_POS_DATA: returns a pointer to the appropriate 
place
+ *				   where the key begins for the current
+ *				   mounted version.
+ * FMT_VERSION_DATA_NODE_HAS_CRYPTO_LOOKUP: true if the current mounted
+ *					    version contains the
+ *					    @crypto_lookup field.
+ * UBIFS_DATA_NODE_SZ: now returns the appropriate size for this data 
structure
+ *		       depending on the version.
   */
  struct ubifs_data_node {
  	struct ubifs_ch ch;
@@ -556,7 +590,8 @@ struct ubifs_data_node {
  	__le32 size;
  	__le16 compr_type;
  	__u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! 
*/
-	__u8 data[];
+	__u64 crypto_lookup;
+	__u8 __data[];
  } __packed;

  /**
@@ -614,10 +649,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 ubifsec secure 
deletion
+ * @padding2: reserved for future, zeroes
   */
  struct ubifs_sb_node {
  	struct ubifs_ch ch;
@@ -645,7 +682,9 @@ struct ubifs_sb_node {
  	__le32 time_gran;
  	__u8 uuid[16];
  	__le32 ro_compat_version;
-	__u8 padding2[3968];
+	__le32 crypto_lebs;
+	__u8 use_ubifsec;
+	__u8 padding2[3963];
  } __packed;

  /**
@@ -736,13 +775,25 @@ struct ubifs_ref_node {
   * @lnum: LEB number of the target node
   * @offs: offset within @lnum
   * @len: target node length
- * @key: key
+ * @__key: key.
+ *
+ * This data structure format is version 5, which includes the 
crypto_lookup
+ * field. Since key is unbounded, the new field must be before it.
+ * Compatibility macros:
+ * FMT_VERSION_BRANCH_POS_KEY: returns a pointer to the appropriate place
+ *			       where the key begins for the current 
mounted
+ *			       version.
+ * FMT_VERSION_BRANCH_HAS_CRYPTO_LOOKUP: true if the current mounted 
version
+ *					 contains the crypto_lookup field.
+ * UBIFS_BRANCH_SZ: now returns the appropriate size for this data 
structure
+ *		    depending on the version.
   */
  struct ubifs_branch {
  	__le32 lnum;
  	__le32 offs;
  	__le32 len;
-	__u8 key[];
+	__le64 crypto_lookup;
+	__u8 __key[];
  } __packed;

  /**
@@ -750,7 +801,7 @@ struct ubifs_branch {
   * @ch: common header
   * @child_cnt: number of child index nodes
   * @level: tree level
- * @branches: LEB number / offset / length / key branches
+ * @branches: LEB number / offset / length / crypto_lookup / key branches
   */
  struct ubifs_idx_node {
  	struct ubifs_ch ch;
Joel Reardon - Feb. 23, 2012, 3:29 p.m.
This patch extends to interface for compression and decompression of data 
nodes to take a cryptographic key
as a parameter. If it is set to NULL, then the current behaviour persists. 
If it is non-null, then it is taken
as a pointer to an array of length UBIFSEC_KEYSIZE (=16 bytes) which 
contains the key to use to encrypt
the data node. Each data node should be encrypted with a separate key as 
it uses the same initialization vector  (of 0).

In all places where the compress/decompress are called, a NULL parameter 
is used, so it will have no effect on
deployed systems. It will be needed when adding secure deletion to UBIFS 
using individually encrypted data nodes.

It was tested by with hundred runs of integck along with power cut tests.

------

Signed-off-by: Joel Reardon<reardonj@inf.ethz.ch>
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/compress.c 
linux-3.2.1-ubifsec/fs/ubifs/compress.c
--- linux-3.2.1-vanilla/fs/ubifs/compress.c	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/compress.c	2012-02-23 
16:07:44.287023169 +0100
@@ -27,9 +27,11 @@
   * decompression.
   */

-#include <linux/crypto.h>
  #include "ubifs.h"

+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+
  /* Fake description object for the "none" compressor */
  static struct ubifs_compressor none_compr = {
  	.compr_type = UBIFS_COMPR_NONE,
@@ -74,6 +76,40 @@ static struct ubifs_compressor zlib_comp
  /* All UBIFS compressors */
  struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];

+int ubifs_aes_crypt(u8 *str, int len, u8 *key, int keylen, u8 *iv, int 
ivlen)
+{
+	struct crypto_blkcipher *tfm;
+	struct blkcipher_desc desc;
+	struct scatterlist sg;
+	int err = 0;
+	tfm = crypto_alloc_blkcipher(UBIFSEC_CRYPTO_ALGORITHM, 0, 0);
+
+	if (IS_ERR(tfm)) {
+		ubifs_err("failed to load transform for aes: %ld",
+			  PTR_ERR(tfm));
+		return err;
+	}
+
+	err = crypto_blkcipher_setkey(tfm, key, keylen);
+	desc.tfm = tfm;
+	desc.flags = 0;
+	if (err) {
+		ubifs_err("setkey() failed  flags=%x",
+			  crypto_blkcipher_get_flags(tfm));
+		return err;
+	}
+	memset(&sg, 0, sizeof(struct scatterlist));
+
+	sg_set_buf(&sg, str, len);
+	desc.info = iv;
+	err = crypto_blkcipher_encrypt(&desc, &sg, &sg, len);
+	crypto_free_blkcipher(tfm);
+	if (err)
+		return err;
+	return 0;
+}
+
+
  /**
   * ubifs_compress - compress data.
   * @in_buf: data to compress
@@ -93,7 +129,7 @@ struct ubifs_compressor *ubifs_compresso
   * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
   */
  void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int 
*out_len,
-		    int *compr_type)
+		    int *compr_type, u8* key)
  {
  	int err;
  	struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
@@ -115,7 +151,7 @@ void ubifs_compress(const void *in_buf,
  		ubifs_warn("cannot compress %d bytes, compressor %s, "
  			   "error %d, leave data uncompressed",
  			   in_len, compr->name, err);
-		 goto no_compr;
+		goto no_compr;
  	}

  	/*
@@ -124,13 +160,20 @@ void ubifs_compress(const void *in_buf,
  	 */
  	if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
  		goto no_compr;
-
-	return;
+	goto encrypt;

  no_compr:
  	memcpy(out_buf, in_buf, in_len);
  	*out_len = in_len;
  	*compr_type = UBIFS_COMPR_NONE;
+	goto encrypt;
+encrypt:
+	if (key) {
+		u8 iv[AES_KEYSIZE_128];
+		memset(iv, 0, AES_KEYSIZE_128);
+		ubifs_aes_crypt(out_buf, *out_len, key, AES_KEYSIZE_128,
+				iv, AES_KEYSIZE_128);
+	}
  }

  /**
@@ -145,8 +188,9 @@ no_compr:
   * The length of the uncompressed data is returned in @out_len. This 
functions
   * returns %0 on success or a negative error code on failure.
   */
-int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
-		     int *out_len, int compr_type)
+int ubifs_decompress(void *in_buf, int in_len, void *out_buf,
+		     int *out_len, int compr_type, u8* key)
+
  {
  	int err;
  	struct ubifs_compressor *compr;
@@ -163,6 +207,12 @@ int ubifs_decompress(const void *in_buf,
  		return -EINVAL;
  	}

+	if (key) {
+		u8 iv[AES_KEYSIZE_128];
+		memset(iv, 0, AES_KEYSIZE_128);
+		ubifs_aes_crypt(in_buf, in_len, key, AES_KEYSIZE_128,
+				iv, AES_KEYSIZE_128);
+	}
  	if (compr_type == UBIFS_COMPR_NONE) {
  		memcpy(out_buf, in_buf, in_len);
  		*out_len = in_len;
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/file.c linux-3.2.1-ubifsec/fs/ubifs/file.c
--- linux-3.2.1-vanilla/fs/ubifs/file.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/file.c	2012-02-23 16:15:48.607046613 
+0100
@@ -80,7 +80,7 @@ static int read_block(struct inode *inod
  	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
  	out_len = UBIFS_BLOCK_SIZE;
  	err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
-			       le16_to_cpu(dn->compr_type));
+			       le16_to_cpu(dn->compr_type), NULL);
  	if (err || len != out_len)
  		goto dump;

@@ -649,7 +649,8 @@ static int populate_page(struct ubifs_in
  			dlen = le32_to_cpu(dn->ch.len) - 
UBIFS_DATA_NODE_SZ;
  			out_len = UBIFS_BLOCK_SIZE;
  			err = ubifs_decompress(&dn->data, dlen, addr, 
&out_len,
- 
le16_to_cpu(dn->compr_type));
+ 
le16_to_cpu(dn->compr_type),
+					       NULL);
  			if (err || len != out_len)
  				goto out_err;

diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/journal.c 
linux-3.2.1-ubifsec/fs/ubifs/journal.c
--- linux-3.2.1-vanilla/fs/ubifs/journal.c	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/journal.c	2012-02-23 
16:15:05.415044519 +0100
@@ -728,7 +728,7 @@ int ubifs_jnl_write_data(struct ubifs_in
  		compr_type = ui->compr_type;

  	out_len = dlen - UBIFS_DATA_NODE_SZ;
-	ubifs_compress(buf, len, &data->data, &out_len, &compr_type);
+	ubifs_compress(buf, len, &data->data, &out_len, &compr_type, 
NULL);
  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);

  	dlen = UBIFS_DATA_NODE_SZ + out_len;
@@ -1111,11 +1111,12 @@ static int recomp_data_node(struct ubifs

  	len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
  	compr_type = le16_to_cpu(dn->compr_type);
-	err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type);
+	err = ubifs_decompress(
+		&dn->data, len, buf, &out_len, compr_type, NULL);
  	if (err)
  		goto out;

-	ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type);
+	ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type, 
NULL);
  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
  	dn->compr_type = cpu_to_le16(compr_type);
  	dn->size = cpu_to_le32(*new_len);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/ubifs.h linux-3.2.1-ubifsec/fs/ubifs/ubifs.h
--- linux-3.2.1-vanilla/fs/ubifs/ubifs.h	2012-01-12 
20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/ubifs.h	2012-02-23 
16:09:03.071026982 +0100
@@ -163,6 +163,14 @@
  /* Maximum number of data nodes to bulk-read */
  #define UBIFS_MAX_BULK_READ 32

+/* Size of 128 bits in bytes */
+#define AES_KEYSIZE_128 16
+
+/* Key size in bytes for UBIFSEC */
+#define UBIFSEC_KEYSIZE AES_KEYSIZE_128
+#define UBIFSEC_CRYPTO_ALGORITHM "ctr(aes)"
+#define POISON_KEY(p) memset(p, 0xff, UBIFSEC_KEYSIZE)
+
  /*
   * Lockdep classes for UBIFS inode @ui_mutex.
   */
@@ -1775,9 +1783,10 @@ long ubifs_compat_ioctl(struct file *fil
  int __init ubifs_compressors_init(void);
  void ubifs_compressors_exit(void);
  void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int 
*out_len,
-		    int *compr_type);
-int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
-		     int compr_type);
+		    int *compr_type, u8* key);
+int ubifs_decompress(void *buf, int len, void *out, int *out_len,
+		     int compr_type, u8 *key);
+int ubifs_aes_crypt(u8 *str, int len, u8 *key, int keylen, u8 *iv, int 
ivlen);

  #include "debug.h"
  #include "misc.h"
Artem Bityutskiy - Feb. 29, 2012, 4:10 p.m.
On Mon, 2012-02-20 at 21:15 +0100, Joel Reardon wrote:
> This patch moves the computation of CRCs for data nodes from 
> within ubifs_prepare_node to a separate function ubifs_set_datanode_crc, 
> which takes a data node, and computes and sets the CRC. This is to avoid 
> duplication of the CRC computation code in other places where it may be 
> needed.
> 
> Signed-off-by: Joel Reardon <reardonj@inf.ethz.ch>
> diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
> linux-3.2.1-vanilla/fs/ubifs/io.c linux-3.2.1-ubifsec/fs/ubifs/io.c
> --- linux-3.2.1-vanilla/fs/ubifs/io.c   2012-01-12 20:42:45.000000000 
> +0100
> +++ linux-3.2.1-ubifsec/fs/ubifs/io.c   2012-02-20 20:17:48.796684293 
> +0100
> @@ -367,6 +367,18 @@ static unsigned long long next_sqnum(str
>   }

This patch is line-wrapped and cannot be applied. Would you please send
a non-wrapped version. You may experiment by sending to yourself, then
saving, and then applying using "git am".

> 
>   /**
> + * ubifs_set_datanode_crc - writes the crc for a data node to the common
> + * header.
> + * @node: the data node
> + */
> +void ubifs_set_datanode_crc(void *node)
> +{
> +       struct ubifs_ch *ch = (struct ubifs_ch *) node;
> +       int len = le32_to_cpu(ch->len);
> +       ch->crc = cpu_to_le32(crc32(UBIFS_CRC32_INIT, node + 8, len - 8));
> +}

This changes is not needed unless there is other code which needs this
function. So once I get a non-wrapped patch I can create a branch for
you in the UBIFS tree and collect your patches. Once they are ready,
they can be merged.
Artem Bityutskiy - Feb. 29, 2012, 5:09 p.m.
On Thu, 2012-02-23 at 15:59 +0100, Joel Reardon wrote:
> >
> > Could you make a separate patch which adds new on-flash format and make
> > sure that new ubifs binaries can mount the old formats and work with
> > them. And that old ubifs binaries gracefully reject the new format.
> >
> 
> This patch provides a new version of two on-flash data structures for 
> UBIFS:

Similarly - wrapped patch and git am wont' apply it, sorry.

> ubifs_branch and ubifs_data_node have been grown by 8 bytes to include a 
> 64-bit reference
> to a key position, which is needed by a proposed ubifs secure deletion 
> addition. This patch is generated
> against linux-3.2.1.

Please, use linux-ubifs tree instead:
git://git.infradead.org/linux-ubifs.git

It has the newest stuff.

> Because both data structures use C99 flexible arrays, it is not possible 
> to add the new field as
> the last member of the structure.

>  Thus, it was added one before last, the 
> last was renamed, and in a
> handful of places where it was used, a macro accessor is used to get the 
> version-correct position.

Hmm, we can make it to be key[UBIFS_SK_LEN] instead, if it helps.
Artem Bityutskiy - Feb. 29, 2012, 5:25 p.m.
On Thu, 2012-02-09 at 16:24 +0100, Joel Reardon wrote:
> 
> Each data nodes includes a reference to a key in the KSA. This key is read and 
> used to decrypt the data. When a new data node is written, an unused key is 
> selected from the KSA and used to encrypt the data node. The reference to the 
> key is then included with the node. The keys in the KSA are written before 
> actually being used to encrypt data. To securely delete a data node, we simply 
> mark the corresponding key position as deleted, and during the next purging 
> operation the KSA erase block that contains the key is then updated to a 
> version that does not contain the key.

Why do you need to have your '__u64 crypto_lookup' both in the data node
and the index? Isn't it enough to have them only inside the data nodes?
ubifs_branch anyway points to the data node and you can read your
'crypto_lookup' from there.
Joel Reardon - March 1, 2012, 1:41 p.m.
This is true. The reason its done is as an optimization for the 
following reason.

When deleting a data node, the key position is marked as deleted. The key 
positions then requires a datanode read to find. By keeping it in memory (thus the TNC), 
marking a key pos as deleted doesn't require a flash read. This improves 
e.g., truncations and full file deletion speed, which would otherwise read 
each data node from flash to get the positions. If it is not stored in 
ubifs_branch (but still stored in the tree), then it would have to be 
loaded once 'on-demand' after mounting. This is also an option, of course. 
Currently, deleting a file performs a walk on all the TNC's data nodes 
that are removed, so the extra mark-delete incurs no observable cost.

Cheers,
Joel Reardon

On Wed, 29 Feb 2012, Artem Bityutskiy wrote:

> On Thu, 2012-02-09 at 16:24 +0100, Joel Reardon wrote:
>>
>> Each data nodes includes a reference to a key in the KSA. This key is read and
>> used to decrypt the data. When a new data node is written, an unused key is
>> selected from the KSA and used to encrypt the data node. The reference to the
>> key is then included with the node. The keys in the KSA are written before
>> actually being used to encrypt data. To securely delete a data node, we simply
>> mark the corresponding key position as deleted, and during the next purging
>> operation the KSA erase block that contains the key is then updated to a
>> version that does not contain the key.
>
> Why do you need to have your '__u64 crypto_lookup' both in the data node
> and the index? Isn't it enough to have them only inside the data nodes?
> ubifs_branch anyway points to the data node and you can read your
> 'crypto_lookup' from there.
>
> -- 
> Best Regards,
> Artem Bityutskiy
>
Artem Bityutskiy - March 9, 2012, 7:17 a.m.
On Thu, 2012-02-23 at 16:29 +0100, Joel Reardon wrote:
> This patch extends to interface for compression and decompression of data 
> nodes to take a cryptographic key
> as a parameter. If it is set to NULL, then the current behaviour persists. 
> If it is non-null, then it is taken
> as a pointer to an array of length UBIFSEC_KEYSIZE (=16 bytes) which 
> contains the key to use to encrypt
> the data node. Each data node should be encrypted with a separate key as 
> it uses the same initialization vector  (of 0).

This patch is also wrapped... Would you consider using git - commit your
patches, then git format-patch, then git send-email them - git tools
will take everything right. Use --dry-run with git send-email first to
check everything is right.
Artem Bityutskiy - March 9, 2012, 7:36 a.m.
On Thu, 2012-03-01 at 14:41 +0100, Joel Reardon wrote:
> This is true. The reason its done is as an optimization for the 
> following reason.
> 
> When deleting a data node, the key position is marked as deleted.

Would you please explain again how the key position is being marked as
deleted please. Would be nice to have a wiki or a public document with
design reference somewhere, so you could just point "see page 5" as an
answer, and update it if needed.

>  The key 
> positions then requires a datanode read to find.

Sorry, would you please provide a bit more detailed information. I am
sure you explained it before, but the explanation is buried somewhere.

I am ready to create an ubifs branch for you and keep a text file with
design/FAQ there, and update the branch as UBIFS moves forward, and
apply your small incremental patches - as soon as we have an
applicable / nice patch.

>  By keeping it in memory (thus the TNC), 
> marking a key pos as deleted doesn't require a flash read.


Well, I'd say that this should be solved with another layer of caching.
E.g., we have so called "LNC" (Leaf node cache) - we keep direntries at
the leaf level to avoid extra reads. You could extend LNC and keep keys
there.

Consider this approach:

1. You throw out this optimization so far
2. Keep working on your stuff - you have enough issues to deal with.
You'll have less compatibility issues when you throw that out. The
design will be simpler as well.
3. When / if other things are done, you try to extend LNC to always
cache the keys.

>  This improves 
> e.g., truncations and full file deletion speed, which would otherwise read 
> each data node from flash to get the positions. If it is not stored in 
> ubifs_branch (but still stored in the tree), then it would have to be 
> loaded once 'on-demand' after mounting. This is also an option, of course. 
> Currently, deleting a file performs a walk on all the TNC's data nodes 
> that are removed, so the extra mark-delete incurs no observable cost.

I wonder also if it is wise to enable secure deletion globally. Yes, we
pay the cost of maintaining the keys anyways, but we could avoid paying
the costs at deletion time when deleting non-securely.

Isn't it wiser to have a special interface for secure deletion which
would be slower than normal deletion? I believe this is the right
approach. And I believe block-based file-systems would go this way. Just
think about MMC which has secure erase trim which is so slow - I do not
think anyone would use it for everything by default - people would have
a separate interface.

Did you explore, by the way, if something like this is being worked on
for other FSes in Linux?
Joel Reardon - March 9, 2012, 7:29 p.m.
>
> I wonder also if it is wise to enable secure deletion globally. Yes, we
> pay the cost of maintaining the keys anyways, but we could avoid paying
> the costs at deletion time when deleting non-securely.
>
> Isn't it wiser to have a special interface for secure deletion which
> would be slower than normal deletion? I believe this is the right
> approach. And I believe block-based file-systems would go this way. Just
> think about MMC which has secure erase trim which is so slow - I do not
> think anyone would use it for everything by default - people would have
> a separate interface.

Here there is a wide space of solutions. One approach used in block-based
systems is to use a +s attribute, and then progate this whenever files are
copied etc. However, it presents the major useability problem in that a
user must remember to set this attribute for this files. And no
application can be reliably expected to set this value correctly since it
is not a standard action. Sensitive data not marked as such will thus not
be securely deleted. It suffers the same way as requiring users to use srm
when appropriate---after the first time they forget they'll probably never
again remember.

In this solution, keys are marked to be deleted when the data node
encrypted with that key is removed from the TNC. So a really simple
change:
1. node is added - key marked as used;
2. node is removed - key marked as deleted;
3. node is modified to a new value; old key marked deleted, new key marked
as used.

The keys themselves are not immediately removed, this occurs during
UBIFS commit (although it can also happen independently, but also as a
periodic background action). Thus, deletion has a low cost, just erasing
the small set of key storing blocks in the background, and the cost will
likely be
the same regardless if the entire partition is purged instead of
just some data marked as sensitive: it only takes one key on an
LEB to warrant erasure of the LEB, and there are (LEB_SIZE >> 16)
keys per LEB.

However, without caching the keys in the TNC, then deletion takes as long
as reading a file. Thankfully, it will be nowhere near as bad as MMC
secure erase trim, which (I presume) actually GCs and erases all the EBs that
store file data. In this solution, it only needs to read the data node's
header to get the key position, and mark it as deleted. Deletion happens
in the backgroun.

To me, being able to set secure erase or not as a partition level setting
makes alot of sense. The OS partition does not need it, but the user file data
partition will have it, and UBI makes sense that wear levelling is done
among all the partitions properly. Then taint status for files'
sensitivity doesn't need to be maintained. The deployer simply chooses for
this part of the FS, do they want secure deletion over the data or not,
one time at the beginning. (Compare this to the decision on whether or
not to encrypt their entire partition or later encrypting each file they
make.)


>
> Did you explore, by the way, if something like this is being worked on
> for other FSes in Linux?
>

In my related works research I found nothing like this. Some advocated
putting a key in the inode for a file then securely deleting things at a
file-level granularity by GC and erasing the inode. Another suggestion
multiple overwrites with zeros but that doesn't seem like it works with
modern denser flash memories.

I'll remove the change to tree branch, and repost correctly the
version change where only data node is effected. Btw, when I was
developing it I used the last 8 bytes from the key as the key position,
because the key was 16 bytes but only 8 were used. Could you comment on
the last 8 bytes of ubifs keys?


Joel
Artem Bityutskiy - March 12, 2012, 1:30 p.m.
On Fri, 2012-03-09 at 20:29 +0100, Joel Reardon wrote:
> To me, being able to set secure erase or not as a partition level setting
> makes alot of sense. The OS partition does not need it, but the user file data
> partition will have it, and UBI makes sense that wear levelling is done
> among all the partitions properly. Then taint status for files'
> sensitivity doesn't need to be maintained. The deployer simply chooses for
> this part of the FS, do they want secure deletion over the data or not,
> one time at the beginning. (Compare this to the decision on whether or
> not to encrypt their entire partition or later encrypting each file they
> make.)

Well, it makes sense. I do not insist on having a separate interface for
secure deletion. But duplication of the same information in the B-tree
slots and the data nodes the slots point to does not make much sense to
me.

I mostly look at this from the maintainability and upstreamability POW
and I see that despite on the clever ideas the changes broke backward
compatibility, patches are big and intrusive. From my point of view -
contributors come and go but I keep maintaining this beast :-)

> I'll remove the change to tree branch, and repost correctly the
> version change where only data node is effected.

But please, keep in mind my motivations and ensure that what I suggest
makes sense from your POW!

>  Btw, when I was
> developing it I used the last 8 bytes from the key as the key position,
> because the key was 16 bytes but only 8 were used. Could you comment on
> the last 8 bytes of ubifs keys?

I think you can use them. But is it possible to kill these things from
the data nodes themselves? We can always find it by looking up the index
by the data node key, right?
Joel Reardon - March 12, 2012, 1:34 p.m.
>
> I think you can use them. But is it possible to kill these things from
> the data nodes themselves? We can always find it by looking up the index
> by the data node key, right?
>

Yep, thats exactly right. Originally it was just inside the data node;
I put it into the TNC as a optimization later during development. If I use
the last eight bytes from the data node's key, and I remove the position
from ubifs_branch, then there is no longer any change to the on-disk
format, so thats should be useful. Yeah, storing the same value twice
means also needing a consistency check. What can be done is that when the
value is loaded once after mounting, it is stored in in the z-node in
memory.
Artem Bityutskiy - March 12, 2012, 1:36 p.m.
On Mon, 2012-03-12 at 15:30 +0200, Artem Bityutskiy wrote:
> >  Btw, when I was
> > developing it I used the last 8 bytes from the key as the key position,
> > because the key was 16 bytes but only 8 were used. Could you comment on
> > the last 8 bytes of ubifs keys?
> 
> I think you can use them. But is it possible to kill these things from
> the data nodes themselves? We can always find it by looking up the index
> by the data node key, right?

Joel, but please, send small patches, preparation patches, etc. Do not
disappear for several months and do not come back with another big
patch. Tell about your intentions in advance.

E.g., if you decide to start using those unused 8 bytes - first do small
preparations like removing the notion of "key scheme" which we
provisioned but never used (from comments as well). Clean-up the "space"
for yourself. Then start using them for your purposes. As I said, as
soon as I get the first patch I like, I'll create a separate branch in
the UBIFS git tree for your work.

Thanks!
Joel Reardon - March 12, 2012, 1:37 p.m.
Sounds good, I'll use the main git repo and as the first patch I'll claim
those 8 bytes and make key.h reflect whats going on.

Cheers,
Joel

On Mon, 12 Mar 2012, Artem Bityutskiy wrote:

> On Mon, 2012-03-12 at 15:30 +0200, Artem Bityutskiy wrote:
> > >  Btw, when I was
> > > developing it I used the last 8 bytes from the key as the key position,
> > > because the key was 16 bytes but only 8 were used. Could you comment on
> > > the last 8 bytes of ubifs keys?
> >
> > I think you can use them. But is it possible to kill these things from
> > the data nodes themselves? We can always find it by looking up the index
> > by the data node key, right?
>
> Joel, but please, send small patches, preparation patches, etc. Do not
> disappear for several months and do not come back with another big
> patch. Tell about your intentions in advance.
>
> E.g., if you decide to start using those unused 8 bytes - first do small
> preparations like removing the notion of "key scheme" which we
> provisioned but never used (from comments as well). Clean-up the "space"
> for yourself. Then start using them for your purposes. As I said, as
> soon as I get the first patch I like, I'll create a separate branch in
> the UBIFS git tree for your work.
>
> Thanks!
>
> --
> Best Regards,
> Artem Bityutskiy
>
>
Joel Reardon - March 14, 2012, 10:20 a.m.
For removing the key scheme notion, is it correct to remove:
UBIFS_KEY_MAX_LEN and UBIFS_SK_, UBIFS_S_KEY_BLOCK_BITS, ... and replace
it with a fixed UBIFS_KEY_LEN (and other values), thus also ignoring
key_fmt in key_max_inode_size and simply use a fixed key scheme? Or should
I simply reduce MAX_LEN to 8 but still allow multiple bit assignments
within those 8 bytes via selecting a different key_fmt.

Cheers,
Joel Reardon



On Mon, 12 Mar 2012, Artem Bityutskiy wrote:

> On Mon, 2012-03-12 at 15:30 +0200, Artem Bityutskiy wrote:
> > >  Btw, when I was
> > > developing it I used the last 8 bytes from the key as the key position,
> > > because the key was 16 bytes but only 8 were used. Could you comment on
> > > the last 8 bytes of ubifs keys?
> >
> > I think you can use them. But is it possible to kill these things from
> > the data nodes themselves? We can always find it by looking up the index
> > by the data node key, right?
>
> Joel, but please, send small patches, preparation patches, etc. Do not
> disappear for several months and do not come back with another big
> patch. Tell about your intentions in advance.
>
> E.g., if you decide to start using those unused 8 bytes - first do small
> preparations like removing the notion of "key scheme" which we
> provisioned but never used (from comments as well). Clean-up the "space"
> for yourself. Then start using them for your purposes. As I said, as
> soon as I get the first patch I like, I'll create a separate branch in
> the UBIFS git tree for your work.
>
> Thanks!
>
> --
> Best Regards,
> Artem Bityutskiy
>
>
Artem Bityutskiy - March 14, 2012, 10:27 a.m.
On Wed, 2012-03-14 at 11:20 +0100, Joel Reardon wrote:
> For removing the key scheme notion, is it correct to remove:
> UBIFS_KEY_MAX_LEN and UBIFS_SK_, UBIFS_S_KEY_BLOCK_BITS, ... and replace
> it with a fixed UBIFS_KEY_LEN (and other values), thus also ignoring
> key_fmt in key_max_inode_size and simply use a fixed key scheme? Or should
> I simply reduce MAX_LEN to 8 but still allow multiple bit assignments
> within those 8 bytes via selecting a different key_fmt.

Yes, sounds reasonable.

Patch

diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/file.c linux-3.2.1-ubifsec/fs/ubifs/file.c
--- linux-3.2.1-vanilla/fs/ubifs/file.c	2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/file.c	2012-02-08 16:54:49.101506843 +0100
@@ -61,6 +61,8 @@  static int read_block(struct inode *inod
  	int err, len, out_len;
  	union ubifs_key key;
  	unsigned int dlen;
+	u8 crypto_key[UBIFSEC_KEYSIZE];
+	u8 *pkey = NULL;

  	data_key_init(c, &key, inode->i_ino, block);
  	err = ubifs_tnc_lookup(c, &key, dn);
@@ -79,8 +81,14 @@  static int read_block(struct inode *inod

  	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
  	out_len = UBIFS_BLOCK_SIZE;
+	if (c->use_ubifsec) {
+		keymap_read_key(c, le64_to_cpu(dn->crypto_lookup), crypto_key);
+		pkey = crypto_key;
+	}
  	err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
-			       le16_to_cpu(dn->compr_type));
+			       le16_to_cpu(dn->compr_type), pkey);
+	POISON_KEY(crypto_key);
+
  	if (err || len != out_len)
  		goto dump;

@@ -636,6 +644,8 @@  static int populate_page(struct ubifs_in
  			memset(addr, 0, UBIFS_BLOCK_SIZE);
  		} else if (key_block(c, &bu->zbranch[nn].key) == page_block) {
  			struct ubifs_data_node *dn;
+			u8 crypto_key[UBIFSEC_KEYSIZE];
+			u8 *pkey = NULL;

  			dn = bu->buf + (bu->zbranch[nn].offs - offs);

@@ -648,8 +658,17 @@  static int populate_page(struct ubifs_in

  			dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
  			out_len = UBIFS_BLOCK_SIZE;
+			if (c->use_ubifsec) {
+				keymap_read_key(c,
+ le64_to_cpu(dn->crypto_lookup),
+						crypto_key);
+				pkey = crypto_key;
+			}
  			err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
- le16_to_cpu(dn->compr_type));
+ le16_to_cpu(dn->compr_type),
+					       pkey);
+			POISON_KEY(crypto_key);
+
  			if (err || len != out_len)
  				goto out_err;

diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/gc.c linux-3.2.1-ubifsec/fs/ubifs/gc.c
--- linux-3.2.1-vanilla/fs/ubifs/gc.c	2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/gc.c	2012-02-08 16:54:49.105506843 +0100
@@ -322,15 +322,30 @@  static int move_node(struct ubifs_info *
  		     struct ubifs_scan_node *snod, struct ubifs_wbuf *wbuf)
  {
  	int err, new_lnum = wbuf->lnum, new_offs = wbuf->offs + wbuf->used;
+	u64 crypto_lookup = 0;

  	cond_resched();
+	/* When moving a node, inform the keymap and determine if it wants
+     * to promote the key to a longer-term key storage area.
+     */
+	if (c->use_ubifsec && key_type(c, &snod->key) == UBIFS_DATA_KEY) {
+		struct ubifs_data_node *dn =
+			(struct ubifs_data_node *) snod->node;
+		crypto_lookup = le64_to_cpu(dn->crypto_lookup);
+		if (keymap_gc_should_promote(c, crypto_lookup)) {
+			u64 new_pos;
+			err = keymap_swap_encryption_key(c, dn);
+			new_pos = le64_to_cpu(dn->crypto_lookup);
+			crypto_lookup = new_pos;
+		}
+	}
+
  	err = ubifs_wbuf_write_nolock(wbuf, snod->node, snod->len);
  	if (err)
  		return err;
-
  	err = ubifs_tnc_replace(c, &snod->key, sleb->lnum,
  				snod->offs, new_lnum, new_offs,
-				snod->len);
+				snod->len, crypto_lookup);
  	list_del(&snod->list);
  	kfree(snod);
  	return err;
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/io.c linux-3.2.1-ubifsec/fs/ubifs/io.c
--- linux-3.2.1-vanilla/fs/ubifs/io.c	2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/io.c	2012-02-08 16:54:49.105506843 +0100
@@ -367,6 +367,19 @@  static unsigned long long next_sqnum(str
  }

  /**
+ * ubifs_set_datanode_crc - writes the crc for a data node to the common
+ * header.
+ * @node: the data node
+ * @len: the length of data
+ */
+void ubifs_set_datanode_crc(void *node)
+{
+	struct ubifs_ch *ch = (struct ubifs_ch *) node;
+	int len = le32_to_cpu(ch->len);
+	ch->crc = cpu_to_le32(crc32(UBIFS_CRC32_INIT, node + 8, len - 8));
+}
+
+/**
   * ubifs_prepare_node - prepare node to be written to flash.
   * @c: UBIFS file-system description object
   * @node: the node to pad
@@ -379,7 +392,6 @@  static unsigned long long next_sqnum(str
   */
  void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
  {
-	uint32_t crc;
  	struct ubifs_ch *ch = node;
  	unsigned long long sqnum = next_sqnum(c);

@@ -390,8 +402,7 @@  void ubifs_prepare_node(struct ubifs_inf
  	ch->group_type = UBIFS_NO_NODE_GROUP;
  	ch->sqnum = cpu_to_le64(sqnum);
  	ch->padding[0] = ch->padding[1] = 0;
-	crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
-	ch->crc = cpu_to_le32(crc);
+	ubifs_set_datanode_crc(node);

  	if (pad) {
  		len = ALIGN(len, 8);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/journal.c linux-3.2.1-ubifsec/fs/ubifs/journal.c
--- linux-3.2.1-vanilla/fs/ubifs/journal.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/journal.c	2012-02-08 16:54:49.105506843 
+0100
@@ -696,6 +696,9 @@  int ubifs_jnl_write_data(struct ubifs_in
  	int err, lnum, offs, compr_type, out_len;
  	int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
  	struct ubifs_inode *ui = ubifs_inode(inode);
+	u8 crypto_key[UBIFSEC_KEYSIZE];
+	u8 *pkey = NULL;
+	u64 pos = 0;

  	dbg_jnl("ino %lu, blk %u, len %d, key %s",
  		(unsigned long)key_inum(c, key), key_block(c, key), len,
@@ -718,6 +721,15 @@  int ubifs_jnl_write_data(struct ubifs_in

  	data->ch.node_type = UBIFS_DATA_NODE;
  	key_write(c, key, &data->key);
+
+	if (c->use_ubifsec) {
+		err = keymap_free_key(c, &pos, crypto_key);
+		data->crypto_lookup = cpu_to_le64(pos);
+		if (err)
+			return -ENOMEM;
+		pkey = crypto_key;
+	}
+
  	data->size = cpu_to_le32(len);
  	zero_data_node_unused(data);

@@ -728,7 +740,8 @@  int ubifs_jnl_write_data(struct ubifs_in
  		compr_type = ui->compr_type;

  	out_len = dlen - UBIFS_DATA_NODE_SZ;
-	ubifs_compress(buf, len, &data->data, &out_len, &compr_type);
+	ubifs_compress(buf, len, &data->data, &out_len, &compr_type, pkey);
+	POISON_KEY(crypto_key);
  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);

  	dlen = UBIFS_DATA_NODE_SZ + out_len;
@@ -745,7 +758,7 @@  int ubifs_jnl_write_data(struct ubifs_in
  	ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf, key_inum(c, key));
  	release_head(c, DATAHD);

-	err = ubifs_tnc_add(c, key, lnum, offs, dlen);
+	err = ubifs_tnc_add_with_crypto_lookup(c, key, lnum, offs, dlen, pos);
  	if (err)
  		goto out_ro;

@@ -1099,10 +1112,14 @@  out_free:
   * This function is used when an inode is truncated and the last data node of
   * the inode has to be re-compressed and re-written.
   */
-static int recomp_data_node(struct ubifs_data_node *dn, int *new_len)
+static int recomp_data_node(struct ubifs_info *c, struct ubifs_data_node *dn,
+			    int *new_len)
  {
  	void *buf;
+	u64 old_pos;
  	int err, len, compr_type, out_len;
+	u8 crypto_key[UBIFSEC_KEYSIZE];
+	u8 *pkey = NULL;

  	out_len = le32_to_cpu(dn->size);
  	buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS);
@@ -1111,11 +1128,31 @@  static int recomp_data_node(struct ubifs

  	len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
  	compr_type = le16_to_cpu(dn->compr_type);
-	err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type);
+	if (c->use_ubifsec) {
+		err = keymap_read_key(c, le64_to_cpu(dn->crypto_lookup),
+				      crypto_key);
+		if (err)
+			goto out;
+		pkey = crypto_key;
+	}
+	err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type, 
pkey);
+
  	if (err)
  		goto out;
+	if (c->use_ubifsec) {
+		u64 new_pos;
+		old_pos = le64_to_cpu(dn->crypto_lookup);
+
+		err = keymap_free_key(c, &new_pos, crypto_key);
+		dn->crypto_lookup = cpu_to_le64(new_pos);
+		ubifs_assert(pkey == crypto_key);
+		if (err)
+			goto out;
+		keymap_mark_deleted(c, old_pos);
+	}

-	ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type);
+	ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type, pkey);
+	POISON_KEY(crypto_key);
  	ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
  	dn->compr_type = cpu_to_le16(compr_type);
  	dn->size = cpu_to_le32(*new_len);
@@ -1190,7 +1227,7 @@  int ubifs_jnl_truncate(struct ubifs_info
  				int compr_type = le16_to_cpu(dn->compr_type);

  				if (compr_type != UBIFS_COMPR_NONE) {
-					err = recomp_data_node(dn, &dlen);
+					err = recomp_data_node(c, dn, &dlen);
  					if (err)
  						goto out_free;
  				} else {
@@ -1224,7 +1261,9 @@  int ubifs_jnl_truncate(struct ubifs_info

  	if (dlen) {
  		sz = offs + UBIFS_INO_NODE_SZ + UBIFS_TRUN_NODE_SZ;
-		err = ubifs_tnc_add(c, &key, lnum, sz, dlen);
+		err = ubifs_tnc_add_with_crypto_lookup(
+			c, &key, lnum, sz, dlen,
+			le64_to_cpu(dn->crypto_lookup));
  		if (err)
  			goto out_ro;
  	}
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/keymap.c linux-3.2.1-ubifsec/fs/ubifs/keymap.c
--- linux-3.2.1-vanilla/fs/ubifs/keymap.c	1970-01-01 01:00:00.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/keymap.c	2012-02-08 16:57:56.945515934 
+0100
@@ -0,0 +1,1314 @@ 
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ * Copyright (C) 2006, 2007 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along 
with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *	  Artem Bityutskiy (Битюцкий Артём)
+ *	  Zoltan Sogor
+ */
+
+/*
+ * keymap.c
+ * Author: Joel Reardon
+ *
+ * The keymap implements the key storage, assignment, and deletion for UBIFSec
+ * to ensure secure deletion of data.
+ */
+
+#include "ubifs.h"
+#include <linux/random.h>
+
+#define KEYMAP_STATE_FREE 0
+#define KEYMAP_STATE_USED 1
+#define KEYMAP_STATE_DELETED 2
+#define KEYMAP_STATES_PER_BYTE 4
+#define KEYMAP_STATES_PER_BYTE_SHIFT 2
+#define KEYMAP_CHECKPOINT_MAGIC 0x00602e23
+
+#define RETURN_VAL_IF(v, e) do { if ((e)) return (v); } while (0)
+#define RETURN_ON_ERR(e) do { if ((e)) return (e); } while (0)
+
+/* TODO(reardon): ubifs allows updates to the file system during a commit,
+ * adding such changes to empty journal that becomes the new journal after
+ * commiting; so we must allow ubifsec to assign keys out during a purge.
+ * It can be implemented as follows: when trying to get a key, check if
+ * purge_ongoing is set true. If not, then its the standard path. Otherwise,
+ * Keys are assigned from a block that does not contain deleted data---i.e.,
+ * one whose purging will be skipped and whose keys will otherwise be
+ * marked as non-assignable. During this update, the key state map is not
+ * changed  but instead an entry is  added to a queue of changes made during
+ * purging. After writing the new KSA, the key state map is updated with the
+ * change queue. Purging is then completed and  the key state map is again
+ * correct.
+ */
+
+/* TODO(reardon): add a consistency check / full scan to rebuild checkpoint.
+ * This can have two flavours: to recovery from a missing checkpoint,
+ * simply do a full scan of all the data nodes in the TNC, and then mark their
+ * crypto positions as 'used' and the rest as 'unused'. To perform a
+ * consistency check, then read all data nodes and mark all the valid nodes's
+ * crypto positions as used, the invalid nodes (i.e., not contained in the 
TNC)
+ * as deleted, and all other posistions as unused. Then check for accord with
+ * regards to the checkpointed value and the TNC. This can be internally or as
+ * a standalone tool. However, currently, if a valid checkpoint cannot be
+ * recovered then UBIFSec reports an error and fails to mount.
+ */
+
+/* The crypto key positions are stored in zbraches in the TNC. It may be best
+ * to refactor it so that the data in each node is part of a data structure
+ * that is allocated separately, or has a variable allocation: e.g.:
+ * struct ubifs_zbranch * zbr = make_zbr(c), where make_zbr() uses c's
+ * use_ubifsec to decide whether to allocate a full zbr or a reduced one.
+ * Zbrs themselves may use a substructure of lnum,offs,len,crypto_lookup to
+ * reduce the parameter load of ubifs_tnc_add() and in the same way remove the
+ * need for ubifs_tnc_add_with_crypto_lookup.
+ */
+
+/* Currently, the KSA ranges are fixed into a short-term and long-term area,
+ * with immediate promotion if a node is garbage collected. If this is made
+ * more user-configurable, than the following define will need to be changed,
+ * along with an entire interface to be added to control it during the
+ * formatting of the partition. This is only the max size of a KSA used for
+ * sizing the array.
+ */
+#define KEYMAP_MAX_KSA_RANGES 2
+
+/* The key cache is a way of optimizing read performance by reading an entire
+ * page worth of keys into memory and keeping it locally. This way, if a
+ * key is requested on the same page (i.e., being assigned out sequentally)
+ * then it will be returned without requiring another read of the device.
+ * However, this is a trade-off with security: keeping keys in memory is
+ * always less desirable than having no keys in memory against some kinds of
+ * attacks; if the attacker is only able to read the system's memory at only
+ * one moment in time, then having as few keys as possible available is
+ * obviously a benefit.
+ */
+struct key_cache {
+	u8 *page;	/* the page of data that has been read from flash */
+	int page_num;	/* the page number (rel. to the beginning of the KSA,
+			 * that is stored in page. If page_num is -1 then the
+			 * page is not storing any valid data. */
+};
+
+/* A KSA range is a set of erase blocks that are devoted to storing keys. The
+ * compete set is called the KSA, and a KSA range is a subset of the KSA where
+ * all the keys in the range have a similar expected lifetime. The expected
+ * lifetimes are determined heuristically through generation garbage
+ * collection: each time a data node is garbage collected, it may be promoted
+ * to the next (longer-lived) KSA range.  The number of garbage collections
+ * until promotion is stored in gcs_until_promotion. If this value is 0, then
+ * it is the final KSA range (i.e., longest lived). If it is 1, then it is
+ * automatically promoted. For any other value, a random number is generated
+ * to determine if it should be promoted. (As this is all anyhow heuristical
+ * and to obtain simply fewer KSA erasures for purging, detailed accounting of
+ * garbage collections is both unnessessary and inefficient).
+ *
+ * There are two caches for the KSA. The read cache stores the last page of
+ * keys used to read a key for reading a data node. The write cache stores the
+ * last page of keys used to read a key for writing a new data node. Whether
+ * it is read or write is decided based on whether the key being read is equal
+ * to the cur_pos value. If either cache has the valid page for our read, then
+ * the cached value is used instead of reading it from the flash. Otherwise
+ * the key is read and tehe cahced is updated.
+ */
+struct ksa_range {
+	u32 ksa_first;  /* first LEB in this KSA range, relative to the KSA */
+	u32 ksa_size;   /* last LEB in this KSA range, relative to the KSA */
+	u32 gcs_until_promotion;  /* the number of garbage collections until
+				   * promotion to the next KSA. */
+	u64 cur_pos;  /* A pointer to a key position in this KSA range used for
+		       * key assignment. Finding an unused key begins from this
+		       * value. Its value is most often the last key assigned
+		       * from this KSA. The exception is after purging when
+		       * it is reset to the first key position. */
+	u32 erases;  /* The number of erasures in this KSA. This is only used 
to
+		      * determine the effectiveness of the KSA partitioning. */
+	struct key_cache rd_cache;  /* A reference to the read cache. */
+	struct key_cache wr_cache;  /* A reference to the write cache. */
+};
+
+/* This is the main keymaps data structure for UBIFSec. There is only instance
+ * of the keymap for the UBIFS main context. Its main purpose is to be aware
+ * of which LEBs belong to the KSA, how the KSA is divided into ranges, the
+ * state for each key, and mutexes to ensure thread safety.
+ */
+struct ubifs_keymap {
+	u32 key_size;  /* geometry: size of a key in bytes */
+	u32 keys_per_eb;  /* geometry: number of keys per KSA LEB. */
+	u32 ksa_size;  /* geometry: number of LEBS in the KSA */
+	u32 ksa_first;  /* the first LEB belonging to the KSA */
+	u32 ckpt_leb;  /* the LEB that is used to store keypoints of the KSA. 
*/
+
+	/* a double-array [ksa_size]x[keys_per_eb] that stores the
+	 * state of the key at that position. The state consumes two bits and
+	 * is tightly packed in the bytes. The first index is from 0
+	 * to the number of KSA LEBs - 1, and the second is from 0 to
+	 * the number of keys per (KSA LEB - 1) >> 2.
+	 */
+	u8 **state;
+	u64 free;  /* Number of unused keys in the system. */
+	/* A LEB-sized buffer used during atomic updates to write new
+	 * versions of the KSA and checkpoint. */
+	u8 *kbuf;
+	u64 deleted;  /* Number of deleted keys in the system. */
+	u32 ckpt_sz;  /* The size of an uncompressed checkpoint */
+	u8 *ckpt_buf; /* Buffer used to store the uncompressed checkpoint while
+		       * mounting and commiting. */
+	u32 next_checkpoint_off;  /* Offset in the checkpoint block where the
+				   * next checkpoint will be written. */
+
+	/* This mutex must be locked when update the state of a key. */
+	struct mutex state_mutex;
+	/* This mutex must be locked when using kbuf. */
+	struct mutex kbuf_mutex;
+	/* This mutex must be locked when doing a purge. */
+	struct mutex purge_mutex;
+	/* True if there a purge happening. Must be read under the purge mutex
+	 * lock  */
+	int purge_ongoing;
+
+	u32 erasures;  /* Count of KSA LEB erasures due to purging. */
+	int read_only;  /* Is the file-system mounted read only? */
+	/* References to the KSA range data structure for each KSA range. */
+	struct ksa_range ksa[KEYMAP_MAX_KSA_RANGES];
+	int ksa_ranges; /* The actual number of KSA ranges. */
+};
+
+/* This function sets a key position's state. */
+static inline
+void set_state(struct ubifs_keymap *km, int eb, int offset, int value)
+{
+	static const int minor_mask = (1 << KEYMAP_STATES_PER_BYTE_SHIFT) - 1;
+	int major = offset >> KEYMAP_STATES_PER_BYTE_SHIFT;
+	int shift = 2 * (offset & minor_mask);
+	int mask  = minor_mask << shift;
+	int old = km->state[eb][major];
+	km->state[eb][major] = old - (old & mask) + (value << shift);
+}
+
+/* This function gets a key position's state. */
+static inline
+int get_state(struct ubifs_keymap *km, int eb, int offset)
+{
+	static const int minor_mask = (1 << KEYMAP_STATES_PER_BYTE_SHIFT) - 1;
+	int major = offset >> KEYMAP_STATES_PER_BYTE_SHIFT;
+	int shift = 2 * (offset & minor_mask);
+	return (km->state[eb][major] >> shift) & minor_mask;
+}
+
+/* TODO(reardon): to optimize the common event of reading all states
+ * sequentially (e.g., purge, checkpoint), make a caching reading function.
+ */
+
+/* This function invalidates the current page in the key_cache that is passed.
+ * It also poisons the memory. */
+static void key_cache_invalidate(const struct ubifs_info *c,
+				 struct key_cache *cache)
+{
+	memset(cache->page, 0xff, c->min_io_size);
+	cache->page_num = -1;
+}
+
+/* This function frees the data for a keymap ksa range. It simply poisons the
+ * memory for the read and write caches, then frees them.
+ */
+static void keymap_ksa_free(const struct ubifs_info *c, struct ksa_range *ksa)
+{
+	key_cache_invalidate(c, &(ksa->wr_cache));
+	key_cache_invalidate(c, &(ksa->rd_cache));
+	kfree(ksa->wr_cache.page);
+	kfree(ksa->rd_cache.page);
+}
+
+/* This function invalidates both the read and write cache for the passed KSA
+ * range */
+static void ksa_key_cache_invalidate(const struct ubifs_info *c,
+				     struct ksa_range *ksa)
+{
+	key_cache_invalidate(c, &ksa->rd_cache);
+	key_cache_invalidate(c, &ksa->wr_cache);
+}
+
+static int keymap_eb_to_ksa_range(const struct ubifs_keymap *km, const u32 
eb);
+
+/* This function writes some KSA range information to the kernel log. */
+static void keymap_ksa_trace(struct ubifs_keymap *km, const int ksa_num)
+{
+	struct ksa_range *ksa = km->ksa + ksa_num;
+	int i;
+	int state_cnt[3];
+	memset(state_cnt, 0, 3 * sizeof(int));
+	for (i = 0; i < ksa->ksa_size; ++i) {
+		int j;
+		for (j = 0; j < km->keys_per_eb; ++j)
+			state_cnt[get_state(km, i + ksa->ksa_first, j)]++;
+	}
+	ubifs_msg("(keymap) ksa=%d free=%d used=%d delete=%d erases=%d",
+		  ksa_num, state_cnt[0], state_cnt[1], state_cnt[2],
+		  (int) ksa->erases);
+}
+
+/* This function calls keymap_ksa_trace for each KSA in the keymap. */
+static void keymap_trace(struct ubifs_keymap *km)
+{
+	int i;
+	for (i = 0; i < km->ksa_ranges; ++i)
+		keymap_ksa_trace(km, i);
+}
+
+/* This function converts a 64-bit key position into the 32-bit LEB number
+ * and 32-bit offset in the LEB where the key can be found.
+ */
+static void pos_to_eb_offset(const u64 pos, u32 *eb, u32 *offset)
+{
+	*offset = 0xffffffff & pos;
+	*eb = 0xffffffff & (pos >> 32);
+}
+
+/* This function converts the LEB number and offset for a key into the 64-bit
+ * key position value.
+ */
+static u64 eb_offset_to_pos(u32 eb, u32 offset)
+{
+	return (((u64)eb) << 32) + offset;
+}
+
+/* This function allows external components of UBIFS become aware of the
+ * number of keys per KSA LEB without knowing the internals of the keymap.
+ */
+int keymap_keys_per_eb(struct ubifs_info *c)
+{
+	return c->leb_size / UBIFSEC_KEYSIZE;
+}
+
+/* This function initializes an already-allocated key_cache data structure. */
+static int key_cache_init(struct ubifs_info *c, struct key_cache *cache)
+{
+	cache->page = kmalloc(c->min_io_size, GFP_NOFS);
+	RETURN_VAL_IF(-ENOMEM, !cache->page);
+	cache->page_num = -1;
+	return 0;
+}
+
+/* This function adds a new KSA range to the keymap, which it inializes with
+ * the following parameters:
+ *   pos: the array index for ksa where the new ksa range should be added.
+ *   ebs: the number of LEBS in the range
+ *   promotion: the value to set as gcs_until_promotion.
+ *
+ * The function sets the first KSA LEB for this range as follows:
+ *   0, if pos == 0
+ *   one more than the last KSA LEB for the previous KSA range, if pos > 0.
+ *
+ * If ebs is set to 0, then the size of this range is set to difference
+ * between the total number of KSA LEBs and the range's starting LEB.
+ */
+static int add_ksa_range(struct ubifs_info *c, int pos, u32 ebs, int 
promotion)
+{
+	struct ubifs_keymap *km;
+	int err;
+	km = c->km;
+	if (pos < 0 || pos >= km->ksa_ranges) {
+		ubifs_err("error adding KSA range: pos %d is invalid.", pos);
+		return -EINVAL;
+	}
+	if (pos == 0) {
+		km->ksa[0].ksa_first = 0;
+	} else {
+		km->ksa[pos].ksa_first =
+			km->ksa[pos - 1].ksa_first + km->ksa[pos - 1].ksa_size;
+	}
+	if (ebs < 0 || ebs > km->ksa_size - km->ksa[pos].ksa_first) {
+		ubifs_err("error adding KSA range: cannot allocate %d ebs "
+			  "to pos %d", (int) ebs, pos);
+		return -EINVAL;
+	}
+	if (ebs == 0) {
+		km->ksa[pos].ksa_size = km->ksa_size - km->ksa[pos].ksa_first;
+		ubifs_assert(promotion == 0);
+	} else {
+		km->ksa[pos].ksa_size = ebs;
+	}
+	km->ksa[pos].gcs_until_promotion = promotion;
+	km->ksa[pos].erases = 0;
+	km->ksa[pos].cur_pos = eb_offset_to_pos(km->ksa[pos].ksa_first, 0);
+	err = key_cache_init(c, &km->ksa[pos].rd_cache);
+	err = key_cache_init(c, &km->ksa[pos].wr_cache);
+	RETURN_ON_ERR(err);
+	ubifs_msg("(keymap) added KSA range %d: %d->%d, protomotion at %d",
+		  pos, (int) km->ksa[pos].ksa_first,
+		  (int) km->ksa[pos].ksa_first + (int) km->ksa[pos].ksa_size,
+		  promotion);
+	return 0;
+}
+
+/* This function initializes the KSA range to a default value. We use two KSA
+ * ranges, each half the size of the KSA, and automatically promote any key
+ * whose data node is once garbage collected. This creates a short-term and
+ * long-term storage area. If there are less than 6 LEBs in the KSA, then only
+ * a single KSA range is used.
+ */
+static int keymap_init_ksa_ranges(struct ubifs_info *c)
+{
+	int err = 0;
+	u32 blocks = c->km->ksa_size >> 1;
+	if (c->km->ksa_size < 6) {
+		c->km->ksa_ranges = 1;
+		err = add_ksa_range(c, 0, 0, 0);
+	} else {
+		c->km->ksa_ranges = 2;
+		err = add_ksa_range(c, 0, blocks, 1);
+		err = add_ksa_range(c, 1, 0, 0);
+	}
+	RETURN_ON_ERR(err);
+	return 0;
+}
+
+static void keymap_mark_used_internal(struct ubifs_keymap *c, u64 pos);
+static int keymap_checkpoint_pack(struct ubifs_info *c, u8* buf, int len);
+static int keymap_checkpoint_unpack(struct ubifs_info *c, u8* buf, int len);
+
+/* This function initializes the keymap data structure contained in the
+ * ubifs_info structure FOR A FRESHLY FORMATED PARTITION. This means that it
+ * erases all the KSA blocks, as it assumes it does not contain valid keys.
+ * This should only be called when formatting UBIFS or mounting it when the
+ * flash memory is all 0xFF.  It marks all the keys as deleted, then purges,
+ * which effectively fills the entire KSA with fresh data and sets all the
+ * variables correctly.
+ */
+int keymap_initialize_fresh(struct ubifs_info *c)
+{
+	int i;
+	int j;
+	int err;
+	struct ubifs_keymap *km = c->km;
+	ubifs_assert(c->empty);
+	km->free = 0;
+	km->next_checkpoint_off = 0;
+	mutex_lock(&km->kbuf_mutex);
+	for (i = 0; i < km->ksa_size; ++i) {
+		for (j = 0; j < km->keys_per_eb; ++j) {
+			set_state(km, i, j, KEYMAP_STATE_DELETED);
+			km->deleted++;
+		}
+	}
+	mutex_unlock(&km->kbuf_mutex);
+	RETURN_VAL_IF(0, km->read_only);
+	err = keymap_purge(c);
+	return err;
+}
+
+/* This function writes a checkpoint of the current key state map to the LEB
+ * reserved for key state map checkpoints. It first packs the current state
+ * map to the ckpt_buf, then compresses using UBIFS's existing LZO compressor.
+ * The result is then prefixed with the length of the compressed checkpoint,
+ * and appended with a magic number (i.e., not all 0xFF) to signal that it has
+ * been successfully written. This is all written onto the beginning of kbuf.
+ *
+ * The size of the checkpoint is then page-aligned, and then the first free
+ * page in the checkpoint LEB is checked to see if it will fit. If it fits,
+ * then it is written onto those pages. If it does not fit, then kbuf is
+ * instead written using atomic update to the checkpoint LEB, such that the
+ * successful result is a checkpoint LEB with only one checkpoint, and
+ * otherwise the old LEB remains.
+ */
+
+/* TODO(reardon): currently, the compressed checkpoint cannot exceed a LEB.
+ * The solution is of course to span it over multiple LEBs---but this needs to
+ * be implemented. */
+int keymap_write_checkpoint(struct ubifs_info *c)
+{
+	int err = 0;
+	int compr = UBIFS_COMPR_LZO;
+	int len = c->leb_size - 8;
+	int len_al;
+	struct ubifs_keymap *km = c->km;
+
+	RETURN_VAL_IF(0, !km);
+	RETURN_VAL_IF(-EROFS, km->read_only);
+
+	mutex_lock(&km->kbuf_mutex);
+	memset(km->kbuf, 0xff, c->leb_size);
+	keymap_checkpoint_pack(c, km->ckpt_buf, km->ckpt_sz);
+	ubifs_compress(km->ckpt_buf, km->ckpt_sz, km->kbuf + sizeof(u32),
+		       &len, &compr,  NULL);
+
+	*(u32 *)(km->kbuf) = cpu_to_le32(len);
+	len += sizeof(u32);
+	*(u32 *)(km->kbuf + len) = cpu_to_le32(KEYMAP_CHECKPOINT_MAGIC);
+	len += sizeof(u32);
+	len_al = ALIGN(len,  c->min_io_size);
+
+	if (km->next_checkpoint_off + len_al > c->leb_size) {
+		km->next_checkpoint_off = len_al;
+		km->erasures++;
+		err = ubifs_leb_change(c, km->ckpt_leb, km->kbuf,
+				       len_al, UBI_SHORTTERM);
+	} else {
+		err = ubifs_leb_write(c, km->ckpt_leb, km->kbuf,
+				      km->next_checkpoint_off,
+				      len_al, UBI_SHORTTERM);
+		km->next_checkpoint_off += len_al;
+	}
+
+	mutex_unlock(&km->kbuf_mutex);
+	return err;
+}
+
+/* This function finds the next checkpoint on the checkpoint block and returns
+ * the length and whether it was correctly formatted. Purported checkpoint
+ * lengths MUST be range-checked with regards to the buffer length.
+ */
+static int find_next_checkpoint(char *buf, int buf_len, int offset,
+				int *valid, int *length)
+{
+	int len;
+	int su32 = sizeof(u32);
+	if (offset + su32 >= buf_len)
+		goto failure;
+
+	len = le32_to_cpu(*(u32 *)(buf+offset));
+	if (len >= 0 && len + offset + su32 < buf_len) {
+		*length = len;
+	} else {
+		ubifs_err("checkpoint reported an invalid length (%d)", len);
+		goto failure;
+	}
+
+	*valid = 0;
+	if (KEYMAP_CHECKPOINT_MAGIC ==
+	    le32_to_cpu(*(u32 *)(buf + su32 + len + offset))) {
+		*valid = 1;
+	}
+	return 0;
+
+failure:
+	*valid = 0;
+	*length = 0;
+	return -EINVAL;
+}
+
+/* This function reads the most recent checkpoint from the checkpoint LEB,
+ * decompresses it, and then reads the state of each key into the key state
+ * map. It does this by sequentially readin checkpoints from the checkpoint
+ * block until no more are available. The first four bytes of a checkpoint
+ * stores the length, which is used to jump ahead to the end and verify the
+ * magic number.
+ */
+int keymap_read_checkpoint(struct ubifs_info *c)
+{
+	int err = 0;
+	int offset = 0;
+	int last_valid;
+	int ckpt_len, full_ckpt_len, ckpt_offset;
+	int i;
+	int empty_after = c->leb_size;
+	char *buf;
+	struct ubifs_keymap *km = c->km;
+
+	RETURN_VAL_IF(0, !km);
+	buf = km->kbuf;
+
+	mutex_lock(&km->kbuf_mutex);
+	err = ubi_read(c->ubi, c->km->ckpt_leb, buf, 0, c->leb_size);
+	if (err)
+		goto out;
+	/* Find the length of data on the erase block. */
+	for (i = c->leb_size - 1; i >= 0; --i) {
+		if ((u8)(buf[i]) != 0xff)
+			break;
+		empty_after = i;
+	}
+
+	/* If this is a freshly-formatted UBIFSec partition, then format the
+	 * key storage area.
+	 */
+	if (c->empty) {
+		ubifs_assert(empty_after == 0);
+		goto format_keyspace;
+	}
+
+	/* If this is not freshly formatted yet no checkpoints are written,
+	 * then return an error.
+	 */
+	if (empty_after == 0) {
+		ubifs_err("checkpoint block is empty, but this is not an "\
+			  "empty partition.  Perform a full scan of data "\
+			  "nodes.");
+		err =  -EINVAL;
+		goto out;
+	}
+
+	offset = 0;
+	ckpt_offset = -1;
+	ckpt_len = 0;
+	last_valid = 0;
+	while (offset < empty_after) {
+		int len, valid;
+		err = find_next_checkpoint(buf, c->leb_size, offset,
+					   &valid, &len);
+		if (err)
+			goto out;
+		if (valid) {
+			ckpt_offset = offset + sizeof(u32);
+			ckpt_len = len;
+			last_valid = 1;
+		} else {
+			last_valid = 0;
+		}
+		offset += ALIGN(len + sizeof(u32) * 2, c->min_io_size);
+	}
+	if (ckpt_offset == -1) {
+		ubifs_err("no valid checkpoint found");
+		err = -EINVAL;
+		goto out;
+	}
+	if (!last_valid && !c->need_recovery) {
+		ubifs_err("last checkpoint is invalid but file system "\
+			  "should have been safely unmounted---perform "\
+			  "a full scan.");
+		err = -EINVAL;
+		goto out;
+	}
+
+	km->next_checkpoint_off = offset;
+	full_ckpt_len = km->ckpt_sz;
+	err = ubifs_decompress(km->kbuf + ckpt_offset, ckpt_len, km->ckpt_buf,
+			       &full_ckpt_len, UBIFS_COMPR_LZO, NULL);
+	if (err)
+		goto out;
+	err = keymap_checkpoint_unpack(c, km->ckpt_buf, full_ckpt_len);
+	keymap_trace(c->km);
+out:
+	mutex_unlock(&km->kbuf_mutex);
+	return err;
+
+format_keyspace:
+	/* This is a fresh file system. */
+	mutex_unlock(&km->kbuf_mutex);
+	err = keymap_initialize_fresh(c);
+	return err;
+}
+
+/* This function packs the key state map into an uncompressed checkpoint,
+ * storing it on the buffer buf. The len varaible indicates the size of the
+ * buffer, and all writes to the buffer are checked by assertion against this
+ * length before they are performed.
+ */
+static int keymap_checkpoint_pack(struct ubifs_info *c, u8 *buf, int len)
+{
+	int i;
+	int j;
+	int k = 0;
+	int err = 0;
+	struct ubifs_keymap *km = c->km;
+
+	mutex_lock(&km->state_mutex);
+	for (i = 0; i < km->ksa_size; ++i) {
+		for (j = 0; j < km->keys_per_eb; j += 8) {
+			u8 val = 0;
+			int l = 0;
+			if (k >= len) {
+				err = -EINVAL;
+				goto out;
+			}
+			for (l = 0; l < 8; ++l) {
+				int state = get_state(km, i, j+l);
+				if (state == KEYMAP_STATE_USED)
+					val += (1 << l);
+			}
+			ubifs_assert(k < len);
+			buf[k++] = val;
+		}
+	}
+out:
+	mutex_unlock(&km->state_mutex);
+	return err;
+}
+
+/* This function unpacks a checkpoint (in its uncompressed form, as stored in
+ * buf) and sets the key state map accordingly. It performs the reverse as
+ * keymap_checkpoint_unpack.
+ */
+static int keymap_checkpoint_unpack(struct ubifs_info *c, u8 *buf, int len)
+{
+	int i;
+	int j;
+	int k = 0;
+	int last = -1;
+	int err = 0;
+	struct ubifs_keymap *km = c->km;
+	mutex_lock(&km->state_mutex);
+	for (i = 0; i < km->ksa_size; ++i) {
+		for (j = 0; j < km->keys_per_eb; j += 8) {
+			u8 val;
+			int l;
+			if (k >= len) {
+				err = -EINVAL;
+				goto out;
+			}
+			val = buf[k++];
+			last = val;
+			for (l = 0; l < 8; ++l) {
+				int state;
+				set_state(km, i, j + l, 1 & val);
+				val = val >> 1;
+				state = get_state(km, i, j + l);
+				if (state == KEYMAP_STATE_FREE)
+					km->free++;
+			}
+		}
+	}
+out:
+	mutex_unlock(&km->state_mutex);
+	return err;
+}
+
+/* This function allows external access to the number of free keys in the
+ * keymap.
+ */
+u64 keymap_freekeys(struct ubifs_info *c)
+{
+	RETURN_VAL_IF(0, !c->km);
+	return c->km->free;
+}
+
+/* This function generates a new random key and places it in the to field. The
+ * keymap stores the size of the key used as a field. We assume that
+ * get_random_bytes() will always yield cryptographically-suitable random
+ * data. If that changes, this will need to be updated.
+ */
+static void generate_key(struct ubifs_keymap *km, u8 *to)
+{
+	get_random_bytes(to, km->key_size);
+}
+
+/* This function performs the purging operation on a single key storage area
+ * LEB. All unused and deleted keys on that erase block are replaced with
+ * fresh random data. It reads the entire erase block currently stored on the
+ * storage medium, and then updates its in memory with the new version, which
+ * is then written using atomic update.
+ */
+
+/* TODO(reardon): currently, blocks containing no deleted keys are not
+ * updated. This is okay, but an attacker who is able to see these keys can
+ * then decrypt data that will be written at an unknown future time. It is
+ * useful to mark such erase blocks as potentially exposed, so that the keys
+ * are only assigned from then after repurging. Each KSA range would then
+ * maintain its exposed LEBs, which would be purged if needed. Exposed LEBs
+ * would be empty, so they can be indepently and immediately purged as a
+ * one-off, then used to assign keys.
+ *
+ * This optimization prevents purging many KSA LEBs at each purging when the
+ * storage medium is usually empty, but also limits the utility of this
+ * exposure attack.
+ */
+static int do_purge(struct ubifs_info *c, int eb)
+{
+	int i;
+	u64 old_free = c->km->free;
+	struct ubifs_keymap *km = c->km;
+	int err = 0;
+	ubifs_assert(km);
+	ubifs_assert(!km->read_only);
+	mutex_lock(&km->kbuf_mutex);
+
+	/* Read the entire key leb. */
+	err = ubi_read(c->ubi, eb + km->ksa_first, km->kbuf, 0, c->leb_size);
+
+	if (err) {
+		ubifs_err("(keymap) cannot read LEB %d, error %d",
+			  eb + (int) km->ksa_first, err);
+		goto out;
+	}
+
+	mutex_lock(&km->state_mutex);
+	/* Update unused and deleted keys. */
+	for (i = 0; i < km->keys_per_eb; ++i) {
+		if (get_state(km, eb, i) == KEYMAP_STATE_FREE ||
+				get_state(km, eb, i) == KEYMAP_STATE_DELETED) {
+			/* If the key is deleted, we need to update the
+			 * accounting information.
+			 */
+			if (get_state(km, eb, i) == KEYMAP_STATE_DELETED) {
+				set_state(km, eb, i, KEYMAP_STATE_FREE);
+				km->free++;
+				km->deleted--;
+			}
+			/* Replace the stale key with a fresh key */
+			generate_key(km, km->kbuf + (i * c->km->key_size));
+		}
+	}
+	mutex_unlock(&km->state_mutex);
+
+	if (old_free != km->free) {
+		km->erasures++;
+		km->ksa[keymap_eb_to_ksa_range(km, eb)].erases++;
+		ubifs_leb_change(c, eb + km->ksa_first, c->km->kbuf,
+				 c->leb_size,  UBI_SHORTTERM);
+	}
+
+out:
+	mutex_unlock(&km->kbuf_mutex);
+	return err;
+}
+
+/* This functions performs a purge on the KSA. It proceeds iteratively over
+ * all the LEBs in the KSA, calling do_purge on each one. It also invalides
+ * the caches for each KSA range.
+ */
+int keymap_purge(struct ubifs_info *c)
+{
+	int err;
+	int i;
+	struct ubifs_keymap *km = c->km;
+	RETURN_VAL_IF(0, !km);
+	RETURN_VAL_IF(-EROFS, km->read_only);
+
+	mutex_lock(&km->purge_mutex);
+	if (km->purge_ongoing) {
+		mutex_unlock(&km->purge_mutex);
+		return -EAGAIN;
+	}
+	km->purge_ongoing = 1;
+	mutex_unlock(&km->purge_mutex);
+
+	for (i = 0; i < km->ksa_ranges; ++i) {
+		ksa_key_cache_invalidate(c, km->ksa + i);
+		km->ksa[i].cur_pos = eb_offset_to_pos(km->ksa[i].ksa_first, 0);
+	}
+
+	for (i = 0; i < km->ksa_size; ++i) {
+		err = do_purge(c, i);
+		if (err)
+			goto out;
+	}
+	err = keymap_write_checkpoint(c);
+
+out:
+	mutex_lock(&km->purge_mutex);
+	km->purge_ongoing = 0;
+	mutex_unlock(&km->purge_mutex);
+
+	return err;
+}
+
+/* This function allocates a keymap data structure and initializes its fields.
+ * The ubifs_info context is passed as a parameter and its km field is set to
+ * the keymap that is preprared by this function. If memory cannot be
+ * allocated, it returns -ENOMEM. Otherwise it returns 0.
+ */
+int keymap_init(struct ubifs_info *c, int read_only, int use_ubifsec)
+{
+	struct ubifs_keymap *km;
+	c->km = NULL;
+
+	RETURN_VAL_IF(0, !use_ubifsec);
+
+	km = kmalloc(sizeof(struct ubifs_keymap), GFP_NOFS);
+	RETURN_VAL_IF(-ENOMEM, !km);
+
+	km->ksa_size = 0;
+	km->ksa_first = 0;
+	km->key_size = UBIFSEC_KEYSIZE;
+	km->keys_per_eb = c->leb_size / km->key_size;
+	km->deleted = 0;
+	km->erasures = 0;
+	km->free = 0;
+	km->state = NULL;
+	km->ckpt_buf = NULL;
+	km->purge_ongoing = 0;
+	km->read_only = read_only;
+	km->kbuf = vmalloc(sizeof(u8) * c->leb_size);
+	if (!km->kbuf) {
+		kfree(km);
+		return -ENOMEM;
+	}
+
+	mutex_init(&km->state_mutex);
+	mutex_init(&km->kbuf_mutex);
+	mutex_init(&km->purge_mutex);
+
+	c->km = km;
+	return 0;
+}
+
+/* This function tells the keymap that the ubifs_info context has its range of
+ * LEBs for the keymap reserved: [c->crypto_first, c->crypto_first +
+ * c->crypto_lebs - 1]. Initialization of the keymap is completed in this
+ * function, where the geometry of the keymap is computed and the checkpoint
+ * buffer and key state map data structures are allocated. All keys are given
+ * an initial state of unused, and the function completes by calling
+ * keymap_read_checkpoint to load the current checkpoint to the keystate map.
+ */
+int keymap_assign_lebs(struct ubifs_info *c)
+{
+	struct ubifs_keymap *km;
+	int i;
+	int err;
+
+	km = c->km;
+	RETURN_VAL_IF(0, !km);
+
+	km->ksa_size = c->crypto_lebs - 1;
+	km->ksa_first = c->crypto_first + 1;
+	km->ckpt_leb = c->crypto_first;
+	km->ckpt_sz = ((km->ksa_size * km->keys_per_eb) >> 3);
+	km->ckpt_buf = kmalloc(km->ckpt_sz, GFP_NOFS);
+
+	RETURN_VAL_IF(-ENOMEM, !km->ckpt_buf);
+	/* the state is a double array: first index for each KSA LEB, second
+	 * index for each key on a KSA LEB.
+	 */
+	km->state = kmalloc(sizeof(u8 *) * km->ksa_size, GFP_NOFS);
+	RETURN_VAL_IF(-ENOMEM, !km->state);
+
+	for (i = 0; i < km->ksa_size; ++i) {
+		int len;
+
+		ubifs_assert(km->keys_per_eb % 4 == 0);
+		len = (sizeof(u8) * km->keys_per_eb)
+			>> KEYMAP_STATES_PER_BYTE_SHIFT;
+		km->state[i] = kmalloc(len, GFP_NOFS);
+		RETURN_VAL_IF(-ENOMEM, !(km->state[i]));
+		memset(km->state[i], 0, len);
+		km->free += km->keys_per_eb;
+	}
+	err = keymap_init_ksa_ranges(c);
+	if (err)
+		return err;
+
+	return keymap_read_checkpoint(c);
+}
+
+/* This function frees the memory being used by the keymap.
+ */
+void keymap_free(struct ubifs_info *c)
+{
+	int i;
+	struct ubifs_keymap *km = c->km;
+
+	if (!km)
+		return;
+	mutex_destroy(&km->state_mutex);
+	mutex_destroy(&km->kbuf_mutex);
+	mutex_destroy(&km->purge_mutex);
+	kfree(km->ckpt_buf);
+	for (i = 0; i < km->ksa_ranges; ++i)
+		keymap_ksa_free(c, &(km->ksa[i]));
+	if (km->state) {
+		for (i = 0; i < km->ksa_size; ++i)
+			kfree(km->state[i]);
+		kfree(km->state);
+	}
+	vfree(km->kbuf);
+	kfree(km);
+	c->km = NULL;
+}
+
+/* This function increments the key position refernce for the ksa range
+ * parameter to the next one based on a cyclical ordering with two levels of
+ * granularity: the major is the LEB number, the minor is the key position in
+ * the LEB.
+ */
+static void ksa_range_increment_pos(struct ubifs_keymap *km,
+				    struct ksa_range *ksa)
+{
+	u32 offset;
+	u32 eb;
+
+	ubifs_assert(km);
+	ubifs_assert(ksa);
+
+	pos_to_eb_offset(ksa->cur_pos, &eb, &offset);
+	offset++;
+	if (offset == km->keys_per_eb) {
+		offset = 0;
+		eb++;
+	}
+	if (eb == ksa->ksa_first + ksa->ksa_size)
+		eb = ksa->ksa_first;
+	ksa->cur_pos = eb_offset_to_pos(eb, offset);
+}
+
+/* This function returns true if the key position passed in corresponds to a
+ * unused key. It must be accessed when the key state map is locked.
+ */
+/* TODO(reardon): there's a decent optimizaiton that can be done here:
+ * advancing the KSA position to the next LEB may not be efficient if that
+ * LEB is mostly used, and only has a few unused keys. Here we assume that
+ * either data is deleted soon, or it is deleted later. In this case, its
+ * not efficient to put new data on a KSA block that is otherwise used, as
+ * deleting this new value may trigger an purge on this block only to delete
+ * this one value. More efficient to fill a completely empty block with new
+ * data then such blocks. This may be implemented as a two-pass technique
+ * for advancement, where first, any block with >50% used keys will be
+ * simply ignored. Afterwards, such blocks are indeed considered as space
+ * becomes more constrained.
+ */
+static
+int keymap_is_free(struct ubifs_keymap *km, u64 pos)
+{
+	u32 eb, offset;
+	pos_to_eb_offset(pos, &eb, &offset);
+	return get_state(km, eb, offset) == KEYMAP_STATE_FREE;
+}
+
+/* This function fills pos and key with an unused key in the ksa range as
+ * indicated by the array index ksa_pos. pos must not be null. If key is null,
+ * then the key is not read from the flash storage medium but still assigned.
+ * The key pos is marked as used. If no unused keys are available, then ENOMEM
+ * is returned.
+ */
+int keymap_free_key_in_range(
+	struct ubifs_info *c, int ksa_pos, u64 *pos, u8 *key)
+{
+	struct ubifs_keymap *km = c->km;
+	struct ksa_range *ksa = km->ksa + ksa_pos;
+	int err = 0;
+	u64 start;
+
+	RETURN_VAL_IF(0, !km);
+	RETURN_VAL_IF(-EROFS, km->read_only);
+
+	ubifs_assert(ksa_pos >= 0 && ksa_pos < km->ksa_ranges);
+	ubifs_assert(pos);
+
+	start = ksa->cur_pos;
+
+	if (km->free == 0)
+		RETURN_VAL_IF(-ENOMEM, km->deleted > 0);
+
+	mutex_lock(&km->state_mutex);
+	while (!keymap_is_free(km, ksa->cur_pos)) {
+		ksa_range_increment_pos(km, ksa);
+		if (start == ksa->cur_pos) {
+			err = -ENOMEM;
+			goto out;
+		}
+	}
+	*pos = ksa->cur_pos;
+
+	if (key)
+		keymap_read_key(c, *pos, key);
+
+	keymap_mark_used_internal(km, ksa->cur_pos);
+
+out:
+	mutex_unlock(&km->state_mutex);
+	return err;
+}
+
+/* This function performs the same as keymap_free_key_in_range, except that it
+ * will search for a key in any KSA range greater than or equal to the ksa_pos
+ * array index value. The search begins at the smallest KSA range index, and
+ * returns the first found unused key.
+ */
+int keymap_free_key_in_min_range(
+	struct ubifs_info *c, int ksa_pos, u64 *pos, u8 *key)
+{
+	struct ubifs_keymap *km = c->km;
+	int i;
+	int err;
+
+	RETURN_VAL_IF(0, !km);
+	RETURN_VAL_IF(-EROFS, km->read_only);
+
+	if (km->free == 0)
+		RETURN_VAL_IF(-ENOMEM, km->deleted > 0);
+
+	for (i = ksa_pos; i < km->ksa_ranges; ++i) {
+		err = keymap_free_key_in_range(c, i, pos, key);
+		if (!err)
+			return 0;
+		RETURN_VAL_IF(err, err != -ENOMEM);
+	}
+	return -ENOMEM;
+}
+
+/* This function performs the same as keymap_free_key_in_range, except that it
+ * will search for a key in all the KSA ranges sequentially, starting with the
+ * smallest. The first found unused key is returned.
+ */
+int keymap_free_key(struct ubifs_info *c, u64 *pos, u8 *key)
+{
+	return keymap_free_key_in_min_range(c, 0, pos, key);
+}
+
+int keymap_eb_to_ksa_range(const struct ubifs_keymap *km, const u32 eb)
+{
+	int i;
+	for (i = 1; i < km->ksa_ranges; ++i)
+		if (eb < km->ksa[i].ksa_first)
+			return i - 1;
+	return km->ksa_ranges - 1;
+}
+
+int keymap_pos_to_ksa_range(struct ubifs_keymap *km, u64 pos)
+{
+	u32 eb, offset;
+
+	pos_to_eb_offset(pos, &eb, &offset);
+	return keymap_eb_to_ksa_range(km, eb);
+}
+
+/* This function swaps the encryption key for a data node. The idea for this
+ * is that the data node is being garbage collected, so we can re-encrypt it
+ * at effectiveness no addition cost (safe for the cipher operations). We do
+ * this to 'promote' a datanode to a higher area of the KSA (that is to say,
+ * longer-lived). Each time a datanode survives UBIFS's garbage collection, we
+ * take that as a clue that this data is long-term achieval data. The ultimate
+ * goal is to have all the keys that will never be deleted sitting on the same
+ * KSA LEBs, so that it is never purged.
+ */
+int keymap_swap_encryption_key(struct ubifs_info *c,
+			       struct ubifs_data_node *dn)
+{
+	u8 old_key[UBIFSEC_KEYSIZE];
+	u8 new_key[UBIFSEC_KEYSIZE];
+	char iv[UBIFSEC_KEYSIZE];
+	char *pbuf;
+	u64 old_pos = 0;
+	u64 new_pos = 0;
+	int dlen;
+	int err = 0;
+
+	RETURN_VAL_IF(0, !c->km);
+
+	memset(old_key, 0, UBIFSEC_KEYSIZE);
+	memset(new_key, 0, UBIFSEC_KEYSIZE);
+
+	old_pos = le64_to_cpu(dn->crypto_lookup);
+	err = keymap_read_key(c, old_pos, old_key);
+	RETURN_ON_ERR(err);
+	err = keymap_promote_key(c, old_pos, &new_pos, new_key);
+
+	if (err == -ENOMEM)
+		return err;
+	if (err) {
+		ubifs_err("(keymap) promote key failed: %d", err);
+		return err;
+	}
+	pbuf = kmalloc(4096, GFP_NOFS);
+	RETURN_VAL_IF(-ENOMEM, !pbuf);
+
+	dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
+	memcpy(pbuf, dn->data, dlen);
+
+	memset(iv, 0, UBIFSEC_KEYSIZE);
+	ubifs_aes_crypt(
+		pbuf, dlen, old_key, UBIFSEC_KEYSIZE, iv, UBIFSEC_KEYSIZE);
+	POISON_KEY(old_key);
+
+	memset(iv, 0, UBIFSEC_KEYSIZE);
+	ubifs_aes_crypt(
+		pbuf, dlen, new_key, UBIFSEC_KEYSIZE, iv, UBIFSEC_KEYSIZE);
+	POISON_KEY(new_key);
+
+	memcpy(dn->data, pbuf, dlen);
+	kfree(pbuf);
+	dn->crypto_lookup = cpu_to_le64(new_pos);
+	ubifs_set_datanode_crc(dn);
+
+	return 0;
+}
+
+/* This function promotes a key to a higher (longer-term) KSA block. If no
+ * space is available at a higher block, then it returns -ENOMEM, and no
+ * action should be taken. Otherwise, the caller should decrypt the data with
+ * the old key, encrypt it with the new key, mark the old position
+ * as deleted, and the new position as used.
+ */
+int keymap_promote_key(struct ubifs_info *c, u64 old_pos, u64 *new_pos, u8 
*key)
+{
+	struct ubifs_keymap *km = c->km;
+	int ksa_range;
+	RETURN_VAL_IF(0, !km);
+	ubifs_assert(!km->read_only);
+
+	ksa_range = keymap_pos_to_ksa_range(km, old_pos);
+	ubifs_assert(ksa_range >= 0 && ksa_range < km->ksa_ranges - 1);
+	return keymap_free_key_in_min_range(c, ksa_range + 1, new_pos, key);
+}
+
+/* This function determines if a key position should be promoted to a
+ * higher KSA range. The criteria is the key's current KSA range, and that
+ * KSA range's promotion policy: (expected) number of garbage collections
+ * between promotions. If it is 0, it will not be protomoted. If it is 1, it
+ * will be promoted. Otherwise, it is promoted with probability
+ * 1/2**gcs_until_promotion.
+ */
+int keymap_gc_should_promote(struct ubifs_info *c, u64 pos)
+{
+	int value;
+	int shift;
+	int ksa_range;
+	struct ubifs_keymap *km = c->km;
+
+	RETURN_VAL_IF(0, !km);
+	RETURN_VAL_IF(0, km->read_only);
+
+	ksa_range = keymap_pos_to_ksa_range(km, pos);
+	RETURN_VAL_IF(0, km->ksa[ksa_range].gcs_until_promotion == 0);
+	RETURN_VAL_IF(1, km->ksa[ksa_range].gcs_until_promotion == 1);
+
+	shift = sizeof(int) << 3;
+	get_random_bytes((u8 *) &value, sizeof(int));
+	shift -= km->ksa[ksa_range].gcs_until_promotion;
+	if (shift < 0)
+		shift = 0;
+	if ((value << shift) == 0)
+		return 1;
+
+	return 0;
+}
+
+/* This function sets pos to an unused key position by calling
+ * keymap_free_key with a NULL key.
+ */
+int keymap_free_pos(struct ubifs_info *c, u64 *pos)
+{
+	return keymap_free_key(c, pos, NULL);
+}
+
+/* This function reads a key as defined by the LEB number and offset, and puts
+ * the read key in the buffer buf. It tries to use the appropriate KSA range
+ * cache if it is valid for the position, otherwise it reads it from flash and
+ * updates the corresponding read/write cache. It assumes it is a write
+ * operation if the key being read is the same as the KSA range's current
+ * key assignment position.
+ */
+static int keymap_read_key_cache(struct ubifs_info *c, u32 eb,
+				 u32 offset, u8 *buf)
+{
+	struct ubifs_keymap *km = c->km;
+	struct ksa_range *ksa;
+	struct key_cache *cache;
+	int err;
+	int byte_offset;
+	int page;
+	int page_offset;
+	int page_num;
+
+	RETURN_VAL_IF(0, !km);
+	ksa = &(km->ksa[keymap_eb_to_ksa_range(km, eb)]);
+	cache = NULL;
+	byte_offset = offset * c->km->key_size;
+	page = byte_offset >> c->min_io_shift;
+	page_offset = byte_offset - (page << c->min_io_shift);
+	page_num = page + eb * (c->leb_size >> c->min_io_shift);
+
+	/* Determine if its a write based on cur pos, and set the correct 
cache.
+	 * Unless the other cache is actually on the same page, in which case
+	 * use that instead.
+	 */
+	if (eb_offset_to_pos(eb, offset) == ksa->cur_pos &&
+			keymap_is_free(km, ksa->cur_pos)) {
+		cache = &ksa->wr_cache;
+		if (ksa->rd_cache.page_num == page_num)
+			cache = &ksa->rd_cache;
+	} else {
+		cache = &ksa->rd_cache;
+		if (ksa->wr_cache.page_num == page_num)
+			cache = &ksa->wr_cache;
+	}
+
+	if (cache->page_num != page_num) {
+		err = ubi_read(c->ubi, eb + c->km->ksa_first, cache->page,
+			       page << c->min_io_shift, c->min_io_size);
+		RETURN_ON_ERR(err);
+		cache->page_num = page_num;
+	}
+	memcpy(buf, cache->page + page_offset, c->km->key_size);
+	return 0;
+}
+
+/* This function reads a key and stores the result in buf. It converts the key
+ * position to an LEB number and offset, then calls keymap_read_key_cache.
+ */
+int keymap_read_key(struct ubifs_info *c, u64 pos, u8* buf)
+{
+	u32 eb;
+	u32 offset;
+	RETURN_VAL_IF(0, !c->km);
+	pos_to_eb_offset(pos, &eb, &offset);
+	RETURN_VAL_IF(-EINVAL, eb > c->km->ksa_size ||
+			       offset > c->km->keys_per_eb);
+	return keymap_read_key_cache(c, eb, offset, buf);
+}
+
+/* This function marks a key position as being used in the key state map. It
+ * assumes that the key state map is already locked.
+ */
+static void keymap_mark_used_internal(struct ubifs_keymap *km, u64 pos)
+{
+	u32 eb, offset;
+	pos_to_eb_offset(pos, &eb, &offset);
+	if (offset >= km->keys_per_eb || eb > km->ksa_size) {
+		ubifs_err("(keymap) [%d:%d] out of range to mark used.",
+			  (int) eb, (int) offset);
+		return;
+	}
+	if (get_state(km, eb, offset) == KEYMAP_STATE_FREE)
+		km->free--;
+	set_state(km, eb, offset, KEYMAP_STATE_USED);
+}
+
+/* This function marks a key position as used, and it can be called from
+ * outside keymap.c.  It simply locks the key state map and calls the internal
+ * version.
+ */
+void keymap_mark_used(struct ubifs_info *c, u64 pos)
+{
+	struct ubifs_keymap *km = c->km;
+	if (!km)
+		return;
+	ubifs_assert(!km->read_only);
+	mutex_lock(&km->state_mutex);
+	keymap_mark_used_internal(km, pos);
+	mutex_unlock(&km->state_mutex);
+}
+
+/* This function marks a key position as deleted.
+ */
+void keymap_mark_deleted(struct ubifs_info *c, u64 pos)
+{
+	u32 eb, offset;
+	struct ubifs_keymap *km = c->km;
+	if (!km)
+		return;
+	ubifs_assert(!km->read_only);
+
+	mutex_lock(&km->state_mutex);
+	pos_to_eb_offset(pos, &eb, &offset);
+
+	if (offset >= km->keys_per_eb || eb > km->ksa_size) {
+		ubifs_err("(keymap) [%d:%d] out of range to mark deleted.",
+			  (int) eb, (int) offset);
+		goto unlock;
+	}
+
+	if (get_state(km, eb, offset) != KEYMAP_STATE_DELETED)
+		km->deleted++;
+
+	set_state(km, eb, offset, KEYMAP_STATE_DELETED);
+
+unlock:
+	mutex_unlock(&km->state_mutex);
+}
+
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/Makefile linux-3.2.1-ubifsec/fs/ubifs/Makefile
--- linux-3.2.1-vanilla/fs/ubifs/Makefile	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/Makefile	2012-02-08 16:58:48.913518449 
+0100
@@ -1,6 +1,6 @@ 
  obj-$(CONFIG_UBIFS_FS) += ubifs.o

-ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o
+ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o keymap.o
  ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
  ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
  ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/replay.c linux-3.2.1-ubifsec/fs/ubifs/replay.c
--- linux-3.2.1-vanilla/fs/ubifs/replay.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/replay.c	2012-02-08 16:54:49.145506844 
+0100
@@ -67,6 +67,7 @@  struct replay_entry {
  			loff_t new_size;
  		};
  	};
+	unsigned long long crypto_lookup;
  };

  /**
@@ -249,10 +250,12 @@  static int apply_replay_entry(struct ubi
  			default:
  				err = ubifs_tnc_remove(c, &r->key);
  				break;
-			}
-		else
-			err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
-					    r->len);
+		} else {
+			err = ubifs_tnc_add_with_crypto_lookup(
+				c, &r->key, r->lnum, r->offs, r->len,
+				r->crypto_lookup);
+
+		}
  		if (err)
  			return err;

@@ -354,10 +357,11 @@  static void destroy_replay_list(struct u
   * order, the older modifications are applied first. This function returns 
zero
   * in case of success and a negative error code in case of failure.
   */
-static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
-		       union ubifs_key *key, unsigned long long sqnum,
-		       int deletion, int *used, loff_t old_size,
-		       loff_t new_size)
+static int insert_node(
+	struct ubifs_info *c, int lnum, int offs, int len,
+	union ubifs_key *key, unsigned long long sqnum,
+	int deletion, int *used, loff_t old_size, loff_t new_size,
+	unsigned long long crypto_lookup)
  {
  	struct replay_entry *r;

@@ -372,6 +376,7 @@  static int insert_node(struct ubifs_info

  	if (!deletion)
  		*used += ALIGN(len, 8);
+	r->crypto_lookup = crypto_lookup;
  	r->lnum = lnum;
  	r->offs = offs;
  	r->len = len;
@@ -607,7 +612,7 @@  static int replay_bud(struct ubifs_info
  				deletion = 1;
  			err = insert_node(c, lnum, snod->offs, snod->len,
  					  &snod->key, snod->sqnum, deletion,
-					  &used, 0, new_size);
+					  &used, 0, new_size, 0);
  			break;
  		}
  		case UBIFS_DATA_NODE:
@@ -616,10 +621,11 @@  static int replay_bud(struct ubifs_info
  			loff_t new_size = le32_to_cpu(dn->size) +
  					  key_block(c, &snod->key) *
  					  UBIFS_BLOCK_SIZE;
-
-			err = insert_node(c, lnum, snod->offs, snod->len,
-					  &snod->key, snod->sqnum, deletion,
-					  &used, 0, new_size);
+			err = insert_node(
+				c, lnum, snod->offs, snod->len,
+				&snod->key, snod->sqnum, deletion,
+				&used, 0, new_size,
+				le64_to_cpu(dn->crypto_lookup));
  			break;
  		}
  		case UBIFS_DENT_NODE:
@@ -659,7 +665,7 @@  static int replay_bud(struct ubifs_info
  			trun_key_init(c, &key, le32_to_cpu(trun->inum));
  			err = insert_node(c, lnum, snod->offs, snod->len,
  					  &key, snod->sqnum, 1, &used,
-					  old_size, new_size);
+					  old_size, new_size, 0);
  			break;
  		}
  		default:
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/sb.c linux-3.2.1-ubifsec/fs/ubifs/sb.c
--- linux-3.2.1-vanilla/fs/ubifs/sb.c	2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/sb.c	2012-02-08 16:54:49.145506844 +0100
@@ -82,6 +82,7 @@  static int create_default_filesystem(str
  	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 crypto_lebs, crypto_first;
  	long long tmp64, main_bytes;
  	__le64 tmp_le64;

@@ -139,8 +140,22 @@  static int create_default_filesystem(str
  		 */
  		orph_lebs += 1;
  #endif
+	if (c->use_ubifsec) {
+		/* Compute the size of the key space area based on partition
+		 * geometry.
+		 */
+		unsigned long long partition_bytes = c->leb_cnt * c->leb_size;
+		unsigned long long data_nodes =
+			partition_bytes >> UBIFS_BLOCK_SHIFT;
+		do_div(data_nodes, keymap_keys_per_eb(c));
+		crypto_lebs = data_nodes + UBIFSEC_CRYPTO_LEBS_MIN +
+			(data_nodes >> UBIFSEC_CRYPTO_LEBS_SCALE_SHIFT);
+	} else {
+		crypto_lebs = 0;
+	}

-	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 - crypto_lebs;
  	main_lebs -= orph_lebs;

  	lpt_first = UBIFS_LOG_LNUM + log_lebs;
@@ -155,6 +170,7 @@  static int create_default_filesystem(str
  		lpt_first + lpt_lebs - 1);

  	main_first = c->leb_cnt - main_lebs;
+	crypto_first = c->leb_cnt - main_lebs - crypto_lebs;

  	/* Create default superblock */
  	tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
@@ -175,6 +191,7 @@  static int create_default_filesystem(str
  	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->crypto_lebs   = cpu_to_le32(crypto_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);
@@ -182,6 +199,7 @@  static int create_default_filesystem(str
  	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
@@ -440,7 +458,7 @@  static int validate_sb(struct ubifs_info
  	}

  	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->crypto_lebs != c->leb_cnt) {
  		err = 12;
  		goto failed;
  	}
@@ -603,6 +621,7 @@  int ubifs_read_superblock(struct ubifs_i
  	c->max_bud_bytes = le64_to_cpu(sup->max_bud_bytes);
  	c->log_lebs      = le32_to_cpu(sup->log_lebs);
  	c->lpt_lebs      = le32_to_cpu(sup->lpt_lebs);
+	c->crypto_lebs   = le32_to_cpu(sup->crypto_lebs);
  	c->orph_lebs     = le32_to_cpu(sup->orph_lebs);
  	c->jhead_cnt     = le32_to_cpu(sup->jhead_cnt) + NONDATA_JHEADS_CNT;
  	c->fanout        = le32_to_cpu(sup->fanout);
@@ -610,6 +629,7 @@  int ubifs_read_superblock(struct ubifs_i
  	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);
@@ -643,8 +663,10 @@  int ubifs_read_superblock(struct ubifs_i
  	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->crypto_lebs;
  	c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+	c->crypto_first = c->leb_cnt - c->main_lebs - c->crypto_lebs;
  	c->main_first = c->leb_cnt - c->main_lebs;

  	err = validate_sb(c, sup);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/super.c linux-3.2.1-ubifsec/fs/ubifs/super.c
--- linux-3.2.1-vanilla/fs/ubifs/super.c	2012-01-12 20:42:45.000000000 
+0100
+++ linux-3.2.1-ubifsec/fs/ubifs/super.c	2012-02-08 16:54:49.149506844 
+0100
@@ -438,7 +438,8 @@  static int ubifs_show_options(struct seq
  		seq_printf(s, ",chk_data_crc");
  	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));
@@ -938,6 +939,8 @@  static int check_volume_empty(struct ubi
   * 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_commit_interval: seconds between a forced commit
+ * Opt_use_ubifsec: use ubifsec secure deletion feature
   * Opt_err: just end of array marker
   */
  enum {
@@ -948,6 +951,8 @@  enum {
  	Opt_chk_data_crc,
  	Opt_no_chk_data_crc,
  	Opt_override_compr,
+	Opt_commit_interval,
+	Opt_use_ubifsec,
  	Opt_err,
  };

@@ -959,6 +964,8 @@  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_commit_interval, "commit_interval=%s"},
+	{Opt_use_ubifsec, "use_ubifsec"},
  	{Opt_err, NULL},
  };

@@ -1036,6 +1043,18 @@  static int ubifs_parse_options(struct ub
  			c->mount_opts.chk_data_crc = 1;
  			c->no_chk_data_crc = 1;
  			break;
+		case Opt_commit_interval:
+		{
+			struct timeval tv;
+			unsigned long seconds;
+			char *name = match_strdup(&args[0]);
+			kstrtoul(name, 10, &seconds);
+			kfree(name);
+			c->commit_interval = seconds;
+			do_gettimeofday(&tv);
+			c->next_commit = tv.tv_sec + c->commit_interval;
+			break;
+		}
  		case Opt_override_compr:
  		{
  			char *name = match_strdup(&args[0]);
@@ -1058,6 +1077,12 @@  static int ubifs_parse_options(struct ub
  			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;
@@ -1236,6 +1261,12 @@  static int mount_ubifs(struct ubifs_info
  	err = ubifs_read_superblock(c);
  	if (err)
  		goto out_free;
+	keymap_init(c, c->ro_media, c->use_ubifsec);
+	if (c->use_ubifsec && !c->km)
+		goto out_free;
+
+	/* After reading super block, give the keymap its geometry. */
+	keymap_assign_lebs(c);

  	/*
  	 * Make sure the compressor which is set as default in the superblock
@@ -1487,6 +1518,7 @@  static int mount_ubifs(struct ubifs_info
  		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;

@@ -1514,6 +1546,7 @@  out_free:
  	kfree(c->bu.buf);
  	vfree(c->ileb_buf);
  	vfree(c->sbuf);
+	keymap_free(c);
  	kfree(c->bottom_up_buf);
  	ubifs_debugging_exit(c);
  	return err;
@@ -1553,6 +1586,7 @@  static void ubifs_umount(struct ubifs_in
  	kfree(c->bu.buf);
  	vfree(c->ileb_buf);
  	vfree(c->sbuf);
+	keymap_free(c);
  	kfree(c->bottom_up_buf);
  	ubifs_debugging_exit(c);
  }
@@ -2010,6 +2044,8 @@  static struct ubifs_info *alloc_ubifs_in

  		c->highest_inum = UBIFS_FIRST_INO;
  		c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
+		c->commit_interval = (unsigned long) -1;
+		c->use_ubifsec = 0;

  		ubi_get_volume_info(ubi, &c->vi);
  		ubi_get_device_info(c->vi.ubi_num, &c->di);
diff -uprN -X linux-3.2.1-vanilla/Documentation/dontdiff 
linux-3.2.1-vanilla/fs/ubifs/tnc.c linux-3.2.1-ubifsec/fs/ubifs/tnc.c
--- linux-3.2.1-vanilla/fs/ubifs/tnc.c	2012-01-12 20:42:45.000000000 +0100
+++ linux-3.2.1-ubifsec/fs/ubifs/tnc.c	2012-02-08 16:54:49.149506844 +0100
@@ -2154,19 +2154,22 @@  do_split:
  }

  /**
- * ubifs_tnc_add - add a node to TNC.
+ * ubifs_tnc_add_with_crypto_lookup - add a node to TNC.
   * @c: UBIFS file-system description object
   * @key: key to add
   * @lnum: LEB number of node
   * @offs: node offset
   * @len: node length
+ * @crypto_lookup: the node's key position in the KSA
   *
   * This function adds a node with key @key to TNC. The node may be new or it 
may
   * obsolete some existing one. Returns %0 on success or negative error code on
   * failure.
   */
-int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
-		  int offs, int len)
+int ubifs_tnc_add_with_crypto_lookup(struct ubifs_info *c,
+				     const union ubifs_key *key, int lnum,
+				     int offs, int len,
+				     unsigned long long crypto_lookup)
  {
  	int found, n, err = 0;