ia64/xen-unstable

changeset 5993:5eead9930294

Implement watching of nodes which don't exist.
Requires permission check every time event is generated.
Requires generalization of permissions: ask arbitrary number of
parents whether it's OK to tell about node (eg. watching
/dir/subdir/x when /dir is deleted: root permissions will now
determine whether we fire event).
Add test that we don't leak information on whether a file exists
or not.
Signed-off-by: Rusty Russel <rusty@rustcorp.com.au>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Aug 02 18:04:28 2005 +0000 (2005-08-02)
parents a05338d886d9
children 7db8ef0e440a
files tools/xenstore/testsuite/07watch.sh tools/xenstore/xenstored_core.c tools/xenstore/xenstored_watch.c tools/xenstore/xs_lib.h
line diff
     1.1 --- a/tools/xenstore/testsuite/07watch.sh	Tue Aug 02 18:04:00 2005 +0000
     1.2 +++ b/tools/xenstore/testsuite/07watch.sh	Tue Aug 02 18:04:28 2005 +0000
     1.3 @@ -160,3 +160,22 @@ 1 ackwatch token
     1.4  1 waitwatch' | ./xs_test 2>&1`" = "1:/test2/foo:token
     1.5  1:contents2
     1.6  1:waitwatch timeout" ]
     1.7 +
     1.8 +# We can watch something which doesn't exist.
     1.9 +[ "`echo '1 watch /dir/subdir token
    1.10 +2 mkdir /dir/subdir
    1.11 +1 waitwatch' | ./xs_test 2>&1`" = "1:/dir/subdir:token" ]
    1.12 +
    1.13 +# If we don't have permission, we won't see event (rm).
    1.14 +[ "`echo '1 setid 1
    1.15 +1 watch /dir/subdir token
    1.16 +setperm /dir 0 NONE
    1.17 +rm /dir/subdir
    1.18 +1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
    1.19 +
    1.20 +# If we don't have permission, we won't see event (create).
    1.21 +[ "`echo '1 setid 1
    1.22 +1 watch /dir/subdir token
    1.23 +mkdir /dir/subdir
    1.24 +write /dir/subdir/entry create contents
    1.25 +1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
     2.1 --- a/tools/xenstore/xenstored_core.c	Tue Aug 02 18:04:00 2005 +0000
     2.2 +++ b/tools/xenstore/xenstored_core.c	Tue Aug 02 18:04:28 2005 +0000
     2.3 @@ -707,7 +707,7 @@ static enum xs_perm_type perm_for_id(dom
     2.4  
     2.5  	/* Owners and tools get it all... */
     2.6  	if (!id || perms[0].id == id)
     2.7 -		return XS_PERM_READ|XS_PERM_WRITE|XS_PERM_CREATE|XS_PERM_OWNER;
     2.8 +		return XS_PERM_READ|XS_PERM_WRITE|XS_PERM_OWNER;
     2.9  
    2.10  	for (i = 1; i < num; i++)
    2.11  		if (perms[i].id == id)
    2.12 @@ -716,20 +716,13 @@ static enum xs_perm_type perm_for_id(dom
    2.13  	return perms[0].perms;
    2.14  }
    2.15  
    2.16 -/* We have a weird permissions system.  You can allow someone into a
    2.17 - * specific node without allowing it in the parents.  If it's going to
    2.18 - * fail, however, we don't want the errno to indicate any information
    2.19 - * about the node. */
    2.20 -static int check_with_parents(struct connection *conn, const char *node,
    2.21 -			      int errnum)
    2.22 +/* What do parents say? */
    2.23 +static enum xs_perm_type ask_parents(struct connection *conn,
    2.24 +				     const char *node)
    2.25  {
    2.26  	struct xs_permissions *perms;
    2.27  	unsigned int num;
    2.28  
    2.29 -	/* We always tell them about memory failures. */
    2.30 -	if (errnum == ENOMEM)
    2.31 -		return errnum;
    2.32 -
    2.33  	do {
    2.34  		node = get_parent(node);
    2.35  		perms = get_perms(conn->transaction, node, &num);
    2.36 @@ -741,10 +734,23 @@ static int check_with_parents(struct con
    2.37  	if (!perms)
    2.38  		corrupt(conn, "No permissions file at root");
    2.39  
    2.40 -	if (!(perm_for_id(conn->id, perms, num) & XS_PERM_READ))
    2.41 -		return EACCES;
    2.42 +	return perm_for_id(conn->id, perms, num);
    2.43 +}
    2.44  
    2.45 -	return errnum;
    2.46 +/* We have a weird permissions system.  You can allow someone into a
    2.47 + * specific node without allowing it in the parents.  If it's going to
    2.48 + * fail, however, we don't want the errno to indicate any information
    2.49 + * about the node. */
    2.50 +static int errno_from_parents(struct connection *conn, const char *node,
    2.51 +			      int errnum)
    2.52 +{
    2.53 +	/* We always tell them about memory failures. */
    2.54 +	if (errnum == ENOMEM)
    2.55 +		return errnum;
    2.56 +
    2.57 +	if (ask_parents(conn, node) & XS_PERM_READ)
    2.58 +		return errnum;
    2.59 +	return EACCES;
    2.60  }
    2.61  
    2.62  char *canonicalize(struct connection *conn, const char *node)
    2.63 @@ -776,24 +782,26 @@ bool check_node_perms(struct connection 
    2.64  	}
    2.65  
    2.66  	perms = get_perms(conn->transaction, node, &num);
    2.67 -	/* No permissions.  If we want to create it and
    2.68 -	 * it doesn't exist, check parent directory. */
    2.69 -	if (!perms && errno == ENOENT && (perm & XS_PERM_CREATE)) {
    2.70 -		char *parent = get_parent(node);
    2.71 -		if (!parent)
    2.72 -			return false;
    2.73  
    2.74 -		perms = get_perms(conn->transaction, parent, &num);
    2.75 -	}
    2.76 -	if (!perms) {
    2.77 -		errno = check_with_parents(conn, node, errno);
    2.78 +	if (perms) {
    2.79 +		if (perm_for_id(conn->id, perms, num) & perm)
    2.80 +			return true;
    2.81 +		errno = EACCES;
    2.82  		return false;
    2.83  	}
    2.84  
    2.85 -	if (perm_for_id(conn->id, perms, num) & perm)
    2.86 -		return true;
    2.87 +	/* If it's OK not to exist, we consult parents. */
    2.88 +	if (errno == ENOENT && (perm & XS_PERM_ENOENT_OK)) {
    2.89 +		if (ask_parents(conn, node) & perm)
    2.90 +			return true;
    2.91 +		/* Parents say they should not know. */
    2.92 +		errno = EACCES;
    2.93 +		return false;
    2.94 +	}
    2.95  
    2.96 -	errno = check_with_parents(conn, node, EACCES);
    2.97 +	/* They might not have permission to even *see* this node, in
    2.98 +	 * which case we return EACCES even if it's ENOENT or EIO. */
    2.99 +	errno = errno_from_parents(conn, node, errno);
   2.100  	return false;
   2.101  }
   2.102  
   2.103 @@ -930,9 +938,9 @@ static void do_write(struct connection *
   2.104  	if (streq(vec[1], XS_WRITE_NONE))
   2.105  		mode = XS_PERM_WRITE;
   2.106  	else if (streq(vec[1], XS_WRITE_CREATE))
   2.107 -		mode = XS_PERM_WRITE|XS_PERM_CREATE;
   2.108 +		mode = XS_PERM_WRITE|XS_PERM_ENOENT_OK;
   2.109  	else if (streq(vec[1], XS_WRITE_CREATE_EXCL))
   2.110 -		mode = XS_PERM_WRITE|XS_PERM_CREATE;
   2.111 +		mode = XS_PERM_WRITE|XS_PERM_ENOENT_OK;
   2.112  	else {
   2.113  		send_error(conn, EINVAL);
   2.114  		return;
   2.115 @@ -951,7 +959,7 @@ static void do_write(struct connection *
   2.116  		}
   2.117  
   2.118  		/* Not going to create it? */
   2.119 -		if (!(mode & XS_PERM_CREATE)) {
   2.120 +		if (streq(vec[1], XS_WRITE_NONE)) {
   2.121  			send_error(conn, ENOENT);
   2.122  			return;
   2.123  		}
   2.124 @@ -985,7 +993,7 @@ static void do_write(struct connection *
   2.125  static void do_mkdir(struct connection *conn, const char *node)
   2.126  {
   2.127  	node = canonicalize(conn, node);
   2.128 -	if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE)) {
   2.129 +	if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_ENOENT_OK)) {
   2.130  		send_error(conn, errno);
   2.131  		return;
   2.132  	}
     3.1 --- a/tools/xenstore/xenstored_watch.c	Tue Aug 02 18:04:00 2005 +0000
     3.2 +++ b/tools/xenstore/xenstored_watch.c	Tue Aug 02 18:04:28 2005 +0000
     3.3 @@ -95,10 +95,19 @@ static int destroy_watch_event(void *_ev
     3.4  	return 0;
     3.5  }
     3.6  
     3.7 -static void add_event(struct watch *watch, const char *node)
     3.8 +static void add_event(struct connection *conn,
     3.9 +		      struct watch *watch, const char *node)
    3.10  {
    3.11  	struct watch_event *event;
    3.12  
    3.13 +	/* Check read permission: no permission, no watch event.
    3.14 +	 * If it doesn't exist, we need permission to read parent.
    3.15 +	 */
    3.16 +	if (!check_node_perms(conn, node, XS_PERM_READ|XS_PERM_ENOENT_OK)) {
    3.17 +		fprintf(stderr, "No permission for %s\n", node);
    3.18 +		return;
    3.19 +	}
    3.20 +
    3.21  	if (watch->relative_path) {
    3.22  		node += strlen(watch->relative_path);
    3.23  		if (*node == '/') /* Could be "" */
    3.24 @@ -132,9 +141,9 @@ void fire_watches(struct connection *con
    3.25  
    3.26  		list_for_each_entry(watch, &i->watches, list) {
    3.27  			if (is_child(node, watch->node))
    3.28 -				add_event(watch, node);
    3.29 +				add_event(i, watch, node);
    3.30  			else if (recurse && is_child(watch->node, node))
    3.31 -				add_event(watch, watch->node);
    3.32 +				add_event(i, watch, watch->node);
    3.33  			else
    3.34  				continue;
    3.35  			/* If connection not doing anything, queue this. */
    3.36 @@ -206,7 +215,7 @@ void do_watch(struct connection *conn, s
    3.37  
    3.38  	relative = !strstarts(vec[0], "/");
    3.39  	vec[0] = canonicalize(conn, vec[0]);
    3.40 -	if (!check_node_perms(conn, vec[0], XS_PERM_READ)) {
    3.41 +	if (!is_valid_nodename(vec[0])) {
    3.42  		send_error(conn, errno);
    3.43  		return;
    3.44  	}
     4.1 --- a/tools/xenstore/xs_lib.h	Tue Aug 02 18:04:00 2005 +0000
     4.2 +++ b/tools/xenstore/xs_lib.h	Tue Aug 02 18:04:28 2005 +0000
     4.3 @@ -30,7 +30,7 @@ enum xs_perm_type {
     4.4  	XS_PERM_READ = 1,
     4.5  	XS_PERM_WRITE = 2,
     4.6  	/* Internal use. */
     4.7 -	XS_PERM_CREATE = 4,
     4.8 +	XS_PERM_ENOENT_OK = 4,
     4.9  	XS_PERM_OWNER = 8,
    4.10  };
    4.11