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