Commit 866eef48 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher

gfs2: Add trusted xattr support

Add support for an additional filesystem version (sb_fs_format = 1802).
When a filesystem with the new version is mounted, the filesystem
supports "trusted.*" xattrs.

In addition, version 1802 filesystems implement a form of forward
compatibility for xattrs: when xattrs with an unknown prefix (ea_type)
are found on a version 1802 filesystem, those attributes are not shown
by listxattr, and they are not accessible by getxattr, setxattr, or
removexattr.

This mechanism might turn out to be what we need in the future, but if
not, we can always bump the filesystem version and break compatibility
instead.
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: default avatarAndrew Price <anprice@redhat.com>
parent 47b7ec1d
...@@ -489,6 +489,19 @@ static int init_sb(struct gfs2_sbd *sdp, int silent) ...@@ -489,6 +489,19 @@ static int init_sb(struct gfs2_sbd *sdp, int silent)
goto out; goto out;
} }
switch(sdp->sd_sb.sb_fs_format) {
case GFS2_FS_FORMAT_MAX:
sb->s_xattr = gfs2_xattr_handlers_max;
break;
case GFS2_FS_FORMAT_MIN:
sb->s_xattr = gfs2_xattr_handlers_min;
break;
default:
BUG();
}
/* Set up the buffer cache and SB for real */ /* Set up the buffer cache and SB for real */
if (sdp->sd_sb.sb_bsize < bdev_logical_block_size(sb->s_bdev)) { if (sdp->sd_sb.sb_bsize < bdev_logical_block_size(sb->s_bdev)) {
ret = -EINVAL; ret = -EINVAL;
...@@ -1110,7 +1123,6 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1110,7 +1123,6 @@ static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_op = &gfs2_super_ops; sb->s_op = &gfs2_super_ops;
sb->s_d_op = &gfs2_dops; sb->s_d_op = &gfs2_dops;
sb->s_export_op = &gfs2_export_ops; sb->s_export_op = &gfs2_export_ops;
sb->s_xattr = gfs2_xattr_handlers;
sb->s_qcop = &gfs2_quotactl_ops; sb->s_qcop = &gfs2_quotactl_ops;
sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
......
...@@ -58,7 +58,9 @@ extern struct file_system_type gfs2meta_fs_type; ...@@ -58,7 +58,9 @@ extern struct file_system_type gfs2meta_fs_type;
extern const struct export_operations gfs2_export_ops; extern const struct export_operations gfs2_export_ops;
extern const struct super_operations gfs2_super_ops; extern const struct super_operations gfs2_super_ops;
extern const struct dentry_operations gfs2_dops; extern const struct dentry_operations gfs2_dops;
extern const struct xattr_handler *gfs2_xattr_handlers[];
extern const struct xattr_handler *gfs2_xattr_handlers_max[];
extern const struct xattr_handler **gfs2_xattr_handlers_min;
#endif /* __SUPER_DOT_H__ */ #endif /* __SUPER_DOT_H__ */
...@@ -70,6 +70,20 @@ static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize) ...@@ -70,6 +70,20 @@ static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize)
return 0; return 0;
} }
static bool gfs2_eatype_valid(struct gfs2_sbd *sdp, u8 type)
{
switch(sdp->sd_sb.sb_fs_format) {
case GFS2_FS_FORMAT_MAX:
return true;
case GFS2_FS_FORMAT_MIN:
return type <= GFS2_EATYPE_SECURITY;
default:
return false;
}
}
typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh, typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh,
struct gfs2_ea_header *ea, struct gfs2_ea_header *ea,
struct gfs2_ea_header *prev, void *private); struct gfs2_ea_header *prev, void *private);
...@@ -77,6 +91,7 @@ typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -77,6 +91,7 @@ typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh,
static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh, static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh,
ea_call_t ea_call, void *data) ea_call_t ea_call, void *data)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_ea_header *ea, *prev = NULL; struct gfs2_ea_header *ea, *prev = NULL;
int error = 0; int error = 0;
...@@ -89,9 +104,8 @@ static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -89,9 +104,8 @@ static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh,
if (!(bh->b_data <= (char *)ea && (char *)GFS2_EA2NEXT(ea) <= if (!(bh->b_data <= (char *)ea && (char *)GFS2_EA2NEXT(ea) <=
bh->b_data + bh->b_size)) bh->b_data + bh->b_size))
goto fail; goto fail;
if (!GFS2_EATYPE_VALID(ea->ea_type)) if (!gfs2_eatype_valid(sdp, ea->ea_type))
goto fail; goto fail;
error = ea_call(ip, bh, ea, prev, data); error = ea_call(ip, bh, ea, prev, data);
if (error) if (error)
return error; return error;
...@@ -344,6 +358,7 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -344,6 +358,7 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
void *private) void *private)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct ea_list *ei = private; struct ea_list *ei = private;
struct gfs2_ea_request *er = ei->ei_er; struct gfs2_ea_request *er = ei->ei_er;
unsigned int ea_size; unsigned int ea_size;
...@@ -353,6 +368,8 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -353,6 +368,8 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
if (ea->ea_type == GFS2_EATYPE_UNUSED) if (ea->ea_type == GFS2_EATYPE_UNUSED)
return 0; return 0;
BUG_ON(ea->ea_type > GFS2_EATYPE_SECURITY &&
sdp->sd_sb.sb_fs_format == GFS2_FS_FORMAT_MIN);
switch (ea->ea_type) { switch (ea->ea_type) {
case GFS2_EATYPE_USR: case GFS2_EATYPE_USR:
prefix = "user."; prefix = "user.";
...@@ -366,8 +383,12 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, ...@@ -366,8 +383,12 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
prefix = "security."; prefix = "security.";
l = 9; l = 9;
break; break;
case GFS2_EATYPE_TRUSTED:
prefix = "trusted.";
l = 8;
break;
default: default:
BUG(); return 0;
} }
ea_size = l + ea->ea_name_len + 1; ea_size = l + ea->ea_name_len + 1;
...@@ -1463,7 +1484,25 @@ static const struct xattr_handler gfs2_xattr_security_handler = { ...@@ -1463,7 +1484,25 @@ static const struct xattr_handler gfs2_xattr_security_handler = {
.set = gfs2_xattr_set, .set = gfs2_xattr_set,
}; };
const struct xattr_handler *gfs2_xattr_handlers[] = { static bool
gfs2_xattr_trusted_list(struct dentry *dentry)
{
return capable(CAP_SYS_ADMIN);
}
static const struct xattr_handler gfs2_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.flags = GFS2_EATYPE_TRUSTED,
.list = gfs2_xattr_trusted_list,
.get = gfs2_xattr_get,
.set = gfs2_xattr_set,
};
const struct xattr_handler *gfs2_xattr_handlers_max[] = {
/* GFS2_FS_FORMAT_MAX */
&gfs2_xattr_trusted_handler,
/* GFS2_FS_FORMAT_MIN */
&gfs2_xattr_user_handler, &gfs2_xattr_user_handler,
&gfs2_xattr_security_handler, &gfs2_xattr_security_handler,
&posix_acl_access_xattr_handler, &posix_acl_access_xattr_handler,
...@@ -1471,3 +1510,4 @@ const struct xattr_handler *gfs2_xattr_handlers[] = { ...@@ -1471,3 +1510,4 @@ const struct xattr_handler *gfs2_xattr_handlers[] = {
NULL, NULL,
}; };
const struct xattr_handler **gfs2_xattr_handlers_min = gfs2_xattr_handlers_max + 1;
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#define GFS2_FORMAT_DE 1200 #define GFS2_FORMAT_DE 1200
#define GFS2_FORMAT_QU 1500 #define GFS2_FORMAT_QU 1500
/* These are part of the superblock */ /* These are part of the superblock */
#define GFS2_FORMAT_FS 1801 #define GFS2_FORMAT_FS 1802
#define GFS2_FORMAT_MULTI 1900 #define GFS2_FORMAT_MULTI 1900
/* /*
...@@ -389,8 +389,9 @@ struct gfs2_leaf { ...@@ -389,8 +389,9 @@ struct gfs2_leaf {
#define GFS2_EATYPE_USR 1 #define GFS2_EATYPE_USR 1
#define GFS2_EATYPE_SYS 2 #define GFS2_EATYPE_SYS 2
#define GFS2_EATYPE_SECURITY 3 #define GFS2_EATYPE_SECURITY 3
#define GFS2_EATYPE_TRUSTED 4
#define GFS2_EATYPE_LAST 3 #define GFS2_EATYPE_LAST 4
#define GFS2_EATYPE_VALID(x) ((x) <= GFS2_EATYPE_LAST) #define GFS2_EATYPE_VALID(x) ((x) <= GFS2_EATYPE_LAST)
#define GFS2_EAFLAG_LAST 0x01 /* last ea in block */ #define GFS2_EAFLAG_LAST 0x01 /* last ea in block */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment