n<domid> no access
See http://wiki.xen.org/wiki/XenBus section
`Permissions' for details of the permissions system.
+ It is possible to set permissions for the special watch paths
+ "@introduceDomain" and "@releaseDomain" to enable receiving those
+ watches in unprivileged domains.
---------- Watches ----------
@releaseDomain occurs on any domain crash or
shutdown, and also on RELEASE
and domain destruction
+ <wspecial> events are sent to privileged callers or explicitly
+ via SET_PERMS enabled domains only.
When a watch is first set up it is triggered once straight
away, with <path> equal to <wpath>. Watches may be triggered
return write_node_raw(conn, &key, node, no_quota_check);
}
-static enum xs_perm_type perm_for_conn(struct connection *conn,
- const struct node_perms *perms)
+enum xs_perm_type perm_for_conn(struct connection *conn,
+ const struct node_perms *perms)
{
unsigned int i;
enum xs_perm_type mask = XS_PERM_READ|XS_PERM_WRITE|XS_PERM_OWNER;
if (perms.num < 2)
return EINVAL;
- /* First arg is node name. */
- /* We must own node to do this (tools can do this too). */
- node = get_node_canonicalized(conn, in, in->buffer, &name,
- XS_PERM_WRITE | XS_PERM_OWNER);
- if (!node)
- return errno;
-
permstr = in->buffer + strlen(in->buffer) + 1;
perms.num--;
- perms.p = talloc_array(node, struct xs_permissions, perms.num);
+ perms.p = talloc_array(in, struct xs_permissions, perms.num);
if (!perms.p)
return ENOMEM;
if (!xs_strings_to_perms(perms.p, perms.num, permstr))
return errno;
+ /* First arg is node name. */
+ if (strstarts(in->buffer, "@")) {
+ if (set_perms_special(conn, in->buffer, &perms))
+ return errno;
+ send_ack(conn, XS_SET_PERMS);
+ return 0;
+ }
+
+ /* We must own node to do this (tools can do this too). */
+ node = get_node_canonicalized(conn, in, in->buffer, &name,
+ XS_PERM_WRITE | XS_PERM_OWNER);
+ if (!node)
+ return errno;
+
/* Unprivileged domains may not change the owner. */
if (domain_is_unprivileged(conn) &&
perms.p[0].id != node->perms.p[0].id)
struct connection *new_connection(connwritefn_t *write, connreadfn_t *read);
void check_store(void);
void corrupt(struct connection *conn, const char *fmt, ...);
+enum xs_perm_type perm_for_conn(struct connection *conn,
+ const struct node_perms *perms);
/* Is this a valid node name? */
bool is_valid_nodename(const char *node);
xenevtchn_handle *xce_handle = NULL;
+static struct node_perms dom_release_perms;
+static struct node_perms dom_introduce_perms;
+
struct domain
{
struct list_head list;
{
}
+static int set_dom_perms_default(struct node_perms *perms)
+{
+ perms->num = 1;
+ perms->p = talloc_array(NULL, struct xs_permissions, perms->num);
+ if (!perms->p)
+ return -1;
+ perms->p->id = 0;
+ perms->p->perms = XS_PERM_NONE;
+
+ return 0;
+}
+
+static struct node_perms *get_perms_special(const char *name)
+{
+ if (!strcmp(name, "@releaseDomain"))
+ return &dom_release_perms;
+ if (!strcmp(name, "@introduceDomain"))
+ return &dom_introduce_perms;
+ return NULL;
+}
+
+int set_perms_special(struct connection *conn, const char *name,
+ struct node_perms *perms)
+{
+ struct node_perms *p;
+
+ p = get_perms_special(name);
+ if (!p)
+ return EINVAL;
+
+ if ((perm_for_conn(conn, p) & (XS_PERM_WRITE | XS_PERM_OWNER)) !=
+ (XS_PERM_WRITE | XS_PERM_OWNER))
+ return EACCES;
+
+ p->num = perms->num;
+ talloc_free(p->p);
+ p->p = perms->p;
+ talloc_steal(NULL, perms->p);
+
+ return 0;
+}
+
+bool check_perms_special(const char *name, struct connection *conn)
+{
+ struct node_perms *p;
+
+ p = get_perms_special(name);
+ if (!p)
+ return false;
+
+ return perm_for_conn(conn, p) & XS_PERM_READ;
+}
+
static int dom0_init(void)
{
evtchn_port_t port;
xenevtchn_notify(xce_handle, dom0->port);
+ if (set_dom_perms_default(&dom_release_perms) ||
+ set_dom_perms_default(&dom_introduce_perms))
+ return -1;
+
return 0;
}
void domain_watch_dec(struct connection *conn);
int domain_watch(struct connection *conn);
+/* Special node permission handling. */
+int set_perms_special(struct connection *conn, const char *name,
+ struct node_perms *perms);
+bool check_perms_special(const char *name, struct connection *conn);
+
/* Write rate limiting */
#define WRL_FACTOR 1000 /* for fixed-point arithmetic */
/* Create an event for each watch. */
list_for_each_entry(i, &connections, list) {
+ /* introduce/release domain watches */
+ if (check_special_event(name) && !check_perms_special(name, i))
+ continue;
+
list_for_each_entry(watch, &i->watches, list) {
if (exact) {
if (streq(name, watch->node))