Skip to content

Commit

Permalink
Merge tag 'upstream-5.3-rc1' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/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()
  • Loading branch information
Linus Torvalds committed Jul 15, 2019
2 parents f2772a0 + 8009ce9 commit a318423
Show file tree
Hide file tree
Showing 12 changed files with 338 additions and 92 deletions.
13 changes: 12 additions & 1 deletion fs/ubifs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
86 changes: 86 additions & 0 deletions fs/ubifs/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
27 changes: 26 additions & 1 deletion fs/ubifs/compress.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -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;
Expand All @@ -235,4 +259,5 @@ void ubifs_compressors_exit(void)
{
compr_exit(&lzo_compr);
compr_exit(&zlib_compr);
compr_exit(&zstd_compr);
}
5 changes: 1 addition & 4 deletions fs/ubifs/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
53 changes: 47 additions & 6 deletions fs/ubifs/master.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
Loading

0 comments on commit a318423

Please sign in to comment.