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(sb: 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, path: &realpath);
48 old_cred = ovl_override_creds(sb: dentry->d_sb);
49 err = vfs_getxattr(mnt_idmap(mnt: 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(sb: dentry->d_sb);
68 if (value) {
69 err = ovl_do_setxattr(ofs, dentry: realdentry, name, value, size,
70 flags);
71 } else {
72 WARN_ON(flags != XATTR_REPLACE);
73 err = ovl_do_removexattr(ofs, dentry: realdentry, name);
74 }
75 revert_creds(old_cred);
76 ovl_drop_write(dentry);
77
78 /* copy c/mtime */
79 ovl_copyattr(to: 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, path: &realpath);
92 old_cred = ovl_override_creds(sb: dentry->d_sb);
93 res = vfs_getxattr(mnt_idmap(mnt: 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, name: 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(ns: &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(sb: 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(sb: dentry->d_sb);
123 res = vfs_listxattr(d: 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(p: s, maxlen: 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(sb: dentry->d_sb, s)) {
141 res -= slen;
142 memmove(s, s + slen, len);
143 } else if (ovl_is_escaped_xattr(sb: dentry->d_sb, name: 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(error: -EOPNOTSUPP);
167
168 escaped = kmalloc(size: escaped_len + 1, GFP_KERNEL);
169 if (escaped == NULL)
170 return ERR_PTR(error: -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(prefix: handler->prefix, name);
190 if (IS_ERR(ptr: escaped))
191 return PTR_ERR(ptr: escaped);
192
193 r = ovl_xattr_get(dentry, inode, name: escaped, value: buffer, size);
194
195 kfree(objp: 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(prefix: handler->prefix, name);
210 if (IS_ERR(ptr: escaped))
211 return PTR_ERR(ptr: escaped);
212
213 r = ovl_xattr_set(dentry, inode, name: escaped, value, size, flags);
214
215 kfree(objp: 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, value: 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
272

source code of linux/fs/overlayfs/xattrs.c