vhost: catch overflow causing mmap of size 0

Message ID 20200116104427.3810-1-maxime.coquelin@redhat.com (mailing list archive)
State Accepted, archived
Delegated to: Maxime Coquelin
Headers
Series vhost: catch overflow causing mmap of size 0 |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/travis-robot warning Travis build: failed
ci/iol-testing success Testing PASS
ci/iol-nxp-Performance fail Performance Testing issues
ci/iol-mellanox-Performance success Performance Testing PASS
ci/Intel-compilation fail Compilation issues
ci/iol-intel-Performance success Performance Testing PASS

Commit Message

Maxime Coquelin Jan. 16, 2020, 10:44 a.m. UTC
  This patch catches an overflow that could happen if an
invalid region size or page alignement is provided by the
guest via the VHOST_USER_SET_MEM_TABLE request.

If the sum of the size to mmap and the alignment overflows
uint64_t, then RTE_ALIGN_CEIL(mmap_size, alignment) macro
will return 0. This value was passed as is as size argument
to mmap().

While kernel handling of mmap() syscall returns an error
if size is 0, it is better to catch it earlier and provide
a meaningful error log.

Fixes: ec09c280b839 ("vhost: fix mmap not aligned with hugepage size")
Cc: stable@dpdk.org

Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
---
 lib/librte_vhost/vhost_user.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
  

Comments

Tiwei Bie Jan. 17, 2020, 7:51 a.m. UTC | #1
On Thu, Jan 16, 2020 at 11:44:27AM +0100, Maxime Coquelin wrote:
> This patch catches an overflow that could happen if an
> invalid region size or page alignement is provided by the

s/alignement/alignment/

> guest via the VHOST_USER_SET_MEM_TABLE request.
> 
> If the sum of the size to mmap and the alignment overflows
> uint64_t, then RTE_ALIGN_CEIL(mmap_size, alignment) macro
> will return 0. This value was passed as is as size argument
> to mmap().
> 
> While kernel handling of mmap() syscall returns an error
> if size is 0, it is better to catch it earlier and provide
> a meaningful error log.
> 
> Fixes: ec09c280b839 ("vhost: fix mmap not aligned with hugepage size")
> Cc: stable@dpdk.org
> 
> Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> ---
>  lib/librte_vhost/vhost_user.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
> index 0b7d1e288e..41ec069cb6 100644
> --- a/lib/librte_vhost/vhost_user.c
> +++ b/lib/librte_vhost/vhost_user.c
> @@ -1145,6 +1145,21 @@ vhost_user_set_mem_table(struct virtio_net **pdev, struct VhostUserMsg *msg,
>  			goto err_mmap;
>  		}
>  		mmap_size = RTE_ALIGN_CEIL(mmap_size, alignment);
> +		if (mmap_size == 0) {
> +			/*
> +			 * It could happen if initial mmap_size + alignment
> +			 * overflows the sizeof uint64, which could happen if
> +			 * either mmap_size or alignment value is wrong.
> +			 *
> +			 * mmap() kernel implementation would return an error,
> +			 * but better catch it before and provide useful info
> +			 * in the logs.
> +			 */
> +			VHOST_LOG_CONFIG(ERR, "mmap size (0x%" PRIx64 ") "
> +					"or alignment (0x%" PRIx64 ") is invalid\n",
> +					reg->size + mmap_offset, alignment);
> +			goto err_mmap;
> +		}
>  
>  		populate = (dev->dequeue_zero_copy) ? MAP_POPULATE : 0;
>  		mmap_addr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
> -- 
> 2.21.0

Reviewed-by: Tiwei Bie <tiwei.bie@intel.com>
  
Maxime Coquelin Feb. 5, 2020, 9:49 a.m. UTC | #2
On 1/16/20 11:44 AM, Maxime Coquelin wrote:
> This patch catches an overflow that could happen if an
> invalid region size or page alignement is provided by the
> guest via the VHOST_USER_SET_MEM_TABLE request.
> 
> If the sum of the size to mmap and the alignment overflows
> uint64_t, then RTE_ALIGN_CEIL(mmap_size, alignment) macro
> will return 0. This value was passed as is as size argument
> to mmap().
> 
> While kernel handling of mmap() syscall returns an error
> if size is 0, it is better to catch it earlier and provide
> a meaningful error log.
> 
> Fixes: ec09c280b839 ("vhost: fix mmap not aligned with hugepage size")
> Cc: stable@dpdk.org
> 
> Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> ---
>  lib/librte_vhost/vhost_user.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)

Applied to dpdk-next-virtio tree.

Thanks,
Maxime
  

Patch

diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
index 0b7d1e288e..41ec069cb6 100644
--- a/lib/librte_vhost/vhost_user.c
+++ b/lib/librte_vhost/vhost_user.c
@@ -1145,6 +1145,21 @@  vhost_user_set_mem_table(struct virtio_net **pdev, struct VhostUserMsg *msg,
 			goto err_mmap;
 		}
 		mmap_size = RTE_ALIGN_CEIL(mmap_size, alignment);
+		if (mmap_size == 0) {
+			/*
+			 * It could happen if initial mmap_size + alignment
+			 * overflows the sizeof uint64, which could happen if
+			 * either mmap_size or alignment value is wrong.
+			 *
+			 * mmap() kernel implementation would return an error,
+			 * but better catch it before and provide useful info
+			 * in the logs.
+			 */
+			VHOST_LOG_CONFIG(ERR, "mmap size (0x%" PRIx64 ") "
+					"or alignment (0x%" PRIx64 ") is invalid\n",
+					reg->size + mmap_offset, alignment);
+			goto err_mmap;
+		}
 
 		populate = (dev->dequeue_zero_copy) ? MAP_POPULATE : 0;
 		mmap_addr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,