cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

crc-t10dif.c (3232B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * T10 Data Integrity Field CRC16 calculation
      4 *
      5 * Copyright (c) 2007 Oracle Corporation.  All rights reserved.
      6 * Written by Martin K. Petersen <martin.petersen@oracle.com>
      7 */
      8
      9#include <linux/types.h>
     10#include <linux/module.h>
     11#include <linux/crc-t10dif.h>
     12#include <linux/err.h>
     13#include <linux/init.h>
     14#include <crypto/hash.h>
     15#include <crypto/algapi.h>
     16#include <linux/static_key.h>
     17#include <linux/notifier.h>
     18
     19static struct crypto_shash __rcu *crct10dif_tfm;
     20static DEFINE_STATIC_KEY_TRUE(crct10dif_fallback);
     21static DEFINE_MUTEX(crc_t10dif_mutex);
     22static struct work_struct crct10dif_rehash_work;
     23
     24static int crc_t10dif_notify(struct notifier_block *self, unsigned long val, void *data)
     25{
     26	struct crypto_alg *alg = data;
     27
     28	if (val != CRYPTO_MSG_ALG_LOADED ||
     29	    strcmp(alg->cra_name, CRC_T10DIF_STRING))
     30		return NOTIFY_DONE;
     31
     32	schedule_work(&crct10dif_rehash_work);
     33	return NOTIFY_OK;
     34}
     35
     36static void crc_t10dif_rehash(struct work_struct *work)
     37{
     38	struct crypto_shash *new, *old;
     39
     40	mutex_lock(&crc_t10dif_mutex);
     41	old = rcu_dereference_protected(crct10dif_tfm,
     42					lockdep_is_held(&crc_t10dif_mutex));
     43	new = crypto_alloc_shash(CRC_T10DIF_STRING, 0, 0);
     44	if (IS_ERR(new)) {
     45		mutex_unlock(&crc_t10dif_mutex);
     46		return;
     47	}
     48	rcu_assign_pointer(crct10dif_tfm, new);
     49	mutex_unlock(&crc_t10dif_mutex);
     50
     51	if (old) {
     52		synchronize_rcu();
     53		crypto_free_shash(old);
     54	} else {
     55		static_branch_disable(&crct10dif_fallback);
     56	}
     57}
     58
     59static struct notifier_block crc_t10dif_nb = {
     60	.notifier_call = crc_t10dif_notify,
     61};
     62
     63__u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len)
     64{
     65	struct {
     66		struct shash_desc shash;
     67		__u16 crc;
     68	} desc;
     69	int err;
     70
     71	if (static_branch_unlikely(&crct10dif_fallback))
     72		return crc_t10dif_generic(crc, buffer, len);
     73
     74	rcu_read_lock();
     75	desc.shash.tfm = rcu_dereference(crct10dif_tfm);
     76	desc.crc = crc;
     77	err = crypto_shash_update(&desc.shash, buffer, len);
     78	rcu_read_unlock();
     79
     80	BUG_ON(err);
     81
     82	return desc.crc;
     83}
     84EXPORT_SYMBOL(crc_t10dif_update);
     85
     86__u16 crc_t10dif(const unsigned char *buffer, size_t len)
     87{
     88	return crc_t10dif_update(0, buffer, len);
     89}
     90EXPORT_SYMBOL(crc_t10dif);
     91
     92static int __init crc_t10dif_mod_init(void)
     93{
     94	INIT_WORK(&crct10dif_rehash_work, crc_t10dif_rehash);
     95	crypto_register_notifier(&crc_t10dif_nb);
     96	crc_t10dif_rehash(&crct10dif_rehash_work);
     97	return 0;
     98}
     99
    100static void __exit crc_t10dif_mod_fini(void)
    101{
    102	crypto_unregister_notifier(&crc_t10dif_nb);
    103	cancel_work_sync(&crct10dif_rehash_work);
    104	crypto_free_shash(rcu_dereference_protected(crct10dif_tfm, 1));
    105}
    106
    107module_init(crc_t10dif_mod_init);
    108module_exit(crc_t10dif_mod_fini);
    109
    110static int crc_t10dif_transform_show(char *buffer, const struct kernel_param *kp)
    111{
    112	struct crypto_shash *tfm;
    113	int len;
    114
    115	if (static_branch_unlikely(&crct10dif_fallback))
    116		return sprintf(buffer, "fallback\n");
    117
    118	rcu_read_lock();
    119	tfm = rcu_dereference(crct10dif_tfm);
    120	len = snprintf(buffer, PAGE_SIZE, "%s\n",
    121		       crypto_shash_driver_name(tfm));
    122	rcu_read_unlock();
    123
    124	return len;
    125}
    126
    127module_param_call(transform, NULL, crc_t10dif_transform_show, NULL, 0444);
    128
    129MODULE_DESCRIPTION("T10 DIF CRC calculation (library API)");
    130MODULE_LICENSE("GPL");
    131MODULE_SOFTDEP("pre: crct10dif");