|
|
@@ -714,13 +714,31 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static inline int __get_request_mask(struct inode *in) {
|
|
|
+ struct ceph_mds_request *req = current->journal_info;
|
|
|
+ int mask = 0;
|
|
|
+ if (req && req->r_target_inode == in) {
|
|
|
+ if (req->r_op == CEPH_MDS_OP_LOOKUP ||
|
|
|
+ req->r_op == CEPH_MDS_OP_LOOKUPINO ||
|
|
|
+ req->r_op == CEPH_MDS_OP_LOOKUPPARENT ||
|
|
|
+ req->r_op == CEPH_MDS_OP_GETATTR) {
|
|
|
+ mask = le32_to_cpu(req->r_args.getattr.mask);
|
|
|
+ } else if (req->r_op == CEPH_MDS_OP_OPEN ||
|
|
|
+ req->r_op == CEPH_MDS_OP_CREATE) {
|
|
|
+ mask = le32_to_cpu(req->r_args.open.mask);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return mask;
|
|
|
+}
|
|
|
+
|
|
|
ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
|
|
|
size_t size)
|
|
|
{
|
|
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
|
|
- int err;
|
|
|
struct ceph_inode_xattr *xattr;
|
|
|
struct ceph_vxattr *vxattr = NULL;
|
|
|
+ int req_mask;
|
|
|
+ int err;
|
|
|
|
|
|
if (!ceph_is_valid_xattr(name))
|
|
|
return -ENODATA;
|
|
|
@@ -734,13 +752,24 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ req_mask = __get_request_mask(inode);
|
|
|
+
|
|
|
spin_lock(&ci->i_ceph_lock);
|
|
|
dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
|
|
|
ci->i_xattrs.version, ci->i_xattrs.index_version);
|
|
|
|
|
|
if (ci->i_xattrs.version == 0 ||
|
|
|
- !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) {
|
|
|
+ !((req_mask & CEPH_CAP_XATTR_SHARED) ||
|
|
|
+ __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1))) {
|
|
|
spin_unlock(&ci->i_ceph_lock);
|
|
|
+
|
|
|
+ /* security module gets xattr while filling trace */
|
|
|
+ if (current->journal_info != NULL) {
|
|
|
+ pr_warn_ratelimited("sync getxattr %p "
|
|
|
+ "during filling trace\n", inode);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
/* get xattrs from mds (if we don't already have them) */
|
|
|
err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
|
|
|
if (err)
|
|
|
@@ -767,6 +796,9 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
|
|
|
|
|
|
memcpy(value, xattr->val, xattr->val_len);
|
|
|
|
|
|
+ if (current->journal_info != NULL &&
|
|
|
+ !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN))
|
|
|
+ ci->i_ceph_flags |= CEPH_I_SEC_INITED;
|
|
|
out:
|
|
|
spin_unlock(&ci->i_ceph_lock);
|
|
|
return err;
|
|
|
@@ -1017,7 +1049,15 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
|
|
|
do_sync_unlocked:
|
|
|
if (lock_snap_rwsem)
|
|
|
up_read(&mdsc->snap_rwsem);
|
|
|
- err = ceph_sync_setxattr(dentry, name, value, size, flags);
|
|
|
+
|
|
|
+ /* security module set xattr while filling trace */
|
|
|
+ if (current->journal_info != NULL) {
|
|
|
+ pr_warn_ratelimited("sync setxattr %p "
|
|
|
+ "during filling trace\n", inode);
|
|
|
+ err = -EBUSY;
|
|
|
+ } else {
|
|
|
+ err = ceph_sync_setxattr(dentry, name, value, size, flags);
|
|
|
+ }
|
|
|
out:
|
|
|
ceph_free_cap_flush(prealloc_cf);
|
|
|
kfree(newname);
|
|
|
@@ -1166,3 +1206,25 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
|
|
|
|
|
|
return __ceph_removexattr(dentry, name);
|
|
|
}
|
|
|
+
|
|
|
+#ifdef CONFIG_SECURITY
|
|
|
+bool ceph_security_xattr_wanted(struct inode *in)
|
|
|
+{
|
|
|
+ return in->i_security != NULL;
|
|
|
+}
|
|
|
+
|
|
|
+bool ceph_security_xattr_deadlock(struct inode *in)
|
|
|
+{
|
|
|
+ struct ceph_inode_info *ci;
|
|
|
+ bool ret;
|
|
|
+ if (in->i_security == NULL)
|
|
|
+ return false;
|
|
|
+ ci = ceph_inode(in);
|
|
|
+ spin_lock(&ci->i_ceph_lock);
|
|
|
+ ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) &&
|
|
|
+ !(ci->i_xattrs.version > 0 &&
|
|
|
+ __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0));
|
|
|
+ spin_unlock(&ci->i_ceph_lock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif
|