Example #1
0
/* This is the main crypto function - zero-copy edition */
static int
__crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop)
{
	struct scatterlist *src_sg, *dst_sg;
	struct crypt_op *cop = &kcop->cop;
	int ret = 0;

	ret = get_userbuf(ses_ptr, cop->src, cop->len, cop->dst, cop->len,
	                  kcop->task, kcop->mm, &src_sg, &dst_sg);
	if (unlikely(ret)) {
		derr(1, "Error getting user pages. Falling back to non zero copy.");
		return __crypto_run_std(ses_ptr, cop);
	}

	ret = hash_n_crypt(ses_ptr, cop, src_sg, dst_sg, cop->len);

	release_user_pages(ses_ptr);
	return ret;
}
Example #2
0
/* This is the main crypto function - zero-copy edition */
static int
__crypto_auth_run_zc(struct csession *ses_ptr, struct kernel_crypt_auth_op *kcaop)
{
	struct scatterlist *dst_sg, *auth_sg, *src_sg;
	struct crypt_auth_op *caop = &kcaop->caop;
	int ret = 0;

	if (caop->flags & COP_FLAG_AEAD_SRTP_TYPE) {
		if (unlikely(ses_ptr->cdata.init != 0 &&
			(ses_ptr->cdata.stream == 0 || ses_ptr->cdata.aead != 0)))
		{
			dprintk(0, KERN_ERR, "Only stream modes are allowed in SRTP mode (but not AEAD)\n");
			return -EINVAL;
		}

		ret = get_userbuf_srtp(ses_ptr, kcaop, &auth_sg, &dst_sg);
		if (unlikely(ret)) {
			dprintk(1, KERN_ERR, "get_userbuf_srtp(): Error getting user pages.\n");
			return ret;
		}

		ret = srtp_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
			   dst_sg, caop->len);

		release_user_pages(ses_ptr);
	} else { /* TLS and normal cases. Here auth data are usually small
	          * so we just copy them to a free page, instead of trying
	          * to map them.
	          */
		unsigned char* auth_buf = NULL;
		struct scatterlist tmp;

		if (unlikely(caop->auth_len > PAGE_SIZE)) {
			dprintk(1, KERN_ERR, "auth data len is excessive.\n");
			return -EINVAL;
		}

		auth_buf = (char *)__get_free_page(GFP_KERNEL);
		if (unlikely(!auth_buf)) {
			dprintk(1, KERN_ERR, "unable to get a free page.\n");
			return -ENOMEM;
		}

		if (caop->auth_src && caop->auth_len > 0) {
			if (unlikely(copy_from_user(auth_buf, caop->auth_src, caop->auth_len))) {
				dprintk(1, KERN_ERR, "unable to copy auth data from userspace.\n");
				ret = -EFAULT;
				goto free_auth_buf;
			}

			sg_init_one(&tmp, auth_buf, caop->auth_len);
			auth_sg = &tmp;
		} else {
			auth_sg = NULL;
		}

		if (caop->flags & COP_FLAG_AEAD_TLS_TYPE && ses_ptr->cdata.aead == 0) {
			ret = get_userbuf_tls(ses_ptr, kcaop, &dst_sg);
			if (unlikely(ret)) {
				dprintk(1, KERN_ERR, "get_userbuf_tls(): Error getting user pages.\n");
				goto free_auth_buf;
			}

			ret = tls_auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
				   dst_sg, caop->len);
		} else {
			int dst_len;

			if (unlikely(ses_ptr->cdata.init == 0 ||
					ses_ptr->cdata.stream == 0 ||
					ses_ptr->cdata.aead == 0))
			{
				dprintk(0, KERN_ERR, "Only stream and AEAD ciphers are allowed for authenc\n");
				ret = -EINVAL;
				goto free_auth_buf;
			}

			if (caop->op == COP_ENCRYPT) dst_len = caop->len + cryptodev_cipher_get_tag_size(&ses_ptr->cdata);
			else dst_len = caop->len;

			ret = get_userbuf(ses_ptr, caop->src, caop->len, caop->dst, dst_len,
					  kcaop->task, kcaop->mm, &src_sg, &dst_sg);
			if (unlikely(ret)) {
				dprintk(1, KERN_ERR, "get_userbuf(): Error getting user pages.\n");
				goto free_auth_buf;
			}

			ret = auth_n_crypt(ses_ptr, kcaop, auth_sg, caop->auth_len,
					   src_sg, dst_sg, caop->len);
		}

		release_user_pages(ses_ptr);

free_auth_buf:
		free_page((unsigned long)auth_buf);
	}

	return ret;
}