Commit 42bd06e9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tags/upstream-4.20-rc1' of git://git.infradead.org/linux-ubifs

Pull UBIFS updates from Richard Weinberger:

 - Full filesystem authentication feature, UBIFS is now able to have the
   whole filesystem structure authenticated plus user data encrypted and
   authenticated.

 - Minor cleanups

* tag 'tags/upstream-4.20-rc1' of git://git.infradead.org/linux-ubifs: (26 commits)
  ubifs: Remove unneeded semicolon
  Documentation: ubifs: Add authentication whitepaper
  ubifs: Enable authentication support
  ubifs: Do not update inode size in-place in authenticated mode
  ubifs: Add hashes and HMACs to default filesystem
  ubifs: authentication: Authenticate super block node
  ubifs: Create hash for default LPT
  ubfis: authentication: Authenticate master node
  ubifs: authentication: Authenticate LPT
  ubifs: Authenticate replayed journal
  ubifs: Add auth nodes to garbage collector journal head
  ubifs: Add authentication nodes to journal
  ubifs: authentication: Add hashes to index nodes
  ubifs: Add hashes to the tree node cache
  ubifs: Create functions to embed a HMAC in a node
  ubifs: Add helper functions for authentication support
  ubifs: Add separate functions to init/crc a node
  ubifs: Format changes for authentication support
  ubifs: Store read superblock node
  ubifs: Drop write_node
  ...
parents 4710e789 84db119f
This diff is collapsed.
...@@ -91,6 +91,13 @@ chk_data_crc do not skip checking CRCs on data nodes ...@@ -91,6 +91,13 @@ chk_data_crc do not skip checking CRCs on data nodes
compr=none override default compressor and set it to "none" compr=none override default compressor and set it to "none"
compr=lzo override default compressor and set it to "lzo" compr=lzo override default compressor and set it to "lzo"
compr=zlib override default compressor and set it to "zlib" compr=zlib override default compressor and set it to "zlib"
auth_key= specify the key used for authenticating the filesystem.
Passing this option makes authentication mandatory.
The passed key must be present in the kernel keyring
and must be of type 'logon'
auth_hash_name= The hash algorithm used for authentication. Used for
both hashing and for creating HMACs. Typical values
include "sha256" or "sha512"
Quick usage instructions Quick usage instructions
......
...@@ -1072,6 +1072,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, ...@@ -1072,6 +1072,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
* be a result of power cut during erasure. * be a result of power cut during erasure.
*/ */
ai->maybe_bad_peb_count += 1; ai->maybe_bad_peb_count += 1;
/* fall through */
case UBI_IO_BAD_HDR: case UBI_IO_BAD_HDR:
/* /*
* If we're facing a bad VID header we have to drop *all* * If we're facing a bad VID header we have to drop *all*
......
...@@ -1334,8 +1334,10 @@ static int bytes_str_to_int(const char *str) ...@@ -1334,8 +1334,10 @@ static int bytes_str_to_int(const char *str)
switch (*endp) { switch (*endp) {
case 'G': case 'G':
result *= 1024; result *= 1024;
/* fall through */
case 'M': case 'M':
result *= 1024; result *= 1024;
/* fall through */
case 'K': case 'K':
result *= 1024; result *= 1024;
if (endp[1] == 'i' && endp[2] == 'B') if (endp[1] == 'i' && endp[2] == 'B')
......
...@@ -7,6 +7,7 @@ config UBIFS_FS ...@@ -7,6 +7,7 @@ config UBIFS_FS
select CRYPTO if UBIFS_FS_ZLIB select CRYPTO if UBIFS_FS_ZLIB
select CRYPTO_LZO if UBIFS_FS_LZO select CRYPTO_LZO if UBIFS_FS_LZO
select CRYPTO_DEFLATE if UBIFS_FS_ZLIB select CRYPTO_DEFLATE if UBIFS_FS_ZLIB
select CRYPTO_HASH_INFO
depends on MTD_UBI depends on MTD_UBI
help help
UBIFS is a file system for flash devices which works on top of UBI. UBIFS is a file system for flash devices which works on top of UBI.
...@@ -85,3 +86,13 @@ config UBIFS_FS_SECURITY ...@@ -85,3 +86,13 @@ config UBIFS_FS_SECURITY
the extended attribute support in advance. the extended attribute support in advance.
If you are not using a security module, say N. If you are not using a security module, say N.
config UBIFS_FS_AUTHENTICATION
bool "UBIFS authentication support"
select CRYPTO_HMAC
help
Enable authentication support for UBIFS. This feature offers protection
against offline changes for both data and metadata of the filesystem.
If you say yes here you should also select a hashing algorithm such as
sha256, these are not selected automatically since there are many
different options.
...@@ -8,3 +8,4 @@ ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o ...@@ -8,3 +8,4 @@ ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o
ubifs-y += misc.o ubifs-y += misc.o
ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o
ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o
ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o
This diff is collapsed.
...@@ -165,6 +165,8 @@ const char *dbg_ntype(int type) ...@@ -165,6 +165,8 @@ const char *dbg_ntype(int type)
return "commit start node"; return "commit start node";
case UBIFS_ORPH_NODE: case UBIFS_ORPH_NODE:
return "orphan node"; return "orphan node";
case UBIFS_AUTH_NODE:
return "auth node";
default: default:
return "unknown node"; return "unknown node";
} }
...@@ -542,6 +544,10 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) ...@@ -542,6 +544,10 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node)
(unsigned long long)le64_to_cpu(orph->inos[i])); (unsigned long long)le64_to_cpu(orph->inos[i]));
break; break;
} }
case UBIFS_AUTH_NODE:
{
break;
}
default: default:
pr_err("node type %d was not recognized\n", pr_err("node type %d was not recognized\n",
(int)ch->node_type); (int)ch->node_type);
......
...@@ -254,7 +254,8 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -254,7 +254,8 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
snod->type == UBIFS_DATA_NODE || snod->type == UBIFS_DATA_NODE ||
snod->type == UBIFS_DENT_NODE || snod->type == UBIFS_DENT_NODE ||
snod->type == UBIFS_XENT_NODE || snod->type == UBIFS_XENT_NODE ||
snod->type == UBIFS_TRUN_NODE); snod->type == UBIFS_TRUN_NODE ||
snod->type == UBIFS_AUTH_NODE);
if (snod->type != UBIFS_INO_NODE && if (snod->type != UBIFS_INO_NODE &&
snod->type != UBIFS_DATA_NODE && snod->type != UBIFS_DATA_NODE &&
...@@ -364,12 +365,13 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) ...@@ -364,12 +365,13 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
/* Write nodes to their new location. Use the first-fit strategy */ /* Write nodes to their new location. Use the first-fit strategy */
while (1) { while (1) {
int avail; int avail, moved = 0;
struct ubifs_scan_node *snod, *tmp; struct ubifs_scan_node *snod, *tmp;
/* Move data nodes */ /* Move data nodes */
list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
avail = c->leb_size - wbuf->offs - wbuf->used; avail = c->leb_size - wbuf->offs - wbuf->used -
ubifs_auth_node_sz(c);
if (snod->len > avail) if (snod->len > avail)
/* /*
* Do not skip data nodes in order to optimize * Do not skip data nodes in order to optimize
...@@ -377,14 +379,21 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) ...@@ -377,14 +379,21 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
*/ */
break; break;
err = ubifs_shash_update(c, c->jheads[GCHD].log_hash,
snod->node, snod->len);
if (err)
goto out;
err = move_node(c, sleb, snod, wbuf); err = move_node(c, sleb, snod, wbuf);
if (err) if (err)
goto out; goto out;
moved = 1;
} }
/* Move non-data nodes */ /* Move non-data nodes */
list_for_each_entry_safe(snod, tmp, &nondata, list) { list_for_each_entry_safe(snod, tmp, &nondata, list) {
avail = c->leb_size - wbuf->offs - wbuf->used; avail = c->leb_size - wbuf->offs - wbuf->used -
ubifs_auth_node_sz(c);
if (avail < min) if (avail < min)
break; break;
...@@ -402,9 +411,41 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) ...@@ -402,9 +411,41 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
continue; continue;
} }
err = ubifs_shash_update(c, c->jheads[GCHD].log_hash,
snod->node, snod->len);
if (err)
goto out;
err = move_node(c, sleb, snod, wbuf); err = move_node(c, sleb, snod, wbuf);
if (err) if (err)
goto out; goto out;
moved = 1;
}
if (ubifs_authenticated(c) && moved) {
struct ubifs_auth_node *auth;
auth = kmalloc(ubifs_auth_node_sz(c), GFP_NOFS);
if (!auth) {
err = -ENOMEM;
goto out;
}
err = ubifs_prepare_auth_node(c, auth,
c->jheads[GCHD].log_hash);
if (err) {
kfree(auth);
goto out;
}
err = ubifs_wbuf_write_nolock(wbuf, auth,
ubifs_auth_node_sz(c));
if (err) {
kfree(auth);
goto out;
}
ubifs_add_dirt(c, wbuf->lnum, ubifs_auth_node_sz(c));
} }
if (list_empty(&sleb->nodes) && list_empty(&nondata)) if (list_empty(&sleb->nodes) && list_empty(&nondata))
......
...@@ -365,20 +365,8 @@ static unsigned long long next_sqnum(struct ubifs_info *c) ...@@ -365,20 +365,8 @@ static unsigned long long next_sqnum(struct ubifs_info *c)
return sqnum; return sqnum;
} }
/** void ubifs_init_node(struct ubifs_info *c, void *node, int len, int pad)
* ubifs_prepare_node - prepare node to be written to flash.
* @c: UBIFS file-system description object
* @node: the node to pad
* @len: node length
* @pad: if the buffer has to be padded
*
* This function prepares node at @node to be written to the media - it
* calculates node CRC, fills the common header, and adds proper padding up to
* the next minimum I/O unit if @pad is not zero.
*/
void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
{ {
uint32_t crc;
struct ubifs_ch *ch = node; struct ubifs_ch *ch = node;
unsigned long long sqnum = next_sqnum(c); unsigned long long sqnum = next_sqnum(c);
...@@ -389,8 +377,6 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) ...@@ -389,8 +377,6 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
ch->group_type = UBIFS_NO_NODE_GROUP; ch->group_type = UBIFS_NO_NODE_GROUP;
ch->sqnum = cpu_to_le64(sqnum); ch->sqnum = cpu_to_le64(sqnum);
ch->padding[0] = ch->padding[1] = 0; ch->padding[0] = ch->padding[1] = 0;
crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
ch->crc = cpu_to_le32(crc);
if (pad) { if (pad) {
len = ALIGN(len, 8); len = ALIGN(len, 8);
...@@ -399,6 +385,68 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) ...@@ -399,6 +385,68 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
} }
} }
void ubifs_crc_node(struct ubifs_info *c, void *node, int len)
{
struct ubifs_ch *ch = node;
uint32_t crc;
crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
ch->crc = cpu_to_le32(crc);
}
/**
* ubifs_prepare_node_hmac - prepare node to be written to flash.
* @c: UBIFS file-system description object
* @node: the node to pad
* @len: node length
* @hmac_offs: offset of the HMAC in the node
* @pad: if the buffer has to be padded
*
* This function prepares node at @node to be written to the media - it
* calculates node CRC, fills the common header, and adds proper padding up to
* the next minimum I/O unit if @pad is not zero. if @hmac_offs is positive then
* a HMAC is inserted into the node at the given offset.
*
* This function returns 0 for success or a negative error code otherwise.
*/
int ubifs_prepare_node_hmac(struct ubifs_info *c, void *node, int len,
int hmac_offs, int pad)
{
int err;
ubifs_init_node(c, node, len, pad);
if (hmac_offs > 0) {
err = ubifs_node_insert_hmac(c, node, len, hmac_offs);
if (err)
return err;
}
ubifs_crc_node(c, node, len);
return 0;
}
/**
* ubifs_prepare_node - prepare node to be written to flash.
* @c: UBIFS file-system description object
* @node: the node to pad
* @len: node length
* @pad: if the buffer has to be padded
*
* This function prepares node at @node to be written to the media - it
* calculates node CRC, fills the common header, and adds proper padding up to
* the next minimum I/O unit if @pad is not zero.
*/
void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
{
/*
* Deliberately ignore return value since this function can only fail
* when a hmac offset is given.
*/
ubifs_prepare_node_hmac(c, node, len, 0, pad);
}
/** /**
* ubifs_prep_grp_node - prepare node of a group to be written to flash. * ubifs_prep_grp_node - prepare node of a group to be written to flash.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -849,12 +897,13 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) ...@@ -849,12 +897,13 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
} }
/** /**
* ubifs_write_node - write node to the media. * ubifs_write_node_hmac - write node to the media.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @buf: the node to write * @buf: the node to write
* @len: node length * @len: node length
* @lnum: logical eraseblock number * @lnum: logical eraseblock number
* @offs: offset within the logical eraseblock * @offs: offset within the logical eraseblock
* @hmac_offs: offset of the HMAC within the node
* *
* This function automatically fills node magic number, assigns sequence * This function automatically fills node magic number, assigns sequence
* number, and calculates node CRC checksum. The length of the @buf buffer has * number, and calculates node CRC checksum. The length of the @buf buffer has
...@@ -862,8 +911,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) ...@@ -862,8 +911,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
* appends padding node and padding bytes if needed. Returns zero in case of * appends padding node and padding bytes if needed. Returns zero in case of
* success and a negative error code in case of failure. * success and a negative error code in case of failure.
*/ */
int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, int ubifs_write_node_hmac(struct ubifs_info *c, void *buf, int len, int lnum,
int offs) int offs, int hmac_offs)
{ {
int err, buf_len = ALIGN(len, c->min_io_size); int err, buf_len = ALIGN(len, c->min_io_size);
...@@ -878,7 +927,10 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, ...@@ -878,7 +927,10 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
if (c->ro_error) if (c->ro_error)
return -EROFS; return -EROFS;
ubifs_prepare_node(c, buf, len, 1); err = ubifs_prepare_node_hmac(c, buf, len, hmac_offs, 1);
if (err)
return err;
err = ubifs_leb_write(c, lnum, buf, offs, buf_len); err = ubifs_leb_write(c, lnum, buf, offs, buf_len);
if (err) if (err)
ubifs_dump_node(c, buf); ubifs_dump_node(c, buf);
...@@ -886,6 +938,26 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, ...@@ -886,6 +938,26 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
return err; return err;
} }
/**
* ubifs_write_node - write node to the media.
* @c: UBIFS file-system description object
* @buf: the node to write
* @len: node length
* @lnum: logical eraseblock number
* @offs: offset within the logical eraseblock
*
* This function automatically fills node magic number, assigns sequence
* number, and calculates node CRC checksum. The length of the @buf buffer has
* to be aligned to the minimal I/O unit size. This function automatically
* appends padding node and padding bytes if needed. Returns zero in case of
* success and a negative error code in case of failure.
*/
int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
int offs)
{
return ubifs_write_node_hmac(c, buf, len, lnum, offs, -1);
}
/** /**
* ubifs_read_node_wbuf - read node from the media or write-buffer. * ubifs_read_node_wbuf - read node from the media or write-buffer.
* @wbuf: wbuf to check for un-written data * @wbuf: wbuf to check for un-written data
......
This diff is collapsed.
...@@ -236,6 +236,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) ...@@ -236,6 +236,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
bud->lnum = lnum; bud->lnum = lnum;
bud->start = offs; bud->start = offs;
bud->jhead = jhead; bud->jhead = jhead;
bud->log_hash = NULL;
ref->ch.node_type = UBIFS_REF_NODE; ref->ch.node_type = UBIFS_REF_NODE;
ref->lnum = cpu_to_le32(bud->lnum); ref->lnum = cpu_to_le32(bud->lnum);
...@@ -275,6 +276,14 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) ...@@ -275,6 +276,14 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
if (err) if (err)
goto out_unlock; goto out_unlock;
err = ubifs_shash_update(c, c->log_hash, ref, UBIFS_REF_NODE_SZ);
if (err)
goto out_unlock;
err = ubifs_shash_copy_state(c, c->log_hash, c->jheads[jhead].log_hash);
if (err)
goto out_unlock;
c->lhead_offs += c->ref_node_alsz; c->lhead_offs += c->ref_node_alsz;
ubifs_add_bud(c, bud); ubifs_add_bud(c, bud);
...@@ -377,6 +386,14 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) ...@@ -377,6 +386,14 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
cs->cmt_no = cpu_to_le64(c->cmt_no); cs->cmt_no = cpu_to_le64(c->cmt_no);
ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0);
err = ubifs_shash_init(c, c->log_hash);
if (err)
goto out;
err = ubifs_shash_update(c, c->log_hash, cs, UBIFS_CS_NODE_SZ);
if (err < 0)
goto out;
/* /*
* Note, we do not lock 'c->log_mutex' because this is the commit start * Note, we do not lock 'c->log_mutex' because this is the commit start
* phase and we are exclusively using the log. And we do not lock * phase and we are exclusively using the log. And we do not lock
...@@ -402,6 +419,12 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) ...@@ -402,6 +419,12 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0); ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0);
len += UBIFS_REF_NODE_SZ; len += UBIFS_REF_NODE_SZ;
err = ubifs_shash_update(c, c->log_hash, ref,
UBIFS_REF_NODE_SZ);
if (err)
goto out;
ubifs_shash_copy_state(c, c->log_hash, c->jheads[i].log_hash);
} }
ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len); ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len);
...@@ -516,6 +539,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum) ...@@ -516,6 +539,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
if (err) if (err)
return err; return err;
list_del(&bud->list); list_del(&bud->list);
kfree(bud->log_hash);
kfree(bud); kfree(bud);
} }
mutex_lock(&c->log_mutex); mutex_lock(&c->log_mutex);
......
...@@ -604,11 +604,12 @@ static int calc_pnode_num_from_parent(const struct ubifs_info *c, ...@@ -604,11 +604,12 @@ static int calc_pnode_num_from_parent(const struct ubifs_info *c,
* @lpt_first: LEB number of first LPT LEB * @lpt_first: LEB number of first LPT LEB
* @lpt_lebs: number of LEBs for LPT is passed and returned here * @lpt_lebs: number of LEBs for LPT is passed and returned here
* @big_lpt: use big LPT model is passed and returned here * @big_lpt: use big LPT model is passed and returned here
* @hash: hash of the LPT is returned here
* *
* This function returns %0 on success and a negative error code on failure. * This function returns %0 on success and a negative error code on failure.
*/ */
int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
int *lpt_lebs, int *big_lpt) int *lpt_lebs, int *big_lpt, u8 *hash)
{ {
int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row; int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row;
int blnum, boffs, bsz, bcnt; int blnum, boffs, bsz, bcnt;
...@@ -617,6 +618,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -617,6 +618,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
void *buf = NULL, *p; void *buf = NULL, *p;
struct ubifs_lpt_lprops *ltab = NULL; struct ubifs_lpt_lprops *ltab = NULL;
int *lsave = NULL; int *lsave = NULL;
struct shash_desc *desc;
err = calc_dflt_lpt_geom(c, main_lebs, big_lpt); err = calc_dflt_lpt_geom(c, main_lebs, big_lpt);
if (err) if (err)
...@@ -630,6 +632,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -630,6 +632,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
/* Needed by 'ubifs_pack_lsave()' */ /* Needed by 'ubifs_pack_lsave()' */
c->main_first = c->leb_cnt - *main_lebs; c->main_first = c->leb_cnt - *main_lebs;
desc = ubifs_hash_get_desc(c);
if (IS_ERR(desc))
return PTR_ERR(desc);
lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_KERNEL); lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_KERNEL);
pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL); pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL);
nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL); nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL);
...@@ -677,6 +683,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -677,6 +683,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
/* Add first pnode */ /* Add first pnode */
ubifs_pack_pnode(c, p, pnode); ubifs_pack_pnode(c, p, pnode);
err = ubifs_shash_update(c, desc, p, c->pnode_sz);
if (err)
goto out;
p += c->pnode_sz; p += c->pnode_sz;
len = c->pnode_sz; len = c->pnode_sz;
pnode->num += 1; pnode->num += 1;
...@@ -711,6 +721,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -711,6 +721,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
len = 0; len = 0;
} }
ubifs_pack_pnode(c, p, pnode); ubifs_pack_pnode(c, p, pnode);
err = ubifs_shash_update(c, desc, p, c->pnode_sz);
if (err)
goto out;
p += c->pnode_sz; p += c->pnode_sz;
len += c->pnode_sz; len += c->pnode_sz;
/* /*
...@@ -830,6 +844,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -830,6 +844,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
if (err) if (err)
goto out; goto out;
err = ubifs_shash_final(c, desc, hash);
if (err)
goto out;
c->nhead_lnum = lnum; c->nhead_lnum = lnum;
c->nhead_offs = ALIGN(len, c->min_io_size); c->nhead_offs = ALIGN(len, c->min_io_size);
...@@ -853,6 +871,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, ...@@ -853,6 +871,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
out: out:
c->ltab = NULL; c->ltab = NULL;
kfree(desc);
kfree(lsave); kfree(lsave);
vfree(ltab); vfree(ltab);
vfree(buf); vfree(buf);
...@@ -1439,26 +1458,25 @@ struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c, ...@@ -1439,26 +1458,25 @@ struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
} }
/** /**
* ubifs_lpt_lookup - lookup LEB properties in the LPT. * ubifs_pnode_lookup - lookup a pnode in the LPT.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @lnum: LEB number to lookup * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT)
* *
* This function returns a pointer to the LEB properties on success or a * This function returns a pointer to the pnode on success or a negative
* negative error code on failure. * error code on failure.
*/ */
struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum) struct ubifs_pnode *ubifs_pnode_lookup(struct ubifs_info *c, int i)
{ {
int err, i, h, iip, shft; int err, h, iip, shft;
struct ubifs_nnode *nnode; struct ubifs_nnode *nnode;
struct ubifs_pnode *pnode;
if (!c->nroot) { if (!c->nroot) {
err = ubifs_read_nnode(c, NULL, 0); err = ubifs_read_nnode(c, NULL, 0);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
} }
i <<= UBIFS_LPT_FANOUT_SHIFT;
nnode = c->nroot; nnode = c->nroot;
i = lnum - c->main_first;
shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
for (h = 1; h < c->lpt_hght; h++) { for (h = 1; h < c->lpt_hght; h++) {
iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
...@@ -1468,7 +1486,24 @@ struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum) ...@@ -1468,7 +1486,24 @@ struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
return ERR_CAST(nnode); return ERR_CAST(nnode);
} }
iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
pnode = ubifs_get_pnode(c, nnode, iip); return ubifs_get_pnode(c, nnode, iip);
}
/**
* ubifs_lpt_lookup - lookup LEB properties in the LPT.
* @c: UBIFS file-system description object
* @lnum: LEB number to lookup
*
* This function returns a pointer to the LEB properties on success or a
* negative error code on failure.
*/
struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
{
int i, iip;
struct ubifs_pnode *pnode;
i = lnum - c->main_first;
pnode = ubifs_pnode_lookup(c, i >> UBIFS_LPT_FANOUT_SHIFT);
if (IS_ERR(pnode)) if (IS_ERR(pnode))
return ERR_CAST(pnode); return ERR_CAST(pnode);
iip = (i & (UBIFS_LPT_FANOUT - 1)); iip = (i & (UBIFS_LPT_FANOUT - 1));
...@@ -1619,6 +1654,131 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum) ...@@ -1619,6 +1654,131 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
return &pnode->lprops[iip]; return &pnode->lprops[iip];
} }
/**
* ubifs_lpt_calc_hash - Calculate hash of the LPT pnodes
* @c: UBIFS file-system description object
* @hash: the returned hash of the LPT pnodes
*
* This function iterates over the LPT pnodes and creates a hash over them.
* Returns 0 for success or a negative error code otherwise.
*/
int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash)
{
struct ubifs_nnode *nnode, *nn;
struct ubifs_cnode *cnode;
struct shash_desc *desc;
int iip = 0, i;
int bufsiz = max_t(int, c->nnode_sz, c->pnode_sz);
void *buf;
int err;
if (!ubifs_authenticated(c))
return 0;
desc = ubifs_hash_get_desc(c);
if (IS_ERR(desc))
return PTR_ERR(desc);
buf = kmalloc(bufsiz, GFP_NOFS);
if (!buf) {
err = -ENOMEM;
goto out;
}
if (!c->nroot) {
err = ubifs_read_nnode(c, NULL, 0);
if (err)
return err;
}
cnode = (struct ubifs_cnode *)c->nroot;
while (cnode) {
nnode = cnode->parent;
nn = (struct ubifs_nnode *)cnode;
if (cnode->level > 1) {
while (iip < UBIFS_LPT_FANOUT) {
if (nn->nbranch[iip].lnum == 0) {
/* Go right */
iip++;
continue;
}
nnode = ubifs_get_nnode(c, nn, iip);
if (IS_ERR(nnode)) {
err = PTR_ERR(nnode);
goto out;
}
/* Go down */
iip = 0;
cnode = (struct ubifs_cnode *)nnode;
break;
}
if (iip < UBIFS_LPT_FANOUT)
continue;
} else {
struct ubifs_pnode *pnode;
for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
if (nn->nbranch[i].lnum == 0)
continue;
pnode = ubifs_get_pnode(c, nn, i);
if (IS_ERR(pnode)) {
err = PTR_ERR(pnode);
goto out;
}
ubifs_pack_pnode(c, buf, pnode);
err = ubifs_shash_update(c, desc, buf,
c->pnode_sz);
if (err)
goto out;
}
}
/* Go up and to the right */
iip = cnode->iip + 1;
cnode = (struct ubifs_cnode *)nnode;
}
err = ubifs_shash_final(c, desc, hash);
out:
kfree(desc);
kfree(buf);
return err;
}
/**
* lpt_check_hash - check the hash of the LPT.
* @c: UBIFS file-system description object
*
* This function calculates a hash over all pnodes in the LPT and compares it with
* the hash stored in the master node. Returns %0 on success and a negative error
* code on failure.
*/
static int lpt_check_hash(struct ubifs_info *c)
{
int err;
u8 hash[UBIFS_HASH_ARR_SZ];
if (!ubifs_authenticated(c))
return 0;
err = ubifs_lpt_calc_hash(c, hash);
if (err)
return err;
if (ubifs_check_hash(c, c->mst_node->hash_lpt, hash)) {
err = -EPERM;
ubifs_err(c, "Failed to authenticate LPT");
} else {
err = 0;
}
return err;
}
/** /**
* lpt_init_rd - initialize the LPT for reading. * lpt_init_rd - initialize the LPT for reading.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -1660,6 +1820,10 @@ static int lpt_init_rd(struct ubifs_info *c) ...@@ -1660,6 +1820,10 @@ static int lpt_init_rd(struct ubifs_info *c)
if (err) if (err)
return err; return err;
err = lpt_check_hash(c);
if (err)
return err;
dbg_lp("space_bits %d", c->space_bits); dbg_lp("space_bits %d", c->space_bits);
dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
......
...@@ -618,38 +618,6 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c, ...@@ -618,38 +618,6 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
return ubifs_get_pnode(c, nnode, iip); return ubifs_get_pnode(c, nnode, iip);
} }
/**
* pnode_lookup - lookup a pnode in the LPT.
* @c: UBIFS file-system description object
* @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT))
*
* This function returns a pointer to the pnode on success or a negative
* error code on failure.
*/
static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i)
{
int err, h, iip, shft;
struct ubifs_nnode *nnode;
if (!c->nroot) {
err = ubifs_read_nnode(c, NULL, 0);
if (err)
return ERR_PTR(err);
}
i <<= UBIFS_LPT_FANOUT_SHIFT;
nnode = c->nroot;
shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
for (h = 1; h < c->lpt_hght; h++) {
iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
shft -= UBIFS_LPT_FANOUT_SHIFT;
nnode = ubifs_get_nnode(c, nnode, iip);
if (IS_ERR(nnode))
return ERR_CAST(nnode);
}
iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
return ubifs_get_pnode(c, nnode, iip);
}
/** /**
* add_pnode_dirt - add dirty space to LPT LEB properties. * add_pnode_dirt - add dirty space to LPT LEB properties.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -702,7 +670,7 @@ static int make_tree_dirty(struct ubifs_info *c) ...@@ -702,7 +670,7 @@ static int make_tree_dirty(struct ubifs_info *c)
{ {
struct ubifs_pnode *pnode; struct ubifs_pnode *pnode;
pnode = pnode_lookup(c, 0); pnode = ubifs_pnode_lookup(c, 0);
if (IS_ERR(pnode)) if (IS_ERR(pnode))
return PTR_ERR(pnode); return PTR_ERR(pnode);
...@@ -956,7 +924,7 @@ static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum, ...@@ -956,7 +924,7 @@ static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum,
struct ubifs_pnode *pnode; struct ubifs_pnode *pnode;
struct ubifs_nbranch *branch; struct ubifs_nbranch *branch;
pnode = pnode_lookup(c, node_num); pnode = ubifs_pnode_lookup(c, node_num);
if (IS_ERR(pnode)) if (IS_ERR(pnode))
return PTR_ERR(pnode); return PTR_ERR(pnode);
branch = &pnode->parent->nbranch[pnode->iip]; branch = &pnode->parent->nbranch[pnode->iip];
...@@ -1279,6 +1247,10 @@ int ubifs_lpt_start_commit(struct ubifs_info *c) ...@@ -1279,6 +1247,10 @@ int ubifs_lpt_start_commit(struct ubifs_info *c)
if (err) if (err)
goto out; goto out;
err = ubifs_lpt_calc_hash(c, c->mst_node->hash_lpt);
if (err)
goto out;
/* Copy the LPT's own lprops for end commit to write */ /* Copy the LPT's own lprops for end commit to write */
memcpy(c->ltab_cmt, c->ltab, memcpy(c->ltab_cmt, c->ltab,
sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
...@@ -1558,7 +1530,7 @@ static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs) ...@@ -1558,7 +1530,7 @@ static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs)
struct ubifs_nbranch *branch; struct ubifs_nbranch *branch;
cond_resched(); cond_resched();
pnode = pnode_lookup(c, i); pnode = ubifs_pnode_lookup(c, i);
if (IS_ERR(pnode)) if (IS_ERR(pnode))
return PTR_ERR(pnode); return PTR_ERR(pnode);
branch = &pnode->parent->nbranch[pnode->iip]; branch = &pnode->parent->nbranch[pnode->iip];
...@@ -1710,7 +1682,7 @@ int dbg_check_ltab(struct ubifs_info *c) ...@@ -1710,7 +1682,7 @@ int dbg_check_ltab(struct ubifs_info *c)
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
struct ubifs_pnode *pnode; struct ubifs_pnode *pnode;
pnode = pnode_lookup(c, i); pnode = ubifs_pnode_lookup(c, i);
if (IS_ERR(pnode)) if (IS_ERR(pnode))
return PTR_ERR(pnode); return PTR_ERR(pnode);
cond_resched(); cond_resched();
......
...@@ -24,6 +24,42 @@ ...@@ -24,6 +24,42 @@
#include "ubifs.h" #include "ubifs.h"
/**
* ubifs_compare_master_node - compare two UBIFS master nodes
* @c: UBIFS file-system description object
* @m1: the first node
* @m2: the second node
*
* This function compares two UBIFS master nodes. Returns 0 if they are equal
* and nonzero if not.
*/
int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
{
int ret;
int behind;
int hmac_offs = offsetof(struct ubifs_mst_node, hmac);
/*
* Do not compare the common node header since the sequence number and
* hence the CRC are different.
*/
ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ,
hmac_offs - UBIFS_CH_SZ);
if (ret)
return ret;
/*
* Do not compare the embedded HMAC aswell which also must be different
* due to the different common node header.
*/
behind = hmac_offs + UBIFS_MAX_HMAC_LEN;
if (UBIFS_MST_NODE_SZ > behind)
return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind);
return 0;
}
/** /**
* scan_for_master - search the valid master node. * scan_for_master - search the valid master node.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c) ...@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c)
{ {
struct ubifs_scan_leb *sleb; struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod; struct ubifs_scan_node *snod;
int lnum, offs = 0, nodes_cnt; int lnum, offs = 0, nodes_cnt, err;
lnum = UBIFS_MST_LNUM; lnum = UBIFS_MST_LNUM;
...@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c) ...@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c)
goto out_dump; goto out_dump;
if (snod->offs != offs) if (snod->offs != offs)
goto out; goto out;
if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, if (ubifs_compare_master_node(c, c->mst_node, snod->node))
(void *)snod->node + UBIFS_CH_SZ,
UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
goto out; goto out;
c->mst_offs = offs; c->mst_offs = offs;
ubifs_scan_destroy(sleb); ubifs_scan_destroy(sleb);
if (!ubifs_authenticated(c))
return 0;
err = ubifs_node_verify_hmac(c, c->mst_node,
sizeof(struct ubifs_mst_node),
offsetof(struct ubifs_mst_node, hmac));
if (err) {
ubifs_err(c, "Failed to verify master node HMAC");
return -EPERM;
}
return 0; return 0;
out: out:
...@@ -305,6 +352,8 @@ int ubifs_read_master(struct ubifs_info *c) ...@@ -305,6 +352,8 @@ int ubifs_read_master(struct ubifs_info *c)
c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead);
c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark);
ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash);
c->calc_idx_sz = c->bi.old_idx_sz; c->calc_idx_sz = c->bi.old_idx_sz;
if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
...@@ -378,7 +427,9 @@ int ubifs_write_master(struct ubifs_info *c) ...@@ -378,7 +427,9 @@ int ubifs_write_master(struct ubifs_info *c)
c->mst_offs = offs; c->mst_offs = offs;
c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
err = ubifs_write_node(c, c->mst_node, len, lnum, offs); ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
offsetof(struct ubifs_mst_node, hmac));
if (err) if (err)
return err; return err;
...@@ -389,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c) ...@@ -389,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c)
if (err) if (err)
return err; return err;
} }
err = ubifs_write_node(c, c->mst_node, len, lnum, offs); err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
offsetof(struct ubifs_mst_node, hmac));
return err; return err;
} }
...@@ -197,7 +197,8 @@ static inline int ubifs_return_leb(struct ubifs_info *c, int lnum) ...@@ -197,7 +197,8 @@ static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
*/ */
static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt) 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->key_len + c->hash_len)
* child_cnt;
} }
/** /**
...@@ -212,7 +213,7 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c, ...@@ -212,7 +213,7 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
int bnum) int bnum)
{ {
return (struct ubifs_branch *)((void *)idx->branches + return (struct ubifs_branch *)((void *)idx->branches +
(UBIFS_BRANCH_SZ + c->key_len) * bnum); (UBIFS_BRANCH_SZ + c->key_len + c->hash_len) * bnum);
} }
/** /**
......
...@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c, ...@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
save_flags = mst->flags; save_flags = mst->flags;
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1); err = ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ,
offsetof(struct ubifs_mst_node, hmac), 1);
if (err)
goto out;
err = ubifs_leb_change(c, lnum, mst, sz); err = ubifs_leb_change(c, lnum, mst, sz);
if (err) if (err)
goto out; goto out;
...@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c) ...@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c)
offs2 = (void *)mst2 - buf2; offs2 = (void *)mst2 - buf2;
if (offs1 == offs2) { if (offs1 == offs2) {
/* Same offset, so must be the same */ /* Same offset, so must be the same */
if (memcmp((void *)mst1 + UBIFS_CH_SZ, if (ubifs_compare_master_node(c, mst1, mst2))
(void *)mst2 + UBIFS_CH_SZ,
UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
goto out_err; goto out_err;
mst = mst1; mst = mst1;
} else if (offs2 + sz == offs1) { } else if (offs2 + sz == offs1) {
...@@ -1461,16 +1462,82 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e) ...@@ -1461,16 +1462,82 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
return err; return err;
} }
/**
* inode_fix_size - fix inode size
* @c: UBIFS file-system description object
* @e: inode size information for recovery
*/
static int inode_fix_size(struct ubifs_info *c, struct size_entry *e)
{
struct inode *inode;
struct ubifs_inode *ui;
int err;
if (c->ro_mount)
ubifs_assert(c, !e->inode);
if (e->inode) {
/* Remounting rw, pick up inode we stored earlier */
inode = e->inode;
} else {
inode = ubifs_iget(c->vfs_sb, e->inum);
if (IS_ERR(inode))
return PTR_ERR(inode);
if (inode->i_size >= e->d_size) {
/*
* The original inode in the index already has a size
* big enough, nothing to do
*/
iput(inode);
return 0;
}
dbg_rcvry("ino %lu size %lld -> %lld",
(unsigned long)e->inum,
inode->i_size, e->d_size);
ui = ubifs_inode(inode);
inode->i_size = e->d_size;
ui->ui_size = e->d_size;
ui->synced_i_size = e->d_size;
e->inode = inode;
}
/*
* In readonly mode just keep the inode pinned in memory until we go
* readwrite. In readwrite mode write the inode to the journal with the
* fixed size.
*/
if (c->ro_mount)
return 0;
err = ubifs_jnl_write_inode(c, inode);
iput(inode);
if (err)
return err;
rb_erase(&e->rb, &c->size_tree);
kfree(e);
return 0;
}
/** /**
* ubifs_recover_size - recover inode size. * ubifs_recover_size - recover inode size.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @in_place: If true, do a in-place size fixup
* *
* This function attempts to fix inode size discrepancies identified by the * This function attempts to fix inode size discrepancies identified by the
* 'ubifs_recover_size_accum()' function. * 'ubifs_recover_size_accum()' function.
* *
* This functions returns %0 on success and a negative error code on failure. * This functions returns %0 on success and a negative error code on failure.
*/ */
int ubifs_recover_size(struct ubifs_info *c) int ubifs_recover_size(struct ubifs_info *c, bool in_place)
{ {
struct rb_node *this = rb_first(&c->size_tree); struct rb_node *this = rb_first(&c->size_tree);
...@@ -1479,6 +1546,9 @@ int ubifs_recover_size(struct ubifs_info *c) ...@@ -1479,6 +1546,9 @@ int ubifs_recover_size(struct ubifs_info *c)
int err; int err;
e = rb_entry(this, struct size_entry, rb); e = rb_entry(this, struct size_entry, rb);
this = rb_next(this);
if (!e->exists) { if (!e->exists) {
union ubifs_key key; union ubifs_key key;
...@@ -1502,40 +1572,26 @@ int ubifs_recover_size(struct ubifs_info *c) ...@@ -1502,40 +1572,26 @@ int ubifs_recover_size(struct ubifs_info *c)
} }
if (e->exists && e->i_size < e->d_size) { if (e->exists && e->i_size < e->d_size) {
if (c->ro_mount) { ubifs_assert(c, !(c->ro_mount && in_place));
/* Fix the inode size and pin it in memory */
struct inode *inode; /*
struct ubifs_inode *ui; * We found data that is outside the found inode size,
* fixup the inode size
ubifs_assert(c, !e->inode); */
inode = ubifs_iget(c->vfs_sb, e->inum); if (in_place) {
if (IS_ERR(inode))
return PTR_ERR(inode);
ui = ubifs_inode(inode);
if (inode->i_size < e->d_size) {
dbg_rcvry("ino %lu size %lld -> %lld",
(unsigned long)e->inum,
inode->i_size, e->d_size);
inode->i_size = e->d_size;
ui->ui_size = e->d_size;
ui->synced_i_size = e->d_size;
e->inode = inode;
this = rb_next(this);
continue;
}
iput(inode);
} else {
/* Fix the size in place */
err = fix_size_in_place(c, e); err = fix_size_in_place(c, e);
if (err) if (err)
return err; return err;
iput(e->inode); iput(e->inode);
} else {
err = inode_fix_size(c, e);
if (err)
return err;
continue;
} }
} }
this = rb_next(this);
rb_erase(&e->rb, &c->size_tree); rb_erase(&e->rb, &c->size_tree);
kfree(e); kfree(e);
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -579,6 +579,9 @@ static int init_constants_early(struct ubifs_info *c) ...@@ -579,6 +579,9 @@ static int init_constants_early(struct ubifs_info *c)
c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ; c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ;
c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ; c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ;
c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ; c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ;
c->ranges[UBIFS_AUTH_NODE].min_len = UBIFS_AUTH_NODE_SZ;
c->ranges[UBIFS_AUTH_NODE].max_len = UBIFS_AUTH_NODE_SZ +
UBIFS_MAX_HMAC_LEN;
c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ; c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ;
c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ; c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ;
...@@ -816,6 +819,9 @@ static int alloc_wbufs(struct ubifs_info *c) ...@@ -816,6 +819,9 @@ static int alloc_wbufs(struct ubifs_info *c)
c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
c->jheads[i].wbuf.jhead = i; c->jheads[i].wbuf.jhead = i;
c->jheads[i].grouped = 1; c->jheads[i].grouped = 1;
c->jheads[i].log_hash = ubifs_hash_get_desc(c);
if (IS_ERR(c->jheads[i].log_hash))
goto out;
} }
/* /*
...@@ -826,6 +832,12 @@ static int alloc_wbufs(struct ubifs_info *c) ...@@ -826,6 +832,12 @@ static int alloc_wbufs(struct ubifs_info *c)
c->jheads[GCHD].grouped = 0; c->jheads[GCHD].grouped = 0;
return 0; return 0;
out:
while (i--)
kfree(c->jheads[i].log_hash);
return err;
} }
/** /**
...@@ -840,6 +852,7 @@ static void free_wbufs(struct ubifs_info *c) ...@@ -840,6 +852,7 @@ static void free_wbufs(struct ubifs_info *c)
for (i = 0; i < c->jhead_cnt; i++) { for (i = 0; i < c->jhead_cnt; i++) {
kfree(c->jheads[i].wbuf.buf); kfree(c->jheads[i].wbuf.buf);
kfree(c->jheads[i].wbuf.inodes); kfree(c->jheads[i].wbuf.inodes);
kfree(c->jheads[i].log_hash);
} }
kfree(c->jheads); kfree(c->jheads);
c->jheads = NULL; c->jheads = NULL;
...@@ -924,6 +937,8 @@ static int check_volume_empty(struct ubifs_info *c) ...@@ -924,6 +937,8 @@ static int check_volume_empty(struct ubifs_info *c)
* Opt_no_chk_data_crc: do not 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_override_compr: override default compressor
* Opt_assert: set ubifs_assert() action * Opt_assert: set ubifs_assert() action
* Opt_auth_key: The key name used for authentication
* Opt_auth_hash_name: The hash type used for authentication
* Opt_err: just end of array marker * Opt_err: just end of array marker
*/ */
enum { enum {
...@@ -935,6 +950,8 @@ enum { ...@@ -935,6 +950,8 @@ enum {
Opt_no_chk_data_crc, Opt_no_chk_data_crc,
Opt_override_compr, Opt_override_compr,
Opt_assert, Opt_assert,
Opt_auth_key,
Opt_auth_hash_name,
Opt_ignore, Opt_ignore,
Opt_err, Opt_err,
}; };
...@@ -947,6 +964,8 @@ static const match_table_t tokens = { ...@@ -947,6 +964,8 @@ static const match_table_t tokens = {
{Opt_chk_data_crc, "chk_data_crc"}, {Opt_chk_data_crc, "chk_data_crc"},
{Opt_no_chk_data_crc, "no_chk_data_crc"}, {Opt_no_chk_data_crc, "no_chk_data_crc"},
{Opt_override_compr, "compr=%s"}, {Opt_override_compr, "compr=%s"},
{Opt_auth_key, "auth_key=%s"},
{Opt_auth_hash_name, "auth_hash_name=%s"},
{Opt_ignore, "ubi=%s"}, {Opt_ignore, "ubi=%s"},
{Opt_ignore, "vol=%s"}, {Opt_ignore, "vol=%s"},
{Opt_assert, "assert=%s"}, {Opt_assert, "assert=%s"},
...@@ -1070,6 +1089,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, ...@@ -1070,6 +1089,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
kfree(act); kfree(act);
break; break;
} }
case Opt_auth_key:
c->auth_key_name = kstrdup(args[0].from, GFP_KERNEL);
if (!c->auth_key_name)
return -ENOMEM;
break;
case Opt_auth_hash_name:
c->auth_hash_name = kstrdup(args[0].from, GFP_KERNEL);
if (!c->auth_hash_name)
return -ENOMEM;
break;
case Opt_ignore: case Opt_ignore:
break; break;
default: default:
...@@ -1249,6 +1278,19 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1249,6 +1278,19 @@ static int mount_ubifs(struct ubifs_info *c)
c->mounting = 1; c->mounting = 1;
if (c->auth_key_name) {
if (IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) {
err = ubifs_init_authentication(c);
if (err)
goto out_free;
} else {
ubifs_err(c, "auth_key_name, but UBIFS is built without"
" authentication support");
err = -EINVAL;
goto out_free;
}
}
err = ubifs_read_superblock(c); err = ubifs_read_superblock(c);
if (err) if (err)
goto out_free; goto out_free;
...@@ -1367,12 +1409,21 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1367,12 +1409,21 @@ static int mount_ubifs(struct ubifs_info *c)
} }
if (c->need_recovery) { if (c->need_recovery) {
err = ubifs_recover_size(c); if (!ubifs_authenticated(c)) {
if (err) err = ubifs_recover_size(c, true);
goto out_orphans; if (err)
goto out_orphans;
}
err = ubifs_rcvry_gc_commit(c); err = ubifs_rcvry_gc_commit(c);
if (err) if (err)
goto out_orphans; goto out_orphans;
if (ubifs_authenticated(c)) {
err = ubifs_recover_size(c, false);
if (err)
goto out_orphans;
}
} else { } else {
err = take_gc_lnum(c); err = take_gc_lnum(c);
if (err) if (err)
...@@ -1391,7 +1442,7 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1391,7 +1442,7 @@ static int mount_ubifs(struct ubifs_info *c)
if (err) if (err)
goto out_orphans; goto out_orphans;
} else if (c->need_recovery) { } else if (c->need_recovery) {
err = ubifs_recover_size(c); err = ubifs_recover_size(c, false);
if (err) if (err)
goto out_orphans; goto out_orphans;
} else { } else {
...@@ -1557,7 +1608,10 @@ static void ubifs_umount(struct ubifs_info *c) ...@@ -1557,7 +1608,10 @@ static void ubifs_umount(struct ubifs_info *c)
free_wbufs(c); free_wbufs(c);
free_orphans(c); free_orphans(c);
ubifs_lpt_free(c, 0); ubifs_lpt_free(c, 0);
ubifs_exit_authentication(c);
kfree(c->auth_key_name);
kfree(c->auth_hash_name);
kfree(c->cbuf); kfree(c->cbuf);
kfree(c->rcvrd_mst_node); kfree(c->rcvrd_mst_node);
kfree(c->mst_node); kfree(c->mst_node);
...@@ -1605,16 +1659,10 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1605,16 +1659,10 @@ static int ubifs_remount_rw(struct ubifs_info *c)
goto out; goto out;
if (c->old_leb_cnt != c->leb_cnt) { if (c->old_leb_cnt != c->leb_cnt) {
struct ubifs_sb_node *sup; struct ubifs_sb_node *sup = c->sup_node;
sup = ubifs_read_sb_node(c);
if (IS_ERR(sup)) {
err = PTR_ERR(sup);
goto out;
}
sup->leb_cnt = cpu_to_le32(c->leb_cnt); sup->leb_cnt = cpu_to_le32(c->leb_cnt);
err = ubifs_write_sb_node(c, sup); err = ubifs_write_sb_node(c, sup);
kfree(sup);
if (err) if (err)
goto out; goto out;
} }
...@@ -1624,9 +1672,11 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1624,9 +1672,11 @@ static int ubifs_remount_rw(struct ubifs_info *c)
err = ubifs_write_rcvrd_mst_node(c); err = ubifs_write_rcvrd_mst_node(c);
if (err) if (err)
goto out; goto out;
err = ubifs_recover_size(c); if (!ubifs_authenticated(c)) {
if (err) err = ubifs_recover_size(c, true);
goto out; if (err)
goto out;
}
err = ubifs_clean_lebs(c, c->sbuf); err = ubifs_clean_lebs(c, c->sbuf);
if (err) if (err)
goto out; goto out;
...@@ -1692,10 +1742,19 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1692,10 +1742,19 @@ static int ubifs_remount_rw(struct ubifs_info *c)
goto out; goto out;
} }
if (c->need_recovery) if (c->need_recovery) {
err = ubifs_rcvry_gc_commit(c); err = ubifs_rcvry_gc_commit(c);
else if (err)
goto out;
if (ubifs_authenticated(c)) {
err = ubifs_recover_size(c, false);
if (err)
goto out;
}
} else {
err = ubifs_leb_unmap(c, c->gc_lnum); err = ubifs_leb_unmap(c, c->gc_lnum);
}
if (err) if (err)
goto out; goto out;
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#include "ubifs.h" #include "ubifs.h"
static int try_read_node(const struct ubifs_info *c, void *buf, int type, static int try_read_node(const struct ubifs_info *c, void *buf, int type,
int len, int lnum, int offs); struct ubifs_zbranch *zbr);
static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_zbranch *zbr, void *node); struct ubifs_zbranch *zbr, void *node);
...@@ -433,9 +433,7 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, ...@@ -433,9 +433,7 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @buf: buffer to read to * @buf: buffer to read to
* @type: node type * @type: node type
* @len: node length (not aligned) * @zbr: the zbranch describing the node to read
* @lnum: LEB number of node to read
* @offs: offset of node to read
* *
* This function tries to read a node of known type and length, checks it and * This function tries to read a node of known type and length, checks it and
* stores it in @buf. This function returns %1 if a node is present and %0 if * stores it in @buf. This function returns %1 if a node is present and %0 if
...@@ -453,8 +451,11 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, ...@@ -453,8 +451,11 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
* journal nodes may potentially be corrupted, so checking is required. * journal nodes may potentially be corrupted, so checking is required.
*/ */
static int try_read_node(const struct ubifs_info *c, void *buf, int type, static int try_read_node(const struct ubifs_info *c, void *buf, int type,
int len, int lnum, int offs) struct ubifs_zbranch *zbr)
{ {
int len = zbr->len;
int lnum = zbr->lnum;
int offs = zbr->offs;
int err, node_len; int err, node_len;
struct ubifs_ch *ch = buf; struct ubifs_ch *ch = buf;
uint32_t crc, node_crc; uint32_t crc, node_crc;
...@@ -487,6 +488,12 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type, ...@@ -487,6 +488,12 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
if (crc != node_crc) if (crc != node_crc)
return 0; return 0;
err = ubifs_node_check_hash(c, buf, zbr->hash);
if (err) {
ubifs_bad_hash(c, buf, zbr->hash, lnum, offs);
return 0;
}
return 1; return 1;
} }
...@@ -507,8 +514,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, ...@@ -507,8 +514,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs); dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum, ret = try_read_node(c, node, key_type(c, key), zbr);
zbr->offs);
if (ret == 1) { if (ret == 1) {
union ubifs_key node_key; union ubifs_key node_key;
struct ubifs_dent_node *dent = node; struct ubifs_dent_node *dent = node;
...@@ -1713,6 +1719,12 @@ static int validate_data_node(struct ubifs_info *c, void *buf, ...@@ -1713,6 +1719,12 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
goto out; goto out;
} }
err = ubifs_node_check_hash(c, buf, zbr->hash);
if (err) {
ubifs_bad_hash(c, buf, zbr->hash, zbr->lnum, zbr->offs);
return err;
}
len = le32_to_cpu(ch->len); len = le32_to_cpu(ch->len);
if (len != zbr->len) { if (len != zbr->len) {
ubifs_err(c, "bad node length %d, expected %d", len, zbr->len); ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);
...@@ -2260,13 +2272,14 @@ static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode, ...@@ -2260,13 +2272,14 @@ static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode,
* @lnum: LEB number of node * @lnum: LEB number of node
* @offs: node offset * @offs: node offset
* @len: node length * @len: node length
* @hash: The hash over the node
* *
* This function adds a node with key @key to TNC. The node may be new or it may * 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 * obsolete some existing one. Returns %0 on success or negative error code on
* failure. * failure.
*/ */
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
int offs, int len) int offs, int len, const u8 *hash)
{ {
int found, n, err = 0; int found, n, err = 0;
struct ubifs_znode *znode; struct ubifs_znode *znode;
...@@ -2281,6 +2294,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, ...@@ -2281,6 +2294,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
zbr.lnum = lnum; zbr.lnum = lnum;
zbr.offs = offs; zbr.offs = offs;
zbr.len = len; zbr.len = len;
ubifs_copy_hash(c, hash, zbr.hash);
key_copy(c, key, &zbr.key); key_copy(c, key, &zbr.key);
err = tnc_insert(c, znode, &zbr, n + 1); err = tnc_insert(c, znode, &zbr, n + 1);
} else if (found == 1) { } else if (found == 1) {
...@@ -2291,6 +2305,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, ...@@ -2291,6 +2305,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
zbr->lnum = lnum; zbr->lnum = lnum;
zbr->offs = offs; zbr->offs = offs;
zbr->len = len; zbr->len = len;
ubifs_copy_hash(c, hash, zbr->hash);
} else } else
err = found; err = found;
if (!err) if (!err)
...@@ -2392,13 +2407,14 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2392,13 +2407,14 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
* @lnum: LEB number of node * @lnum: LEB number of node
* @offs: node offset * @offs: node offset
* @len: node length * @len: node length
* @hash: The hash over the node
* @nm: node name * @nm: node name
* *
* This is the same as 'ubifs_tnc_add()' but it should be used with keys which * This is the same as 'ubifs_tnc_add()' but it should be used with keys which
* may have collisions, like directory entry keys. * may have collisions, like directory entry keys.
*/ */
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
int lnum, int offs, int len, int lnum, int offs, int len, const u8 *hash,
const struct fscrypt_name *nm) const struct fscrypt_name *nm)
{ {
int found, n, err = 0; int found, n, err = 0;
...@@ -2441,6 +2457,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2441,6 +2457,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
zbr->lnum = lnum; zbr->lnum = lnum;
zbr->offs = offs; zbr->offs = offs;
zbr->len = len; zbr->len = len;
ubifs_copy_hash(c, hash, zbr->hash);
goto out_unlock; goto out_unlock;
} }
} }
...@@ -2452,6 +2469,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2452,6 +2469,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
zbr.lnum = lnum; zbr.lnum = lnum;
zbr.offs = offs; zbr.offs = offs;
zbr.len = len; zbr.len = len;
ubifs_copy_hash(c, hash, zbr.hash);
key_copy(c, key, &zbr.key); key_copy(c, key, &zbr.key);
err = tnc_insert(c, znode, &zbr, n + 1); err = tnc_insert(c, znode, &zbr, n + 1);
if (err) if (err)
......
...@@ -38,6 +38,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ...@@ -38,6 +38,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
struct ubifs_znode *znode, int lnum, int offs, int len) struct ubifs_znode *znode, int lnum, int offs, int len)
{ {
struct ubifs_znode *zp; struct ubifs_znode *zp;
u8 hash[UBIFS_HASH_ARR_SZ];
int i, err; int i, err;
/* Make index node */ /* Make index node */
...@@ -52,6 +53,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ...@@ -52,6 +53,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
br->lnum = cpu_to_le32(zbr->lnum); br->lnum = cpu_to_le32(zbr->lnum);
br->offs = cpu_to_le32(zbr->offs); br->offs = cpu_to_le32(zbr->offs);
br->len = cpu_to_le32(zbr->len); br->len = cpu_to_le32(zbr->len);
ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
if (!zbr->lnum || !zbr->len) { if (!zbr->lnum || !zbr->len) {
ubifs_err(c, "bad ref in znode"); ubifs_err(c, "bad ref in znode");
ubifs_dump_znode(c, znode); ubifs_dump_znode(c, znode);
...@@ -62,6 +64,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ...@@ -62,6 +64,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
} }
} }
ubifs_prepare_node(c, idx, len, 0); ubifs_prepare_node(c, idx, len, 0);
ubifs_node_calc_hash(c, idx, hash);
znode->lnum = lnum; znode->lnum = lnum;
znode->offs = offs; znode->offs = offs;
...@@ -78,10 +81,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, ...@@ -78,10 +81,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
zbr->lnum = lnum; zbr->lnum = lnum;
zbr->offs = offs; zbr->offs = offs;
zbr->len = len; zbr->len = len;
ubifs_copy_hash(c, hash, zbr->hash);
} else { } else {
c->zroot.lnum = lnum; c->zroot.lnum = lnum;
c->zroot.offs = offs; c->zroot.offs = offs;
c->zroot.len = len; c->zroot.len = len;
ubifs_copy_hash(c, hash, c->zroot.hash);
} }
c->calc_idx_sz += ALIGN(len, 8); c->calc_idx_sz += ALIGN(len, 8);
...@@ -647,6 +652,8 @@ static int get_znodes_to_commit(struct ubifs_info *c) ...@@ -647,6 +652,8 @@ static int get_znodes_to_commit(struct ubifs_info *c)
znode->cnext = c->cnext; znode->cnext = c->cnext;
break; break;
} }
znode->cparent = znode->parent;
znode->ciip = znode->iip;
znode->cnext = cnext; znode->cnext = cnext;
znode = cnext; znode = cnext;
cnt += 1; cnt += 1;
...@@ -840,6 +847,8 @@ static int write_index(struct ubifs_info *c) ...@@ -840,6 +847,8 @@ static int write_index(struct ubifs_info *c)
} }
while (1) { while (1) {
u8 hash[UBIFS_HASH_ARR_SZ];
cond_resched(); cond_resched();
znode = cnext; znode = cnext;
...@@ -857,6 +866,7 @@ static int write_index(struct ubifs_info *c) ...@@ -857,6 +866,7 @@ static int write_index(struct ubifs_info *c)
br->lnum = cpu_to_le32(zbr->lnum); br->lnum = cpu_to_le32(zbr->lnum);
br->offs = cpu_to_le32(zbr->offs); br->offs = cpu_to_le32(zbr->offs);
br->len = cpu_to_le32(zbr->len); br->len = cpu_to_le32(zbr->len);
ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
if (!zbr->lnum || !zbr->len) { if (!zbr->lnum || !zbr->len) {
ubifs_err(c, "bad ref in znode"); ubifs_err(c, "bad ref in znode");
ubifs_dump_znode(c, znode); ubifs_dump_znode(c, znode);
...@@ -868,6 +878,23 @@ static int write_index(struct ubifs_info *c) ...@@ -868,6 +878,23 @@ static int write_index(struct ubifs_info *c)
} }
len = ubifs_idx_node_sz(c, znode->child_cnt); len = ubifs_idx_node_sz(c, znode->child_cnt);
ubifs_prepare_node(c, idx, len, 0); ubifs_prepare_node(c, idx, len, 0);
ubifs_node_calc_hash(c, idx, hash);
mutex_lock(&c->tnc_mutex);
if (znode->cparent)
ubifs_copy_hash(c, hash,
znode->cparent->zbranch[znode->ciip].hash);
if (znode->parent) {
if (!ubifs_zn_obsolete(znode))
ubifs_copy_hash(c, hash,
znode->parent->zbranch[znode->iip].hash);
} else {
ubifs_copy_hash(c, hash, c->zroot.hash);
}
mutex_unlock(&c->tnc_mutex);
/* Determine the index node position */ /* Determine the index node position */
if (lnum == -1) { if (lnum == -1) {
......
...@@ -265,9 +265,7 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c, ...@@ -265,9 +265,7 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
/** /**
* read_znode - read an indexing node from flash and fill znode. * read_znode - read an indexing node from flash and fill znode.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @lnum: LEB of the indexing node to read * @zzbr: the zbranch describing the node to read
* @offs: node offset
* @len: node length
* @znode: znode to read to * @znode: znode to read to
* *
* This function reads an indexing node from the flash media and fills znode * This function reads an indexing node from the flash media and fills znode
...@@ -276,9 +274,12 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c, ...@@ -276,9 +274,12 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
* is wrong with it, this function prints complaint messages and returns * is wrong with it, this function prints complaint messages and returns
* %-EINVAL. * %-EINVAL.
*/ */
static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
struct ubifs_znode *znode) struct ubifs_znode *znode)
{ {
int lnum = zzbr->lnum;
int offs = zzbr->offs;
int len = zzbr->len;
int i, err, type, cmp; int i, err, type, cmp;
struct ubifs_idx_node *idx; struct ubifs_idx_node *idx;
...@@ -292,6 +293,12 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, ...@@ -292,6 +293,12 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
return err; return err;
} }
err = ubifs_node_check_hash(c, idx, zzbr->hash);
if (err) {
ubifs_bad_hash(c, idx, zzbr->hash, lnum, offs);
return err;
}
znode->child_cnt = le16_to_cpu(idx->child_cnt); znode->child_cnt = le16_to_cpu(idx->child_cnt);
znode->level = le16_to_cpu(idx->level); znode->level = le16_to_cpu(idx->level);
...@@ -308,13 +315,14 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, ...@@ -308,13 +315,14 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
} }
for (i = 0; i < znode->child_cnt; i++) { for (i = 0; i < znode->child_cnt; i++) {
const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
struct ubifs_zbranch *zbr = &znode->zbranch[i]; struct ubifs_zbranch *zbr = &znode->zbranch[i];
key_read(c, &br->key, &zbr->key); key_read(c, &br->key, &zbr->key);
zbr->lnum = le32_to_cpu(br->lnum); zbr->lnum = le32_to_cpu(br->lnum);
zbr->offs = le32_to_cpu(br->offs); zbr->offs = le32_to_cpu(br->offs);
zbr->len = le32_to_cpu(br->len); zbr->len = le32_to_cpu(br->len);
ubifs_copy_hash(c, ubifs_branch_hash(c, br), zbr->hash);
zbr->znode = NULL; zbr->znode = NULL;
/* Validate branch */ /* Validate branch */
...@@ -425,7 +433,7 @@ struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c, ...@@ -425,7 +433,7 @@ struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
if (!znode) if (!znode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode); err = read_znode(c, zbr, znode);
if (err) if (err)
goto out; goto out;
...@@ -496,5 +504,11 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, ...@@ -496,5 +504,11 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
return -EINVAL; return -EINVAL;
} }
err = ubifs_node_check_hash(c, node, zbr->hash);
if (err) {
ubifs_bad_hash(c, node, zbr->hash, zbr->lnum, zbr->offs);
return err;
}
return 0; return 0;
} }
...@@ -286,6 +286,7 @@ enum { ...@@ -286,6 +286,7 @@ enum {
#define UBIFS_IDX_NODE_SZ sizeof(struct ubifs_idx_node) #define UBIFS_IDX_NODE_SZ sizeof(struct ubifs_idx_node)
#define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node) #define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node)
#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node) #define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node)
#define UBIFS_AUTH_NODE_SZ sizeof(struct ubifs_auth_node)
/* Extended attribute entry nodes are identical to directory entry nodes */ /* Extended attribute entry nodes are identical to directory entry nodes */
#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ #define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
/* Only this does not have to be multiple of 8 bytes */ /* Only this does not have to be multiple of 8 bytes */
...@@ -300,6 +301,12 @@ enum { ...@@ -300,6 +301,12 @@ enum {
/* The largest UBIFS node */ /* The largest UBIFS node */
#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ #define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
/* The maxmimum size of a hash, enough for sha512 */
#define UBIFS_MAX_HASH_LEN 64
/* The maxmimum size of a hmac, enough for hmac(sha512) */
#define UBIFS_MAX_HMAC_LEN 64
/* /*
* xattr name of UBIFS encryption context, we don't use a prefix * xattr name of UBIFS encryption context, we don't use a prefix
* nor a long name to not waste space on the flash. * nor a long name to not waste space on the flash.
...@@ -365,6 +372,7 @@ enum { ...@@ -365,6 +372,7 @@ enum {
* UBIFS_IDX_NODE: index node * UBIFS_IDX_NODE: index node
* UBIFS_CS_NODE: commit start node * UBIFS_CS_NODE: commit start node
* UBIFS_ORPH_NODE: orphan node * UBIFS_ORPH_NODE: orphan node
* UBIFS_AUTH_NODE: authentication node
* UBIFS_NODE_TYPES_CNT: count of supported node types * UBIFS_NODE_TYPES_CNT: count of supported node types
* *
* Note, we index arrays by these numbers, so keep them low and contiguous. * Note, we index arrays by these numbers, so keep them low and contiguous.
...@@ -384,6 +392,7 @@ enum { ...@@ -384,6 +392,7 @@ enum {
UBIFS_IDX_NODE, UBIFS_IDX_NODE,
UBIFS_CS_NODE, UBIFS_CS_NODE,
UBIFS_ORPH_NODE, UBIFS_ORPH_NODE,
UBIFS_AUTH_NODE,
UBIFS_NODE_TYPES_CNT, UBIFS_NODE_TYPES_CNT,
}; };
...@@ -421,15 +430,19 @@ enum { ...@@ -421,15 +430,19 @@ enum {
* UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to * UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
* support 64bit cookies for lookups by hash * support 64bit cookies for lookups by hash
* UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files * UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files
* UBIFS_FLG_AUTHENTICATION: this filesystem contains hashes for authentication
*/ */
enum { enum {
UBIFS_FLG_BIGLPT = 0x02, UBIFS_FLG_BIGLPT = 0x02,
UBIFS_FLG_SPACE_FIXUP = 0x04, UBIFS_FLG_SPACE_FIXUP = 0x04,
UBIFS_FLG_DOUBLE_HASH = 0x08, UBIFS_FLG_DOUBLE_HASH = 0x08,
UBIFS_FLG_ENCRYPTION = 0x10, UBIFS_FLG_ENCRYPTION = 0x10,
UBIFS_FLG_AUTHENTICATION = 0x20,
}; };
#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION) #define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT | UBIFS_FLG_SPACE_FIXUP | \
UBIFS_FLG_DOUBLE_HASH | UBIFS_FLG_ENCRYPTION | \
UBIFS_FLG_AUTHENTICATION)
/** /**
* struct ubifs_ch - common header node. * struct ubifs_ch - common header node.
...@@ -633,6 +646,10 @@ struct ubifs_pad_node { ...@@ -633,6 +646,10 @@ struct ubifs_pad_node {
* @time_gran: time granularity in nanoseconds * @time_gran: time granularity in nanoseconds
* @uuid: UUID generated when the file system image was created * @uuid: UUID generated when the file system image was created
* @ro_compat_version: UBIFS R/O compatibility version * @ro_compat_version: UBIFS R/O compatibility version
* @hmac: HMAC to authenticate the superblock node
* @hmac_wkm: HMAC of a well known message (the string "UBIFS") as a convenience
* to the user to check if the correct key is passed.
* @hash_algo: The hash algo used for this filesystem (one of enum hash_algo)
*/ */
struct ubifs_sb_node { struct ubifs_sb_node {
struct ubifs_ch ch; struct ubifs_ch ch;
...@@ -660,7 +677,10 @@ struct ubifs_sb_node { ...@@ -660,7 +677,10 @@ struct ubifs_sb_node {
__le32 time_gran; __le32 time_gran;
__u8 uuid[16]; __u8 uuid[16];
__le32 ro_compat_version; __le32 ro_compat_version;
__u8 padding2[3968]; __u8 hmac[UBIFS_MAX_HMAC_LEN];
__u8 hmac_wkm[UBIFS_MAX_HMAC_LEN];
__le16 hash_algo;
__u8 padding2[3838];
} __packed; } __packed;
/** /**
...@@ -695,6 +715,9 @@ struct ubifs_sb_node { ...@@ -695,6 +715,9 @@ struct ubifs_sb_node {
* @empty_lebs: number of empty logical eraseblocks * @empty_lebs: number of empty logical eraseblocks
* @idx_lebs: number of indexing logical eraseblocks * @idx_lebs: number of indexing logical eraseblocks
* @leb_cnt: count of LEBs used by file-system * @leb_cnt: count of LEBs used by file-system
* @hash_root_idx: the hash of the root index node
* @hash_lpt: the hash of the LPT
* @hmac: HMAC to authenticate the master node
* @padding: reserved for future, zeroes * @padding: reserved for future, zeroes
*/ */
struct ubifs_mst_node { struct ubifs_mst_node {
...@@ -727,7 +750,10 @@ struct ubifs_mst_node { ...@@ -727,7 +750,10 @@ struct ubifs_mst_node {
__le32 empty_lebs; __le32 empty_lebs;
__le32 idx_lebs; __le32 idx_lebs;
__le32 leb_cnt; __le32 leb_cnt;
__u8 padding[344]; __u8 hash_root_idx[UBIFS_MAX_HASH_LEN];
__u8 hash_lpt[UBIFS_MAX_HASH_LEN];
__u8 hmac[UBIFS_MAX_HMAC_LEN];
__u8 padding[152];
} __packed; } __packed;
/** /**
...@@ -746,12 +772,26 @@ struct ubifs_ref_node { ...@@ -746,12 +772,26 @@ struct ubifs_ref_node {
__u8 padding[28]; __u8 padding[28];
} __packed; } __packed;
/**
* struct ubifs_auth_node - node for authenticating other nodes
* @ch: common header
* @hmac: The HMAC
*/
struct ubifs_auth_node {
struct ubifs_ch ch;
__u8 hmac[];
} __packed;
/** /**
* struct ubifs_branch - key/reference/length branch * struct ubifs_branch - key/reference/length branch
* @lnum: LEB number of the target node * @lnum: LEB number of the target node
* @offs: offset within @lnum * @offs: offset within @lnum
* @len: target node length * @len: target node length
* @key: key * @key: key
*
* In an authenticated UBIFS we have the hash of the referenced node after @key.
* This can't be added to the struct type definition because @key is a
* dynamically sized element already.
*/ */
struct ubifs_branch { struct ubifs_branch {
__le32 lnum; __le32 lnum;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment