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

Commit e158e02f authored by Sascha Hauer's avatar Sascha Hauer Committed by Richard Weinberger
Browse files

ubifs: authentication: Authenticate super block node



This adds a HMAC covering the super block node and adds the logic that
decides if a filesystem shall be mounted unauthenticated or
authenticated.

Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent b5b1f083
Loading
Loading
Loading
Loading
+69 −1
Original line number Diff line number Diff line
@@ -517,6 +517,65 @@ static struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
	return sup;
}

static int authenticate_sb_node(struct ubifs_info *c,
				const struct ubifs_sb_node *sup)
{
	unsigned int sup_flags = le32_to_cpu(sup->flags);
	u8 hmac_wkm[UBIFS_HMAC_ARR_SZ];
	int authenticated = !!(sup_flags & UBIFS_FLG_AUTHENTICATION);
	int hash_algo;
	int err;

	if (c->authenticated && !authenticated) {
		ubifs_err(c, "authenticated FS forced, but found FS without authentication");
		return -EINVAL;
	}

	if (!c->authenticated && authenticated) {
		ubifs_err(c, "authenticated FS found, but no key given");
		return -EINVAL;
	}

	ubifs_msg(c, "Mounting in %sauthenticated mode",
		  c->authenticated ? "" : "un");

	if (!c->authenticated)
		return 0;

	if (!IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION))
		return -EOPNOTSUPP;

	hash_algo = le16_to_cpu(sup->hash_algo);
	if (hash_algo >= HASH_ALGO__LAST) {
		ubifs_err(c, "superblock uses unknown hash algo %d",
			  hash_algo);
		return -EINVAL;
	}

	if (strcmp(hash_algo_name[hash_algo], c->auth_hash_name)) {
		ubifs_err(c, "This filesystem uses %s for hashing,"
			     " but %s is specified", hash_algo_name[hash_algo],
			     c->auth_hash_name);
		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;
	}

	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);

	return err;
}

/**
 * ubifs_write_sb_node - write superblock node.
 * @c: UBIFS file-system description object
@@ -527,8 +586,13 @@ static struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup)
{
	int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
	int err;

	err = ubifs_prepare_node_hmac(c, sup, UBIFS_SB_NODE_SZ,
				      offsetof(struct ubifs_sb_node, hmac), 1);
	if (err)
		return err;

	ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1);
	return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len);
}

@@ -642,6 +706,10 @@ int ubifs_read_superblock(struct ubifs_info *c)
	c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
	c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);

	err = authenticate_sb_node(c, sup);
	if (err)
		goto out;

	if ((sup_flags & ~UBIFS_FLG_MASK) != 0) {
		ubifs_err(c, "Unknown feature flags found: %#x",
			  sup_flags & ~UBIFS_FLG_MASK);