mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-04 11:24:04 +08:00
This pull request contains the following changes for UBIFS
- Support for zstd compression - Support for offline signed filesystems - Various fixes for regressions -----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEdgfidid8lnn52cLTZvlZhesYu8EFAl0reJsWHHJpY2hhcmRA c2lnbWEtc3Rhci5hdAAKCRBm+VmF6xi7wTcMD/0XMJTpaPcw2oAvlWld8i223qIe 5cwrtDD8JU1/3LXaFf0cfFhT8SklH+X0UgEVorfLVSNZwmpym8I8PxKTxZ5thc4V tVvVC8PqVel/2jXXzxSKJUNclzI1eCBMhC0dC2Sdl2FnoTTRyKBT9H2eKdZD8wCd 4SWrTv1f9RAwTerPF1r7LaTXXreAdQYXxpVFAJBiV8+K+7VHiC+PLb3SgcRazayc kJnG8pF/IHiqSVBmzbLwX+5RRuRmS7wbTu4OcBNEyq9jy5/w7gmgCW3uQhownuo+ +4hEE/4d4yJb8cybYVrRLxUslv/EuB8aLhZ/bvi+D6eDNXBU/VANtWSZU63GCseD PC4RYAPAGfBWi/o7Rs+xm2Kxr8FIW4q9WHtM7j0fElcwIbR+nckQRrEJ13kFuFs7 1TWbpd0Y0v/Ip+Xcut19Gaxap1Yk04JK9wvqLmfHxOqdkznJWKpQ3pAlsXtFfTZv DODYkTFfbp2z1tXZHN4Fu/aZ2w2/Rx/OKci8XIa3Fe2VgyZccm4G+6zl1HICbmKl /3jmcDi7E6OlFnv2ujDVQC3fA2CiqEgBCVx9E+bxzHROvdWXIrbU9RTiqMDKtYcc FD8HJI9PXefxy+Ca0gCf5MA31ION0+TFyP+udeU1SIGm8n/SX8u0FEbm9bOs6kWT NIZjp0wlQQg4bTq4lg== =rllw -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
a318423b61
@ -6,8 +6,10 @@ config UBIFS_FS
|
||||
select CRYPTO if UBIFS_FS_ADVANCED_COMPR
|
||||
select CRYPTO if UBIFS_FS_LZO
|
||||
select CRYPTO if UBIFS_FS_ZLIB
|
||||
select CRYPTO if UBIFS_FS_ZSTD
|
||||
select CRYPTO_LZO if UBIFS_FS_LZO
|
||||
select CRYPTO_DEFLATE if UBIFS_FS_ZLIB
|
||||
select CRYPTO_ZSTD if UBIFS_FS_ZSTD
|
||||
select CRYPTO_HASH_INFO
|
||||
select UBIFS_FS_XATTR if FS_ENCRYPTION
|
||||
depends on MTD_UBI
|
||||
@ -38,6 +40,14 @@ config UBIFS_FS_ZLIB
|
||||
help
|
||||
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
|
||||
bool "Access time support"
|
||||
default n
|
||||
@ -77,8 +87,9 @@ config UBIFS_FS_SECURITY
|
||||
|
||||
config UBIFS_FS_AUTHENTICATION
|
||||
bool "UBIFS authentication support"
|
||||
depends on KEYS
|
||||
select KEYS
|
||||
select CRYPTO_HMAC
|
||||
select SYSTEM_DATA_VERIFICATION
|
||||
help
|
||||
Enable authentication support for UBIFS. This feature offers protection
|
||||
against offline changes for both data and metadata of the filesystem.
|
||||
|
@ -10,10 +10,12 @@
|
||||
*/
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/verification.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <keys/user-type.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
|
||||
#include "ubifs.h"
|
||||
|
||||
@ -198,6 +200,77 @@ int __ubifs_node_check_hash(const struct ubifs_info *c, const void *node,
|
||||
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
|
||||
* @c: UBIFS file-system description object
|
||||
@ -478,3 +551,16 @@ int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac)
|
||||
return err;
|
||||
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 = {
|
||||
};
|
||||
#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 */
|
||||
struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
|
||||
|
||||
@ -216,13 +234,19 @@ int __init ubifs_compressors_init(void)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = compr_init(&zlib_compr);
|
||||
err = compr_init(&zstd_compr);
|
||||
if (err)
|
||||
goto out_lzo;
|
||||
|
||||
err = compr_init(&zlib_compr);
|
||||
if (err)
|
||||
goto out_zstd;
|
||||
|
||||
ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
|
||||
return 0;
|
||||
|
||||
out_zstd:
|
||||
compr_exit(&zstd_compr);
|
||||
out_lzo:
|
||||
compr_exit(&lzo_compr);
|
||||
return err;
|
||||
@ -235,4 +259,5 @@ void ubifs_compressors_exit(void)
|
||||
{
|
||||
compr_exit(&lzo_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)
|
||||
*ltail_lnum = c->lhead_lnum;
|
||||
|
||||
c->lhead_offs += len;
|
||||
if (c->lhead_offs == c->leb_size) {
|
||||
c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
|
||||
c->lhead_offs = 0;
|
||||
}
|
||||
ubifs_assert(c, c->lhead_offs < c->leb_size);
|
||||
|
||||
remove_buds(c);
|
||||
|
||||
|
@ -48,6 +48,39 @@ int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
|
||||
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.
|
||||
* @c: UBIFS file-system description object
|
||||
@ -102,14 +135,22 @@ static int scan_for_master(struct ubifs_info *c)
|
||||
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;
|
||||
if (ubifs_hmac_zero(c, c->mst_node->hmac)) {
|
||||
err = mst_node_check_hash(c, c->mst_node,
|
||||
c->sup_node->hash_mst);
|
||||
if (err)
|
||||
ubifs_err(c, "Failed to verify master node hash");
|
||||
} 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;
|
||||
|
||||
out:
|
||||
|
@ -126,25 +126,11 @@ static void __orphan_drop(struct ubifs_info *c, struct ubifs_orphan *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) {
|
||||
spin_unlock(&c->orphan_lock);
|
||||
dbg_gen("deleted twice ino %lu",
|
||||
(unsigned long)inum);
|
||||
dbg_gen("deleted twice ino %lu", orph->inum);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -153,19 +139,11 @@ static void orphan_delete(struct ubifs_info *c, ino_t inum)
|
||||
orph->dnext = c->orph_dnext;
|
||||
c->orph_dnext = orph;
|
||||
spin_unlock(&c->orphan_lock);
|
||||
dbg_gen("delete later ino %lu",
|
||||
(unsigned long)inum);
|
||||
dbg_gen("delete later ino %lu", orph->inum);
|
||||
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);
|
||||
|
||||
spin_unlock(&c->orphan_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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)
|
||||
{
|
||||
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,
|
||||
{
|
||||
struct ubifs_scan_node *snod;
|
||||
struct ubifs_orph_node *orph;
|
||||
struct ubifs_ino_node *ino = NULL;
|
||||
unsigned long long cmt_no;
|
||||
ino_t inum;
|
||||
int i, n, err, first = 1;
|
||||
@ -676,23 +675,40 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
|
||||
if (first)
|
||||
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;
|
||||
for (i = 0; i < n; i++) {
|
||||
union ubifs_key key1, key2;
|
||||
|
||||
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)
|
||||
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);
|
||||
if (err)
|
||||
return err;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
*last_cmt_no = cmt_no;
|
||||
@ -704,7 +720,15 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
|
||||
*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,
|
||||
goto out_err;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
|
||||
|
@ -578,17 +578,26 @@ static int authenticate_sb_node(struct ubifs_info *c,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
/*
|
||||
* The super block node can either be authenticated by a HMAC or
|
||||
* by a signature in a ubifs_sig_node directly following the
|
||||
* super block node to support offline image creation.
|
||||
*/
|
||||
if (ubifs_hmac_zero(c, sup->hmac)) {
|
||||
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)
|
||||
ubifs_err(c, "Failed to authenticate superblock: %d", err);
|
||||
|
||||
@ -744,21 +753,16 @@ int ubifs_read_superblock(struct ubifs_info *c)
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
int old_leb_cnt = c->leb_cnt;
|
||||
|
||||
c->leb_cnt = min_t(int, c->max_leb_cnt, c->vi.size);
|
||||
if (c->ro_mount)
|
||||
dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs",
|
||||
c->old_leb_cnt, c->leb_cnt);
|
||||
else {
|
||||
dbg_mnt("Auto resizing (sb) from %d LEBs to %d LEBs",
|
||||
c->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;
|
||||
}
|
||||
sup->leb_cnt = cpu_to_le32(c->leb_cnt);
|
||||
|
||||
c->superblock_need_write = 1;
|
||||
|
||||
dbg_mnt("Auto resizing from %d LEBs to %d LEBs",
|
||||
old_leb_cnt, c->leb_cnt);
|
||||
}
|
||||
|
||||
c->log_bytes = (long long)c->log_lebs * c->leb_size;
|
||||
@ -916,9 +920,7 @@ int ubifs_fixup_free_space(struct ubifs_info *c)
|
||||
c->space_fixup = 0;
|
||||
sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
|
||||
|
||||
err = ubifs_write_sb_node(c, sup);
|
||||
if (err)
|
||||
return err;
|
||||
c->superblock_need_write = 1;
|
||||
|
||||
ubifs_msg(c, "free space fixup complete");
|
||||
return err;
|
||||
|
@ -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].max_len = UBIFS_AUTH_NODE_SZ +
|
||||
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].max_len = UBIFS_MAX_INO_NODE_SZ;
|
||||
@ -1043,6 +1045,8 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
|
||||
c->mount_opts.compr_type = UBIFS_COMPR_LZO;
|
||||
else if (!strcmp(name, "zlib"))
|
||||
c->mount_opts.compr_type = UBIFS_COMPR_ZLIB;
|
||||
else if (!strcmp(name, "zstd"))
|
||||
c->mount_opts.compr_type = UBIFS_COMPR_ZSTD;
|
||||
else {
|
||||
ubifs_err(c, "unknown compressor \"%s\"", name); //FIXME: is c ready?
|
||||
kfree(name);
|
||||
@ -1296,8 +1300,7 @@ static int mount_ubifs(struct ubifs_info *c)
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
sz = ALIGN(c->max_idx_node_sz, c->min_io_size);
|
||||
sz = ALIGN(sz + c->max_idx_node_sz, c->min_io_size);
|
||||
sz = ALIGN(c->max_idx_node_sz, c->min_io_size) * 2;
|
||||
c->cbuf = kmalloc(sz, GFP_NOFS);
|
||||
if (!c->cbuf) {
|
||||
err = -ENOMEM;
|
||||
@ -1360,6 +1363,26 @@ static int mount_ubifs(struct ubifs_info *c)
|
||||
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);
|
||||
if (err)
|
||||
goto out_lpt;
|
||||
@ -1642,15 +1665,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
|
||||
if (err)
|
||||
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) {
|
||||
ubifs_msg(c, "completing deferred recovery");
|
||||
err = ubifs_write_rcvrd_mst_node(c);
|
||||
@ -1682,6 +1696,16 @@ static int ubifs_remount_rw(struct ubifs_info *c)
|
||||
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);
|
||||
if (!c->ileb_buf) {
|
||||
err = -ENOMEM;
|
||||
|
@ -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
|
||||
* 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
|
||||
* @key, then %0 is returned and slot number of the closest branch is stored
|
||||
* in @n;
|
||||
* @key, then %0 is returned and slot number of the closest branch or %-1
|
||||
* 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
|
||||
* 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,
|
||||
|
||||
static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key,
|
||||
struct ubifs_dent_node *dent, uint32_t cookie,
|
||||
struct ubifs_znode **zn, int *n)
|
||||
struct ubifs_znode **zn, int *n, int exact)
|
||||
{
|
||||
int err;
|
||||
struct ubifs_znode *znode = *zn;
|
||||
struct ubifs_zbranch *zbr;
|
||||
union ubifs_key *dkey;
|
||||
|
||||
if (!exact) {
|
||||
err = tnc_next(c, &znode, n);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
zbr = &znode->zbranch[*n];
|
||||
dkey = &zbr->key;
|
||||
@ -1930,7 +1936,7 @@ static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
|
||||
if (unlikely(err < 0))
|
||||
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:
|
||||
mutex_unlock(&c->tnc_mutex);
|
||||
@ -2723,7 +2729,7 @@ int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
|
||||
if (unlikely(err < 0))
|
||||
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)
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -275,6 +275,8 @@ enum {
|
||||
#define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node)
|
||||
#define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_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 */
|
||||
#define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ
|
||||
/* Only this does not have to be multiple of 8 bytes */
|
||||
@ -301,6 +303,8 @@ enum {
|
||||
*/
|
||||
#define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
|
||||
|
||||
/* Type field in ubifs_sig_node */
|
||||
#define UBIFS_SIGNATURE_TYPE_PKCS7 1
|
||||
|
||||
/*
|
||||
* On-flash inode flags.
|
||||
@ -336,12 +340,14 @@ enum {
|
||||
* UBIFS_COMPR_NONE: no compression
|
||||
* UBIFS_COMPR_LZO: LZO compression
|
||||
* UBIFS_COMPR_ZLIB: ZLIB compression
|
||||
* UBIFS_COMPR_ZSTD: ZSTD compression
|
||||
* UBIFS_COMPR_TYPES_CNT: count of supported compression types
|
||||
*/
|
||||
enum {
|
||||
UBIFS_COMPR_NONE,
|
||||
UBIFS_COMPR_LZO,
|
||||
UBIFS_COMPR_ZLIB,
|
||||
UBIFS_COMPR_ZSTD,
|
||||
UBIFS_COMPR_TYPES_CNT,
|
||||
};
|
||||
|
||||
@ -361,6 +367,7 @@ enum {
|
||||
* UBIFS_CS_NODE: commit start node
|
||||
* UBIFS_ORPH_NODE: orphan node
|
||||
* UBIFS_AUTH_NODE: authentication node
|
||||
* UBIFS_SIG_NODE: signature node
|
||||
* UBIFS_NODE_TYPES_CNT: count of supported node types
|
||||
*
|
||||
* Note, we index arrays by these numbers, so keep them low and contiguous.
|
||||
@ -381,6 +388,7 @@ enum {
|
||||
UBIFS_CS_NODE,
|
||||
UBIFS_ORPH_NODE,
|
||||
UBIFS_AUTH_NODE,
|
||||
UBIFS_SIG_NODE,
|
||||
UBIFS_NODE_TYPES_CNT,
|
||||
};
|
||||
|
||||
@ -638,6 +646,8 @@ struct ubifs_pad_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)
|
||||
* @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_ch ch;
|
||||
@ -668,7 +678,8 @@ struct ubifs_sb_node {
|
||||
__u8 hmac[UBIFS_MAX_HMAC_LEN];
|
||||
__u8 hmac_wkm[UBIFS_MAX_HMAC_LEN];
|
||||
__le16 hash_algo;
|
||||
__u8 padding2[3838];
|
||||
__u8 hash_mst[UBIFS_MAX_HASH_LEN];
|
||||
__u8 padding2[3774];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
@ -770,6 +781,23 @@ struct ubifs_auth_node {
|
||||
__u8 hmac[];
|
||||
} __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
|
||||
* @lnum: LEB number of the target node
|
||||
|
@ -1104,7 +1104,6 @@ struct ubifs_debug_info;
|
||||
* used to store indexing nodes (@leb_size - @max_idx_node_sz)
|
||||
* @leb_cnt: 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_mount: the file-system was mounted as read-only
|
||||
* @ro_error: UBIFS switched to R/O mode because an error happened
|
||||
@ -1295,6 +1294,7 @@ struct ubifs_info {
|
||||
unsigned int rw_incompat:1;
|
||||
unsigned int assert_action:2;
|
||||
unsigned int authenticated:1;
|
||||
unsigned int superblock_need_write:1;
|
||||
|
||||
struct mutex tnc_mutex;
|
||||
struct ubifs_zbranch zroot;
|
||||
@ -1352,7 +1352,6 @@ struct ubifs_info {
|
||||
int idx_leb_size;
|
||||
int leb_cnt;
|
||||
int max_leb_cnt;
|
||||
int old_leb_cnt;
|
||||
unsigned int ro_media:1;
|
||||
unsigned int ro_mount:1;
|
||||
unsigned int ro_error:1;
|
||||
@ -1680,6 +1679,9 @@ static inline int ubifs_auth_node_sz(const struct ubifs_info *c)
|
||||
else
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user