|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 5/5] v4v: Introduce basic access control to V4V
Hi,
At 17:26 +0100 on 28 Jun (1340904386), Jean Guyader wrote:
> +#ifdef V4V_DEBUG
> +void
> +v4v_viptables_print_rule (struct v4v_viptables_rule_node *rule)
> +{
> + if (rule == NULL)
> + {
> + printk("(null)\n");
> + return;
> + }
The indentation doesn't follow the coding style at all in this patch.
> +int
> +v4v_viptables_add (struct domain *src_d,
> XEN_GUEST_HANDLE(v4v_viptables_rule_t) rule,
> + int32_t position)
> +{
> + struct v4v_viptables_rule_node* new;
> + struct list_head* tmp;
> +
> + /* First rule is n.1 */
> + position--;
> +
> + new = xmalloc (struct v4v_viptables_rule_node);
What if xmalloc() fails?
> + if (copy_field_from_guest (new, rule, src))
> + return -EFAULT;
> + if (copy_field_from_guest (new, rule, dst))
> + return -EFAULT;
> + if (copy_field_from_guest (new, rule, accept))
> + return -EFAULT;
Leaking 'new' here.
> +#ifdef V4V_DEBUG
> + printk(KERN_ERR "VIPTables: ");
> + v4v_viptables_print_rule(new);
> +#endif /* V4V_DEBUG */
> +
> + tmp = &viprules;
> + while (position != 0 && tmp->next != &viprules)
> + {
> + tmp = tmp->next;
> + position--;
> + }
> + list_add(&new->list, tmp);
Doesn't this need to be protected by a lock? AFAICS this function is
called under domain_lock(d) but modifies a global shared list, and the
readers don't take any locks. If you expect table updates to be rare
then maybe write-locking the L1 lock would suffice.
> +
> + return 0;
> +}
> +
> +int
> +v4v_viptables_del (struct domain *src_d,
> XEN_GUEST_HANDLE(v4v_viptables_rule_t) rule,
> + int32_t position)
> +{
> + struct list_head *tmp = NULL;
> + struct list_head *next = NULL;
> + struct v4v_viptables_rule_node *node;
> + struct v4v_viptables_rule *r;
> +
> + if (position != -1)
> + {
> + /* We want to delete the rule number <position> */
> + tmp = &viprules;
> + while (position != 0 && tmp->next != &viprules)
> + {
> + tmp = tmp->next;
> + position--;
> + }
> + }
> + else if (!guest_handle_is_null(rule))
> + {
> + /* We want to delete the rule <rule> */
> + r = xmalloc (struct v4v_viptables_rule);
It's probably OK for this to go on the stack - it's not that big, and...
> + if (copy_field_from_guest (r, rule, src))
> + return -EFAULT;
> + if (copy_field_from_guest (r, rule, dst))
> + return -EFAULT;
> + if (copy_field_from_guest (r, rule, accept))
> + return -EFAULT;
... it would stop you leaking 'r' here.
> + list_for_each(tmp, &viprules)
> + {
> + node = list_entry(tmp, struct v4v_viptables_rule_node, list);
> +
> + if ((node->src.domain == r->src.domain) &&
> + (node->src.port == r->src.port) &&
> + (node->dst.domain == r->dst.domain) &&
> + (node->dst.port == r->dst.port))
> + {
> + position = 0;
> + break;
> + }
> + }
> + xfree(r);
> + }
> + else
> + {
> + /* We want to flush the rules! */
> + printk(KERN_ERR "VIPTables: flushing rules\n");
> + list_for_each_safe(tmp, next, &viprules)
> + {
> + node = list_entry(tmp, struct v4v_viptables_rule_node, list);
> + list_del(tmp);
> + xfree(node);
> + }
> + }
> +
> +#ifdef V4V_DEBUG
> + if (position == 0 && tmp != &viprules)
> + {
> + printk(KERN_ERR "VIPTables: deleting rule: ");
> + node = list_entry(tmp, struct v4v_viptables_rule_node, list);
> + v4v_viptables_print_rule(node);
> + list_del(tmp);
> + xfree(node);
This list_del/xfree should definitely not be #ifdef V4V_DEBUG :)
> + }
> +#endif /* V4V_DEBUG */
> +
> + return 0;
> +}
> +
> +static size_t
> +v4v_viptables_list (struct domain *src_d,
> XEN_GUEST_HANDLE(v4v_viptables_list_t) list_hnd)
> +{
> + struct list_head *ptr;
> + struct v4v_viptables_rule_node *node;
> + struct v4v_viptables_list rules_list;
> + uint32_t nbrules;
> +
> + memset(&rules_list, 0, sizeof (rules_list));
> + if (copy_field_from_guest (&rules_list, list_hnd, nb_rules))
> + return -EFAULT;
> +
> + ptr = viprules.next;
> + while (rules_list.nb_rules != 0 && ptr->next != &viprules)
> + {
> + ptr = ptr->next;
> + rules_list.start_rule--;
> + }
> +
> + if (rules_list.nb_rules != 0)
> + return -EFAULT;
Surely s/nb_rules/start_rule/ in both the while() and the if() above?
How much testing has this had? It seems like this function could never
get as far as copying the rules out.
> +
> + nbrules = 0;
> + while (nbrules < rules_list.nb_rules && ptr != &viprules)
> + {
> + node = list_entry(ptr, struct v4v_viptables_rule_node, list);
> +
> + rules_list.rules[rules_list.nb_rules].src = node->src;
> + rules_list.rules[rules_list.nb_rules].dst = node->dst;
> + rules_list.rules[rules_list.nb_rules].accept = node->accept;
Aiee! Good thing it never gets that far, because (a) you're indirecting
a user-supplied distance into a stack array, and (b) the stack array has
zero length.
> +
> + nbrules++;
> + ptr = ptr->next;
> + }
> +
> + if (copy_to_guest(list_hnd, &rules_list, 1))
> + return -EFAULT;
And at the end you only copy the header back to the caller. :|
> +
> + return 0;
> +}
> +
> +static size_t
> +v4v_viptables_check (v4v_addr_t * src, v4v_addr_t * dst)
> +{
> + struct list_head *ptr;
> + struct v4v_viptables_rule_node *node;
> +
> + list_for_each(ptr, &viprules)
> + {
> + node = list_entry(ptr, struct v4v_viptables_rule_node, list);
> +
> + if ((node->src.domain == DOMID_INVALID || node->src.domain ==
> src->domain) &&
Having defined a new magic V4V_DOMID_* to avoid using DOMID_INVALID, you
should probably use it here.
(oh, and while I'm here please keep lines < 80 characters).
> + (node->src.port == -1 || node->src.port ==
> src->port) &&
Likewise, why is this not V4V_PORT_NONE?
> + (node->dst.domain == DOMID_INVALID || node->dst.domain ==
> dst->domain) &&
> + (node->dst.port == -1 || node->dst.port ==
> dst->port))
And what about protocol? Protocol seems to have ended up as a bit of a
second-class citizen in v4v; it's defined, and indeed required, but not
used for routing or for acccess control, so all traffic to a given port
_on every protocol_ ends up on the same ring.
This is the inverse of the TCP/IP namespace that you're copying, where
protocol demux happens before port demux. And I think it will bite
someone if you ever, for example, want to send ICMP or GRE over a v4v
channel.
> + return !node->accept;
> + }
> +
> + /* Defaulting to ACCEPT */
> + return 0;
> +}
>
> /*Hypercall to do the send*/
> static size_t
> @@ -1351,6 +1566,15 @@ v4v_send (struct domain *src_d, v4v_addr_t * src_addr,
> return -ECONNREFUSED;
> }
>
> + if (v4v_viptables_check(src_addr, dst_addr) != 0)
> + {
> + read_unlock (&v4v_lock);
> + printk(KERN_ERR "V4V: VIPTables REJECTED %i:%i -> %i:%i\n",
> + src_addr->domain, src_addr->port,
> + dst_addr->domain, dst_addr->port);
This should be at most a gdprintk to stop a badly behaved VM from
spamming the console.
> + return -ECONNREFUSED;
> + }
> +
> do
> {
> if ( !dst_d->v4v )
> @@ -1437,6 +1661,15 @@ v4v_sendv (struct domain *src_d, v4v_addr_t * src_addr,
> return -ECONNREFUSED;
> }
>
> + if (v4v_viptables_check(src_addr, dst_addr) != 0)
> + {
> + read_unlock (&v4v_lock);
> + printk(KERN_ERR "V4V: VIPTables REJECTED %i:%i -> %i:%i\n",
> + src_addr->domain, src_addr->port,
> + dst_addr->domain, dst_addr->port);
Likewise.
> + return -ECONNREFUSED;
> + }
> +
> do
> {
> if ( !dst_d->v4v )
> @@ -1596,6 +1829,38 @@ do_v4v_op (int cmd, XEN_GUEST_HANDLE (void) arg1,
> rc = v4v_notify (d, ring_data_hnd);
> break;
> }
> + case V4VOP_viptables_add:
> + {
> + uint32_t position = arg4;
> + XEN_GUEST_HANDLE (v4v_viptables_rule_t) rule_hnd =
> + guest_handle_cast (arg1, v4v_viptables_rule_t);
> + rc = -EPERM;
> + if (!IS_PRIV(d))
> + goto out;
> + rc = v4v_viptables_add (d, rule_hnd, position);
> + break;
> + }
> + case V4VOP_viptables_del:
> + {
> + uint32_t position = arg4;
> + XEN_GUEST_HANDLE (v4v_viptables_rule_t) rule_hnd =
> + guest_handle_cast (arg1, v4v_viptables_rule_t);
> + rc = -EPERM;
> + if (!IS_PRIV(d))
> + goto out;
> + rc = v4v_viptables_del (d, rule_hnd, position);
> + break;
> + }
> + case V4VOP_viptables_list:
> + {
> + XEN_GUEST_HANDLE (v4v_viptables_list_t) rules_list_hnd =
> + guest_handle_cast(arg1, v4v_viptables_list_t);
> + rc = -EPERM;
> + if (!IS_PRIV(d))
> + goto out;
> + rc = v4v_viptables_list (d, rules_list_hnd);
> + break;
> + }
> default:
> rc = -ENOSYS;
> break;
> diff --git a/xen/include/public/v4v.h b/xen/include/public/v4v.h
> index 197770e..d8ca507 100644
> --- a/xen/include/public/v4v.h
> +++ b/xen/include/public/v4v.h
> @@ -213,6 +213,9 @@
> * NULL, NULL, nent, 0)
> */
>
> +#define V4VOP_viptables_add 6
> +#define V4VOP_viptables_del 7
> +#define V4VOP_viptables_list 8
This will need documentation, and descriptions of the arguments
(assuming the actual definitions don't end up moving back into this
file).
And they should probably go below the V4VOP_sendv definition.
Cheers,
Tim.
> #define V4VOP_sendv 5
> /*
> diff --git a/xen/include/xen/v4v.h b/xen/include/xen/v4v.h
> index 641a6a8..e5b4cb7 100644
> --- a/xen/include/xen/v4v.h
> +++ b/xen/include/xen/v4v.h
> @@ -103,6 +103,32 @@ struct v4v_ring_message_header
> uint8_t data[0];
> } V4V_PACKED;
>
> +typedef struct v4v_viptables_rule
> +{
> + struct v4v_addr src;
> + struct v4v_addr dst;
> + uint32_t accept;
> +} V4V_PACKED v4v_viptables_rule_t;
> +
> +DEFINE_XEN_GUEST_HANDLE (v4v_viptables_rule_t);
> +
> +struct v4v_viptables_rule_node
> +{
> + struct list_head list;
> + struct v4v_addr src;
> + struct v4v_addr dst;
> + uint32_t accept;
> +} V4V_PACKED;
> +
> +typedef struct v4v_viptables_list
> +{
> + uint32_t start_rule;
> + uint32_t nb_rules;
> + struct v4v_viptables_rule rules[0];
> +} V4V_PACKED v4v_viptables_list_t;
> +
> +DEFINE_XEN_GUEST_HANDLE (v4v_viptables_list_t);
> +
> /*
> * Helper functions
> */
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |