summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/opencrypto/cryptodev.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/opencrypto/cryptodev.c')
-rw-r--r--freebsd/sys/opencrypto/cryptodev.c124
1 files changed, 81 insertions, 43 deletions
diff --git a/freebsd/sys/opencrypto/cryptodev.c b/freebsd/sys/opencrypto/cryptodev.c
index 02a03034..d3f4ad1c 100644
--- a/freebsd/sys/opencrypto/cryptodev.c
+++ b/freebsd/sys/opencrypto/cryptodev.c
@@ -268,6 +268,7 @@ crypt_kop_to_32(const struct crypt_kop *from, struct crypt_kop32 *to)
struct csession {
TAILQ_ENTRY(csession) next;
crypto_session_t cses;
+ volatile u_int refs;
u_int32_t ses;
struct mtx lock; /* for op submission */
@@ -294,6 +295,7 @@ struct cryptop_data {
struct fcrypt {
TAILQ_HEAD(csessionlist, csession) csessions;
int sesn;
+ struct mtx lock;
};
static struct timeval warninterval = { .tv_sec = 60, .tv_usec = 0 };
@@ -330,8 +332,7 @@ static const rtems_filesystem_file_handlers_r cryptofops;
#endif /* __rtems__ */
static struct csession *csefind(struct fcrypt *, u_int);
-static int csedelete(struct fcrypt *, struct csession *);
-static struct csession *cseadd(struct fcrypt *, struct csession *);
+static bool csedelete(struct fcrypt *, u_int);
static struct csession *csecreate(struct fcrypt *, crypto_session_t, caddr_t,
u_int64_t, caddr_t, u_int64_t, u_int32_t, u_int32_t, struct enc_xform *,
struct auth_hash *);
@@ -398,8 +399,6 @@ cryptof_ioctl(
struct crypt_op copc;
struct crypt_kop kopc;
#endif
- static struct timeval arc4warn, blfwarn, castwarn, deswarn, md5warn;
- static struct timeval skipwarn, tdeswarn;
switch (cmd) {
case CIOCGSESSION:
@@ -420,28 +419,18 @@ cryptof_ioctl(
case 0:
break;
case CRYPTO_DES_CBC:
- if (ratecheck(&deswarn, &warninterval))
- gone_in(13, "DES cipher via /dev/crypto");
txform = &enc_xform_des;
break;
case CRYPTO_3DES_CBC:
- if (ratecheck(&tdeswarn, &warninterval))
- gone_in(13, "3DES cipher via /dev/crypto");
txform = &enc_xform_3des;
break;
case CRYPTO_BLF_CBC:
- if (ratecheck(&blfwarn, &warninterval))
- gone_in(13, "Blowfish cipher via /dev/crypto");
txform = &enc_xform_blf;
break;
case CRYPTO_CAST_CBC:
- if (ratecheck(&castwarn, &warninterval))
- gone_in(13, "CAST128 cipher via /dev/crypto");
txform = &enc_xform_cast5;
break;
case CRYPTO_SKIPJACK_CBC:
- if (ratecheck(&skipwarn, &warninterval))
- gone_in(13, "Skipjack cipher via /dev/crypto");
txform = &enc_xform_skipjack;
break;
case CRYPTO_AES_CBC:
@@ -454,8 +443,6 @@ cryptof_ioctl(
txform = &enc_xform_null;
break;
case CRYPTO_ARC4:
- if (ratecheck(&arc4warn, &warninterval))
- gone_in(13, "ARC4 cipher via /dev/crypto");
txform = &enc_xform_arc4;
break;
case CRYPTO_CAMELLIA_CBC:
@@ -484,9 +471,6 @@ cryptof_ioctl(
case 0:
break;
case CRYPTO_MD5_HMAC:
- if (ratecheck(&md5warn, &warninterval))
- gone_in(13,
- "MD5-HMAC authenticator via /dev/crypto");
thash = &auth_hash_hmac_md5;
break;
case CRYPTO_POLY1305:
@@ -608,8 +592,8 @@ cryptof_ioctl(
if (thash) {
cria.cri_alg = thash->type;
cria.cri_klen = sop->mackeylen * 8;
- if (thash->keysize != 0 &&
- sop->mackeylen > thash->keysize) {
+ if (sop->mackeylen > thash->keysize ||
+ sop->mackeylen < 0) {
CRYPTDEB("invalid mac key length");
error = EINVAL;
SDT_PROBE1(opencrypto, dev, ioctl, error,
@@ -692,13 +676,10 @@ bail:
break;
case CIOCFSESSION:
ses = *(u_int32_t *)data;
- cse = csefind(fcr, ses);
- if (cse == NULL) {
+ if (!csedelete(fcr, ses)) {
SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
return (EINVAL);
}
- csedelete(fcr, cse);
- csefree(cse);
break;
case CIOCCRYPT:
#ifdef COMPAT_FREEBSD32
@@ -715,6 +696,7 @@ bail:
return (EINVAL);
}
error = cryptodev_op(cse, cop, active_cred, td);
+ csefree(cse);
#ifdef COMPAT_FREEBSD32
if (error == 0 && cmd == CIOCCRYPT32)
crypt_op_to_32(cop, data);
@@ -781,6 +763,7 @@ bail:
return (EINVAL);
}
error = cryptodev_aead(cse, caead, active_cred, td);
+ csefree(cse);
break;
default:
error = EINVAL;
@@ -843,6 +826,47 @@ cod_free(struct cryptop_data *cod)
free(cod, M_XDATA);
}
+static void
+cryptodev_warn(struct csession *cse)
+{
+ static struct timeval arc4warn, blfwarn, castwarn, deswarn, md5warn;
+ static struct timeval skipwarn, tdeswarn;
+
+ switch (cse->cipher) {
+ case CRYPTO_DES_CBC:
+ if (ratecheck(&deswarn, &warninterval))
+ gone_in(13, "DES cipher via /dev/crypto");
+ break;
+ case CRYPTO_3DES_CBC:
+ if (ratecheck(&tdeswarn, &warninterval))
+ gone_in(13, "3DES cipher via /dev/crypto");
+ break;
+ case CRYPTO_BLF_CBC:
+ if (ratecheck(&blfwarn, &warninterval))
+ gone_in(13, "Blowfish cipher via /dev/crypto");
+ break;
+ case CRYPTO_CAST_CBC:
+ if (ratecheck(&castwarn, &warninterval))
+ gone_in(13, "CAST128 cipher via /dev/crypto");
+ break;
+ case CRYPTO_SKIPJACK_CBC:
+ if (ratecheck(&skipwarn, &warninterval))
+ gone_in(13, "Skipjack cipher via /dev/crypto");
+ break;
+ case CRYPTO_ARC4:
+ if (ratecheck(&arc4warn, &warninterval))
+ gone_in(13, "ARC4 cipher via /dev/crypto");
+ break;
+ }
+
+ switch (cse->mac) {
+ case CRYPTO_MD5_HMAC:
+ if (ratecheck(&md5warn, &warninterval))
+ gone_in(13, "MD5-HMAC authenticator via /dev/crypto");
+ break;
+ }
+}
+
static int
cryptodev_op(
struct csession *cse,
@@ -965,6 +989,7 @@ cryptodev_op(
error = EINVAL;
goto bail;
}
+ cryptodev_warn(cse);
again:
/*
@@ -1134,6 +1159,7 @@ cryptodev_aead(
SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
goto bail;
}
+ cryptodev_warn(cse);
again:
/*
* Let the dispatch run unlocked, then, interlock against the
@@ -1383,6 +1409,9 @@ cryptof_close(struct file *fp, struct thread *td)
while ((cse = TAILQ_FIRST(&fcr->csessions))) {
TAILQ_REMOVE(&fcr->csessions, cse, next);
+ KASSERT(cse->refs == 1,
+ ("%s: crypto session %p with %d refs", __func__, cse,
+ cse->refs));
csefree(cse);
}
free(fcr, M_XDATA);
@@ -1425,34 +1454,36 @@ csefind(struct fcrypt *fcr, u_int ses)
{
struct csession *cse;
- TAILQ_FOREACH(cse, &fcr->csessions, next)
- if (cse->ses == ses)
+ mtx_lock(&fcr->lock);
+ TAILQ_FOREACH(cse, &fcr->csessions, next) {
+ if (cse->ses == ses) {
+ refcount_acquire(&cse->refs);
+ mtx_unlock(&fcr->lock);
return (cse);
+ }
+ }
+ mtx_unlock(&fcr->lock);
return (NULL);
}
-static int
-csedelete(struct fcrypt *fcr, struct csession *cse_del)
+static bool
+csedelete(struct fcrypt *fcr, u_int ses)
{
struct csession *cse;
+ mtx_lock(&fcr->lock);
TAILQ_FOREACH(cse, &fcr->csessions, next) {
- if (cse == cse_del) {
+ if (cse->ses == ses) {
TAILQ_REMOVE(&fcr->csessions, cse, next);
- return (1);
+ mtx_unlock(&fcr->lock);
+ csefree(cse);
+ return (true);
}
}
- return (0);
+ mtx_unlock(&fcr->lock);
+ return (false);
}
-static struct csession *
-cseadd(struct fcrypt *fcr, struct csession *cse)
-{
- TAILQ_INSERT_TAIL(&fcr->csessions, cse, next);
- cse->ses = fcr->sesn++;
- return (cse);
-}
-
struct csession *
csecreate(struct fcrypt *fcr, crypto_session_t cses, caddr_t key, u_int64_t keylen,
caddr_t mackey, u_int64_t mackeylen, u_int32_t cipher, u_int32_t mac,
@@ -1464,6 +1495,7 @@ csecreate(struct fcrypt *fcr, crypto_session_t cses, caddr_t key, u_int64_t keyl
if (cse == NULL)
return NULL;
mtx_init(&cse->lock, "cryptodev", "crypto session lock", MTX_DEF);
+ refcount_init(&cse->refs, 1);
cse->key = key;
cse->keylen = keylen/8;
cse->mackey = mackey;
@@ -1473,7 +1505,10 @@ csecreate(struct fcrypt *fcr, crypto_session_t cses, caddr_t key, u_int64_t keyl
cse->mac = mac;
cse->txform = txform;
cse->thash = thash;
- cseadd(fcr, cse);
+ mtx_lock(&fcr->lock);
+ TAILQ_INSERT_TAIL(&fcr->csessions, cse, next);
+ cse->ses = fcr->sesn++;
+ mtx_unlock(&fcr->lock);
return (cse);
}
@@ -1481,6 +1516,8 @@ static void
csefree(struct csession *cse)
{
+ if (!refcount_release(&cse->refs))
+ return;
crypto_freesession(cse->cses);
mtx_destroy(&cse->lock);
if (cse->key)
@@ -1517,13 +1554,14 @@ cryptoioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread
switch (cmd) {
case CRIOGET:
- fcr = malloc(sizeof(struct fcrypt), M_XDATA, M_WAITOK);
+ fcr = malloc(sizeof(struct fcrypt), M_XDATA, M_WAITOK | M_ZERO);
TAILQ_INIT(&fcr->csessions);
- fcr->sesn = 0;
+ mtx_init(&fcr->lock, "fcrypt", NULL, MTX_DEF);
error = falloc(td, &f, &fd, 0);
if (error) {
+ mtx_destroy(&fcr->lock);
free(fcr, M_XDATA);
return (error);
}