File Index
Files and directories
Sign in
FILE

xattrs.c

File preview with syntax highlighting.

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