Blame view

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