166 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- sys/opencrypto/cryptodev.c.orig
 | |
| +++ sys/opencrypto/cryptodev.c
 | |
| @@ -268,6 +268,7 @@
 | |
|  struct csession {
 | |
|  	TAILQ_ENTRY(csession) next;
 | |
|  	u_int64_t	sid;
 | |
| +	volatile u_int	refs;
 | |
|  	u_int32_t	ses;
 | |
|  	struct mtx	lock;		/* for op submission */
 | |
|  
 | |
| @@ -294,6 +295,7 @@
 | |
|  struct fcrypt {
 | |
|  	TAILQ_HEAD(csessionlist, csession) csessions;
 | |
|  	int		sesn;
 | |
| +	struct mtx	lock;
 | |
|  };
 | |
|  
 | |
|  static	int cryptof_ioctl(struct file *, u_long, void *,
 | |
| @@ -320,8 +322,7 @@
 | |
|  };
 | |
|  
 | |
|  static struct csession *csefind(struct fcrypt *, u_int);
 | |
| -static int csedelete(struct fcrypt *, struct csession *);
 | |
| -static struct csession *cseadd(struct fcrypt *, struct csession *);
 | |
| +static int csedelete(struct fcrypt *, u_int);
 | |
|  static struct csession *csecreate(struct fcrypt *, u_int64_t, caddr_t,
 | |
|      u_int64_t, caddr_t, u_int64_t, u_int32_t, u_int32_t, struct enc_xform *,
 | |
|      struct auth_hash *);
 | |
| @@ -612,13 +613,9 @@
 | |
|  		break;
 | |
|  	case CIOCFSESSION:
 | |
|  		ses = *(u_int32_t *)data;
 | |
| -		cse = csefind(fcr, ses);
 | |
| -		if (cse == NULL) {
 | |
| +		error = csedelete(fcr, ses);
 | |
| +		if (error != 0)
 | |
|  			SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
 | |
| -			return (EINVAL);
 | |
| -		}
 | |
| -		csedelete(fcr, cse);
 | |
| -		error = csefree(cse);
 | |
|  		break;
 | |
|  	case CIOCCRYPT:
 | |
|  #ifdef COMPAT_FREEBSD32
 | |
| @@ -635,6 +632,7 @@
 | |
|  			return (EINVAL);
 | |
|  		}
 | |
|  		error = cryptodev_op(cse, cop, active_cred, td);
 | |
| +		(void)csefree(cse);
 | |
|  #ifdef COMPAT_FREEBSD32
 | |
|  		if (error == 0 && cmd == CIOCCRYPT32)
 | |
|  			crypt_op_to_32(cop, data);
 | |
| @@ -701,6 +699,7 @@
 | |
|  			return (EINVAL);
 | |
|  		}
 | |
|  		error = cryptodev_aead(cse, caead, active_cred, td);
 | |
| +		(void)csefree(cse);
 | |
|  		break;
 | |
|  	default:
 | |
|  		error = EINVAL;
 | |
| @@ -1275,6 +1274,9 @@
 | |
|  
 | |
|  	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));
 | |
|  		(void)csefree(cse);
 | |
|  	}
 | |
|  	free(fcr, M_XDATA);
 | |
| @@ -1295,34 +1297,35 @@
 | |
|  {
 | |
|  	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)
 | |
| +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);
 | |
| +			return (csefree(cse));
 | |
|  		}
 | |
|  	}
 | |
| -	return (0);
 | |
| +	mtx_unlock(&fcr->lock);
 | |
| +	return (EINVAL);
 | |
|  }
 | |
|  	
 | |
| -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, u_int64_t sid, caddr_t key, u_int64_t keylen,
 | |
|      caddr_t mackey, u_int64_t mackeylen, u_int32_t cipher, u_int32_t mac,
 | |
| @@ -1334,6 +1337,7 @@
 | |
|  	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;
 | |
| @@ -1343,7 +1347,10 @@
 | |
|  	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);
 | |
|  }
 | |
|  
 | |
| @@ -1352,6 +1359,8 @@
 | |
|  {
 | |
|  	int error;
 | |
|  
 | |
| +	if (!refcount_release(&cse->refs))
 | |
| +		return (0);
 | |
|  	error = crypto_freesession(cse->sid);
 | |
|  	mtx_destroy(&cse->lock);
 | |
|  	if (cse->key)
 | |
| @@ -1389,13 +1398,14 @@
 | |
|  
 | |
|  	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);
 | |
|  		}
 |