xref: /linux/fs/overlayfs/xattrs.c (revision d431e652)
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