diff options
author | swapnili <swapnil.ingle@nutanix.com> | 2021-01-21 15:38:24 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-21 15:38:24 +0100 |
commit | e899af8f842c9ba2d48fb44b507e90187f2fab47 (patch) | |
tree | 3987cf106c923ad52b9605c6486b7868ac3c2cbe /lib | |
parent | 4f3ad36fc3956d9c1ca926615301e40134b75d58 (diff) | |
download | libvfio-user-e899af8f842c9ba2d48fb44b507e90187f2fab47.zip libvfio-user-e899af8f842c9ba2d48fb44b507e90187f2fab47.tar.gz libvfio-user-e899af8f842c9ba2d48fb44b507e90187f2fab47.tar.bz2 |
Misc fixes for DMA_MAP region prot (#233)
* Misc fixes for DMA_MAP region prot
1. Validate prot passed in vfu_addr_to_sg()
2. Let user know region prot via vfu_unmap_dma_cb_t
Signed-off-by: Swapnil Ingle <swapnil.ingle@nutanix.com>
Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dma.c | 10 | ||||
-rw-r--r-- | lib/dma.h | 22 | ||||
-rw-r--r-- | lib/libvfio-user.c | 4 |
3 files changed, 29 insertions, 7 deletions
@@ -344,6 +344,8 @@ dma_map_region(dma_memory_region_t *region, int prot, size_t offset, size_t len) mmap_round(&mmap_offset, &mmap_size, region->page_size); // Do the mmap. + // Note: As per mmap(2) manpage, on some hardware architectures + // (e.g., i386), PROT_WRITE implies PROT_READ mmap_base = mmap(NULL, mmap_size, prot, MAP_SHARED, region->fd, mmap_offset); if (mmap_base == MAP_FAILED) { @@ -369,7 +371,7 @@ _dma_addr_sg_split(const dma_controller_t *dma, dma_sg_t *sg, int max_sg, int prot) { int idx; - int cnt = 0; + int cnt = 0, ret; bool found = true; // Whether the current region is found. while (found && len > 0) { @@ -382,7 +384,10 @@ _dma_addr_sg_split(const dma_controller_t *dma, size_t region_len = MIN(region_end - dma_addr, len); if (cnt < max_sg) { - dma_init_sg(dma, sg, dma_addr, region_len, prot, idx); + ret = dma_init_sg(dma, sg, dma_addr, region_len, prot, idx); + if (ret < 0) { + return ret; + } } cnt++; @@ -408,6 +413,7 @@ out: } else if (cnt > max_sg) { cnt = -cnt - 1; } + errno = 0; return cnt; } @@ -184,11 +184,17 @@ _dma_mark_dirty(const dma_controller_t *dma, const dma_memory_region_t *region, } } -static inline void +static inline int dma_init_sg(const dma_controller_t *dma, dma_sg_t *sg, dma_addr_t dma_addr, uint32_t len, int prot, int region_index) { const dma_memory_region_t *const region = &dma->regions[region_index]; + + if ((prot & PROT_WRITE) && !(region->prot & PROT_WRITE)) { + errno = EACCES; + return -1; + } + sg->dma_addr = region->dma_addr; sg->region = region_index; sg->offset = dma_addr - region->dma_addr; @@ -197,6 +203,8 @@ dma_init_sg(const dma_controller_t *dma, dma_sg_t *sg, dma_addr_t dma_addr, _dma_mark_dirty(dma, region, sg); } sg->mappable = region->virt_addr != NULL; + + return 0; } /* Takes a linear dma address span and returns a sg list suitable for DMA. @@ -206,7 +214,9 @@ dma_init_sg(const dma_controller_t *dma, dma_sg_t *sg, dma_addr_t dma_addr, * Returns: * - On success, number of scatter gather entries created. * - On failure: - * -1 if the dma address span is invalid + * -1 if + * - the DMA address span is invalid + * - protection violation (errno=EACCES) * (-x - 1) if @max_sg is too small, where x is the number of sg entries * necessary to complete this request. */ @@ -216,7 +226,7 @@ dma_addr_to_sg(const dma_controller_t *dma, dma_sg_t *sg, int max_sg, int prot) { static __thread int region_hint; - int cnt; + int cnt, ret; const dma_memory_region_t *const region = &dma->regions[region_hint]; const dma_addr_t region_end = region->dma_addr + region->size; @@ -225,7 +235,11 @@ dma_addr_to_sg(const dma_controller_t *dma, if (likely(max_sg > 0 && len > 0 && dma_addr >= region->dma_addr && dma_addr + len <= region_end && region_hint < dma->nregions)) { - dma_init_sg(dma, sg, dma_addr, len, prot, region_hint); + ret = dma_init_sg(dma, sg, dma_addr, len, prot, region_hint); + if (ret < 0) { + return ret; + } + return 1; } // Slow path: search through regions. diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c index be310a3..d98994e 100644 --- a/lib/libvfio-user.c +++ b/lib/libvfio-user.c @@ -559,7 +559,8 @@ handle_dma_map_or_unmap(vfu_ctx_t *vfu_ctx, uint32_t size, bool map, return ret; } if (vfu_ctx->map_dma != NULL) { - vfu_ctx->map_dma(vfu_ctx, dma_regions[i].addr, dma_regions[i].size); + vfu_ctx->map_dma(vfu_ctx, dma_regions[i].addr, dma_regions[i].size, + dma_regions[i].prot); } } return ret; @@ -1393,6 +1394,7 @@ vfu_addr_to_sg(vfu_ctx_t *vfu_ctx, dma_addr_t dma_addr, errno = EINVAL; return -1; } + return dma_addr_to_sg(vfu_ctx->dma, dma_addr, len, sg, max_sg, prot); } |