Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76381a42 authored by Aneesh Kumar K.V's avatar Aneesh Kumar K.V Committed by Eric Van Hensbergen
Browse files

fs/9p: Add access = client option to opt in acl evaluation.

parent ad77dbce
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -111,7 +111,7 @@ OPTIONS
  		This can be used to share devices/named pipes/sockets between
  		This can be used to share devices/named pipes/sockets between
		hosts.  This functionality will be expanded in later versions.
		hosts.  This functionality will be expanded in later versions.


  access	there are three access modes.
  access	there are four access modes.
			user  = if a user tries to access a file on v9fs
			user  = if a user tries to access a file on v9fs
			        filesystem for the first time, v9fs sends an
			        filesystem for the first time, v9fs sends an
			        attach command (Tattach) for that user.
			        attach command (Tattach) for that user.
@@ -120,6 +120,8 @@ OPTIONS
				the files on the mounted filesystem
				the files on the mounted filesystem
			any   = v9fs does single attach and performs all
			any   = v9fs does single attach and performs all
				operations as one user
				operations as one user
			client = ACL based access check on the 9p client
			         side for access validation


  cachetag	cache tag to use the specified persistent cache.
  cachetag	cache tag to use the specified persistent cache.
		cache tags for existing cache sessions can be listed at
		cache tags for existing cache sessions can be listed at
+77 −1
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@
#include "xattr.h"
#include "xattr.h"
#include "acl.h"
#include "acl.h"
#include "v9fs_vfs.h"
#include "v9fs_vfs.h"
#include "v9fs.h"


static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
{
{
@@ -55,7 +56,14 @@ int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
{
{
	int retval = 0;
	int retval = 0;
	struct posix_acl *pacl, *dacl;
	struct posix_acl *pacl, *dacl;
	struct v9fs_session_info *v9ses;


	v9ses = v9fs_inode2v9ses(inode);
	if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
		set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
		set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
		return 0;
	}
	/* get the default/access acl values and cache them */
	/* get the default/access acl values and cache them */
	dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
	dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
	pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
	pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
@@ -85,7 +93,18 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)


int v9fs_check_acl(struct inode *inode, int mask)
int v9fs_check_acl(struct inode *inode, int mask)
{
{
	struct posix_acl *acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
	struct posix_acl *acl;
	struct v9fs_session_info *v9ses;

	v9ses = v9fs_inode2v9ses(inode);
	if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
		/*
		 * On access = client mode get the acl
		 * values from the server
		 */
		return 0;
	}
	acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);


	if (IS_ERR(acl))
	if (IS_ERR(acl))
		return PTR_ERR(acl);
		return PTR_ERR(acl);
@@ -204,15 +223,41 @@ int v9fs_acl_mode(struct inode *dir, mode_t *modep,


}
}


static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
			       void *buffer, size_t size, int type)
{
	char *full_name;

	switch (type) {
	case ACL_TYPE_ACCESS:
		full_name =  POSIX_ACL_XATTR_ACCESS;
		break;
	case ACL_TYPE_DEFAULT:
		full_name = POSIX_ACL_XATTR_DEFAULT;
		break;
	default:
		BUG();
	}
	return v9fs_xattr_get(dentry, full_name, buffer, size);
}

static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
			      void *buffer, size_t size, int type)
			      void *buffer, size_t size, int type)
{
{
	struct v9fs_session_info *v9ses;
	struct posix_acl *acl;
	struct posix_acl *acl;
	int error;
	int error;


	if (strcmp(name, "") != 0)
	if (strcmp(name, "") != 0)
		return -EINVAL;
		return -EINVAL;


	v9ses = v9fs_inode2v9ses(dentry->d_inode);
	/*
	 * We allow set/get/list of acl when access=client is not specified
	 */
	if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
		return v9fs_remote_get_acl(dentry, name, buffer, size, type);

	acl = v9fs_get_cached_acl(dentry->d_inode, type);
	acl = v9fs_get_cached_acl(dentry->d_inode, type);
	if (IS_ERR(acl))
	if (IS_ERR(acl))
		return PTR_ERR(acl);
		return PTR_ERR(acl);
@@ -224,16 +269,47 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
	return error;
	return error;
}
}


static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
			      const void *value, size_t size,
			      int flags, int type)
{
	char *full_name;

	switch (type) {
	case ACL_TYPE_ACCESS:
		full_name =  POSIX_ACL_XATTR_ACCESS;
		break;
	case ACL_TYPE_DEFAULT:
		full_name = POSIX_ACL_XATTR_DEFAULT;
		break;
	default:
		BUG();
	}
	return v9fs_xattr_set(dentry, full_name, value, size, flags);
}


static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
			      const void *value, size_t size,
			      const void *value, size_t size,
			      int flags, int type)
			      int flags, int type)
{
{
	int retval;
	int retval;
	struct posix_acl *acl;
	struct posix_acl *acl;
	struct v9fs_session_info *v9ses;
	struct inode *inode = dentry->d_inode;
	struct inode *inode = dentry->d_inode;


	if (strcmp(name, "") != 0)
	if (strcmp(name, "") != 0)
		return -EINVAL;
		return -EINVAL;

	v9ses = v9fs_inode2v9ses(dentry->d_inode);
	/*
	 * set the attribute on the remote. Without even looking at the
	 * xattr value. We leave it to the server to validate
	 */
	if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
		return v9fs_remote_set_acl(dentry, name,
					   value, size, flags, type);

	if (S_ISLNK(inode->i_mode))
	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;
		return -EOPNOTSUPP;
	if (!is_owner_or_cap(inode))
	if (!is_owner_or_cap(inode))
+1 −0
Original line number Original line Diff line number Diff line
@@ -149,6 +149,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
	switch (access) {
	switch (access) {
	case V9FS_ACCESS_SINGLE:
	case V9FS_ACCESS_SINGLE:
	case V9FS_ACCESS_USER:
	case V9FS_ACCESS_USER:
	case V9FS_ACCESS_CLIENT:
		uid = current_fsuid();
		uid = current_fsuid();
		any = 0;
		any = 0;
		break;
		break;
+21 −1
Original line number Original line Diff line number Diff line
@@ -193,7 +193,17 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
				v9ses->flags |= V9FS_ACCESS_USER;
				v9ses->flags |= V9FS_ACCESS_USER;
			else if (strcmp(s, "any") == 0)
			else if (strcmp(s, "any") == 0)
				v9ses->flags |= V9FS_ACCESS_ANY;
				v9ses->flags |= V9FS_ACCESS_ANY;
			else {
			else if (strcmp(s, "client") == 0) {
#ifdef CONFIG_9P_FS_POSIX_ACL
				v9ses->flags |= V9FS_ACCESS_CLIENT;
#else
				P9_DPRINTK(P9_DEBUG_ERROR,
					"access=client option not supported\n");
				kfree(s);
				ret = -EINVAL;
				goto free_and_return;
#endif
			} else {
				v9ses->flags |= V9FS_ACCESS_SINGLE;
				v9ses->flags |= V9FS_ACCESS_SINGLE;
				v9ses->uid = simple_strtoul(s, &e, 10);
				v9ses->uid = simple_strtoul(s, &e, 10);
				if (*e != '\0')
				if (*e != '\0')
@@ -278,6 +288,16 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,


	v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
	v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;


	if (!v9fs_proto_dotl(v9ses) &&
	    ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
		/*
		 * We support ACCESS_CLIENT only for dotl.
		 * Fall back to ACCESS_USER
		 */
		v9ses->flags &= ~V9FS_ACCESS_MASK;
		v9ses->flags |= V9FS_ACCESS_USER;
	}
	/*FIXME !! */
	/* for legacy mode, fall back to V9FS_ACCESS_ANY */
	/* for legacy mode, fall back to V9FS_ACCESS_ANY */
	if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
	if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
		((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
		((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
+6 −2
Original line number Original line Diff line number Diff line
@@ -33,13 +33,17 @@
 *
 *
 * Session flags reflect options selected by users at mount time
 * Session flags reflect options selected by users at mount time
 */
 */
#define	V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
			 V9FS_ACCESS_USER |   \
			 V9FS_ACCESS_CLIENT)
#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY

enum p9_session_flags {
enum p9_session_flags {
	V9FS_PROTO_2000U	= 0x01,
	V9FS_PROTO_2000U	= 0x01,
	V9FS_PROTO_2000L	= 0x02,
	V9FS_PROTO_2000L	= 0x02,
	V9FS_ACCESS_SINGLE	= 0x04,
	V9FS_ACCESS_SINGLE	= 0x04,
	V9FS_ACCESS_USER	= 0x08,
	V9FS_ACCESS_USER	= 0x08,
	V9FS_ACCESS_ANY		= 0x0C,
	V9FS_ACCESS_CLIENT	= 0x10
	V9FS_ACCESS_MASK	= 0x0C,
};
};


/* possible values of ->cache */
/* possible values of ->cache */
Loading