Blame view

fs/ubifs/xattr.c 18.3 KB
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  /*
   * This file is part of UBIFS.
   *
   * Copyright (C) 2006-2008 Nokia Corporation.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published by
   * the Free Software Foundation.
   *
   * 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, Inc., 51
   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
   *
   * Authors: Artem Bityutskiy (Битюцкий Артём)
   *          Adrian Hunter
   */
  
  /*
   * This file implements UBIFS extended attributes support.
   *
   * Extended attributes are implemented as regular inodes with attached data,
   * which limits extended attribute size to UBIFS block size (4KiB). Names of
   * extended attributes are described by extended attribute entries (xentries),
   * which are almost identical to directory entries, but have different key type.
   *
   * In other words, the situation with extended attributes is very similar to
   * directories. Indeed, any inode (but of course not xattr inodes) may have a
   * number of associated xentries, just like directory inodes have associated
   * directory entries. Extended attribute entries store the name of the extended
   * attribute, the host inode number, and the extended attribute inode number.
   * Similarly, direntries store the name, the parent and the target inode
   * numbers. Thus, most of the common UBIFS mechanisms may be re-used for
   * extended attributes.
   *
   * The number of extended attributes is not limited, but there is Linux
   * limitation on the maximum possible size of the list of all extended
   * attributes associated with an inode (%XATTR_LIST_MAX), so UBIFS makes sure
   * the sum of all extended attribute names of the inode does not exceed that
   * limit.
   *
   * Extended attributes are synchronous, which means they are written to the
   * flash media synchronously and there is no write-back for extended attribute
   * inodes. The extended attribute values are not stored in compressed form on
   * the media.
   *
   * Since extended attributes are represented by regular inodes, they are cached
   * in the VFS inode cache. The xentries are cached in the LNC cache (see
   * tnc.c).
   *
   * ACL support is not implemented.
   */
073aaa1b1   Al Viro   helpers for acl c...
57
  #include "ubifs.h"
7dcda1c96   Jens Axboe   fs: export empty_...
58
  #include <linux/fs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
59
  #include <linux/slab.h>
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
60
  #include <linux/xattr.h>
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
61
62
63
  
  /*
   * Limit the number of extended attributes per inode so that the total size
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
64
   * (@xattr_size) is guaranteeded to fit in an 'unsigned int'.
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
   */
  #define MAX_XATTRS_PER_INODE 65535
  
  /*
   * Extended attribute type constants.
   *
   * USER_XATTR: user extended attribute ("user.*")
   * TRUSTED_XATTR: trusted extended attribute ("trusted.*)
   * SECURITY_XATTR: security extended attribute ("security.*")
   */
  enum {
  	USER_XATTR,
  	TRUSTED_XATTR,
  	SECURITY_XATTR,
  };
14ffd5d0b   Sedat Dilek   UBIFS: make xattr...
80
81
  static const struct inode_operations empty_iops;
  static const struct file_operations empty_fops;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  
  /**
   * create_xattr - create an extended attribute.
   * @c: UBIFS file-system description object
   * @host: host inode
   * @nm: extended attribute name
   * @value: extended attribute value
   * @size: size of extended attribute value
   *
   * This is a helper function which creates an extended attribute of name @nm
   * and value @value for inode @host. The host inode is also updated on flash
   * because the ctime and extended attribute accounting data changes. This
   * function returns zero in case of success and a negative error code in case
   * of failure.
   */
  static int create_xattr(struct ubifs_info *c, struct inode *host,
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
98
  			const struct fscrypt_name *nm, const void *value, int size)
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
99
  {
fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
100
  	int err, names_len;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
101
102
103
  	struct inode *inode;
  	struct ubifs_inode *ui, *host_ui = ubifs_inode(host);
  	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
5acd6ff8a   Zoltan Sogor   UBIFS: fix budget...
104
105
  				.new_ino_d = ALIGN(size, 8), .dirtied_ino = 1,
  				.dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
106

fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
107
  	if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) {
235c362bd   Sheng Yong   UBIFS: extend deb...
108
  		ubifs_err(c, "inode %lu already has too many xattrs (%d), cannot create more",
fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
109
  			  host->i_ino, host_ui->xattr_cnt);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
110
  		return -ENOSPC;
fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
111
  	}
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
112
113
  	/*
  	 * Linux limits the maximum size of the extended attribute names list
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
114
  	 * to %XATTR_LIST_MAX. This means we should not allow creating more
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
115
116
117
  	 * extended attributes if the name list becomes larger. This limitation
  	 * is artificial for UBIFS, though.
  	 */
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
118
  	names_len = host_ui->xattr_names + host_ui->xattr_cnt + fname_len(nm) + 1;
fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
119
  	if (names_len > XATTR_LIST_MAX) {
235c362bd   Sheng Yong   UBIFS: extend deb...
120
  		ubifs_err(c, "cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
121
  			  host->i_ino, names_len, XATTR_LIST_MAX);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
122
  		return -ENOSPC;
fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
123
  	}
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
124
125
126
127
128
129
130
131
132
133
  
  	err = ubifs_budget_space(c, &req);
  	if (err)
  		return err;
  
  	inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO);
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
  		goto out_budg;
  	}
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
134
  	/* Re-define all operations to be "nothing" */
7dcda1c96   Jens Axboe   fs: export empty_...
135
  	inode->i_mapping->a_ops = &empty_aops;
14ffd5d0b   Sedat Dilek   UBIFS: make xattr...
136
137
  	inode->i_op = &empty_iops;
  	inode->i_fop = &empty_fops;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
138
139
140
141
142
  
  	inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA;
  	ui = ubifs_inode(inode);
  	ui->xattr = 1;
  	ui->flags |= UBIFS_XATTR_FL;
eaecf43a6   Thomas Meyer   UBIFS: Use kmemdu...
143
  	ui->data = kmemdup(value, size, GFP_NOFS);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
144
145
  	if (!ui->data) {
  		err = -ENOMEM;
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
146
  		goto out_free;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
147
  	}
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
148
149
150
151
  	inode->i_size = ui->ui_size = size;
  	ui->data_len = size;
  
  	mutex_lock(&host_ui->ui_mutex);
607a11ad9   Deepa Dinamani   fs: ubifs: replac...
152
  	host->i_ctime = current_time(host);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
153
  	host_ui->xattr_cnt += 1;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
154
  	host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
155
  	host_ui->xattr_size += CALC_XATTR_BYTES(size);
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
156
  	host_ui->xattr_names += fname_len(nm);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
157

d475a5074   Richard Weinberger   ubifs: Add skelet...
158
159
160
161
162
163
  	/*
  	 * We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we
  	 * have to set the UBIFS_CRYPT_FL flag on the host inode.
  	 * To avoid multiple updates of the same inode in the same operation,
  	 * let's do it here.
  	 */
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
164
  	if (strcmp(fname_name(nm), UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
d475a5074   Richard Weinberger   ubifs: Add skelet...
165
  		host_ui->flags |= UBIFS_CRYPT_FL;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
166
167
168
169
170
171
172
173
174
175
176
177
  	err = ubifs_jnl_update(c, host, nm, inode, 0, 1);
  	if (err)
  		goto out_cancel;
  	mutex_unlock(&host_ui->ui_mutex);
  
  	ubifs_release_budget(c, &req);
  	insert_inode_hash(inode);
  	iput(inode);
  	return 0;
  
  out_cancel:
  	host_ui->xattr_cnt -= 1;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
178
  	host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
179
  	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
180
  	host_ui->xattr_names -= fname_len(nm);
d475a5074   Richard Weinberger   ubifs: Add skelet...
181
  	host_ui->flags &= ~UBIFS_CRYPT_FL;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
182
  	mutex_unlock(&host_ui->ui_mutex);
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
183
  out_free:
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
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
  	make_bad_inode(inode);
  	iput(inode);
  out_budg:
  	ubifs_release_budget(c, &req);
  	return err;
  }
  
  /**
   * change_xattr - change an extended attribute.
   * @c: UBIFS file-system description object
   * @host: host inode
   * @inode: extended attribute inode
   * @value: extended attribute value
   * @size: size of extended attribute value
   *
   * This helper function changes the value of extended attribute @inode with new
   * data from @value. Returns zero in case of success and a negative error code
   * in case of failure.
   */
  static int change_xattr(struct ubifs_info *c, struct inode *host,
  			struct inode *inode, const void *value, int size)
  {
  	int err;
  	struct ubifs_inode *host_ui = ubifs_inode(host);
  	struct ubifs_inode *ui = ubifs_inode(inode);
ab92a20bc   Dongsheng Yang   ubifs: make ubifs...
209
  	void *buf = NULL;
74e9c700b   Pascal Eberhard   ubifs: fix host x...
210
  	int old_size;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
211
  	struct ubifs_budget_req req = { .dirtied_ino = 2,
5acd6ff8a   Zoltan Sogor   UBIFS: fix budget...
212
  		.dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
213
214
215
216
217
  
  	ubifs_assert(ui->data_len == inode->i_size);
  	err = ubifs_budget_space(c, &req);
  	if (err)
  		return err;
ab92a20bc   Dongsheng Yang   ubifs: make ubifs...
218
219
  	buf = kmemdup(value, size, GFP_NOFS);
  	if (!buf) {
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
220
  		err = -ENOMEM;
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
221
  		goto out_free;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
222
  	}
ab92a20bc   Dongsheng Yang   ubifs: make ubifs...
223
224
225
  	mutex_lock(&ui->ui_mutex);
  	kfree(ui->data);
  	ui->data = buf;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
226
  	inode->i_size = ui->ui_size = size;
74e9c700b   Pascal Eberhard   ubifs: fix host x...
227
  	old_size = ui->data_len;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
228
  	ui->data_len = size;
ab92a20bc   Dongsheng Yang   ubifs: make ubifs...
229
  	mutex_unlock(&ui->ui_mutex);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
230

c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
231
  	mutex_lock(&host_ui->ui_mutex);
607a11ad9   Deepa Dinamani   fs: ubifs: replac...
232
  	host->i_ctime = current_time(host);
74e9c700b   Pascal Eberhard   ubifs: fix host x...
233
  	host_ui->xattr_size -= CALC_XATTR_BYTES(old_size);
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
234
  	host_ui->xattr_size += CALC_XATTR_BYTES(size);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  	/*
  	 * It is important to write the host inode after the xattr inode
  	 * because if the host inode gets synchronized (via 'fsync()'), then
  	 * the extended attribute inode gets synchronized, because it goes
  	 * before the host inode in the write-buffer.
  	 */
  	err = ubifs_jnl_change_xattr(c, inode, host);
  	if (err)
  		goto out_cancel;
  	mutex_unlock(&host_ui->ui_mutex);
  
  	ubifs_release_budget(c, &req);
  	return 0;
  
  out_cancel:
  	host_ui->xattr_size -= CALC_XATTR_BYTES(size);
74e9c700b   Pascal Eberhard   ubifs: fix host x...
251
  	host_ui->xattr_size += CALC_XATTR_BYTES(old_size);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
252
  	mutex_unlock(&host_ui->ui_mutex);
c78c7e35a   Artem Bityutskiy   UBIFS: xattr bugf...
253
254
  	make_bad_inode(inode);
  out_free:
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
255
256
257
  	ubifs_release_budget(c, &req);
  	return err;
  }
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
258
259
260
261
262
263
  static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
  {
  	struct inode *inode;
  
  	inode = ubifs_iget(c->vfs_sb, inum);
  	if (IS_ERR(inode)) {
235c362bd   Sheng Yong   UBIFS: extend deb...
264
  		ubifs_err(c, "dead extended attribute entry, error %d",
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
265
266
267
268
269
  			  (int)PTR_ERR(inode));
  		return inode;
  	}
  	if (ubifs_inode(inode)->xattr)
  		return inode;
235c362bd   Sheng Yong   UBIFS: extend deb...
270
  	ubifs_err(c, "corrupt extended attribute entry");
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
271
272
273
  	iput(inode);
  	return ERR_PTR(-EINVAL);
  }
ade46c3a6   Richard Weinberger   ubifs: Export xat...
274
  int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
d8db5b1ca   Xiaolei Li   ubifs: Massage as...
275
  		    size_t size, int flags, bool check_lock)
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
276
  {
895d9db25   Subodh Nijsure   UBIFS: Add xattr ...
277
  	struct inode *inode;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
278
  	struct ubifs_info *c = host->i_sb->s_fs_info;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
279
  	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
280
281
  	struct ubifs_dent_node *xent;
  	union ubifs_key key;
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
282
  	int err;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
283

d8db5b1ca   Xiaolei Li   ubifs: Massage as...
284
  	if (check_lock)
700eada82   Richard Weinberger   ubifs: Massage as...
285
  		ubifs_assert(inode_is_locked(host));
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
286
287
288
  
  	if (size > UBIFS_MAX_INO_DATA)
  		return -ERANGE;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
289
  	if (fname_len(&nm) > UBIFS_MAX_NLEN)
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
290
  		return -ENAMETOOLONG;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  
  	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
  	if (!xent)
  		return -ENOMEM;
  
  	/*
  	 * The extended attribute entries are stored in LNC, so multiple
  	 * look-ups do not involve reading the flash.
  	 */
  	xent_key_init(c, &key, host->i_ino, &nm);
  	err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
  	if (err) {
  		if (err != -ENOENT)
  			goto out_free;
  
  		if (flags & XATTR_REPLACE)
  			/* We are asked not to create the xattr */
  			err = -ENODATA;
  		else
  			err = create_xattr(c, host, &nm, value, size);
  		goto out_free;
  	}
  
  	if (flags & XATTR_CREATE) {
  		/* We are asked not to replace the xattr */
  		err = -EEXIST;
  		goto out_free;
  	}
  
  	inode = iget_xattr(c, le64_to_cpu(xent->inum));
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
  		goto out_free;
  	}
  
  	err = change_xattr(c, host, inode, value, size);
  	iput(inode);
  
  out_free:
  	kfree(xent);
  	return err;
  }
ade46c3a6   Richard Weinberger   ubifs: Export xat...
333
334
  ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
  			size_t size)
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
335
  {
ce23e6401   Al Viro   ->getxattr(): pas...
336
  	struct inode *inode;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
337
  	struct ubifs_info *c = host->i_sb->s_fs_info;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
338
  	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
339
340
341
342
  	struct ubifs_inode *ui;
  	struct ubifs_dent_node *xent;
  	union ubifs_key key;
  	int err;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
343
  	if (fname_len(&nm) > UBIFS_MAX_NLEN)
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
344
  		return -ENAMETOOLONG;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
345
346
347
348
  
  	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
  	if (!xent)
  		return -ENOMEM;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  	xent_key_init(c, &key, host->i_ino, &nm);
  	err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
  	if (err) {
  		if (err == -ENOENT)
  			err = -ENODATA;
  		goto out_unlock;
  	}
  
  	inode = iget_xattr(c, le64_to_cpu(xent->inum));
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
  		goto out_unlock;
  	}
  
  	ui = ubifs_inode(inode);
  	ubifs_assert(inode->i_size == ui->data_len);
  	ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len);
ab92a20bc   Dongsheng Yang   ubifs: make ubifs...
366
  	mutex_lock(&ui->ui_mutex);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
367
368
369
  	if (buf) {
  		/* If @buf is %NULL we are supposed to return the length */
  		if (ui->data_len > size) {
235c362bd   Sheng Yong   UBIFS: extend deb...
370
  			ubifs_err(c, "buffer size %zd, xattr len %d",
a6aae4dd0   Artem Bityutskiy   UBIFS: get rid of...
371
  				  size, ui->data_len);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
372
373
374
375
376
377
378
379
380
  			err = -ERANGE;
  			goto out_iput;
  		}
  
  		memcpy(buf, ui->data, ui->data_len);
  	}
  	err = ui->data_len;
  
  out_iput:
ab92a20bc   Dongsheng Yang   ubifs: make ubifs...
381
  	mutex_unlock(&ui->ui_mutex);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
382
383
  	iput(inode);
  out_unlock:
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
384
385
386
  	kfree(xent);
  	return err;
  }
43b113fea   Richard Weinberger   ubifs: Massage ub...
387
388
389
390
391
392
393
394
395
396
397
398
399
  static bool xattr_visible(const char *name)
  {
  	/* File encryption related xattrs are for internal use only */
  	if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
  		return false;
  
  	/* Show trusted namespace only for "power" users */
  	if (strncmp(name, XATTR_TRUSTED_PREFIX,
  		    XATTR_TRUSTED_PREFIX_LEN) == 0 && !capable(CAP_SYS_ADMIN))
  		return false;
  
  	return true;
  }
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
400
401
402
  ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
  {
  	union ubifs_key key;
2b0143b5c   David Howells   VFS: normal files...
403
  	struct inode *host = d_inode(dentry);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
404
405
406
407
  	struct ubifs_info *c = host->i_sb->s_fs_info;
  	struct ubifs_inode *host_ui = ubifs_inode(host);
  	struct ubifs_dent_node *xent, *pxent = NULL;
  	int err, len, written = 0;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
408
  	struct fscrypt_name nm = {0};
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
409

4cb2a01d8   Al Viro   ubifs: switch to %pd
410
411
  	dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino,
  		dentry, size);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
412
413
414
415
416
417
418
419
420
421
422
423
424
  
  	len = host_ui->xattr_names + host_ui->xattr_cnt;
  	if (!buffer)
  		/*
  		 * We should return the minimum buffer size which will fit a
  		 * null-terminated list of all the extended attribute names.
  		 */
  		return len;
  
  	if (len > size)
  		return -ERANGE;
  
  	lowest_xent_key(c, &key, host->i_ino);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
425
  	while (1) {
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
426
  		xent = ubifs_tnc_next_ent(c, &key, &nm);
8d47aef43   Hirofumi Nakagawa   UBIFS: remove unn...
427
  		if (IS_ERR(xent)) {
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
428
429
430
  			err = PTR_ERR(xent);
  			break;
  		}
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
431
432
  		fname_name(&nm) = xent->name;
  		fname_len(&nm) = le16_to_cpu(xent->nlen);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
433

43b113fea   Richard Weinberger   ubifs: Massage ub...
434
  		if (xattr_visible(xent->name)) {
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
435
436
  			memcpy(buffer + written, fname_name(&nm), fname_len(&nm) + 1);
  			written += fname_len(&nm) + 1;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
437
438
439
440
441
442
  		}
  
  		kfree(pxent);
  		pxent = xent;
  		key_read(c, &xent->key, &key);
  	}
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
443
444
445
  
  	kfree(pxent);
  	if (err != -ENOENT) {
235c362bd   Sheng Yong   UBIFS: extend deb...
446
  		ubifs_err(c, "cannot find next direntry, error %d", err);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
447
448
449
450
451
452
453
454
  		return err;
  	}
  
  	ubifs_assert(written <= size);
  	return written;
  }
  
  static int remove_xattr(struct ubifs_info *c, struct inode *host,
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
455
  			struct inode *inode, const struct fscrypt_name *nm)
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
456
457
458
459
  {
  	int err;
  	struct ubifs_inode *host_ui = ubifs_inode(host);
  	struct ubifs_inode *ui = ubifs_inode(inode);
5acd6ff8a   Zoltan Sogor   UBIFS: fix budget...
460
461
  	struct ubifs_budget_req req = { .dirtied_ino = 2, .mod_dent = 1,
  				.dirtied_ino_d = ALIGN(host_ui->data_len, 8) };
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
462
463
464
465
466
467
468
469
  
  	ubifs_assert(ui->data_len == inode->i_size);
  
  	err = ubifs_budget_space(c, &req);
  	if (err)
  		return err;
  
  	mutex_lock(&host_ui->ui_mutex);
607a11ad9   Deepa Dinamani   fs: ubifs: replac...
470
  	host->i_ctime = current_time(host);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
471
  	host_ui->xattr_cnt -= 1;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
472
  	host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
473
  	host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
474
  	host_ui->xattr_names -= fname_len(nm);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
475
476
477
478
479
480
481
482
483
484
485
  
  	err = ubifs_jnl_delete_xattr(c, host, inode, nm);
  	if (err)
  		goto out_cancel;
  	mutex_unlock(&host_ui->ui_mutex);
  
  	ubifs_release_budget(c, &req);
  	return 0;
  
  out_cancel:
  	host_ui->xattr_cnt += 1;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
486
  	host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
487
  	host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
488
  	host_ui->xattr_names += fname_len(nm);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
489
490
491
492
493
  	mutex_unlock(&host_ui->ui_mutex);
  	ubifs_release_budget(c, &req);
  	make_bad_inode(inode);
  	return err;
  }
272eda829   Richard Weinberger   ubifs: Correctly ...
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  /**
   * ubifs_evict_xattr_inode - Evict an xattr inode.
   * @c: UBIFS file-system description object
   * @xattr_inum: xattr inode number
   *
   * When an inode that hosts xattrs is being removed we have to make sure
   * that cached inodes of the xattrs also get removed from the inode cache
   * otherwise we'd waste memory. This function looks up an inode from the
   * inode cache and clears the link counter such that iput() will evict
   * the inode.
   */
  void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum)
  {
  	struct inode *inode;
  
  	inode = ilookup(c->vfs_sb, xattr_inum);
  	if (inode) {
  		clear_nlink(inode);
  		iput(inode);
  	}
  }
ade46c3a6   Richard Weinberger   ubifs: Export xat...
515
  static int ubifs_xattr_remove(struct inode *host, const char *name)
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
516
  {
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
517
  	struct inode *inode;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
518
  	struct ubifs_info *c = host->i_sb->s_fs_info;
f4f61d2cc   Richard Weinberger   ubifs: Implement ...
519
  	struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
520
521
522
  	struct ubifs_dent_node *xent;
  	union ubifs_key key;
  	int err;
5955102c9   Al Viro   wrappers for ->i_...
523
  	ubifs_assert(inode_is_locked(host));
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
524

f4f61d2cc   Richard Weinberger   ubifs: Implement ...
525
  	if (fname_len(&nm) > UBIFS_MAX_NLEN)
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
526
  		return -ENAMETOOLONG;
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  
  	xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
  	if (!xent)
  		return -ENOMEM;
  
  	xent_key_init(c, &key, host->i_ino, &nm);
  	err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
  	if (err) {
  		if (err == -ENOENT)
  			err = -ENODATA;
  		goto out_free;
  	}
  
  	inode = iget_xattr(c, le64_to_cpu(xent->inum));
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
  		goto out_free;
  	}
  
  	ubifs_assert(inode->i_nlink == 1);
6d6b77f16   Miklos Szeredi   filesystems: add ...
547
  	clear_nlink(inode);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
548
549
  	err = remove_xattr(c, host, inode, &nm);
  	if (err)
bfe868486   Miklos Szeredi   filesystems: add ...
550
  		set_nlink(inode, 1);
1e51764a3   Artem Bityutskiy   UBIFS: add new fl...
551
552
553
554
555
556
557
558
  
  	/* If @i_nlink is 0, 'iput()' will delete the inode */
  	iput(inode);
  
  out_free:
  	kfree(xent);
  	return err;
  }
d7f0b70d3   Subodh Nijsure   UBIFS: Add securi...
559

8326c1eec   Hyunchul Lee   ubifs: Add CONFIG...
560
  #ifdef CONFIG_UBIFS_FS_SECURITY
d7f0b70d3   Subodh Nijsure   UBIFS: Add securi...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
  static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
  		      void *fs_info)
  {
  	const struct xattr *xattr;
  	char *name;
  	int err = 0;
  
  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
  		name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
  			       strlen(xattr->name) + 1, GFP_NOFS);
  		if (!name) {
  			err = -ENOMEM;
  			break;
  		}
  		strcpy(name, XATTR_SECURITY_PREFIX);
  		strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
d8db5b1ca   Xiaolei Li   ubifs: Massage as...
577
578
579
580
  		/*
  		 * creating a new inode without holding the inode rwsem,
  		 * no need to check whether inode is locked.
  		 */
ade46c3a6   Richard Weinberger   ubifs: Export xat...
581
  		err = ubifs_xattr_set(inode, name, xattr->value,
d8db5b1ca   Xiaolei Li   ubifs: Massage as...
582
  				      xattr->value_len, 0, false);
d7f0b70d3   Subodh Nijsure   UBIFS: Add securi...
583
584
585
586
587
588
589
590
591
592
593
594
  		kfree(name);
  		if (err < 0)
  			break;
  	}
  
  	return err;
  }
  
  int ubifs_init_security(struct inode *dentry, struct inode *inode,
  			const struct qstr *qstr)
  {
  	int err;
d7f0b70d3   Subodh Nijsure   UBIFS: Add securi...
595
596
  	err = security_inode_init_security(inode, dentry, qstr,
  					   &init_xattrs, 0);
235c362bd   Sheng Yong   UBIFS: extend deb...
597
598
599
  	if (err) {
  		struct ubifs_info *c = dentry->i_sb->s_fs_info;
  		ubifs_err(c, "cannot initialize security for inode %lu, error %d",
fee1756d8   Subodh Nijsure   UBIFS: add ubifs_...
600
  			  inode->i_ino, err);
235c362bd   Sheng Yong   UBIFS: extend deb...
601
  	}
d7f0b70d3   Subodh Nijsure   UBIFS: Add securi...
602
603
  	return err;
  }
8326c1eec   Hyunchul Lee   ubifs: Add CONFIG...
604
  #endif
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
605

ade46c3a6   Richard Weinberger   ubifs: Export xat...
606
  static int xattr_get(const struct xattr_handler *handler,
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
607
608
609
610
611
  			   struct dentry *dentry, struct inode *inode,
  			   const char *name, void *buffer, size_t size)
  {
  	dbg_gen("xattr '%s', ino %lu ('%pd'), buf size %zd", name,
  		inode->i_ino, dentry, size);
17ce1eb0b   Richard Weinberger   ubifs: Fix xattr ...
612
  	name = xattr_full_name(handler, name);
ade46c3a6   Richard Weinberger   ubifs: Export xat...
613
  	return ubifs_xattr_get(inode, name, buffer, size);
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
614
  }
ade46c3a6   Richard Weinberger   ubifs: Export xat...
615
  static int xattr_set(const struct xattr_handler *handler,
593012268   Al Viro   switch xattr_hand...
616
617
618
  			   struct dentry *dentry, struct inode *inode,
  			   const char *name, const void *value,
  			   size_t size, int flags)
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
619
  {
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
620
621
  	dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd",
  		name, inode->i_ino, dentry, size);
17ce1eb0b   Richard Weinberger   ubifs: Fix xattr ...
622
  	name = xattr_full_name(handler, name);
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
623
  	if (value)
d8db5b1ca   Xiaolei Li   ubifs: Massage as...
624
  		return ubifs_xattr_set(inode, name, value, size, flags, true);
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
625
  	else
ade46c3a6   Richard Weinberger   ubifs: Export xat...
626
  		return ubifs_xattr_remove(inode, name);
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
627
  }
dfaf8d2ae   Ben Dooks   ubifs: Make xattr...
628
  static const struct xattr_handler ubifs_user_xattr_handler = {
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
629
  	.prefix = XATTR_USER_PREFIX,
ade46c3a6   Richard Weinberger   ubifs: Export xat...
630
631
  	.get = xattr_get,
  	.set = xattr_set,
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
632
  };
dfaf8d2ae   Ben Dooks   ubifs: Make xattr...
633
  static const struct xattr_handler ubifs_trusted_xattr_handler = {
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
634
  	.prefix = XATTR_TRUSTED_PREFIX,
ade46c3a6   Richard Weinberger   ubifs: Export xat...
635
636
  	.get = xattr_get,
  	.set = xattr_set,
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
637
  };
8326c1eec   Hyunchul Lee   ubifs: Add CONFIG...
638
  #ifdef CONFIG_UBIFS_FS_SECURITY
dfaf8d2ae   Ben Dooks   ubifs: Make xattr...
639
  static const struct xattr_handler ubifs_security_xattr_handler = {
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
640
  	.prefix = XATTR_SECURITY_PREFIX,
ade46c3a6   Richard Weinberger   ubifs: Export xat...
641
642
  	.get = xattr_get,
  	.set = xattr_set,
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
643
  };
8326c1eec   Hyunchul Lee   ubifs: Add CONFIG...
644
  #endif
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
645
646
647
648
  
  const struct xattr_handler *ubifs_xattr_handlers[] = {
  	&ubifs_user_xattr_handler,
  	&ubifs_trusted_xattr_handler,
8326c1eec   Hyunchul Lee   ubifs: Add CONFIG...
649
  #ifdef CONFIG_UBIFS_FS_SECURITY
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
650
  	&ubifs_security_xattr_handler,
8326c1eec   Hyunchul Lee   ubifs: Add CONFIG...
651
  #endif
2b88fc21c   Andreas Gruenbacher   ubifs: Switch to ...
652
653
  	NULL
  };