Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a318423b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+12 −1
Original line number Original line Diff line number Diff line
@@ -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
	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


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.
+86 −0
Original line number Original line Diff line number Diff line
@@ -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,
	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)
		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);
}
+26 −1
Original line number Original line Diff line number Diff line
@@ -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)
	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)
{
{
	compr_exit(&lzo_compr);
	compr_exit(&lzo_compr);
	compr_exit(&zlib_compr);
	compr_exit(&zlib_compr);
	compr_exit(&zstd_compr);
}
}
+1 −4
Original line number Original line Diff line number Diff line
@@ -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);


+47 −6
Original line number Original line Diff line number Diff line
@@ -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)
	if (!ubifs_authenticated(c))
	if (!ubifs_authenticated(c))
		return 0;
		return 0;


	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,
		err = ubifs_node_verify_hmac(c, c->mst_node,
					sizeof(struct ubifs_mst_node),
					sizeof(struct ubifs_mst_node),
					offsetof(struct ubifs_mst_node, hmac));
					offsetof(struct ubifs_mst_node, hmac));
	if (err) {
		if (err)
			ubifs_err(c, "Failed to verify master node HMAC");
			ubifs_err(c, "Failed to verify master node HMAC");
		return -EPERM;
	}
	}


	if (err)
		return -EPERM;

	return 0;
	return 0;


out:
out:
Loading