tools headers UAPI: Sync openat2.h with the kernel sources
[linux-2.6-microblaze.git] / fs / squashfs / xattr.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Squashfs - a compressed read only filesystem for Linux
4  *
5  * Copyright (c) 2010
6  * Phillip Lougher <phillip@squashfs.org.uk>
7  *
8  * xattr.c
9  */
10
11 #include <linux/init.h>
12 #include <linux/module.h>
13 #include <linux/string.h>
14 #include <linux/fs.h>
15 #include <linux/vfs.h>
16 #include <linux/xattr.h>
17 #include <linux/slab.h>
18
19 #include "squashfs_fs.h"
20 #include "squashfs_fs_sb.h"
21 #include "squashfs_fs_i.h"
22 #include "squashfs.h"
23
24 static const struct xattr_handler *squashfs_xattr_handler(int);
25
26 ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
27         size_t buffer_size)
28 {
29         struct inode *inode = d_inode(d);
30         struct super_block *sb = inode->i_sb;
31         struct squashfs_sb_info *msblk = sb->s_fs_info;
32         u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
33                                                  + msblk->xattr_table;
34         int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
35         int count = squashfs_i(inode)->xattr_count;
36         size_t rest = buffer_size;
37         int err;
38
39         /* check that the file system has xattrs */
40         if (msblk->xattr_id_table == NULL)
41                 return -EOPNOTSUPP;
42
43         /* loop reading each xattr name */
44         while (count--) {
45                 struct squashfs_xattr_entry entry;
46                 struct squashfs_xattr_val val;
47                 const struct xattr_handler *handler;
48                 int name_size;
49
50                 err = squashfs_read_metadata(sb, &entry, &start, &offset,
51                                                         sizeof(entry));
52                 if (err < 0)
53                         goto failed;
54
55                 name_size = le16_to_cpu(entry.size);
56                 handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
57                 if (handler && (!handler->list || handler->list(d))) {
58                         const char *prefix = handler->prefix ?: handler->name;
59                         size_t prefix_size = strlen(prefix);
60
61                         if (buffer) {
62                                 if (prefix_size + name_size + 1 > rest) {
63                                         err = -ERANGE;
64                                         goto failed;
65                                 }
66                                 memcpy(buffer, prefix, prefix_size);
67                                 buffer += prefix_size;
68                         }
69                         err = squashfs_read_metadata(sb, buffer, &start,
70                                 &offset, name_size);
71                         if (err < 0)
72                                 goto failed;
73                         if (buffer) {
74                                 buffer[name_size] = '\0';
75                                 buffer += name_size + 1;
76                         }
77                         rest -= prefix_size + name_size + 1;
78                 } else  {
79                         /* no handler or insuffficient privileges, so skip */
80                         err = squashfs_read_metadata(sb, NULL, &start,
81                                 &offset, name_size);
82                         if (err < 0)
83                                 goto failed;
84                 }
85
86
87                 /* skip remaining xattr entry */
88                 err = squashfs_read_metadata(sb, &val, &start, &offset,
89                                                 sizeof(val));
90                 if (err < 0)
91                         goto failed;
92
93                 err = squashfs_read_metadata(sb, NULL, &start, &offset,
94                                                 le32_to_cpu(val.vsize));
95                 if (err < 0)
96                         goto failed;
97         }
98         err = buffer_size - rest;
99
100 failed:
101         return err;
102 }
103
104
105 static int squashfs_xattr_get(struct inode *inode, int name_index,
106         const char *name, void *buffer, size_t buffer_size)
107 {
108         struct super_block *sb = inode->i_sb;
109         struct squashfs_sb_info *msblk = sb->s_fs_info;
110         u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
111                                                  + msblk->xattr_table;
112         int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
113         int count = squashfs_i(inode)->xattr_count;
114         int name_len = strlen(name);
115         int err, vsize;
116         char *target = kmalloc(name_len, GFP_KERNEL);
117
118         if (target == NULL)
119                 return  -ENOMEM;
120
121         /* loop reading each xattr name */
122         for (; count; count--) {
123                 struct squashfs_xattr_entry entry;
124                 struct squashfs_xattr_val val;
125                 int type, prefix, name_size;
126
127                 err = squashfs_read_metadata(sb, &entry, &start, &offset,
128                                                         sizeof(entry));
129                 if (err < 0)
130                         goto failed;
131
132                 name_size = le16_to_cpu(entry.size);
133                 type = le16_to_cpu(entry.type);
134                 prefix = type & SQUASHFS_XATTR_PREFIX_MASK;
135
136                 if (prefix == name_index && name_size == name_len)
137                         err = squashfs_read_metadata(sb, target, &start,
138                                                 &offset, name_size);
139                 else
140                         err = squashfs_read_metadata(sb, NULL, &start,
141                                                 &offset, name_size);
142                 if (err < 0)
143                         goto failed;
144
145                 if (prefix == name_index && name_size == name_len &&
146                                         strncmp(target, name, name_size) == 0) {
147                         /* found xattr */
148                         if (type & SQUASHFS_XATTR_VALUE_OOL) {
149                                 __le64 xattr_val;
150                                 u64 xattr;
151                                 /* val is a reference to the real location */
152                                 err = squashfs_read_metadata(sb, &val, &start,
153                                                 &offset, sizeof(val));
154                                 if (err < 0)
155                                         goto failed;
156                                 err = squashfs_read_metadata(sb, &xattr_val,
157                                         &start, &offset, sizeof(xattr_val));
158                                 if (err < 0)
159                                         goto failed;
160                                 xattr = le64_to_cpu(xattr_val);
161                                 start = SQUASHFS_XATTR_BLK(xattr) +
162                                                         msblk->xattr_table;
163                                 offset = SQUASHFS_XATTR_OFFSET(xattr);
164                         }
165                         /* read xattr value */
166                         err = squashfs_read_metadata(sb, &val, &start, &offset,
167                                                         sizeof(val));
168                         if (err < 0)
169                                 goto failed;
170
171                         vsize = le32_to_cpu(val.vsize);
172                         if (buffer) {
173                                 if (vsize > buffer_size) {
174                                         err = -ERANGE;
175                                         goto failed;
176                                 }
177                                 err = squashfs_read_metadata(sb, buffer, &start,
178                                          &offset, vsize);
179                                 if (err < 0)
180                                         goto failed;
181                         }
182                         break;
183                 }
184
185                 /* no match, skip remaining xattr entry */
186                 err = squashfs_read_metadata(sb, &val, &start, &offset,
187                                                         sizeof(val));
188                 if (err < 0)
189                         goto failed;
190                 err = squashfs_read_metadata(sb, NULL, &start, &offset,
191                                                 le32_to_cpu(val.vsize));
192                 if (err < 0)
193                         goto failed;
194         }
195         err = count ? vsize : -ENODATA;
196
197 failed:
198         kfree(target);
199         return err;
200 }
201
202
203 static int squashfs_xattr_handler_get(const struct xattr_handler *handler,
204                                       struct dentry *unused,
205                                       struct inode *inode,
206                                       const char *name,
207                                       void *buffer, size_t size)
208 {
209         return squashfs_xattr_get(inode, handler->flags, name,
210                 buffer, size);
211 }
212
213 /*
214  * User namespace support
215  */
216 static const struct xattr_handler squashfs_xattr_user_handler = {
217         .prefix = XATTR_USER_PREFIX,
218         .flags  = SQUASHFS_XATTR_USER,
219         .get    = squashfs_xattr_handler_get
220 };
221
222 /*
223  * Trusted namespace support
224  */
225 static bool squashfs_trusted_xattr_handler_list(struct dentry *d)
226 {
227         return capable(CAP_SYS_ADMIN);
228 }
229
230 static const struct xattr_handler squashfs_xattr_trusted_handler = {
231         .prefix = XATTR_TRUSTED_PREFIX,
232         .flags  = SQUASHFS_XATTR_TRUSTED,
233         .list   = squashfs_trusted_xattr_handler_list,
234         .get    = squashfs_xattr_handler_get
235 };
236
237 /*
238  * Security namespace support
239  */
240 static const struct xattr_handler squashfs_xattr_security_handler = {
241         .prefix = XATTR_SECURITY_PREFIX,
242         .flags  = SQUASHFS_XATTR_SECURITY,
243         .get    = squashfs_xattr_handler_get
244 };
245
246 static const struct xattr_handler *squashfs_xattr_handler(int type)
247 {
248         if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL))
249                 /* ignore unrecognised type */
250                 return NULL;
251
252         switch (type & SQUASHFS_XATTR_PREFIX_MASK) {
253         case SQUASHFS_XATTR_USER:
254                 return &squashfs_xattr_user_handler;
255         case SQUASHFS_XATTR_TRUSTED:
256                 return &squashfs_xattr_trusted_handler;
257         case SQUASHFS_XATTR_SECURITY:
258                 return &squashfs_xattr_security_handler;
259         default:
260                 /* ignore unrecognised type */
261                 return NULL;
262         }
263 }
264
265 const struct xattr_handler *squashfs_xattr_handlers[] = {
266         &squashfs_xattr_user_handler,
267         &squashfs_xattr_trusted_handler,
268         &squashfs_xattr_security_handler,
269         NULL
270 };
271