+ */
+int digest_cache_add(struct digest_cache *digest_cache, u8 *digest)
+{
+ struct digest_cache_entry *entry;
+ unsigned int key;
+ int digest_len;
+
+ if (!digest_cache)
+ return 0;
+
+ digest_len = hash_digest_size[digest_cache->algo];
+
+ entry = kmalloc(sizeof(*entry) + digest_len, GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ memcpy(entry->digest, digest, digest_len);
+
+ key = digest_cache_hash_key(digest, digest_cache->num_slots);
+ hlist_add_head(&entry->hnext, &digest_cache->slots[key]);
+ pr_debug("Add digest %s:%*phN from digest list %s\n",
+ hash_algo_name[digest_cache->algo], digest_len, digest,
+ digest_cache->path_str);
+ return 0;
+}
+
+/**
+ * digest_cache_lookup - Searches a digest in the digest cache
+ * @digest_cache: Digest cache
+ * @digest: Digest to search
+ * @algo: Algorithm of the digest to search
+ * @pathname: Path of the file whose digest is looked up
+ *
+ * This function, invoked by IMA or EVM, searches the calculated digest of
+ * a file or file metadata in the digest cache acquired with
+ * digest_cache_get().
+ *
+ * Return: Zero if the digest is found, a negative value if not.
+ */
+int digest_cache_lookup(struct digest_cache *digest_cache, u8 *digest,
+ enum hash_algo algo, const char *pathname)
+{
+ struct digest_cache_entry *entry;
+ unsigned int key;
+ int digest_len;
+ int search_depth = 0;
+
+ if (!digest_cache)
+ return -ENOENT;
+
+ if (digest_cache->algo == HASH_ALGO__LAST) {
+ pr_debug("Algorithm not set for digest list %s\n",
+ digest_cache->path_str);
+ return -ENOENT;
+ }
+
+ digest_len = hash_digest_size[digest_cache->algo];
+
+ if (algo != digest_cache->algo) {
+ pr_debug("Algo mismatch for file %s, digest %s:%*phN in digest list %s (%s)\n",
+ pathname, hash_algo_name[algo], digest_len, digest,
+ digest_cache->path_str,
+ hash_algo_name[digest_cache->algo]);
+ return -ENOENT;
+ }
+
+ key = digest_cache_hash_key(digest, digest_cache->num_slots);
+
+ hlist_for_each_entry_rcu(entry, &digest_cache->slots[key], hnext) {
+ if (!memcmp(entry->digest, digest, digest_len)) {
+ pr_debug("Cache hit at depth %d for file %s, digest %s:%*phN in digest list %s\n",
+ search_depth, pathname, hash_algo_name[algo],
+ digest_len, digest, digest_cache->path_str);
+ return 0;
+ }
+
+ search_depth++;
+ }
+
+ pr_debug("Cache miss for file %s, digest %s:%*phN in digest list %s\n",
+ pathname, hash_algo_name[algo], digest_len, digest,
+ digest_cache->path_str);
+ return -ENOENT;
+}
diff --git a/security/integrity/digest_cache.h b/security/integrity/digest_cache.h
index ff88e8593c6..01cd70f9850 100644
--- a/security/integrity/digest_cache.h
+++ b/security/integrity/digest_cache.h
@@ -66,6 +66,11 @@ static inline unsigned int digest_cache_hash_key(u8 *digest,
void digest_cache_free(struct digest_cache *digest_cache);
struct digest_cache *digest_cache_get(struct dentry *dentry,
struct integrity_iint_cache *iint);
+int digest_cache_init_htable(struct digest_cache *digest_cache,
+ u64 num_digests);
+int digest_cache_add(struct digest_cache *digest_cache, u8 *digest);
+int digest_cache_lookup(struct digest_cache *digest_cache, u8 *digest,
+ enum hash_algo algo, const char *pathname);
#else
static inline void digest_cache_free(struct digest_cache *digest_cache)
{
@@ -77,5 +82,24 @@ digest_cache_get(struct dentry *dentry, struct integrity_iint_cache *iint)
return NULL;
}
+static inline int digest_cache_init_htable(struct digest_cache *digest_cache,
+ u64 num_digests)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int digest_cache_add(struct digest_cache *digest_cache,
+ u8 *digest)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int digest_cache_lookup(struct digest_cache *digest_cache,
+ u8 *digest, enum hash_algo algo,
+ const char *pathname)
+{
+ return -ENOENT;
+}
+
#endif /* CONFIG_INTEGRITY_DIGEST_CACHE */
#endif /* _DIGEST_CACHE_H */
--
2.34.1