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 154079da629SChristian Brauner int v9fs_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry, 155079da629SChristian Brauner struct posix_acl *acl, int type) 156079da629SChristian Brauner { 157079da629SChristian Brauner int retval; 158079da629SChristian Brauner size_t size = 0; 159079da629SChristian Brauner void *value = NULL; 160079da629SChristian Brauner const char *acl_name; 161079da629SChristian Brauner struct v9fs_session_info *v9ses; 162079da629SChristian Brauner struct inode *inode = d_inode(dentry); 163079da629SChristian Brauner 164079da629SChristian Brauner if (acl) { 165079da629SChristian Brauner retval = posix_acl_valid(inode->i_sb->s_user_ns, acl); 166079da629SChristian Brauner if (retval) 167079da629SChristian Brauner goto err_out; 168079da629SChristian Brauner 169079da629SChristian Brauner size = posix_acl_xattr_size(acl->a_count); 170079da629SChristian Brauner 171079da629SChristian Brauner value = kzalloc(size, GFP_NOFS); 172079da629SChristian Brauner if (!value) { 173079da629SChristian Brauner retval = -ENOMEM; 174079da629SChristian Brauner goto err_out; 175079da629SChristian Brauner } 176079da629SChristian Brauner 177079da629SChristian Brauner retval = posix_acl_to_xattr(&init_user_ns, acl, value, size); 178079da629SChristian Brauner if (retval < 0) 179079da629SChristian Brauner goto err_out; 180079da629SChristian Brauner } 181079da629SChristian Brauner 182079da629SChristian Brauner /* 183079da629SChristian Brauner * set the attribute on the remote. Without even looking at the 184079da629SChristian Brauner * xattr value. We leave it to the server to validate 185079da629SChristian Brauner */ 186079da629SChristian Brauner acl_name = posix_acl_xattr_name(type); 187079da629SChristian Brauner v9ses = v9fs_dentry2v9ses(dentry); 188079da629SChristian Brauner if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { 189079da629SChristian Brauner retval = v9fs_xattr_set(dentry, acl_name, value, size, 0); 190079da629SChristian Brauner goto err_out; 191079da629SChristian Brauner } 192079da629SChristian Brauner 193079da629SChristian Brauner if (S_ISLNK(inode->i_mode)) { 194079da629SChristian Brauner retval = -EOPNOTSUPP; 195079da629SChristian Brauner goto err_out; 196079da629SChristian Brauner } 197079da629SChristian Brauner 198079da629SChristian Brauner if (!inode_owner_or_capable(&init_user_ns, inode)) { 199079da629SChristian Brauner retval = -EPERM; 200079da629SChristian Brauner goto err_out; 201079da629SChristian Brauner } 202079da629SChristian Brauner 203079da629SChristian Brauner switch (type) { 204079da629SChristian Brauner case ACL_TYPE_ACCESS: 205079da629SChristian Brauner if (acl) { 206079da629SChristian Brauner struct iattr iattr = {}; 207079da629SChristian Brauner struct posix_acl *acl_mode = acl; 208079da629SChristian Brauner 209079da629SChristian Brauner retval = posix_acl_update_mode(&init_user_ns, inode, 210079da629SChristian Brauner &iattr.ia_mode, 211079da629SChristian Brauner &acl_mode); 212079da629SChristian Brauner if (retval) 213079da629SChristian Brauner goto err_out; 214079da629SChristian Brauner if (!acl_mode) { 215079da629SChristian Brauner /* 216079da629SChristian Brauner * ACL can be represented by the mode bits. 217079da629SChristian Brauner * So don't update ACL below. 218079da629SChristian Brauner */ 219079da629SChristian Brauner kfree(value); 220079da629SChristian Brauner value = NULL; 221079da629SChristian Brauner size = 0; 222079da629SChristian Brauner } 223079da629SChristian Brauner iattr.ia_valid = ATTR_MODE; 224079da629SChristian Brauner /* 225079da629SChristian Brauner * FIXME should we update ctime ? 226079da629SChristian Brauner * What is the following setxattr update the mode ? 227079da629SChristian Brauner */ 228*c1632a0fSChristian Brauner v9fs_vfs_setattr_dotl(&nop_mnt_idmap, dentry, &iattr); 229079da629SChristian Brauner } 230079da629SChristian Brauner break; 231079da629SChristian Brauner case ACL_TYPE_DEFAULT: 232079da629SChristian Brauner if (!S_ISDIR(inode->i_mode)) { 233079da629SChristian Brauner retval = acl ? -EINVAL : 0; 234079da629SChristian Brauner goto err_out; 235079da629SChristian Brauner } 236079da629SChristian Brauner break; 237079da629SChristian Brauner } 238079da629SChristian Brauner 239079da629SChristian Brauner retval = v9fs_xattr_set(dentry, acl_name, value, size, 0); 240079da629SChristian Brauner if (!retval) 241079da629SChristian Brauner set_cached_acl(inode, type, acl); 242079da629SChristian Brauner 243079da629SChristian Brauner err_out: 244079da629SChristian Brauner kfree(value); 245079da629SChristian Brauner return retval; 246079da629SChristian Brauner } 247079da629SChristian 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 } 346