[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 1/7] xen: vNUMA support for PV guests



>>> On 17.10.13 at 00:37, Elena Ufimtseva <ufimtseva@xxxxxxxxx> wrote:
> Changes since RFC v2:
> - fixed code style;

Sadly not enough yet.

> @@ -871,6 +872,77 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
> u_domctl)
>      }
>      break;
>  
> +    case XEN_DOMCTL_setvnumainfo:
> +    {
> +        unsigned int i, j, nr_vnodes, dist_size;
> +        unsigned int dist;

Why can't these all be together?

> +        

Line with only blanks.

> +        ret = -EFAULT;
> +        dist = i = j = 0;

Why can't these be initializers to their declarators?

> +
> +        nr_vnodes = op->u.vnuma.nr_vnodes; 
> +        if ( nr_vnodes == 0 )
> +            goto err_dom;
> +        dist_size = nr_vnodes * nr_vnodes;

Potential for overflow?

> +
> +        d->vnuma.vdistance = xmalloc_bytes(
> +                 sizeof(*d->vnuma.vdistance) * dist_size);
> +        d->vnuma.vnuma_memblks = xmalloc_bytes(
> +                 sizeof(*d->vnuma.vnuma_memblks) * nr_vnodes);
> +        d->vnuma.vcpu_to_vnode = xmalloc_bytes(
> +                 sizeof(*d->vnuma.vcpu_to_vnode) * d->max_vcpus);
> +        d->vnuma.vnode_to_pnode = xmalloc_bytes(
> +                 sizeof(*d->vnuma.vnode_to_pnode) * nr_vnodes);

Is there any reason why any of these really has to use
xmalloc_bytes() instead of xmalloc_array() (which takes care
of overflow conditions as well as type correctness for you)?

Further there's nothing preventing this call from being issued
twice for a given domain, yet you blindly overwrite the old
values (and thus leak them).

> +
> +        if ( d->vnuma.vdistance == NULL || d->vnuma.vnuma_memblks == NULL ||
> +                                           d->vnuma.vcpu_to_vnode == NULL ||
> +                                           d->vnuma.vnode_to_pnode == NULL )
> +        {
> +            ret = -ENOMEM;
> +            goto err_dom;
> +        }
> +        
> +        d->vnuma.nr_vnodes = nr_vnodes; 

Trailing blank.

Also I'd strongly recommend setting this field last, so that other
code won't risk getting confused if some of the copying below
fails - until all copying was successfully done, the domain should
look like not having any vNUMA info.

> +        if ( !guest_handle_is_null(op->u.vnuma.vdistance) )
> +            if ( unlikely(copy_from_guest(d->vnuma.vdistance,

Two if()-s like here should be combined into a single one.

> +                                    op->u.vnuma.vdistance,
> +                                    dist_size)) )
> +                goto err_dom;

And if guest_handle_is_null(op->u.vnuma.vdistance) 
d->vnuma.vdistance will remain uninitialized - is that not a
problem?

(Both this and the preceding comment apply further down
again.)

> +        
> +        if ( !guest_handle_is_null(op->u.vnuma.vnuma_memblks) )
> +            if ( unlikely(copy_from_guest(d->vnuma.vnuma_memblks,
> +                                    op->u.vnuma.vnuma_memblks,
> +                                    nr_vnodes)))
> +                goto err_dom;
> +
> +        if ( !guest_handle_is_null(op->u.vnuma.vcpu_to_vnode) )
> +            if ( unlikely(copy_from_guest(d->vnuma.vcpu_to_vnode,
> +                                      op->u.vnuma.vcpu_to_vnode,
> +                                      d->max_vcpus)) )
> +                goto err_dom;
> +        
> +        if ( !guest_handle_is_null(op->u.vnuma.vnode_to_pnode) )
> +        {
> +            if ( unlikely(copy_from_guest(d->vnuma.vnode_to_pnode,
> +                                        op->u.vnuma.vnode_to_pnode,
> +                                        nr_vnodes)) )
> +                goto err_dom;
> +
> +        }
> +        else
> +            for( i = 0; i < nr_vnodes; i++ )

Missing blank after "for".

> +                d->vnuma.vnode_to_pnode[i] = NUMA_NO_NODE;
> +        ret = 0;
> +err_dom:

This should be indented by one space. I also don't see why it's being
named the way it is (it's for one too unspecific and also completely
unrelated to anything "dom"ish).

> +        if (ret != 0) {

        if ( ret != 0 )
        {

> +            d->vnuma.nr_vnodes = 0;
> +            xfree( d->vnuma.vdistance );
> +            xfree( d->vnuma.vnuma_memblks );
> +            xfree( d->vnuma.vnode_to_pnode );

Bogus blanks around function call arguments.

> @@ -732,7 +733,47 @@ long do_memory_op(unsigned long cmd, 
> XEN_GUEST_HANDLE_PARAM(void) arg)
>          rcu_unlock_domain(d);
>  
>          break;
> +    case XENMEM_get_vnuma_info:
> +    {
> +        struct vnuma_topology_info mtopology;
> +        struct domain *d;
> +        unsigned int max_vcpus, nr_vnodes = 0;

Pretty pointless variables, and definitely a pointless initializer.

>  

The blank line here should actually be retained above the case
label (and similarly a blank line should be there before the next
[default] one).

> +        rc = -EINVAL;
> +        
> +        if( copy_from_guest(&mtopology, arg, 1) )
> +            return -EFAULT;
> +        if ( (d = rcu_lock_domain_by_any_id(mtopology.domid)) == NULL )
> +            return -ESRCH;
> +
> +        nr_vnodes = d->vnuma.nr_vnodes;
> +        max_vcpus = d->max_vcpus;
> +        
> +        if ((nr_vnodes == 0) || (nr_vnodes > max_vcpus))

Starting here and continuing all the way to the end of the function
you're again lacking blanks inside the outermost parentheses.

Also, is the right side of the || really possible?

> +            goto vnumaout;

This yields a -EINVAL return for something that isn't really a
bad function argument. Please use a more appropriate error
code (like -EOPNOTSUPP).

> +
> +        mtopology.nr_vnodes = nr_vnodes;

So this is the only field you changed.

> +
> +        if (copy_to_guest(arg , &mtopology, 1) != 0)

Hence you would be better off copying back just that one field.
And having used copy_from_guest() on the same guest memory
block above, using the __-prefixed variant here is correct and
(for consistency with other similar code) recommended.

> +            goto vnumaout;

And from here on the error return value ought to be -EFAULT.

> +
> +        if (copy_to_guest(mtopology.vnuma_memblks,
> +                                d->vnuma.vnuma_memblks,
> +                                nr_vnodes) != 0)

And here we see that the lack of initialization above _is_ a
(security) problem - you're possibly leaking hypervisor memory
contents to the guest here.

> +            goto vnumaout;
> +        if (copy_to_guest(mtopology.vdistance,
> +                                d->vnuma.vdistance,
> +                                nr_vnodes * nr_vnodes) != 0)
> +            goto vnumaout;
> +        if (copy_to_guest(mtopology.vcpu_to_vnode,
> +                                d->vnuma.vcpu_to_vnode,
> +                                max_vcpus) != 0)
> +            goto vnumaout;
> +        rc = 0;
> +vnumaout:

Again needs to be indented by one space.

> @@ -863,6 +864,17 @@ struct xen_domctl_set_max_evtchn {
>  typedef struct xen_domctl_set_max_evtchn xen_domctl_set_max_evtchn_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_max_evtchn_t);
>  
> +struct xen_domctl_vnuma {
> +    uint16_t nr_vnodes;

Please insert explicit padding here. And if you want the structure
to be extensible without having to increment the domctl interface
version, you'd also require (and check!) the padding space to be
zero-initialized.

> +struct vnuma_memblk {
> +              uint64_t start, end;

Too deep indentation.

> --- a/xen/include/xen/domain.h
> +++ b/xen/include/xen/domain.h
> @@ -4,6 +4,7 @@
>  
>  #include <public/xen.h>
>  #include <asm/domain.h>
> +#include <public/memory.h>

Avoid such unnecessary dependencies if you can. And you can
here ...

> @@ -89,4 +90,14 @@ extern unsigned int xen_processor_pmbits;
>  
>  extern bool_t opt_dom0_vcpus_pin;
>  
> +struct domain_vnuma_info {
> +    uint16_t nr_vnodes;
> +    uint *vdistance;
> +    uint *vcpu_to_vnode;
> +    uint *vnode_to_pnode;
> +    vnuma_memblk_t *vnuma_memblks;

... by using struct vnuma_memblk here.

> --- /dev/null
> +++ b/xen/include/xen/vnuma.h
> @@ -0,0 +1,18 @@
> +#ifndef _VNUMA_H
> +#define _VNUMA_H
> +#include <public/memory.h>
> +
> +/* DEFINE_XEN_GUEST_HANDLE(vnuma_memblk_t); */
> +
> +struct vnuma_topology_info {
> +    domid_t domid;
> +    uint16_t nr_vnodes;
> +    uint32_t _pad;
> +    XEN_GUEST_HANDLE_64(uint) vdistance;
> +    XEN_GUEST_HANDLE_64(uint) vcpu_to_vnode;
> +    XEN_GUEST_HANDLE_64(vnuma_memblk_t) vnuma_memblks;
> +};
> +typedef struct vnuma_topology_info vnuma_topology_info_t;
> +DEFINE_XEN_GUEST_HANDLE(vnuma_topology_info_t);

This being the argument of XENMEM_get_vnuma_info, how can
this live in a non-public header? (I'm sure I had pointed this out
before.)

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.