1420a62ddSAmir Goldstein // SPDX-License-Identifier: GPL-2.0-only 2420a62ddSAmir Goldstein 3420a62ddSAmir Goldstein #include <linux/fs.h> 4420a62ddSAmir Goldstein #include <linux/xattr.h> 5420a62ddSAmir Goldstein #include "overlayfs.h" 6420a62ddSAmir Goldstein 7420a62ddSAmir Goldstein bool ovl_is_private_xattr(struct super_block *sb, const char *name) 8420a62ddSAmir Goldstein { 9420a62ddSAmir Goldstein struct ovl_fs *ofs = OVL_FS(sb); 10420a62ddSAmir Goldstein 11420a62ddSAmir Goldstein if (ofs->config.userxattr) 12420a62ddSAmir Goldstein return strncmp(name, OVL_XATTR_USER_PREFIX, 13*d431e652SAlexander Larsson OVL_XATTR_USER_PREFIX_LEN) == 0; 14420a62ddSAmir Goldstein else 15420a62ddSAmir Goldstein return strncmp(name, OVL_XATTR_TRUSTED_PREFIX, 16*d431e652SAlexander Larsson OVL_XATTR_TRUSTED_PREFIX_LEN) == 0; 17420a62ddSAmir Goldstein } 18420a62ddSAmir Goldstein 19420a62ddSAmir Goldstein static int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name, 20420a62ddSAmir Goldstein const void *value, size_t size, int flags) 21420a62ddSAmir Goldstein { 22420a62ddSAmir Goldstein int err; 23420a62ddSAmir Goldstein struct ovl_fs *ofs = OVL_FS(dentry->d_sb); 24420a62ddSAmir Goldstein struct dentry *upperdentry = ovl_i_dentry_upper(inode); 25420a62ddSAmir Goldstein struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry); 26420a62ddSAmir Goldstein struct path realpath; 27420a62ddSAmir Goldstein const struct cred *old_cred; 28420a62ddSAmir Goldstein 29420a62ddSAmir Goldstein if (!value && !upperdentry) { 30420a62ddSAmir Goldstein ovl_path_lower(dentry, &realpath); 31420a62ddSAmir Goldstein old_cred = ovl_override_creds(dentry->d_sb); 32420a62ddSAmir Goldstein err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0); 33420a62ddSAmir Goldstein revert_creds(old_cred); 34420a62ddSAmir Goldstein if (err < 0) 35420a62ddSAmir Goldstein goto out; 36420a62ddSAmir Goldstein } 37420a62ddSAmir Goldstein 38420a62ddSAmir Goldstein if (!upperdentry) { 39420a62ddSAmir Goldstein err = ovl_copy_up(dentry); 40420a62ddSAmir Goldstein if (err) 41420a62ddSAmir Goldstein goto out; 42420a62ddSAmir Goldstein 43420a62ddSAmir Goldstein realdentry = ovl_dentry_upper(dentry); 44420a62ddSAmir Goldstein } 45420a62ddSAmir Goldstein 46420a62ddSAmir Goldstein err = ovl_want_write(dentry); 47420a62ddSAmir Goldstein if (err) 48420a62ddSAmir Goldstein goto out; 49420a62ddSAmir Goldstein 50420a62ddSAmir Goldstein old_cred = ovl_override_creds(dentry->d_sb); 51420a62ddSAmir Goldstein if (value) { 52420a62ddSAmir Goldstein err = ovl_do_setxattr(ofs, realdentry, name, value, size, 53420a62ddSAmir Goldstein flags); 54420a62ddSAmir Goldstein } else { 55420a62ddSAmir Goldstein WARN_ON(flags != XATTR_REPLACE); 56420a62ddSAmir Goldstein err = ovl_do_removexattr(ofs, realdentry, name); 57420a62ddSAmir Goldstein } 58420a62ddSAmir Goldstein revert_creds(old_cred); 59420a62ddSAmir Goldstein ovl_drop_write(dentry); 60420a62ddSAmir Goldstein 61420a62ddSAmir Goldstein /* copy c/mtime */ 62420a62ddSAmir Goldstein ovl_copyattr(inode); 63420a62ddSAmir Goldstein out: 64420a62ddSAmir Goldstein return err; 65420a62ddSAmir Goldstein } 66420a62ddSAmir Goldstein 67420a62ddSAmir Goldstein static int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name, 68420a62ddSAmir Goldstein void *value, size_t size) 69420a62ddSAmir Goldstein { 70420a62ddSAmir Goldstein ssize_t res; 71420a62ddSAmir Goldstein const struct cred *old_cred; 72420a62ddSAmir Goldstein struct path realpath; 73420a62ddSAmir Goldstein 74420a62ddSAmir Goldstein ovl_i_path_real(inode, &realpath); 75420a62ddSAmir Goldstein old_cred = ovl_override_creds(dentry->d_sb); 76420a62ddSAmir Goldstein res = vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size); 77420a62ddSAmir Goldstein revert_creds(old_cred); 78420a62ddSAmir Goldstein return res; 79420a62ddSAmir Goldstein } 80420a62ddSAmir Goldstein 81420a62ddSAmir Goldstein static bool ovl_can_list(struct super_block *sb, const char *s) 82420a62ddSAmir Goldstein { 83420a62ddSAmir Goldstein /* Never list private (.overlay) */ 84420a62ddSAmir Goldstein if (ovl_is_private_xattr(sb, s)) 85420a62ddSAmir Goldstein return false; 86420a62ddSAmir Goldstein 87420a62ddSAmir Goldstein /* List all non-trusted xattrs */ 88420a62ddSAmir Goldstein if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0) 89420a62ddSAmir Goldstein return true; 90420a62ddSAmir Goldstein 91420a62ddSAmir Goldstein /* list other trusted for superuser only */ 92420a62ddSAmir Goldstein return ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN); 93420a62ddSAmir Goldstein } 94420a62ddSAmir Goldstein 95420a62ddSAmir Goldstein ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) 96420a62ddSAmir Goldstein { 97420a62ddSAmir Goldstein struct dentry *realdentry = ovl_dentry_real(dentry); 98420a62ddSAmir Goldstein ssize_t res; 99420a62ddSAmir Goldstein size_t len; 100420a62ddSAmir Goldstein char *s; 101420a62ddSAmir Goldstein const struct cred *old_cred; 102420a62ddSAmir Goldstein 103420a62ddSAmir Goldstein old_cred = ovl_override_creds(dentry->d_sb); 104420a62ddSAmir Goldstein res = vfs_listxattr(realdentry, list, size); 105420a62ddSAmir Goldstein revert_creds(old_cred); 106420a62ddSAmir Goldstein if (res <= 0 || size == 0) 107420a62ddSAmir Goldstein return res; 108420a62ddSAmir Goldstein 109420a62ddSAmir Goldstein /* filter out private xattrs */ 110420a62ddSAmir Goldstein for (s = list, len = res; len;) { 111420a62ddSAmir Goldstein size_t slen = strnlen(s, len) + 1; 112420a62ddSAmir Goldstein 113420a62ddSAmir Goldstein /* underlying fs providing us with an broken xattr list? */ 114420a62ddSAmir Goldstein if (WARN_ON(slen > len)) 115420a62ddSAmir Goldstein return -EIO; 116420a62ddSAmir Goldstein 117420a62ddSAmir Goldstein len -= slen; 118420a62ddSAmir Goldstein if (!ovl_can_list(dentry->d_sb, s)) { 119420a62ddSAmir Goldstein res -= slen; 120420a62ddSAmir Goldstein memmove(s, s + slen, len); 121420a62ddSAmir Goldstein } else { 122420a62ddSAmir Goldstein s += slen; 123420a62ddSAmir Goldstein } 124420a62ddSAmir Goldstein } 125420a62ddSAmir Goldstein 126420a62ddSAmir Goldstein return res; 127420a62ddSAmir Goldstein } 128420a62ddSAmir Goldstein 129420a62ddSAmir Goldstein static int ovl_own_xattr_get(const struct xattr_handler *handler, 130420a62ddSAmir Goldstein struct dentry *dentry, struct inode *inode, 131420a62ddSAmir Goldstein const char *name, void *buffer, size_t size) 132420a62ddSAmir Goldstein { 133420a62ddSAmir Goldstein return -EOPNOTSUPP; 134420a62ddSAmir Goldstein } 135420a62ddSAmir Goldstein 136420a62ddSAmir Goldstein static int ovl_own_xattr_set(const struct xattr_handler *handler, 137420a62ddSAmir Goldstein struct mnt_idmap *idmap, 138420a62ddSAmir Goldstein struct dentry *dentry, struct inode *inode, 139420a62ddSAmir Goldstein const char *name, const void *value, 140420a62ddSAmir Goldstein size_t size, int flags) 141420a62ddSAmir Goldstein { 142420a62ddSAmir Goldstein return -EOPNOTSUPP; 143420a62ddSAmir Goldstein } 144420a62ddSAmir Goldstein 145420a62ddSAmir Goldstein static int ovl_other_xattr_get(const struct xattr_handler *handler, 146420a62ddSAmir Goldstein struct dentry *dentry, struct inode *inode, 147420a62ddSAmir Goldstein const char *name, void *buffer, size_t size) 148420a62ddSAmir Goldstein { 149420a62ddSAmir Goldstein return ovl_xattr_get(dentry, inode, name, buffer, size); 150420a62ddSAmir Goldstein } 151420a62ddSAmir Goldstein 152420a62ddSAmir Goldstein static int ovl_other_xattr_set(const struct xattr_handler *handler, 153420a62ddSAmir Goldstein struct mnt_idmap *idmap, 154420a62ddSAmir Goldstein struct dentry *dentry, struct inode *inode, 155420a62ddSAmir Goldstein const char *name, const void *value, 156420a62ddSAmir Goldstein size_t size, int flags) 157420a62ddSAmir Goldstein { 158420a62ddSAmir Goldstein return ovl_xattr_set(dentry, inode, name, value, size, flags); 159420a62ddSAmir Goldstein } 160420a62ddSAmir Goldstein 161420a62ddSAmir Goldstein static const struct xattr_handler ovl_own_trusted_xattr_handler = { 162420a62ddSAmir Goldstein .prefix = OVL_XATTR_TRUSTED_PREFIX, 163420a62ddSAmir Goldstein .get = ovl_own_xattr_get, 164420a62ddSAmir Goldstein .set = ovl_own_xattr_set, 165420a62ddSAmir Goldstein }; 166420a62ddSAmir Goldstein 167420a62ddSAmir Goldstein static const struct xattr_handler ovl_own_user_xattr_handler = { 168420a62ddSAmir Goldstein .prefix = OVL_XATTR_USER_PREFIX, 169420a62ddSAmir Goldstein .get = ovl_own_xattr_get, 170420a62ddSAmir Goldstein .set = ovl_own_xattr_set, 171420a62ddSAmir Goldstein }; 172420a62ddSAmir Goldstein 173420a62ddSAmir Goldstein static const struct xattr_handler ovl_other_xattr_handler = { 174420a62ddSAmir Goldstein .prefix = "", /* catch all */ 175420a62ddSAmir Goldstein .get = ovl_other_xattr_get, 176420a62ddSAmir Goldstein .set = ovl_other_xattr_set, 177420a62ddSAmir Goldstein }; 178420a62ddSAmir Goldstein 179420a62ddSAmir Goldstein static const struct xattr_handler * const ovl_trusted_xattr_handlers[] = { 180420a62ddSAmir Goldstein &ovl_own_trusted_xattr_handler, 181420a62ddSAmir Goldstein &ovl_other_xattr_handler, 182420a62ddSAmir Goldstein NULL 183420a62ddSAmir Goldstein }; 184420a62ddSAmir Goldstein 185420a62ddSAmir Goldstein static const struct xattr_handler * const ovl_user_xattr_handlers[] = { 186420a62ddSAmir Goldstein &ovl_own_user_xattr_handler, 187420a62ddSAmir Goldstein &ovl_other_xattr_handler, 188420a62ddSAmir Goldstein NULL 189420a62ddSAmir Goldstein }; 190420a62ddSAmir Goldstein 191420a62ddSAmir Goldstein const struct xattr_handler * const *ovl_xattr_handlers(struct ovl_fs *ofs) 192420a62ddSAmir Goldstein { 193420a62ddSAmir Goldstein return ofs->config.userxattr ? ovl_user_xattr_handlers : 194420a62ddSAmir Goldstein ovl_trusted_xattr_handlers; 195420a62ddSAmir Goldstein } 196420a62ddSAmir Goldstein 197