Commit a318423b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'upstream-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs

Pull UBIFS updates from Richard Weinberger:

 - Support for zstd compression

 - Support for offline signed filesystems

 - Various fixes for regressions

* tag 'upstream-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs:
  ubifs: Don't leak orphans on memory during commit
  ubifs: Check link count of inodes when killing orphans.
  ubifs: Add support for zstd compression.
  ubifs: support offline signed images
  ubifs: remove unnecessary check in ubifs_log_start_commit
  ubifs: Fix typo of output in get_cs_sqnum
  ubifs: Simplify redundant code
  ubifs: Correctly use tnc_next() in search_dh_cookie()
parents f2772a0e 8009ce95
...@@ -6,8 +6,10 @@ config UBIFS_FS ...@@ -6,8 +6,10 @@ config UBIFS_FS
select CRYPTO if UBIFS_FS_ADVANCED_COMPR select CRYPTO if UBIFS_FS_ADVANCED_COMPR
select CRYPTO if UBIFS_FS_LZO select CRYPTO if UBIFS_FS_LZO
select CRYPTO if UBIFS_FS_ZLIB select CRYPTO if UBIFS_FS_ZLIB
select CRYPTO if UBIFS_FS_ZSTD
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_ZSTD if UBIFS_FS_ZSTD
select CRYPTO_HASH_INFO select CRYPTO_HASH_INFO
select UBIFS_FS_XATTR if FS_ENCRYPTION select UBIFS_FS_XATTR if FS_ENCRYPTION
depends on MTD_UBI depends on MTD_UBI
...@@ -38,6 +40,14 @@ config UBIFS_FS_ZLIB ...@@ -38,6 +40,14 @@ config UBIFS_FS_ZLIB
help help
Zlib compresses better than LZO but it is slower. Say 'Y' if unsure. Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
config UBIFS_FS_ZSTD
bool "ZSTD compression support" if UBIFS_FS_ADVANCED_COMPR
depends on UBIFS_FS
default y
help
ZSTD compresses is a big win in speed over Zlib and
in compression ratio over LZO. Say 'Y' if unsure.
config UBIFS_ATIME_SUPPORT config UBIFS_ATIME_SUPPORT
bool "Access time support" bool "Access time support"
default n default n
...@@ -77,8 +87,9 @@ config UBIFS_FS_SECURITY ...@@ -77,8 +87,9 @@ config UBIFS_FS_SECURITY
config UBIFS_FS_AUTHENTICATION config UBIFS_FS_AUTHENTICATION
bool "UBIFS authentication support" bool "UBIFS authentication support"
depends on KEYS select KEYS
select CRYPTO_HMAC select CRYPTO_HMAC
select SYSTEM_DATA_VERIFICATION
help help
Enable authentication support for UBIFS. This feature offers protection Enable authentication support for UBIFS. This feature offers protection
against offline changes for both data and metadata of the filesystem. against offline changes for both data and metadata of the filesystem.
......
...@@ -10,10 +10,12 @@ ...@@ -10,10 +10,12 @@
*/ */
#include <linux/crypto.h> #include <linux/crypto.h>
#include <linux/verification.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include <crypto/sha.h> #include <crypto/sha.h>
#include <crypto/algapi.h> #include <crypto/algapi.h>
#include <keys/user-type.h> #include <keys/user-type.h>
#include <keys/asymmetric-type.h>
#include "ubifs.h" #include "ubifs.h"
...@@ -198,6 +200,77 @@ int __ubifs_node_check_hash(const struct ubifs_info *c, const void *node, ...@@ -198,6 +200,77 @@ int __ubifs_node_check_hash(const struct ubifs_info *c, const void *node,
return 0; return 0;
} }
/**
* ubifs_sb_verify_signature - verify the signature of a superblock
* @c: UBIFS file-system description object
* @sup: The superblock node
*
* To support offline signed images the superblock can be signed with a
* PKCS#7 signature. The signature is placed directly behind the superblock
* node in an ubifs_sig_node.
*
* Returns 0 when the signature can be successfully verified or a negative
* error code if not.
*/
int ubifs_sb_verify_signature(struct ubifs_info *c,
const struct ubifs_sb_node *sup)
{
int err;
struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod;
const struct ubifs_sig_node *signode;
sleb = ubifs_scan(c, UBIFS_SB_LNUM, UBIFS_SB_NODE_SZ, c->sbuf, 0);
if (IS_ERR(sleb)) {
err = PTR_ERR(sleb);
return err;
}
if (sleb->nodes_cnt == 0) {
ubifs_err(c, "Unable to find signature node");
err = -EINVAL;
goto out_destroy;
}
snod = list_first_entry(&sleb->nodes, struct ubifs_scan_node, list);
if (snod->type != UBIFS_SIG_NODE) {
ubifs_err(c, "Signature node is of wrong type");
err = -EINVAL;
goto out_destroy;
}
signode = snod->node;
if (le32_to_cpu(signode->len) > snod->len + sizeof(struct ubifs_sig_node)) {
ubifs_err(c, "invalid signature len %d", le32_to_cpu(signode->len));
err = -EINVAL;
goto out_destroy;
}
if (le32_to_cpu(signode->type) != UBIFS_SIGNATURE_TYPE_PKCS7) {
ubifs_err(c, "Signature type %d is not supported\n",
le32_to_cpu(signode->type));
err = -EINVAL;
goto out_destroy;
}
err = verify_pkcs7_signature(sup, sizeof(struct ubifs_sb_node),
signode->sig, le32_to_cpu(signode->len),
NULL, VERIFYING_UNSPECIFIED_SIGNATURE,
NULL, NULL);
if (err)
ubifs_err(c, "Failed to verify signature");
else
ubifs_msg(c, "Successfully verified super block signature");
out_destroy:
ubifs_scan_destroy(sleb);
return err;
}
/** /**
* ubifs_init_authentication - initialize UBIFS authentication support * ubifs_init_authentication - initialize UBIFS authentication support
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -478,3 +551,16 @@ int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac) ...@@ -478,3 +551,16 @@ int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac)
return err; return err;
return 0; return 0;
} }
/*
* ubifs_hmac_zero - test if a HMAC is zero
* @c: UBIFS file-system description object
* @hmac: the HMAC to test
*
* This function tests if a HMAC is zero and returns true if it is
* and false otherwise.
*/
bool ubifs_hmac_zero(struct ubifs_info *c, const u8 *hmac)
{
return !memchr_inv(hmac, 0, c->hmac_desc_len);
}
...@@ -59,6 +59,24 @@ static struct ubifs_compressor zlib_compr = { ...@@ -59,6 +59,24 @@ static struct ubifs_compressor zlib_compr = {
}; };
#endif #endif
#ifdef CONFIG_UBIFS_FS_ZSTD
static DEFINE_MUTEX(zstd_enc_mutex);
static DEFINE_MUTEX(zstd_dec_mutex);
static struct ubifs_compressor zstd_compr = {
.compr_type = UBIFS_COMPR_ZSTD,
.comp_mutex = &zstd_enc_mutex,
.decomp_mutex = &zstd_dec_mutex,
.name = "zstd",
.capi_name = "zstd",
};
#else
static struct ubifs_compressor zstd_compr = {
.compr_type = UBIFS_COMPR_ZSTD,
.name = "zstd",
};
#endif
/* All UBIFS compressors */ /* All UBIFS compressors */
struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
...@@ -216,13 +234,19 @@ int __init ubifs_compressors_init(void) ...@@ -216,13 +234,19 @@ int __init ubifs_compressors_init(void)
if (err) if (err)
return err; return err;
err = compr_init(&zlib_compr); err = compr_init(&zstd_compr);
if (err) if (err)
goto out_lzo; goto out_lzo;
err = compr_init(&zlib_compr);
if (err)
goto out_zstd;
ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr; ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
return 0; return 0;
out_zstd:
compr_exit(&zstd_compr);
out_lzo: out_lzo:
compr_exit(&lzo_compr); compr_exit(&lzo_compr);
return err; return err;
...@@ -235,4 +259,5 @@ void ubifs_compressors_exit(void) ...@@ -235,4 +259,5 @@ void ubifs_compressors_exit(void)
{ {
compr_exit(&lzo_compr); compr_exit(&lzo_compr);
compr_exit(&zlib_compr); compr_exit(&zlib_compr);
compr_exit(&zstd_compr);
} }
...@@ -438,10 +438,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) ...@@ -438,10 +438,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
*ltail_lnum = c->lhead_lnum; *ltail_lnum = c->lhead_lnum;
c->lhead_offs += len; c->lhead_offs += len;
if (c->lhead_offs == c->leb_size) { ubifs_assert(c, c->lhead_offs < c->leb_size);
c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
c->lhead_offs = 0;
}
remove_buds(c); remove_buds(c);
......
...@@ -48,6 +48,39 @@ int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2) ...@@ -48,6 +48,39 @@ int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
return 0; return 0;
} }
/* mst_node_check_hash - Check hash of a master node
* @c: UBIFS file-system description object
* @mst: The master node
* @expected: The expected hash of the master node
*
* This checks the hash of a master node against a given expected hash.
* Note that we have two master nodes on a UBIFS image which have different
* sequence numbers and consequently different CRCs. To be able to match
* both master nodes we exclude the common node header containing the sequence
* number and CRC from the hash.
*
* Returns 0 if the hashes are equal, a negative error code otherwise.
*/
static int mst_node_check_hash(const struct ubifs_info *c,
const struct ubifs_mst_node *mst,
const u8 *expected)
{
u8 calc[UBIFS_MAX_HASH_LEN];
const void *node = mst;
SHASH_DESC_ON_STACK(shash, c->hash_tfm);
shash->tfm = c->hash_tfm;
crypto_shash_digest(shash, node + sizeof(struct ubifs_ch),
UBIFS_MST_NODE_SZ - sizeof(struct ubifs_ch), calc);
if (ubifs_check_hash(c, expected, calc))
return -EPERM;
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
...@@ -102,14 +135,22 @@ static int scan_for_master(struct ubifs_info *c) ...@@ -102,14 +135,22 @@ static int scan_for_master(struct ubifs_info *c)
if (!ubifs_authenticated(c)) if (!ubifs_authenticated(c))
return 0; return 0;
err = ubifs_node_verify_hmac(c, c->mst_node, if (ubifs_hmac_zero(c, c->mst_node->hmac)) {
sizeof(struct ubifs_mst_node), err = mst_node_check_hash(c, c->mst_node,
offsetof(struct ubifs_mst_node, hmac)); c->sup_node->hash_mst);
if (err) { if (err)
ubifs_err(c, "Failed to verify master node HMAC"); ubifs_err(c, "Failed to verify master node hash");
return -EPERM; } else {
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");
} }
if (err)
return -EPERM;
return 0; return 0;
out: out:
......
...@@ -126,25 +126,11 @@ static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *o) ...@@ -126,25 +126,11 @@ static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *o)
kfree(o); kfree(o);
} }
static void orphan_delete(struct ubifs_info *c, ino_t inum) static void orphan_delete(struct ubifs_info *c, struct ubifs_orphan *orph)
{ {
struct ubifs_orphan *orph, *child_orph, *tmp_o;
spin_lock(&c->orphan_lock);
orph = lookup_orphan(c, inum);
if (!orph) {
spin_unlock(&c->orphan_lock);
ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
dump_stack();
return;
}
if (orph->del) { if (orph->del) {
spin_unlock(&c->orphan_lock); spin_unlock(&c->orphan_lock);
dbg_gen("deleted twice ino %lu", dbg_gen("deleted twice ino %lu", orph->inum);
(unsigned long)inum);
return; return;
} }
...@@ -153,19 +139,11 @@ static void orphan_delete(struct ubifs_info *c, ino_t inum) ...@@ -153,19 +139,11 @@ static void orphan_delete(struct ubifs_info *c, ino_t inum)
orph->dnext = c->orph_dnext; orph->dnext = c->orph_dnext;
c->orph_dnext = orph; c->orph_dnext = orph;
spin_unlock(&c->orphan_lock); spin_unlock(&c->orphan_lock);
dbg_gen("delete later ino %lu", dbg_gen("delete later ino %lu", orph->inum);
(unsigned long)inum);
return; return;
} }
list_for_each_entry_safe(child_orph, tmp_o, &orph->child_list, child_list) {
list_del(&child_orph->child_list);
__orphan_drop(c, child_orph);
}
__orphan_drop(c, orph); __orphan_drop(c, orph);
spin_unlock(&c->orphan_lock);
} }
/** /**
...@@ -223,7 +201,27 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum) ...@@ -223,7 +201,27 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
*/ */
void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum) void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
{ {
orphan_delete(c, inum); struct ubifs_orphan *orph, *child_orph, *tmp_o;
spin_lock(&c->orphan_lock);
orph = lookup_orphan(c, inum);
if (!orph) {
spin_unlock(&c->orphan_lock);
ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
dump_stack();
return;
}
list_for_each_entry_safe(child_orph, tmp_o, &orph->child_list, child_list) {
list_del(&child_orph->child_list);
orphan_delete(c, child_orph);
}
orphan_delete(c, orph);
spin_unlock(&c->orphan_lock);
} }
/** /**
...@@ -630,6 +628,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -630,6 +628,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
{ {
struct ubifs_scan_node *snod; struct ubifs_scan_node *snod;
struct ubifs_orph_node *orph; struct ubifs_orph_node *orph;
struct ubifs_ino_node *ino = NULL;
unsigned long long cmt_no; unsigned long long cmt_no;
ino_t inum; ino_t inum;
int i, n, err, first = 1; int i, n, err, first = 1;
...@@ -676,23 +675,40 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -676,23 +675,40 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
if (first) if (first)
first = 0; first = 0;
ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
if (!ino)
return -ENOMEM;
n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3; n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
union ubifs_key key1, key2; union ubifs_key key1, key2;
inum = le64_to_cpu(orph->inos[i]); inum = le64_to_cpu(orph->inos[i]);
dbg_rcvry("deleting orphaned inode %lu",
(unsigned long)inum);
lowest_ino_key(c, &key1, inum);
highest_ino_key(c, &key2, inum);
err = ubifs_tnc_remove_range(c, &key1, &key2); ino_key_init(c, &key1, inum);
err = ubifs_tnc_lookup(c, &key1, ino);
if (err) if (err)
return err; goto out_free;
/*
* Check whether an inode can really get deleted.
* linkat() with O_TMPFILE allows rebirth of an inode.
*/
if (ino->nlink == 0) {
dbg_rcvry("deleting orphaned inode %lu",
(unsigned long)inum);
lowest_ino_key(c, &key1, inum);
highest_ino_key(c, &key2, inum);
err = ubifs_tnc_remove_range(c, &key1, &key2);
if (err)
goto out_ro;
}
err = insert_dead_orphan(c, inum); err = insert_dead_orphan(c, inum);
if (err) if (err)
return err; goto out_free;
} }
*last_cmt_no = cmt_no; *last_cmt_no = cmt_no;
...@@ -704,7 +720,15 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ...@@ -704,7 +720,15 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
*last_flagged = 0; *last_flagged = 0;
} }
return 0; err = 0;
out_free:
kfree(ino);
return err;
out_ro:
ubifs_ro_mode(c, err);
kfree(ino);
return err;
} }
/** /**
......
...@@ -818,7 +818,7 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs, ...@@ -818,7 +818,7 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
goto out_err; goto out_err;
} }
if (cs_node->ch.node_type != UBIFS_CS_NODE) { if (cs_node->ch.node_type != UBIFS_CS_NODE) {
ubifs_err(c, "Node a CS node, type is %d", cs_node->ch.node_type); ubifs_err(c, "Not a CS node, type is %d", cs_node->ch.node_type);
goto out_err; goto out_err;
} }
if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) { if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
......
...@@ -578,17 +578,26 @@ static int authenticate_sb_node(struct ubifs_info *c, ...@@ -578,17 +578,26 @@ static int authenticate_sb_node(struct ubifs_info *c,
return -EINVAL; return -EINVAL;
} }
err = ubifs_hmac_wkm(c, hmac_wkm); /*
if (err) * The super block node can either be authenticated by a HMAC or
return err; * by a signature in a ubifs_sig_node directly following the
* super block node to support offline image creation.
if (ubifs_check_hmac(c, hmac_wkm, sup->hmac_wkm)) { */
ubifs_err(c, "provided key does not fit"); if (ubifs_hmac_zero(c, sup->hmac)) {
return -ENOKEY; err = ubifs_sb_verify_signature(c, sup);
} else {
err = ubifs_hmac_wkm(c, hmac_wkm);
if (err)
return err;
if (ubifs_check_hmac(c, hmac_wkm, sup->hmac_wkm)) {
ubifs_err(c, "provided key does not fit");
return -ENOKEY;
}
err = ubifs_node_verify_hmac(c, sup, sizeof(*sup),
offsetof(struct ubifs_sb_node,
hmac));
} }
err = ubifs_node_verify_hmac(c, sup, sizeof(*sup),
offsetof(struct ubifs_sb_node, hmac));
if (err) if (err)
ubifs_err(c, "Failed to authenticate superblock: %d", err); ubifs_err(c, "Failed to authenticate superblock: %d", err);
...@@ -744,21 +753,16 @@ int ubifs_read_superblock(struct ubifs_info *c) ...@@ -744,21 +753,16 @@ int ubifs_read_superblock(struct ubifs_info *c)
} }
/* Automatically increase file system size to the maximum size */ /* Automatically increase file system size to the maximum size */
c->old_leb_cnt = c->leb_cnt;
if (c->leb_cnt < c->vi.size && c->leb_cnt < c->max_leb_cnt) { if (c->leb_cnt < c->vi.size && c->leb_cnt < c->max_leb_cnt) {
int old_leb_cnt = c->leb_cnt;
c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size); c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size);
if (c->ro_mount) sup->leb_cnt = cpu_to_le32(c->leb_cnt);
dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs",
c->old_leb_cnt, c->leb_cnt); c->superblock_need_write = 1;
else {
dbg_mnt("Auto resizing (sb) from %d LEBs to %d LEBs", dbg_mnt("Auto resizing from %d LEBs to %d LEBs",
c->old_leb_cnt, c->leb_cnt); old_leb_cnt, c->leb_cnt);
sup->leb_cnt = cpu_to_le32(c->leb_cnt);
err = ubifs_write_sb_node(c, sup);
if (err)
goto out;
c->old_leb_cnt = c->leb_cnt;
}
} }
c->log_bytes = (long long)c->log_lebs * c->leb_size; c->log_bytes = (long long)c->log_lebs * c->leb_size;
...@@ -916,9 +920,7 @@ int ubifs_fixup_free_space(struct ubifs_info *c) ...@@ -916,9 +920,7 @@ int ubifs_fixup_free_space(struct ubifs_info *c)
c->space_fixup = 0; c->space_fixup = 0;
sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP); sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
err = ubifs_write_sb_node(c, sup); c->superblock_need_write = 1;
if (err)
return err;
ubifs_msg(c, "free space fixup complete"); ubifs_msg(c, "free space fixup complete");
return err; return err;
......
...@@ -566,6 +566,8 @@ static int init_constants_early(struct ubifs_info *c) ...@@ -566,6 +566,8 @@ static int init_constants_early(struct ubifs_info *c)
c->ranges[UBIFS_AUTH_NODE].min_len = UBIFS_AUTH_NODE_SZ; c->ranges[UBIFS_AUTH_NODE].min_len = UBIFS_AUTH_NODE_SZ;
c->ranges[UBIFS_AUTH_NODE].max_len = UBIFS_AUTH_NODE_SZ + c->ranges[UBIFS_AUTH_NODE].max_len = UBIFS_AUTH_NODE_SZ +
UBIFS_MAX_HMAC_LEN; UBIFS_MAX_HMAC_LEN;
c->ranges[UBIFS_SIG_NODE].min_len = UBIFS_SIG_NODE_SZ;
c->ranges[UBIFS_SIG_NODE].max_len = c->leb_size - UBIFS_SB_NODE_SZ;
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;
...@@ -1043,6 +1045,8 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, ...@@ -1043,6 +1045,8 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
c->mount_opts.compr_type = UBIFS_COMPR_LZO; c->mount_opts.compr_type = UBIFS_COMPR_LZO;
else if (!strcmp(name, "zlib")) else if (!strcmp(name, "zlib"))
c->mount_opts.compr_type = UBIFS_COMPR_ZLIB; c->mount_opts.compr_type = UBIFS_COMPR_ZLIB;
else if (!strcmp(name, "zstd"))
c->mount_opts.compr_type = UBIFS_COMPR_ZSTD;
else { else {
ubifs_err(c, "unknown compressor \"%s\"", name); //FIXME: is c ready? ubifs_err(c, "unknown compressor \"%s\"", name); //FIXME: is c ready?
kfree(name); kfree(name);
...@@ -1296,8 +1300,7 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1296,8 +1300,7 @@ static int mount_ubifs(struct ubifs_info *c)
if (err) if (err)
goto out_free; goto out_free;
sz = ALIGN(c->max_idx_node_sz, c->min_io_size); sz = ALIGN(c->max_idx_node_sz, c->min_io_size) * 2;
sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
c->cbuf = kmalloc(sz, GFP_NOFS); c->cbuf = kmalloc(sz, GFP_NOFS);
if (!c->cbuf) { if (!c->cbuf) {
err = -ENOMEM; err = -ENOMEM;
...@@ -1360,6 +1363,26 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1360,6 +1363,26 @@ static int mount_ubifs(struct ubifs_info *c)
goto out_lpt; goto out_lpt;
} }
/*
* Handle offline signed images: Now that the master node is
* written and its validation no longer depends on the hash
* in the superblock, we can update the offline signed
* superblock with a HMAC version,
*/
if (ubifs_authenticated(c) && ubifs_hmac_zero(c, c->sup_node->hmac)) {
err = ubifs_hmac_wkm(c, c->sup_node->hmac_wkm);
if (err)
goto out_lpt;
c->superblock_need_write = 1;
}
if (!c->ro_mount && c->superblock_need_write) {
err = ubifs_write_sb_node(c, c->sup_node);
if (err)
goto out_lpt;
c->superblock_need_write = 0;
}
err = dbg_check_idx_size(c, c->bi.old_idx_sz); err = dbg_check_idx_size(c, c->bi.old_idx_sz);
if (err) if (err)
goto out_lpt; goto out_lpt;
...@@ -1642,15 +1665,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1642,15 +1665,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
if (err) if (err)
goto out; goto out;
if (c->old_leb_cnt != c->leb_cnt) {
struct ubifs_sb_node *sup = c->sup_node;
sup->leb_cnt = cpu_to_le32(c->leb_cnt);
err = ubifs_write_sb_node(c, sup);
if (err)
goto out;
}
if (c->need_recovery) { if (c->need_recovery) {
ubifs_msg(c, "completing deferred recovery"); ubifs_msg(c, "completing deferred recovery");
err = ubifs_write_rcvrd_mst_node(c); err = ubifs_write_rcvrd_mst_node(c);
...@@ -1682,6 +1696,16 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1682,6 +1696,16 @@ static int ubifs_remount_rw(struct ubifs_info *c)
goto out; goto out;
} }
if (c->superblock_need_write) {
struct ubifs_sb_node *sup = c->sup_node;
err = ubifs_write_sb_node(c, sup);
if (err)
goto out;
c->superblock_need_write = 0;
}
c->ileb_buf = vmalloc(c->leb_size); c->ileb_buf = vmalloc(c->leb_size);
if (!c->ileb_buf) { if (!c->ileb_buf) {
err = -ENOMEM; err = -ENOMEM;
......
...@@ -1158,8 +1158,8 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c, ...@@ -1158,8 +1158,8 @@ static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
* o exact match, i.e. the found zero-level znode contains key @key, then %1 * o exact match, i.e. the found zero-level znode contains key @key, then %1
* is returned and slot number of the matched branch is stored in @n; * is returned and slot number of the matched branch is stored in @n;
* o not exact match, which means that zero-level znode does not contain * o not exact match, which means that zero-level znode does not contain
* @key, then %0 is returned and slot number of the closest branch is stored * @key, then %0 is returned and slot number of the closest branch or %-1
* in @n; * is stored in @n; In this case calling tnc_next() is mandatory.
* o @key is so small that it is even less than the lowest key of the * o @key is so small that it is even less than the lowest key of the
* leftmost zero-level node, then %0 is returned and %0 is stored in @n. * leftmost zero-level node, then %0 is returned and %0 is stored in @n.
* *
...@@ -1882,13 +1882,19 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1882,13 +1882,19 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key, static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_dent_node *dent, uint32_t cookie, struct ubifs_dent_node *dent, uint32_t cookie,
struct ubifs_znode **zn, int *n) struct ubifs_znode **zn, int *n, int exact)
{ {
int err; int err;
struct ubifs_znode *znode = *zn; struct ubifs_znode *znode = *zn;
struct ubifs_zbranch *zbr; struct ubifs_zbranch *zbr;
union ubifs_key *dkey; union ubifs_key *dkey;
if (!exact) {
err = tnc_next(c, &znode, n);
if (err)
return err;
}
for (;;) { for (;;) {
zbr = &znode->zbranch[*n]; zbr = &znode->zbranch[*n];
dkey = &zbr->key; dkey = &zbr->key;
...@@ -1930,7 +1936,7 @@ static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1930,7 +1936,7 @@ static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
if (unlikely(err < 0)) if (unlikely(err < 0))
goto out_unlock; goto out_unlock;
err = search_dh_cookie(c, key, dent, cookie, &znode, &n); err = search_dh_cookie(c, key, dent, cookie, &znode, &n, err);
out_unlock: out_unlock:
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);
...@@ -2723,7 +2729,7 @@ int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2723,7 +2729,7 @@ int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
if (unlikely(err < 0)) if (unlikely(err < 0))
goto out_free; goto out_free;
err = search_dh_cookie(c, key, dent, cookie, &znode, &n); err = search_dh_cookie(c, key, dent, cookie, &znode, &n, err);
if (err) if (err)
goto out_free; goto out_free;
} }
......
...@@ -275,6 +275,8 @@ enum { ...@@ -275,6 +275,8 @@ enum {
#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) #define UBIFS_AUTH_NODE_SZ sizeof(struct ubifs_auth_node)
#define UBIFS_SIG_NODE_SZ sizeof(struct ubifs_sig_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 */
...@@ -301,6 +303,8 @@ enum { ...@@ -301,6 +303,8 @@ enum {
*/ */
#define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c" #define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
/* Type field in ubifs_sig_node */
#define UBIFS_SIGNATURE_TYPE_PKCS7 1
/* /*
* On-flash inode flags. * On-flash inode flags.
...@@ -336,12 +340,14 @@ enum { ...@@ -336,12 +340,14 @@ enum {
* UBIFS_COMPR_NONE: no compression * UBIFS_COMPR_NONE: no compression
* UBIFS_COMPR_LZO: LZO compression * UBIFS_COMPR_LZO: LZO compression
* UBIFS_COMPR_ZLIB: ZLIB compression * UBIFS_COMPR_ZLIB: ZLIB compression
* UBIFS_COMPR_ZSTD: ZSTD compression
* UBIFS_COMPR_TYPES_CNT: count of supported compression types * UBIFS_COMPR_TYPES_CNT: count of supported compression types
*/ */
enum { enum {
UBIFS_COMPR_NONE, UBIFS_COMPR_NONE,
UBIFS_COMPR_LZO, UBIFS_COMPR_LZO,
UBIFS_COMPR_ZLIB, UBIFS_COMPR_ZLIB,
UBIFS_COMPR_ZSTD,
UBIFS_COMPR_TYPES_CNT, UBIFS_COMPR_TYPES_CNT,
}; };
...@@ -361,6 +367,7 @@ enum { ...@@ -361,6 +367,7 @@ enum {
* 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_AUTH_NODE: authentication node
* UBIFS_SIG_NODE: signature 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.
...@@ -381,6 +388,7 @@ enum { ...@@ -381,6 +388,7 @@ enum {
UBIFS_CS_NODE, UBIFS_CS_NODE,
UBIFS_ORPH_NODE, UBIFS_ORPH_NODE,
UBIFS_AUTH_NODE, UBIFS_AUTH_NODE,
UBIFS_SIG_NODE,
UBIFS_NODE_TYPES_CNT, UBIFS_NODE_TYPES_CNT,
}; };
...@@ -638,6 +646,8 @@ struct ubifs_pad_node { ...@@ -638,6 +646,8 @@ struct ubifs_pad_node {
* @hmac_wkm: HMAC of a well known message (the string "UBIFS") as a convenience * @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. * 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) * @hash_algo: The hash algo used for this filesystem (one of enum hash_algo)
* @hash_mst: hash of the master node, only valid for signed images in which the
* master node does not contain a hmac
*/ */
struct ubifs_sb_node { struct ubifs_sb_node {
struct ubifs_ch ch; struct ubifs_ch ch;
...@@ -668,7 +678,8 @@ struct ubifs_sb_node { ...@@ -668,7 +678,8 @@ struct ubifs_sb_node {
__u8 hmac[UBIFS_MAX_HMAC_LEN]; __u8 hmac[UBIFS_MAX_HMAC_LEN];
__u8 hmac_wkm[UBIFS_MAX_HMAC_LEN]; __u8 hmac_wkm[UBIFS_MAX_HMAC_LEN];
__le16 hash_algo; __le16 hash_algo;
__u8 padding2[3838]; __u8 hash_mst[UBIFS_MAX_HASH_LEN];
__u8 padding2[3774];
} __packed; } __packed;
/** /**
...@@ -770,6 +781,23 @@ struct ubifs_auth_node { ...@@ -770,6 +781,23 @@ struct ubifs_auth_node {
__u8 hmac[]; __u8 hmac[];
} __packed; } __packed;
/**
* struct ubifs_sig_node - node for signing other nodes
* @ch: common header
* @type: type of the signature, currently only UBIFS_SIGNATURE_TYPE_PKCS7
* supported
* @len: The length of the signature data
* @padding: reserved for future, zeroes
* @sig: The signature data
*/
struct ubifs_sig_node {
struct ubifs_ch ch;
__le32 type;
__le32 len;
__u8 padding[32];
__u8 sig[];
} __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
......
...@@ -1104,7 +1104,6 @@ struct ubifs_debug_info; ...@@ -1104,7 +1104,6 @@ struct ubifs_debug_info;
* used to store indexing nodes (@leb_size - @max_idx_node_sz) * used to store indexing nodes (@leb_size - @max_idx_node_sz)
* @leb_cnt: count of logical eraseblocks * @leb_cnt: count of logical eraseblocks
* @max_leb_cnt: maximum count of logical eraseblocks * @max_leb_cnt: maximum count of logical eraseblocks
* @old_leb_cnt: count of logical eraseblocks before re-size
* @ro_media: the underlying UBI volume is read-only * @ro_media: the underlying UBI volume is read-only
* @ro_mount: the file-system was mounted as read-only * @ro_mount: the file-system was mounted as read-only
* @ro_error: UBIFS switched to R/O mode because an error happened * @ro_error: UBIFS switched to R/O mode because an error happened
...@@ -1295,6 +1294,7 @@ struct ubifs_info { ...@@ -1295,6 +1294,7 @@ struct ubifs_info {
unsigned int rw_incompat:1; unsigned int rw_incompat:1;
unsigned int assert_action:2; unsigned int assert_action:2;
unsigned int authenticated:1; unsigned int authenticated:1;
unsigned int superblock_need_write:1;
struct mutex tnc_mutex; struct mutex tnc_mutex;
struct ubifs_zbranch zroot; struct ubifs_zbranch zroot;
...@@ -1352,7 +1352,6 @@ struct ubifs_info { ...@@ -1352,7 +1352,6 @@ struct ubifs_info {
int idx_leb_size; int idx_leb_size;
int leb_cnt; int leb_cnt;
int max_leb_cnt; int max_leb_cnt;
int old_leb_cnt;
unsigned int ro_media:1; unsigned int ro_media:1;
unsigned int ro_mount:1; unsigned int ro_mount:1;
unsigned int ro_error:1; unsigned int ro_error:1;
...@@ -1680,6 +1679,9 @@ static inline int ubifs_auth_node_sz(const struct ubifs_info *c) ...@@ -1680,6 +1679,9 @@ static inline int ubifs_auth_node_sz(const struct ubifs_info *c)
else else
return 0; return 0;
} }
int ubifs_sb_verify_signature(struct ubifs_info *c,
const struct ubifs_sb_node *sup);
bool ubifs_hmac_zero(struct ubifs_info *c, const u8 *hmac);
int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac); int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac);
......
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