1024b7d6aSDominique Martinet // SPDX-License-Identifier: LGPL-2.1 285ff872dSAneesh Kumar K.V /* 385ff872dSAneesh Kumar K.V * Copyright IBM Corporation, 2010 485ff872dSAneesh Kumar K.V * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 585ff872dSAneesh Kumar K.V */ 685ff872dSAneesh Kumar K.V 785ff872dSAneesh Kumar K.V #include <linux/module.h> 885ff872dSAneesh Kumar K.V #include <linux/fs.h> 985ff872dSAneesh Kumar K.V #include <net/9p/9p.h> 1085ff872dSAneesh Kumar K.V #include <net/9p/client.h> 1185ff872dSAneesh Kumar K.V #include <linux/slab.h> 1222d8dcdfSAneesh Kumar K.V #include <linux/sched.h> 1385ff872dSAneesh Kumar K.V #include <linux/posix_acl_xattr.h> 1485ff872dSAneesh Kumar K.V #include "xattr.h" 1585ff872dSAneesh Kumar K.V #include "acl.h" 1676381a42SAneesh Kumar K.V #include "v9fs.h" 175ffc0cb3SAneesh Kumar K.V #include "v9fs_vfs.h" 180f235caeSAl Viro #include "fid.h" 1985ff872dSAneesh Kumar K.V 206cd4d4e8SChristian Brauner static struct posix_acl *v9fs_fid_get_acl(struct p9_fid *fid, const char *name) 2185ff872dSAneesh Kumar K.V { 2285ff872dSAneesh Kumar K.V ssize_t size; 2385ff872dSAneesh Kumar K.V void *value = NULL; 24009ca389SJoe Perches struct posix_acl *acl = NULL; 2585ff872dSAneesh Kumar K.V 2685ff872dSAneesh Kumar K.V size = v9fs_fid_xattr_get(fid, name, NULL, 0); 276cd4d4e8SChristian Brauner if (size < 0) 286cd4d4e8SChristian Brauner return ERR_PTR(size); 296cd4d4e8SChristian Brauner if (size == 0) 306cd4d4e8SChristian Brauner return ERR_PTR(-ENODATA); 316cd4d4e8SChristian Brauner 3285ff872dSAneesh Kumar K.V value = kzalloc(size, GFP_NOFS); 3385ff872dSAneesh Kumar K.V if (!value) 3485ff872dSAneesh Kumar K.V return ERR_PTR(-ENOMEM); 3585ff872dSAneesh Kumar K.V 366cd4d4e8SChristian Brauner size = v9fs_fid_xattr_get(fid, name, value, size); 376cd4d4e8SChristian Brauner if (size < 0) 386cd4d4e8SChristian Brauner acl = ERR_PTR(size); 396cd4d4e8SChristian Brauner else if (size == 0) 406cd4d4e8SChristian Brauner acl = ERR_PTR(-ENODATA); 416cd4d4e8SChristian Brauner else 426cd4d4e8SChristian Brauner acl = posix_acl_from_xattr(&init_user_ns, value, size); 4385ff872dSAneesh Kumar K.V kfree(value); 4485ff872dSAneesh Kumar K.V return acl; 4585ff872dSAneesh Kumar K.V } 4685ff872dSAneesh Kumar K.V 476cd4d4e8SChristian Brauner static struct posix_acl *v9fs_acl_get(struct dentry *dentry, const char *name) 486cd4d4e8SChristian Brauner { 496cd4d4e8SChristian Brauner struct p9_fid *fid; 506cd4d4e8SChristian Brauner struct posix_acl *acl = NULL; 516cd4d4e8SChristian Brauner 526cd4d4e8SChristian Brauner fid = v9fs_fid_lookup(dentry); 536cd4d4e8SChristian Brauner if (IS_ERR(fid)) 546cd4d4e8SChristian Brauner return ERR_CAST(fid); 556cd4d4e8SChristian Brauner 566cd4d4e8SChristian Brauner acl = v9fs_fid_get_acl(fid, name); 576cd4d4e8SChristian Brauner p9_fid_put(fid); 586cd4d4e8SChristian Brauner return acl; 596cd4d4e8SChristian Brauner } 606cd4d4e8SChristian Brauner 616cd4d4e8SChristian Brauner static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, const char *name) 626cd4d4e8SChristian Brauner { 636cd4d4e8SChristian Brauner int retval; 646cd4d4e8SChristian Brauner struct posix_acl *acl = NULL; 656cd4d4e8SChristian Brauner 666cd4d4e8SChristian Brauner acl = v9fs_fid_get_acl(fid, name); 676cd4d4e8SChristian Brauner if (!IS_ERR(acl)) 686cd4d4e8SChristian Brauner return acl; 696cd4d4e8SChristian Brauner 706cd4d4e8SChristian Brauner retval = PTR_ERR(acl); 716cd4d4e8SChristian Brauner if (retval == -ENODATA || retval == -ENOSYS || retval == -EOPNOTSUPP) 726cd4d4e8SChristian Brauner return NULL; 736cd4d4e8SChristian Brauner 746cd4d4e8SChristian Brauner /* map everything else to -EIO */ 756cd4d4e8SChristian Brauner return ERR_PTR(-EIO); 766cd4d4e8SChristian Brauner } 776cd4d4e8SChristian Brauner 7885ff872dSAneesh Kumar K.V int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) 7985ff872dSAneesh Kumar K.V { 8085ff872dSAneesh Kumar K.V int retval = 0; 8185ff872dSAneesh Kumar K.V struct posix_acl *pacl, *dacl; 8276381a42SAneesh Kumar K.V struct v9fs_session_info *v9ses; 8385ff872dSAneesh Kumar K.V 8476381a42SAneesh Kumar K.V v9ses = v9fs_inode2v9ses(inode); 85e782ef71SVenkateswararao Jujjuri (JV) if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) || 86e782ef71SVenkateswararao Jujjuri (JV) ((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) { 8776381a42SAneesh Kumar K.V set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL); 8876381a42SAneesh Kumar K.V set_cached_acl(inode, ACL_TYPE_ACCESS, NULL); 8976381a42SAneesh Kumar K.V return 0; 9076381a42SAneesh Kumar K.V } 9185ff872dSAneesh Kumar K.V /* get the default/access acl values and cache them */ 9297d79299SAndreas Gruenbacher dacl = __v9fs_get_acl(fid, XATTR_NAME_POSIX_ACL_DEFAULT); 9397d79299SAndreas Gruenbacher pacl = __v9fs_get_acl(fid, XATTR_NAME_POSIX_ACL_ACCESS); 9485ff872dSAneesh Kumar K.V 9585ff872dSAneesh Kumar K.V if (!IS_ERR(dacl) && !IS_ERR(pacl)) { 9685ff872dSAneesh Kumar K.V set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl); 9785ff872dSAneesh Kumar K.V set_cached_acl(inode, ACL_TYPE_ACCESS, pacl); 9885ff872dSAneesh Kumar K.V } else 9985ff872dSAneesh Kumar K.V retval = -EIO; 10085ff872dSAneesh Kumar K.V 101c61fa0d6SVenkateswararao Jujjuri (JV) if (!IS_ERR(dacl)) 102c61fa0d6SVenkateswararao Jujjuri (JV) posix_acl_release(dacl); 103c61fa0d6SVenkateswararao Jujjuri (JV) 104c61fa0d6SVenkateswararao Jujjuri (JV) if (!IS_ERR(pacl)) 105c61fa0d6SVenkateswararao Jujjuri (JV) posix_acl_release(pacl); 106c61fa0d6SVenkateswararao Jujjuri (JV) 10785ff872dSAneesh Kumar K.V return retval; 10885ff872dSAneesh Kumar K.V } 10985ff872dSAneesh Kumar K.V 11085ff872dSAneesh Kumar K.V static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) 11185ff872dSAneesh Kumar K.V { 11285ff872dSAneesh Kumar K.V struct posix_acl *acl; 11385ff872dSAneesh Kumar K.V /* 11485ff872dSAneesh Kumar K.V * 9p Always cache the acl value when 11585ff872dSAneesh Kumar K.V * instantiating the inode (v9fs_inode_from_fid) 11685ff872dSAneesh Kumar K.V */ 11785ff872dSAneesh Kumar K.V acl = get_cached_acl(inode, type); 118b8a7a3a6SAndreas Gruenbacher BUG_ON(is_uncached_acl(acl)); 11985ff872dSAneesh Kumar K.V return acl; 12085ff872dSAneesh Kumar K.V } 12185ff872dSAneesh Kumar K.V 1226cd4d4e8SChristian Brauner struct posix_acl *v9fs_iop_get_inode_acl(struct inode *inode, int type, bool rcu) 12385ff872dSAneesh Kumar K.V { 12476381a42SAneesh Kumar K.V struct v9fs_session_info *v9ses; 12576381a42SAneesh Kumar K.V 1260cad6246SMiklos Szeredi if (rcu) 1270cad6246SMiklos Szeredi return ERR_PTR(-ECHILD); 1280cad6246SMiklos Szeredi 12976381a42SAneesh Kumar K.V v9ses = v9fs_inode2v9ses(inode); 130e782ef71SVenkateswararao Jujjuri (JV) if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) || 131e782ef71SVenkateswararao Jujjuri (JV) ((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) { 13276381a42SAneesh Kumar K.V /* 133e782ef71SVenkateswararao Jujjuri (JV) * On access = client and acl = on mode get the acl 13476381a42SAneesh Kumar K.V * values from the server 13576381a42SAneesh Kumar K.V */ 1364e34e719SChristoph Hellwig return NULL; 13776381a42SAneesh Kumar K.V } 1384e34e719SChristoph Hellwig return v9fs_get_cached_acl(inode, type); 13985ff872dSAneesh Kumar K.V 14085ff872dSAneesh Kumar K.V } 1417a4566b0SAneesh Kumar K.V 1426cd4d4e8SChristian Brauner struct posix_acl *v9fs_iop_get_acl(struct user_namespace *mnt_userns, 1436cd4d4e8SChristian Brauner struct dentry *dentry, int type) 1446cd4d4e8SChristian Brauner { 1456cd4d4e8SChristian Brauner struct v9fs_session_info *v9ses; 1466cd4d4e8SChristian Brauner 1476cd4d4e8SChristian Brauner v9ses = v9fs_dentry2v9ses(dentry); 1486cd4d4e8SChristian Brauner /* We allow set/get/list of acl when access=client is not specified. */ 1496cd4d4e8SChristian Brauner if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) 1506cd4d4e8SChristian Brauner return v9fs_acl_get(dentry, posix_acl_xattr_name(type)); 1516cd4d4e8SChristian Brauner return v9fs_get_cached_acl(d_inode(dentry), type); 1526cd4d4e8SChristian Brauner } 1536cd4d4e8SChristian Brauner 154*079da629SChristian Brauner int v9fs_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry, 155*079da629SChristian Brauner struct posix_acl *acl, int type) 156*079da629SChristian Brauner { 157*079da629SChristian Brauner int retval; 158*079da629SChristian Brauner size_t size = 0; 159*079da629SChristian Brauner void *value = NULL; 160*079da629SChristian Brauner const char *acl_name; 161*079da629SChristian Brauner struct v9fs_session_info *v9ses; 162*079da629SChristian Brauner struct inode *inode = d_inode(dentry); 163*079da629SChristian Brauner 164*079da629SChristian Brauner if (acl) { 165*079da629SChristian Brauner retval = posix_acl_valid(inode->i_sb->s_user_ns, acl); 166*079da629SChristian Brauner if (retval) 167*079da629SChristian Brauner goto err_out; 168*079da629SChristian Brauner 169*079da629SChristian Brauner size = posix_acl_xattr_size(acl->a_count); 170*079da629SChristian Brauner 171*079da629SChristian Brauner value = kzalloc(size, GFP_NOFS); 172*079da629SChristian Brauner if (!value) { 173*079da629SChristian Brauner retval = -ENOMEM; 174*079da629SChristian Brauner goto err_out; 175*079da629SChristian Brauner } 176*079da629SChristian Brauner 177*079da629SChristian Brauner retval = posix_acl_to_xattr(&init_user_ns, acl, value, size); 178*079da629SChristian Brauner if (retval < 0) 179*079da629SChristian Brauner goto err_out; 180*079da629SChristian Brauner } 181*079da629SChristian Brauner 182*079da629SChristian Brauner /* 183*079da629SChristian Brauner * set the attribute on the remote. Without even looking at the 184*079da629SChristian Brauner * xattr value. We leave it to the server to validate 185*079da629SChristian Brauner */ 186*079da629SChristian Brauner acl_name = posix_acl_xattr_name(type); 187*079da629SChristian Brauner v9ses = v9fs_dentry2v9ses(dentry); 188*079da629SChristian Brauner if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { 189*079da629SChristian Brauner retval = v9fs_xattr_set(dentry, acl_name, value, size, 0); 190*079da629SChristian Brauner goto err_out; 191*079da629SChristian Brauner } 192*079da629SChristian Brauner 193*079da629SChristian Brauner if (S_ISLNK(inode->i_mode)) { 194*079da629SChristian Brauner retval = -EOPNOTSUPP; 195*079da629SChristian Brauner goto err_out; 196*079da629SChristian Brauner } 197*079da629SChristian Brauner 198*079da629SChristian Brauner if (!inode_owner_or_capable(&init_user_ns, inode)) { 199*079da629SChristian Brauner retval = -EPERM; 200*079da629SChristian Brauner goto err_out; 201*079da629SChristian Brauner } 202*079da629SChristian Brauner 203*079da629SChristian Brauner switch (type) { 204*079da629SChristian Brauner case ACL_TYPE_ACCESS: 205*079da629SChristian Brauner if (acl) { 206*079da629SChristian Brauner struct iattr iattr = {}; 207*079da629SChristian Brauner struct posix_acl *acl_mode = acl; 208*079da629SChristian Brauner 209*079da629SChristian Brauner retval = posix_acl_update_mode(&init_user_ns, inode, 210*079da629SChristian Brauner &iattr.ia_mode, 211*079da629SChristian Brauner &acl_mode); 212*079da629SChristian Brauner if (retval) 213*079da629SChristian Brauner goto err_out; 214*079da629SChristian Brauner if (!acl_mode) { 215*079da629SChristian Brauner /* 216*079da629SChristian Brauner * ACL can be represented by the mode bits. 217*079da629SChristian Brauner * So don't update ACL below. 218*079da629SChristian Brauner */ 219*079da629SChristian Brauner kfree(value); 220*079da629SChristian Brauner value = NULL; 221*079da629SChristian Brauner size = 0; 222*079da629SChristian Brauner } 223*079da629SChristian Brauner iattr.ia_valid = ATTR_MODE; 224*079da629SChristian Brauner /* 225*079da629SChristian Brauner * FIXME should we update ctime ? 226*079da629SChristian Brauner * What is the following setxattr update the mode ? 227*079da629SChristian Brauner */ 228*079da629SChristian Brauner v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr); 229*079da629SChristian Brauner } 230*079da629SChristian Brauner break; 231*079da629SChristian Brauner case ACL_TYPE_DEFAULT: 232*079da629SChristian Brauner if (!S_ISDIR(inode->i_mode)) { 233*079da629SChristian Brauner retval = acl ? -EINVAL : 0; 234*079da629SChristian Brauner goto err_out; 235*079da629SChristian Brauner } 236*079da629SChristian Brauner break; 237*079da629SChristian Brauner } 238*079da629SChristian Brauner 239*079da629SChristian Brauner retval = v9fs_xattr_set(dentry, acl_name, value, size, 0); 240*079da629SChristian Brauner if (!retval) 241*079da629SChristian Brauner set_cached_acl(inode, type, acl); 242*079da629SChristian Brauner 243*079da629SChristian Brauner err_out: 244*079da629SChristian Brauner kfree(value); 245*079da629SChristian Brauner return retval; 246*079da629SChristian Brauner } 247*079da629SChristian Brauner 2480f235caeSAl Viro static int v9fs_set_acl(struct p9_fid *fid, int type, struct posix_acl *acl) 2496e8dc555SAneesh Kumar K.V { 2506e8dc555SAneesh Kumar K.V int retval; 2516e8dc555SAneesh Kumar K.V char *name; 2526e8dc555SAneesh Kumar K.V size_t size; 2536e8dc555SAneesh Kumar K.V void *buffer; 2546e195b0fSDominique Martinet 255d344b0fbSVenkateswararao Jujjuri (JV) if (!acl) 256d344b0fbSVenkateswararao Jujjuri (JV) return 0; 257d344b0fbSVenkateswararao Jujjuri (JV) 2586e8dc555SAneesh Kumar K.V /* Set a setxattr request to server */ 2596e8dc555SAneesh Kumar K.V size = posix_acl_xattr_size(acl->a_count); 2606e8dc555SAneesh Kumar K.V buffer = kmalloc(size, GFP_KERNEL); 2616e8dc555SAneesh Kumar K.V if (!buffer) 2626e8dc555SAneesh Kumar K.V return -ENOMEM; 2635f3a4a28SEric W. Biederman retval = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 2646e8dc555SAneesh Kumar K.V if (retval < 0) 2656e8dc555SAneesh Kumar K.V goto err_free_out; 2666e8dc555SAneesh Kumar K.V switch (type) { 2676e8dc555SAneesh Kumar K.V case ACL_TYPE_ACCESS: 26897d79299SAndreas Gruenbacher name = XATTR_NAME_POSIX_ACL_ACCESS; 2696e8dc555SAneesh Kumar K.V break; 2706e8dc555SAneesh Kumar K.V case ACL_TYPE_DEFAULT: 27197d79299SAndreas Gruenbacher name = XATTR_NAME_POSIX_ACL_DEFAULT; 2726e8dc555SAneesh Kumar K.V break; 2736e8dc555SAneesh Kumar K.V default: 2746e8dc555SAneesh Kumar K.V BUG(); 2756e8dc555SAneesh Kumar K.V } 2760f235caeSAl Viro retval = v9fs_fid_xattr_set(fid, name, buffer, size, 0); 2776e8dc555SAneesh Kumar K.V err_free_out: 2786e8dc555SAneesh Kumar K.V kfree(buffer); 2796e8dc555SAneesh Kumar K.V return retval; 2806e8dc555SAneesh Kumar K.V } 2816e8dc555SAneesh Kumar K.V 282be308f07SAl Viro int v9fs_acl_chmod(struct inode *inode, struct p9_fid *fid) 2836e8dc555SAneesh Kumar K.V { 2846e8dc555SAneesh Kumar K.V int retval = 0; 285bc26ab5fSAl Viro struct posix_acl *acl; 2866e8dc555SAneesh Kumar K.V 2876e8dc555SAneesh Kumar K.V if (S_ISLNK(inode->i_mode)) 2886e8dc555SAneesh Kumar K.V return -EOPNOTSUPP; 2896e8dc555SAneesh Kumar K.V acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); 2906e8dc555SAneesh Kumar K.V if (acl) { 2915bf3258fSChristoph Hellwig retval = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 292bc26ab5fSAl Viro if (retval) 293bc26ab5fSAl Viro return retval; 2947f165aaaSAl Viro set_cached_acl(inode, ACL_TYPE_ACCESS, acl); 2950f235caeSAl Viro retval = v9fs_set_acl(fid, ACL_TYPE_ACCESS, acl); 2966e8dc555SAneesh Kumar K.V posix_acl_release(acl); 2976e8dc555SAneesh Kumar K.V } 2986e8dc555SAneesh Kumar K.V return retval; 2996e8dc555SAneesh Kumar K.V } 3006e8dc555SAneesh Kumar K.V 3013592ac44SAl Viro int v9fs_set_create_acl(struct inode *inode, struct p9_fid *fid, 3025fa6300aSAl Viro struct posix_acl *dacl, struct posix_acl *acl) 303ad77dbceSAneesh Kumar K.V { 3043592ac44SAl Viro set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl); 3053592ac44SAl Viro set_cached_acl(inode, ACL_TYPE_ACCESS, acl); 3065fa6300aSAl Viro v9fs_set_acl(fid, ACL_TYPE_DEFAULT, dacl); 3075fa6300aSAl Viro v9fs_set_acl(fid, ACL_TYPE_ACCESS, acl); 308ad77dbceSAneesh Kumar K.V return 0; 309ad77dbceSAneesh Kumar K.V } 310ad77dbceSAneesh Kumar K.V 3115fa6300aSAl Viro void v9fs_put_acl(struct posix_acl *dacl, 3125fa6300aSAl Viro struct posix_acl *acl) 3135fa6300aSAl Viro { 3145fa6300aSAl Viro posix_acl_release(dacl); 3155fa6300aSAl Viro posix_acl_release(acl); 3165fa6300aSAl Viro } 3175fa6300aSAl Viro 318d3fb6120SAl Viro int v9fs_acl_mode(struct inode *dir, umode_t *modep, 319ad77dbceSAneesh Kumar K.V struct posix_acl **dpacl, struct posix_acl **pacl) 320ad77dbceSAneesh Kumar K.V { 321ad77dbceSAneesh Kumar K.V int retval = 0; 322d3fb6120SAl Viro umode_t mode = *modep; 323ad77dbceSAneesh Kumar K.V struct posix_acl *acl = NULL; 324ad77dbceSAneesh Kumar K.V 325ad77dbceSAneesh Kumar K.V if (!S_ISLNK(mode)) { 326ad77dbceSAneesh Kumar K.V acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT); 327ad77dbceSAneesh Kumar K.V if (IS_ERR(acl)) 328ad77dbceSAneesh Kumar K.V return PTR_ERR(acl); 329ad77dbceSAneesh Kumar K.V if (!acl) 330ad77dbceSAneesh Kumar K.V mode &= ~current_umask(); 331ad77dbceSAneesh Kumar K.V } 332ad77dbceSAneesh Kumar K.V if (acl) { 333ad77dbceSAneesh Kumar K.V if (S_ISDIR(mode)) 3341ec95bf3SAl Viro *dpacl = posix_acl_dup(acl); 33537bc1539SChristoph Hellwig retval = __posix_acl_create(&acl, GFP_NOFS, &mode); 336826cae2fSAl Viro if (retval < 0) 337826cae2fSAl Viro return retval; 338ad77dbceSAneesh Kumar K.V if (retval > 0) 339826cae2fSAl Viro *pacl = acl; 3401ec95bf3SAl Viro else 341826cae2fSAl Viro posix_acl_release(acl); 342ad77dbceSAneesh Kumar K.V } 343ad77dbceSAneesh Kumar K.V *modep = mode; 344ad77dbceSAneesh Kumar K.V return 0; 345ad77dbceSAneesh Kumar K.V } 346ad77dbceSAneesh Kumar K.V 347d9a82a04SAndreas Gruenbacher static int v9fs_xattr_get_acl(const struct xattr_handler *handler, 348b296821aSAl Viro struct dentry *dentry, struct inode *inode, 349b296821aSAl Viro const char *name, void *buffer, size_t size) 3507a4566b0SAneesh Kumar K.V { 35176381a42SAneesh Kumar K.V struct v9fs_session_info *v9ses; 3527a4566b0SAneesh Kumar K.V struct posix_acl *acl; 3537a4566b0SAneesh Kumar K.V int error; 3547a4566b0SAneesh Kumar K.V 35542869c8aSAneesh Kumar K.V v9ses = v9fs_dentry2v9ses(dentry); 35676381a42SAneesh Kumar K.V /* 35776381a42SAneesh Kumar K.V * We allow set/get/list of acl when access=client is not specified 35876381a42SAneesh Kumar K.V */ 35976381a42SAneesh Kumar K.V if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) 36098e9cb57SAndreas Gruenbacher return v9fs_xattr_get(dentry, handler->name, buffer, size); 36176381a42SAneesh Kumar K.V 362b296821aSAl Viro acl = v9fs_get_cached_acl(inode, handler->flags); 3637a4566b0SAneesh Kumar K.V if (IS_ERR(acl)) 3647a4566b0SAneesh Kumar K.V return PTR_ERR(acl); 3657a4566b0SAneesh Kumar K.V if (acl == NULL) 3667a4566b0SAneesh Kumar K.V return -ENODATA; 3675f3a4a28SEric W. Biederman error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 3687a4566b0SAneesh Kumar K.V posix_acl_release(acl); 3697a4566b0SAneesh Kumar K.V 3707a4566b0SAneesh Kumar K.V return error; 3717a4566b0SAneesh Kumar K.V } 3727a4566b0SAneesh Kumar K.V 373d9a82a04SAndreas Gruenbacher static int v9fs_xattr_set_acl(const struct xattr_handler *handler, 374e65ce2a5SChristian Brauner struct user_namespace *mnt_userns, 37559301226SAl Viro struct dentry *dentry, struct inode *inode, 37659301226SAl Viro const char *name, const void *value, 37759301226SAl Viro size_t size, int flags) 3787a4566b0SAneesh Kumar K.V { 37922d8dcdfSAneesh Kumar K.V int retval; 38022d8dcdfSAneesh Kumar K.V struct posix_acl *acl; 38176381a42SAneesh Kumar K.V struct v9fs_session_info *v9ses; 38222d8dcdfSAneesh Kumar K.V 38342869c8aSAneesh Kumar K.V v9ses = v9fs_dentry2v9ses(dentry); 38476381a42SAneesh Kumar K.V /* 38576381a42SAneesh Kumar K.V * set the attribute on the remote. Without even looking at the 38676381a42SAneesh Kumar K.V * xattr value. We leave it to the server to validate 38776381a42SAneesh Kumar K.V */ 38876381a42SAneesh Kumar K.V if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) 38998e9cb57SAndreas Gruenbacher return v9fs_xattr_set(dentry, handler->name, value, size, 390e409de99SAndreas Gruenbacher flags); 39176381a42SAneesh Kumar K.V 39222d8dcdfSAneesh Kumar K.V if (S_ISLNK(inode->i_mode)) 39322d8dcdfSAneesh Kumar K.V return -EOPNOTSUPP; 39421cb47beSChristian Brauner if (!inode_owner_or_capable(&init_user_ns, inode)) 39522d8dcdfSAneesh Kumar K.V return -EPERM; 39622d8dcdfSAneesh Kumar K.V if (value) { 39722d8dcdfSAneesh Kumar K.V /* update the cached acl value */ 3985f3a4a28SEric W. Biederman acl = posix_acl_from_xattr(&init_user_ns, value, size); 39922d8dcdfSAneesh Kumar K.V if (IS_ERR(acl)) 40022d8dcdfSAneesh Kumar K.V return PTR_ERR(acl); 40122d8dcdfSAneesh Kumar K.V else if (acl) { 4020d4d717fSEric W. Biederman retval = posix_acl_valid(inode->i_sb->s_user_ns, acl); 40322d8dcdfSAneesh Kumar K.V if (retval) 40422d8dcdfSAneesh Kumar K.V goto err_out; 40522d8dcdfSAneesh Kumar K.V } 40622d8dcdfSAneesh Kumar K.V } else 40722d8dcdfSAneesh Kumar K.V acl = NULL; 40822d8dcdfSAneesh Kumar K.V 409d9a82a04SAndreas Gruenbacher switch (handler->flags) { 41022d8dcdfSAneesh Kumar K.V case ACL_TYPE_ACCESS: 41122d8dcdfSAneesh Kumar K.V if (acl) { 412e02a53d9SDominique Martinet struct iattr iattr = { 0 }; 413b5c66babSCong Wang struct posix_acl *old_acl = acl; 41407393101SJan Kara 415549c7297SChristian Brauner retval = posix_acl_update_mode(&init_user_ns, inode, 416e65ce2a5SChristian Brauner &iattr.ia_mode, &acl); 41707393101SJan Kara if (retval) 41807393101SJan Kara goto err_out; 41907393101SJan Kara if (!acl) { 42022d8dcdfSAneesh Kumar K.V /* 42122d8dcdfSAneesh Kumar K.V * ACL can be represented 42222d8dcdfSAneesh Kumar K.V * by the mode bits. So don't 42322d8dcdfSAneesh Kumar K.V * update ACL. 42422d8dcdfSAneesh Kumar K.V */ 425b5c66babSCong Wang posix_acl_release(old_acl); 42622d8dcdfSAneesh Kumar K.V value = NULL; 42722d8dcdfSAneesh Kumar K.V size = 0; 42822d8dcdfSAneesh Kumar K.V } 42922d8dcdfSAneesh Kumar K.V iattr.ia_valid = ATTR_MODE; 43022d8dcdfSAneesh Kumar K.V /* FIXME should we update ctime ? 43122d8dcdfSAneesh Kumar K.V * What is the following setxattr update the 43222d8dcdfSAneesh Kumar K.V * mode ? 43322d8dcdfSAneesh Kumar K.V */ 434549c7297SChristian Brauner v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr); 43522d8dcdfSAneesh Kumar K.V } 43622d8dcdfSAneesh Kumar K.V break; 43722d8dcdfSAneesh Kumar K.V case ACL_TYPE_DEFAULT: 43822d8dcdfSAneesh Kumar K.V if (!S_ISDIR(inode->i_mode)) { 4396f81c115SAneesh Kumar K.V retval = acl ? -EINVAL : 0; 44022d8dcdfSAneesh Kumar K.V goto err_out; 44122d8dcdfSAneesh Kumar K.V } 44222d8dcdfSAneesh Kumar K.V break; 44322d8dcdfSAneesh Kumar K.V default: 44422d8dcdfSAneesh Kumar K.V BUG(); 44522d8dcdfSAneesh Kumar K.V } 44698e9cb57SAndreas Gruenbacher retval = v9fs_xattr_set(dentry, handler->name, value, size, flags); 44722d8dcdfSAneesh Kumar K.V if (!retval) 448d9a82a04SAndreas Gruenbacher set_cached_acl(inode, handler->flags, acl); 44922d8dcdfSAneesh Kumar K.V err_out: 45022d8dcdfSAneesh Kumar K.V posix_acl_release(acl); 45122d8dcdfSAneesh Kumar K.V return retval; 4527a4566b0SAneesh Kumar K.V } 4537a4566b0SAneesh Kumar K.V 4547a4566b0SAneesh Kumar K.V const struct xattr_handler v9fs_xattr_acl_access_handler = { 45598e9cb57SAndreas Gruenbacher .name = XATTR_NAME_POSIX_ACL_ACCESS, 4567a4566b0SAneesh Kumar K.V .flags = ACL_TYPE_ACCESS, 4577a4566b0SAneesh Kumar K.V .get = v9fs_xattr_get_acl, 4587a4566b0SAneesh Kumar K.V .set = v9fs_xattr_set_acl, 4597a4566b0SAneesh Kumar K.V }; 4607a4566b0SAneesh Kumar K.V 4617a4566b0SAneesh Kumar K.V const struct xattr_handler v9fs_xattr_acl_default_handler = { 46298e9cb57SAndreas Gruenbacher .name = XATTR_NAME_POSIX_ACL_DEFAULT, 4637a4566b0SAneesh Kumar K.V .flags = ACL_TYPE_DEFAULT, 4647a4566b0SAneesh Kumar K.V .get = v9fs_xattr_get_acl, 4657a4566b0SAneesh Kumar K.V .set = v9fs_xattr_set_acl, 4667a4566b0SAneesh Kumar K.V }; 467