All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Jan Beulich" <JBeulich@suse.com>
To: Jennifer Herbert <Jennifer.Herbert@citrix.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>,
	PaulDurrant <paul.durrant@citrix.com>,
	Wei Liu <wei.liu2@citrix.com>,
	Ian Jackson <ian.jackson@eu.citrix.com>,
	Xen-devel <xen-devel@lists.xen.org>
Subject: Re: [PATCH] dm_op: Add xendevicemodel_modified_memory_bulk.
Date: Mon, 20 Mar 2017 04:18:19 -0600	[thread overview]
Message-ID: <58CFBA7B0200007800144E2C@prv-mh.provo.novell.com> (raw)
In-Reply-To: <1489675444-34062-1-git-send-email-jennifer.herbert@citrix.com>

>>> On 16.03.17 at 15:44, <jennifer.herbert@citrix.com> 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@lists.xen.org
https://lists.xen.org/xen-devel

      parent reply	other threads:[~2017-03-20 10:18 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-16 14:44 [PATCH] dm_op: Add xendevicemodel_modified_memory_bulk Jennifer Herbert
2017-03-17 10:42 ` Paul Durrant
2017-03-20 10:18 ` Jan Beulich [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=58CFBA7B0200007800144E2C@prv-mh.provo.novell.com \
    --to=jbeulich@suse.com \
    --cc=Jennifer.Herbert@citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=paul.durrant@citrix.com \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.