Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include <linux/fs.h>
  4#include <linux/xattr.h>
  5#include "overlayfs.h"
  6
  7static bool ovl_is_escaped_xattr(struct super_block *sb, const char *name)
  8{
  9	struct ovl_fs *ofs = sb->s_fs_info;
 10
 11	if (ofs->config.userxattr)
 12		return strncmp(name, OVL_XATTR_ESCAPE_USER_PREFIX,
 13			       OVL_XATTR_ESCAPE_USER_PREFIX_LEN) == 0;
 14	else
 15		return strncmp(name, OVL_XATTR_ESCAPE_TRUSTED_PREFIX,
 16			       OVL_XATTR_ESCAPE_TRUSTED_PREFIX_LEN - 1) == 0;
 17}
 18
 19static bool ovl_is_own_xattr(struct super_block *sb, const char *name)
 20{
 21	struct ovl_fs *ofs = OVL_FS(sb);
 22
 23	if (ofs->config.userxattr)
 24		return strncmp(name, OVL_XATTR_USER_PREFIX,
 25			       OVL_XATTR_USER_PREFIX_LEN) == 0;
 26	else
 27		return strncmp(name, OVL_XATTR_TRUSTED_PREFIX,
 28			       OVL_XATTR_TRUSTED_PREFIX_LEN) == 0;
 29}
 30
 31bool ovl_is_private_xattr(struct super_block *sb, const char *name)
 32{
 33	return ovl_is_own_xattr(sb, name) && !ovl_is_escaped_xattr(sb, name);
 34}
 35
 36static int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
 37			 const void *value, size_t size, int flags)
 38{
 39	int err;
 40	struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
 41	struct dentry *upperdentry = ovl_i_dentry_upper(inode);
 42	struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
 43	struct path realpath;
 44	const struct cred *old_cred;
 45
 46	if (!value && !upperdentry) {
 47		ovl_path_lower(dentry, &realpath);
 48		old_cred = ovl_override_creds(dentry->d_sb);
 49		err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
 50		revert_creds(old_cred);
 51		if (err < 0)
 52			goto out;
 53	}
 54
 55	if (!upperdentry) {
 56		err = ovl_copy_up(dentry);
 57		if (err)
 58			goto out;
 59
 60		realdentry = ovl_dentry_upper(dentry);
 61	}
 62
 63	err = ovl_want_write(dentry);
 64	if (err)
 65		goto out;
 66
 67	old_cred = ovl_override_creds(dentry->d_sb);
 68	if (value) {
 69		err = ovl_do_setxattr(ofs, realdentry, name, value, size,
 70				      flags);
 71	} else {
 72		WARN_ON(flags != XATTR_REPLACE);
 73		err = ovl_do_removexattr(ofs, realdentry, name);
 74	}
 75	revert_creds(old_cred);
 76	ovl_drop_write(dentry);
 77
 78	/* copy c/mtime */
 79	ovl_copyattr(inode);
 80out:
 81	return err;
 82}
 83
 84static int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
 85			 void *value, size_t size)
 86{
 87	ssize_t res;
 88	const struct cred *old_cred;
 89	struct path realpath;
 90
 91	ovl_i_path_real(inode, &realpath);
 92	old_cred = ovl_override_creds(dentry->d_sb);
 93	res = vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size);
 94	revert_creds(old_cred);
 95	return res;
 96}
 97
 98static bool ovl_can_list(struct super_block *sb, const char *s)
 99{
100	/* Never list private (.overlay) */
101	if (ovl_is_private_xattr(sb, s))
102		return false;
103
104	/* List all non-trusted xattrs */
105	if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
106		return true;
107
108	/* list other trusted for superuser only */
109	return ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
110}
111
112ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
113{
114	struct dentry *realdentry = ovl_dentry_real(dentry);
115	struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
116	ssize_t res;
117	size_t len;
118	char *s;
119	const struct cred *old_cred;
120	size_t prefix_len, name_len;
121
122	old_cred = ovl_override_creds(dentry->d_sb);
123	res = vfs_listxattr(realdentry, list, size);
124	revert_creds(old_cred);
125	if (res <= 0 || size == 0)
126		return res;
127
128	prefix_len = ofs->config.userxattr ?
129		OVL_XATTR_USER_PREFIX_LEN : OVL_XATTR_TRUSTED_PREFIX_LEN;
130
131	/* filter out private xattrs */
132	for (s = list, len = res; len;) {
133		size_t slen = strnlen(s, len) + 1;
134
135		/* underlying fs providing us with an broken xattr list? */
136		if (WARN_ON(slen > len))
137			return -EIO;
138
139		len -= slen;
140		if (!ovl_can_list(dentry->d_sb, s)) {
141			res -= slen;
142			memmove(s, s + slen, len);
143		} else if (ovl_is_escaped_xattr(dentry->d_sb, s)) {
144			res -= OVL_XATTR_ESCAPE_PREFIX_LEN;
145			name_len = slen - prefix_len - OVL_XATTR_ESCAPE_PREFIX_LEN;
146			s += prefix_len;
147			memmove(s, s + OVL_XATTR_ESCAPE_PREFIX_LEN, name_len + len);
148			s += name_len;
149		} else {
150			s += slen;
151		}
152	}
153
154	return res;
155}
156
157static char *ovl_xattr_escape_name(const char *prefix, const char *name)
158{
159	size_t prefix_len = strlen(prefix);
160	size_t name_len = strlen(name);
161	size_t escaped_len;
162	char *escaped, *s;
163
164	escaped_len = prefix_len + OVL_XATTR_ESCAPE_PREFIX_LEN + name_len;
165	if (escaped_len > XATTR_NAME_MAX)
166		return ERR_PTR(-EOPNOTSUPP);
167
168	escaped = kmalloc(escaped_len + 1, GFP_KERNEL);
169	if (escaped == NULL)
170		return ERR_PTR(-ENOMEM);
171
172	s = escaped;
173	memcpy(s, prefix, prefix_len);
174	s += prefix_len;
175	memcpy(s, OVL_XATTR_ESCAPE_PREFIX, OVL_XATTR_ESCAPE_PREFIX_LEN);
176	s += OVL_XATTR_ESCAPE_PREFIX_LEN;
177	memcpy(s, name, name_len + 1);
178
179	return escaped;
180}
181
182static int ovl_own_xattr_get(const struct xattr_handler *handler,
183			     struct dentry *dentry, struct inode *inode,
184			     const char *name, void *buffer, size_t size)
185{
186	char *escaped;
187	int r;
188
189	escaped = ovl_xattr_escape_name(handler->prefix, name);
190	if (IS_ERR(escaped))
191		return PTR_ERR(escaped);
192
193	r = ovl_xattr_get(dentry, inode, escaped, buffer, size);
194
195	kfree(escaped);
196
197	return r;
198}
199
200static int ovl_own_xattr_set(const struct xattr_handler *handler,
201			     struct mnt_idmap *idmap,
202			     struct dentry *dentry, struct inode *inode,
203			     const char *name, const void *value,
204			     size_t size, int flags)
205{
206	char *escaped;
207	int r;
208
209	escaped = ovl_xattr_escape_name(handler->prefix, name);
210	if (IS_ERR(escaped))
211		return PTR_ERR(escaped);
212
213	r = ovl_xattr_set(dentry, inode, escaped, value, size, flags);
214
215	kfree(escaped);
216
217	return r;
218}
219
220static int ovl_other_xattr_get(const struct xattr_handler *handler,
221			       struct dentry *dentry, struct inode *inode,
222			       const char *name, void *buffer, size_t size)
223{
224	return ovl_xattr_get(dentry, inode, name, buffer, size);
225}
226
227static int ovl_other_xattr_set(const struct xattr_handler *handler,
228			       struct mnt_idmap *idmap,
229			       struct dentry *dentry, struct inode *inode,
230			       const char *name, const void *value,
231			       size_t size, int flags)
232{
233	return ovl_xattr_set(dentry, inode, name, value, size, flags);
234}
235
236static const struct xattr_handler ovl_own_trusted_xattr_handler = {
237	.prefix	= OVL_XATTR_TRUSTED_PREFIX,
238	.get = ovl_own_xattr_get,
239	.set = ovl_own_xattr_set,
240};
241
242static const struct xattr_handler ovl_own_user_xattr_handler = {
243	.prefix	= OVL_XATTR_USER_PREFIX,
244	.get = ovl_own_xattr_get,
245	.set = ovl_own_xattr_set,
246};
247
248static const struct xattr_handler ovl_other_xattr_handler = {
249	.prefix	= "", /* catch all */
250	.get = ovl_other_xattr_get,
251	.set = ovl_other_xattr_set,
252};
253
254static const struct xattr_handler * const ovl_trusted_xattr_handlers[] = {
255	&ovl_own_trusted_xattr_handler,
256	&ovl_other_xattr_handler,
257	NULL
258};
259
260static const struct xattr_handler * const ovl_user_xattr_handlers[] = {
261	&ovl_own_user_xattr_handler,
262	&ovl_other_xattr_handler,
263	NULL
264};
265
266const struct xattr_handler * const *ovl_xattr_handlers(struct ovl_fs *ofs)
267{
268	return ofs->config.userxattr ? ovl_user_xattr_handlers :
269		ovl_trusted_xattr_handlers;
270}
271