[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] dm_op: Add xendevicemodel_modified_memory_bulk.
>>> On 16.03.17 at 15:44, <jennifer.herbert@xxxxxxxxxx> wrote: > --- a/xen/arch/x86/hvm/dm.c > +++ b/xen/arch/x86/hvm/dm.c > @@ -119,56 +119,96 @@ static int set_isa_irq_level(struct domain *d, uint8_t > isa_irq, > } > > static int modified_memory(struct domain *d, > - struct xen_dm_op_modified_memory *data) > + struct xen_dm_op_modified_memory *header, > + xen_dm_op_buf_t* buf) > { > - xen_pfn_t last_pfn = data->first_pfn + data->nr - 1; > - unsigned int iter = 0; > - int rc = 0; > + /* Process maximum of 255 pfns before checking for continuation */ > + const uint32_t max_pfns = 0xff; > > - if ( (data->first_pfn > last_pfn) || > - (last_pfn > domain_get_maximum_gpfn(d)) ) > - return -EINVAL; > + xen_pfn_t last_pfn; > + int rc = 0; > + uint32_t offset = header->offset; > + unsigned long pfn; > + unsigned long max_pfn; > + unsigned max_nr; > + uint32_t rem_pfns = max_pfns; Please avoid fixed width types when you don't really need them. Also "unsigned int" please instead of plain "unsigned". > if ( !paging_mode_log_dirty(d) ) > return 0; > > - while ( iter < data->nr ) > + if ( (buf->size / sizeof(struct xen_dm_op_modified_memory_extent)) < > + header->nr_extents ) Indentation. > + return -EINVAL; > + > + while ( offset < header->nr_extents ) > { > - unsigned long pfn = data->first_pfn + iter; > - struct page_info *page; > + struct xen_dm_op_modified_memory_extent extent; > > - page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE); > - if ( page ) > + if ( copy_from_guest_offset(&extent, buf->h, offset, 1) ) > + return -EFAULT; > + > + last_pfn = extent.first_pfn + extent.nr - 1; > + > + if ( last_pfn > domain_get_maximum_gpfn(d) ) Where did the original "(data->first_pfn > last_pfn)" go? > + return -EINVAL; > + > + if ( extent.nr > rem_pfns ) > + max_nr = rem_pfns; > + else > { > - mfn_t gmfn = _mfn(page_to_mfn(page)); > - > - paging_mark_dirty(d, gmfn); > - /* > - * These are most probably not page tables any more > - * don't take a long time and don't die either. > - */ > - sh_remove_shadows(d, gmfn, 1, 0); > - put_page(page); > + max_nr = extent.nr; > + offset++; > } > > - iter++; > + rem_pfns -= max_nr; > + max_pfn = extent.first_pfn + max_nr; > > - /* > - * Check for continuation every 256th iteration and if the > - * iteration is not the last. > - */ > - if ( (iter < data->nr) && ((iter & 0xff) == 0) && > - hypercall_preempt_check() ) > + pfn = extent.first_pfn; > + while ( pfn < max_pfn ) The max_ prefixes chosen are somewhat problematic with a loop condition like this: "max" commonly means the maximum valid one rather than the first following item. Perhaps "end_pfn" and just "nr"? > { > - data->first_pfn += iter; > - data->nr -= iter; > + struct page_info *page; > + page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE); > + > + if ( page ) > + { > + mfn_t gmfn = _mfn(page_to_mfn(page)); > + > + paging_mark_dirty(d, gmfn); > + /* > + * These are most probably not page tables any more > + * don't take a long time and don't die either. > + */ > + sh_remove_shadows(d, gmfn, 1, 0); > + put_page(page); > + } > + pfn++; > + } > > - rc = -ERESTART; > - break; > + if ( max_nr < extent.nr ) > + { > + extent.first_pfn += max_nr; > + extent.nr-= max_nr; > + if ( copy_to_guest_offset(buf->h, offset, &extent, 1) ) > + return -EFAULT; Is this copying back needed when not returning -ERESTART below? I do realize that with the current code structure it's needed for the copy_from above to read back the value, but even if this doesn't look to be a double fetch vulnerability I think it would be better if the value propagation would occur without going through guest memory. > } > - } > > - return rc; > + /* > + * Check for continuation every 256th pfn and if the > + * pfn is not the last. > + */ > + > + if ( (rem_pfns == 0) && (offset <= header->nr_extents) ) DYM < instead of <= here? > + { > + if ( hypercall_preempt_check() ) > + { > + header->offset = offset; > + rc = -ERESTART; > + break; > + } > + rem_pfns += max_pfns; rem_pfns is zero prior to this anyway: Please use = instead of += . > --- a/xen/include/public/hvm/dm_op.h > +++ b/xen/include/public/hvm/dm_op.h > @@ -237,13 +237,19 @@ struct xen_dm_op_set_pci_link_route { > * XEN_DMOP_modified_memory: Notify that a set of pages were modified by > * an emulator. > * > - * NOTE: In the event of a continuation, the @first_pfn is set to the > - * value of the pfn of the remaining set of pages and @nr reduced > - * to the size of the remaining set. > + * DMOP buf 1 contains an array of xen_dm_op_modified_memory_extent with > + * nr_extent entries. > + * > + * On continuation, @offset is set to the next extent to be processed. > */ > #define XEN_DMOP_modified_memory 11 > > struct xen_dm_op_modified_memory { > + uint32_t nr_extents; /* IN - number of extents. */ > + uint32_t offset; /* Caller must set to 0. */ I think you should try to get away without this extra field: For the purpose here, incrementing the handle value together with decrementing nr_extents should be sufficient (just like done with various other batchable hypercalls). And if the field was to stay, "offset" is a bad name imo, as this leaves open whether this is byte- or extent-granular. "cur_extent" perhaps? Jan _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |