~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/overlayfs/xattrs.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 
  3 #include <linux/fs.h>
  4 #include <linux/xattr.h>
  5 #include "overlayfs.h"
  6 
  7 static 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 
 19 static 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 
 31 bool 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 
 36 static 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);
 80 out:
 81         return err;
 82 }
 83 
 84 static 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 
 98 static 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 
112 ssize_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 
157 static 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 
182 static 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 
200 static 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 
220 static 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 
227 static 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 
236 static 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 
242 static 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 
248 static 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 
254 static const struct xattr_handler * const ovl_trusted_xattr_handlers[] = {
255         &ovl_own_trusted_xattr_handler,
256         &ovl_other_xattr_handler,
257         NULL
258 };
259 
260 static const struct xattr_handler * const ovl_user_xattr_handlers[] = {
261         &ovl_own_user_xattr_handler,
262         &ovl_other_xattr_handler,
263         NULL
264 };
265 
266 const 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 navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php