forked from mirrors/linux
		
	crypto: switch af_alg_make_sg() to iov_iter
With that, all ->sendmsg() instances are converted to iov_iter primitives and are agnostic wrt the kind of iov_iter they are working with. So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet. All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually copied and none of them modifies the underlying iovec, etc. Cc: linux-crypto@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									31a25fae85
								
							
						
					
					
						commit
						1d10eb2f15
					
				
					 4 changed files with 64 additions and 102 deletions
				
			
		|  | @ -338,49 +338,31 @@ static const struct net_proto_family alg_family = { | ||||||
| 	.owner	=	THIS_MODULE, | 	.owner	=	THIS_MODULE, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, | int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len) | ||||||
| 		   int write) |  | ||||||
| { | { | ||||||
| 	unsigned long from = (unsigned long)addr; | 	size_t off; | ||||||
| 	unsigned long npages; | 	ssize_t n; | ||||||
| 	unsigned off; | 	int npages, i; | ||||||
| 	int err; |  | ||||||
| 	int i; |  | ||||||
| 
 | 
 | ||||||
| 	err = -EFAULT; | 	n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off); | ||||||
| 	if (!access_ok(write ? VERIFY_READ : VERIFY_WRITE, addr, len)) | 	if (n < 0) | ||||||
| 		goto out; | 		return n; | ||||||
| 
 | 
 | ||||||
| 	off = from & ~PAGE_MASK; | 	npages = PAGE_ALIGN(off + n); | ||||||
| 	npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT; |  | ||||||
| 	if (npages > ALG_MAX_PAGES) |  | ||||||
| 		npages = ALG_MAX_PAGES; |  | ||||||
| 
 |  | ||||||
| 	err = get_user_pages_fast(from, npages, write, sgl->pages); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	npages = err; |  | ||||||
| 	err = -EINVAL; |  | ||||||
| 	if (WARN_ON(npages == 0)) | 	if (WARN_ON(npages == 0)) | ||||||
| 		goto out; | 		return -EINVAL; | ||||||
| 
 |  | ||||||
| 	err = 0; |  | ||||||
| 
 | 
 | ||||||
| 	sg_init_table(sgl->sg, npages); | 	sg_init_table(sgl->sg, npages); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < npages; i++) { | 	for (i = 0, len = n; i < npages; i++) { | ||||||
| 		int plen = min_t(int, len, PAGE_SIZE - off); | 		int plen = min_t(int, len, PAGE_SIZE - off); | ||||||
| 
 | 
 | ||||||
| 		sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); | 		sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); | ||||||
| 
 | 
 | ||||||
| 		off = 0; | 		off = 0; | ||||||
| 		len -= plen; | 		len -= plen; | ||||||
| 		err += plen; |  | ||||||
| 	} | 	} | ||||||
| 
 | 	return n; | ||||||
| out: |  | ||||||
| 	return err; |  | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(af_alg_make_sg); | EXPORT_SYMBOL_GPL(af_alg_make_sg); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -41,8 +41,6 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, | ||||||
| 	struct sock *sk = sock->sk; | 	struct sock *sk = sock->sk; | ||||||
| 	struct alg_sock *ask = alg_sk(sk); | 	struct alg_sock *ask = alg_sk(sk); | ||||||
| 	struct hash_ctx *ctx = ask->private; | 	struct hash_ctx *ctx = ask->private; | ||||||
| 	unsigned long iovlen; |  | ||||||
| 	const struct iovec *iov; |  | ||||||
| 	long copied = 0; | 	long copied = 0; | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
|  | @ -58,37 +56,28 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock, | ||||||
| 
 | 
 | ||||||
| 	ctx->more = 0; | 	ctx->more = 0; | ||||||
| 
 | 
 | ||||||
| 	for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0; | 	while (iov_iter_count(&msg->msg_iter)) { | ||||||
| 	     iovlen--, iov++) { | 		int len = iov_iter_count(&msg->msg_iter); | ||||||
| 		unsigned long seglen = iov->iov_len; |  | ||||||
| 		char __user *from = iov->iov_base; |  | ||||||
| 
 | 
 | ||||||
| 		while (seglen) { | 		if (len > limit) | ||||||
| 			int len = min_t(unsigned long, seglen, limit); | 			len = limit; | ||||||
| 			int newlen; |  | ||||||
| 
 | 
 | ||||||
| 			newlen = af_alg_make_sg(&ctx->sgl, from, len, 0); | 		len = af_alg_make_sg(&ctx->sgl, &msg->msg_iter, len); | ||||||
| 			if (newlen < 0) { | 		if (len < 0) { | ||||||
| 				err = copied ? 0 : newlen; | 			err = copied ? 0 : len; | ||||||
| 				goto unlock; | 			goto unlock; | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, |  | ||||||
| 						newlen); |  | ||||||
| 
 |  | ||||||
| 			err = af_alg_wait_for_completion( |  | ||||||
| 				crypto_ahash_update(&ctx->req), |  | ||||||
| 				&ctx->completion); |  | ||||||
| 
 |  | ||||||
| 			af_alg_free_sg(&ctx->sgl); |  | ||||||
| 
 |  | ||||||
| 			if (err) |  | ||||||
| 				goto unlock; |  | ||||||
| 
 |  | ||||||
| 			seglen -= newlen; |  | ||||||
| 			from += newlen; |  | ||||||
| 			copied += newlen; |  | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, len); | ||||||
|  | 
 | ||||||
|  | 		err = af_alg_wait_for_completion(crypto_ahash_update(&ctx->req), | ||||||
|  | 						 &ctx->completion); | ||||||
|  | 		af_alg_free_sg(&ctx->sgl); | ||||||
|  | 		if (err) | ||||||
|  | 			goto unlock; | ||||||
|  | 
 | ||||||
|  | 		copied += len; | ||||||
|  | 		iov_iter_advance(&msg->msg_iter, len); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = 0; | 	err = 0; | ||||||
|  |  | ||||||
|  | @ -426,67 +426,59 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, | ||||||
| 		&ctx->req)); | 		&ctx->req)); | ||||||
| 	struct skcipher_sg_list *sgl; | 	struct skcipher_sg_list *sgl; | ||||||
| 	struct scatterlist *sg; | 	struct scatterlist *sg; | ||||||
| 	unsigned long iovlen; |  | ||||||
| 	const struct iovec *iov; |  | ||||||
| 	int err = -EAGAIN; | 	int err = -EAGAIN; | ||||||
| 	int used; | 	int used; | ||||||
| 	long copied = 0; | 	long copied = 0; | ||||||
| 
 | 
 | ||||||
| 	lock_sock(sk); | 	lock_sock(sk); | ||||||
| 	for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0; | 	while (iov_iter_count(&msg->msg_iter)) { | ||||||
| 	     iovlen--, iov++) { | 		sgl = list_first_entry(&ctx->tsgl, | ||||||
| 		unsigned long seglen = iov->iov_len; | 				       struct skcipher_sg_list, list); | ||||||
| 		char __user *from = iov->iov_base; | 		sg = sgl->sg; | ||||||
| 
 | 
 | ||||||
| 		while (seglen) { | 		while (!sg->length) | ||||||
| 			sgl = list_first_entry(&ctx->tsgl, | 			sg++; | ||||||
| 					       struct skcipher_sg_list, list); |  | ||||||
| 			sg = sgl->sg; |  | ||||||
| 
 | 
 | ||||||
| 			while (!sg->length) | 		used = ctx->used; | ||||||
| 				sg++; | 		if (!used) { | ||||||
| 
 | 			err = skcipher_wait_for_data(sk, flags); | ||||||
| 			if (!ctx->used) { | 			if (err) | ||||||
| 				err = skcipher_wait_for_data(sk, flags); |  | ||||||
| 				if (err) |  | ||||||
| 					goto unlock; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			used = min_t(unsigned long, ctx->used, seglen); |  | ||||||
| 
 |  | ||||||
| 			used = af_alg_make_sg(&ctx->rsgl, from, used, 1); |  | ||||||
| 			err = used; |  | ||||||
| 			if (err < 0) |  | ||||||
| 				goto unlock; | 				goto unlock; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 			if (ctx->more || used < ctx->used) | 		used = min_t(unsigned long, used, iov_iter_count(&msg->msg_iter)); | ||||||
| 				used -= used % bs; |  | ||||||
| 
 | 
 | ||||||
| 			err = -EINVAL; | 		used = af_alg_make_sg(&ctx->rsgl, &msg->msg_iter, used); | ||||||
| 			if (!used) | 		err = used; | ||||||
| 				goto free; | 		if (err < 0) | ||||||
|  | 			goto unlock; | ||||||
| 
 | 
 | ||||||
| 			ablkcipher_request_set_crypt(&ctx->req, sg, | 		if (ctx->more || used < ctx->used) | ||||||
| 						     ctx->rsgl.sg, used, | 			used -= used % bs; | ||||||
| 						     ctx->iv); |  | ||||||
| 
 | 
 | ||||||
| 			err = af_alg_wait_for_completion( | 		err = -EINVAL; | ||||||
|  | 		if (!used) | ||||||
|  | 			goto free; | ||||||
|  | 
 | ||||||
|  | 		ablkcipher_request_set_crypt(&ctx->req, sg, | ||||||
|  | 					     ctx->rsgl.sg, used, | ||||||
|  | 					     ctx->iv); | ||||||
|  | 
 | ||||||
|  | 		err = af_alg_wait_for_completion( | ||||||
| 				ctx->enc ? | 				ctx->enc ? | ||||||
| 					crypto_ablkcipher_encrypt(&ctx->req) : | 					crypto_ablkcipher_encrypt(&ctx->req) : | ||||||
| 					crypto_ablkcipher_decrypt(&ctx->req), | 					crypto_ablkcipher_decrypt(&ctx->req), | ||||||
| 				&ctx->completion); | 				&ctx->completion); | ||||||
| 
 | 
 | ||||||
| free: | free: | ||||||
| 			af_alg_free_sg(&ctx->rsgl); | 		af_alg_free_sg(&ctx->rsgl); | ||||||
| 
 | 
 | ||||||
| 			if (err) | 		if (err) | ||||||
| 				goto unlock; | 			goto unlock; | ||||||
| 
 | 
 | ||||||
| 			copied += used; | 		copied += used; | ||||||
| 			from += used; | 		skcipher_pull_sgl(sk, used); | ||||||
| 			seglen -= used; | 		iov_iter_advance(&msg->msg_iter, used); | ||||||
| 			skcipher_pull_sgl(sk, used); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = 0; | 	err = 0; | ||||||
|  |  | ||||||
|  | @ -67,8 +67,7 @@ int af_alg_unregister_type(const struct af_alg_type *type); | ||||||
| int af_alg_release(struct socket *sock); | int af_alg_release(struct socket *sock); | ||||||
| int af_alg_accept(struct sock *sk, struct socket *newsock); | int af_alg_accept(struct sock *sk, struct socket *newsock); | ||||||
| 
 | 
 | ||||||
| int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len, | int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len); | ||||||
| 		   int write); |  | ||||||
| void af_alg_free_sg(struct af_alg_sgl *sgl); | void af_alg_free_sg(struct af_alg_sgl *sgl); | ||||||
| 
 | 
 | ||||||
| int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con); | int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Al Viro
						Al Viro