xref: /OK3568_Linux_fs/kernel/fs/squashfs/xattr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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