Skip to content

Commit 74836ec

Browse files
committed
fsverity: rework fsverity_get_digest() again
Address several issues with the calling convention and documentation of fsverity_get_digest(): - Make it provide the hash algorithm as either a FS_VERITY_HASH_ALG_* value or HASH_ALGO_* value, at the caller's choice, rather than only a HASH_ALGO_* value as it did before. This allows callers to work with the fsverity native algorithm numbers if they want to. HASH_ALGO_* is what IMA uses, but other users (e.g. overlayfs) should use FS_VERITY_HASH_ALG_* to match fsverity-utils and the fsverity UAPI. - Make it return the digest size so that it doesn't need to be looked up separately. Use the return value for this, since 0 works nicely for the "file doesn't have fsverity enabled" case. This also makes it clear that no other errors are possible. - Rename the 'digest' parameter to 'raw_digest' and clearly document that it is only useful in combination with the algorithm ID. This hopefully clears up a point of confusion. - Export it to modules, since overlayfs will need it for checking the fsverity digests of lowerdata files (https://lore.kernel.org/r/dd294a44e8f401e6b5140029d8355f88748cd8fd.1686565330.git.alexl@redhat.com). Acked-by: Mimi Zohar <zohar@linux.ibm.com> # for the IMA piece Link: https://lore.kernel.org/r/20230612190047.59755-1-ebiggers@kernel.org Signed-off-by: Eric Biggers <ebiggers@google.com>
1 parent 13e2408 commit 74836ec

File tree

3 files changed

+47
-35
lines changed

3 files changed

+47
-35
lines changed

fs/verity/measure.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,42 @@ EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);
6161
/**
6262
* fsverity_get_digest() - get a verity file's digest
6363
* @inode: inode to get digest of
64-
* @digest: (out) pointer to the digest
65-
* @alg: (out) pointer to the hash algorithm enumeration
64+
* @raw_digest: (out) the raw file digest
65+
* @alg: (out) the digest's algorithm, as a FS_VERITY_HASH_ALG_* value
66+
* @halg: (out) the digest's algorithm, as a HASH_ALGO_* value
6667
*
67-
* Return the file hash algorithm and digest of an fsverity protected file.
68-
* Assumption: before calling this, the file must have been opened.
68+
* Retrieves the fsverity digest of the given file. The file must have been
69+
* opened at least once since the inode was last loaded into the inode cache;
70+
* otherwise this function will not recognize when fsverity is enabled.
6971
*
70-
* Return: 0 on success, -errno on failure
72+
* The file's fsverity digest consists of @raw_digest in combination with either
73+
* @alg or @halg. (The caller can choose which one of @alg or @halg to use.)
74+
*
75+
* IMPORTANT: Callers *must* make use of one of the two algorithm IDs, since
76+
* @raw_digest is meaningless without knowing which algorithm it uses! fsverity
77+
* provides no security guarantee for users who ignore the algorithm ID, even if
78+
* they use the digest size (since algorithms can share the same digest size).
79+
*
80+
* Return: The size of the raw digest in bytes, or 0 if the file doesn't have
81+
* fsverity enabled.
7182
*/
7283
int fsverity_get_digest(struct inode *inode,
73-
u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
74-
enum hash_algo *alg)
84+
u8 raw_digest[FS_VERITY_MAX_DIGEST_SIZE],
85+
u8 *alg, enum hash_algo *halg)
7586
{
7687
const struct fsverity_info *vi;
7788
const struct fsverity_hash_alg *hash_alg;
7889

7990
vi = fsverity_get_info(inode);
8091
if (!vi)
81-
return -ENODATA; /* not a verity file */
92+
return 0; /* not a verity file */
8293

8394
hash_alg = vi->tree_params.hash_alg;
84-
memcpy(digest, vi->file_digest, hash_alg->digest_size);
85-
*alg = hash_alg->algo_id;
86-
return 0;
95+
memcpy(raw_digest, vi->file_digest, hash_alg->digest_size);
96+
if (alg)
97+
*alg = hash_alg - fsverity_hash_algs;
98+
if (halg)
99+
*halg = hash_alg->algo_id;
100+
return hash_alg->digest_size;
87101
}
102+
EXPORT_SYMBOL_GPL(fsverity_get_digest);

include/linux/fsverity.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *arg);
143143

144144
int fsverity_ioctl_measure(struct file *filp, void __user *arg);
145145
int fsverity_get_digest(struct inode *inode,
146-
u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
147-
enum hash_algo *alg);
146+
u8 raw_digest[FS_VERITY_MAX_DIGEST_SIZE],
147+
u8 *alg, enum hash_algo *halg);
148148

149149
/* open.c */
150150

@@ -197,10 +197,14 @@ static inline int fsverity_ioctl_measure(struct file *filp, void __user *arg)
197197
}
198198

199199
static inline int fsverity_get_digest(struct inode *inode,
200-
u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
201-
enum hash_algo *alg)
200+
u8 raw_digest[FS_VERITY_MAX_DIGEST_SIZE],
201+
u8 *alg, enum hash_algo *halg)
202202
{
203-
return -EOPNOTSUPP;
203+
/*
204+
* fsverity is not enabled in the kernel configuration, so always report
205+
* that the file doesn't have fsverity enabled (digest size 0).
206+
*/
207+
return 0;
204208
}
205209

206210
/* open.c */

security/integrity/ima/ima_api.c

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -202,19 +202,19 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
202202
allowed_algos);
203203
}
204204

205-
static int ima_get_verity_digest(struct integrity_iint_cache *iint,
206-
struct ima_max_digest_data *hash)
205+
static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
206+
struct ima_max_digest_data *hash)
207207
{
208-
enum hash_algo verity_alg;
209-
int ret;
208+
enum hash_algo alg;
209+
int digest_len;
210210

211211
/*
212212
* On failure, 'measure' policy rules will result in a file data
213213
* hash containing 0's.
214214
*/
215-
ret = fsverity_get_digest(iint->inode, hash->digest, &verity_alg);
216-
if (ret)
217-
return ret;
215+
digest_len = fsverity_get_digest(iint->inode, hash->digest, NULL, &alg);
216+
if (digest_len == 0)
217+
return false;
218218

219219
/*
220220
* Unlike in the case of actually calculating the file hash, in
@@ -223,9 +223,9 @@ static int ima_get_verity_digest(struct integrity_iint_cache *iint,
223223
* mismatch between the verity algorithm and the xattr signature
224224
* algorithm, if one exists, will be detected later.
225225
*/
226-
hash->hdr.algo = verity_alg;
227-
hash->hdr.length = hash_digest_size[verity_alg];
228-
return 0;
226+
hash->hdr.algo = alg;
227+
hash->hdr.length = digest_len;
228+
return true;
229229
}
230230

231231
/*
@@ -276,16 +276,9 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
276276
memset(&hash.digest, 0, sizeof(hash.digest));
277277

278278
if (iint->flags & IMA_VERITY_REQUIRED) {
279-
result = ima_get_verity_digest(iint, &hash);
280-
switch (result) {
281-
case 0:
282-
break;
283-
case -ENODATA:
279+
if (!ima_get_verity_digest(iint, &hash)) {
284280
audit_cause = "no-verity-digest";
285-
break;
286-
default:
287-
audit_cause = "invalid-verity-digest";
288-
break;
281+
result = -ENODATA;
289282
}
290283
} else if (buf) {
291284
result = ima_calc_buffer_hash(buf, size, &hash.hdr);

0 commit comments

Comments
 (0)