xattr.c 12.2 KB
Newer Older
Josef Bacik's avatar
Josef Bacik committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright (C) 2007 Red Hat.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 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., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/rwsem.h>
#include <linux/xattr.h>
Jim Owens's avatar
Jim Owens committed
24
#include <linux/security.h>
25
#include <linux/posix_acl_xattr.h>
Josef Bacik's avatar
Josef Bacik committed
26 27 28 29 30
#include "ctree.h"
#include "btrfs_inode.h"
#include "transaction.h"
#include "xattr.h"
#include "disk-io.h"
31
#include "props.h"
32
#include "locking.h"
Josef Bacik's avatar
Josef Bacik committed
33

Josef Bacik's avatar
Josef Bacik committed
34

35 36
ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
				void *buffer, size_t size)
Josef Bacik's avatar
Josef Bacik committed
37 38 39 40 41 42 43 44 45
{
	struct btrfs_dir_item *di;
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	int ret = 0;
	unsigned long data_ptr;

	path = btrfs_alloc_path();
46
	if (!path)
Josef Bacik's avatar
Josef Bacik committed
47 48 49
		return -ENOMEM;

	/* lookup the xattr by name */
50
	di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name,
Josef Bacik's avatar
Josef Bacik committed
51
				strlen(name), 0);
Josef Bacik's avatar
Josef Bacik committed
52
	if (!di) {
Josef Bacik's avatar
Josef Bacik committed
53 54
		ret = -ENODATA;
		goto out;
Josef Bacik's avatar
Josef Bacik committed
55 56 57
	} else if (IS_ERR(di)) {
		ret = PTR_ERR(di);
		goto out;
Josef Bacik's avatar
Josef Bacik committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71
	}

	leaf = path->nodes[0];
	/* if size is 0, that means we want the size of the attr */
	if (!size) {
		ret = btrfs_dir_data_len(leaf, di);
		goto out;
	}

	/* now get the data out of our dir_item */
	if (btrfs_dir_data_len(leaf, di) > size) {
		ret = -ERANGE;
		goto out;
	}
Josef Bacik's avatar
Josef Bacik committed
72 73 74 75 76 77 78 79

	/*
	 * The way things are packed into the leaf is like this
	 * |struct btrfs_dir_item|name|data|
	 * where name is the xattr name, so security.foo, and data is the
	 * content of the xattr.  data_ptr points to the location in memory
	 * where the data starts in the in memory leaf
	 */
Josef Bacik's avatar
Josef Bacik committed
80 81 82
	data_ptr = (unsigned long)((char *)(di + 1) +
				   btrfs_dir_name_len(leaf, di));
	read_extent_buffer(leaf, buffer, data_ptr,
Josef Bacik's avatar
Josef Bacik committed
83
			   btrfs_dir_data_len(leaf, di));
Josef Bacik's avatar
Josef Bacik committed
84 85 86 87 88 89 90
	ret = btrfs_dir_data_len(leaf, di);

out:
	btrfs_free_path(path);
	return ret;
}

91 92 93
static int do_setxattr(struct btrfs_trans_handle *trans,
		       struct inode *inode, const char *name,
		       const void *value, size_t size, int flags)
Josef Bacik's avatar
Josef Bacik committed
94
{
95
	struct btrfs_dir_item *di = NULL;
Josef Bacik's avatar
Josef Bacik committed
96 97
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_path *path;
98 99 100 101 102
	size_t name_len = strlen(name);
	int ret = 0;

	if (name_len + size > BTRFS_MAX_XATTR_SIZE(root))
		return -ENOSPC;
Josef Bacik's avatar
Josef Bacik committed
103 104

	path = btrfs_alloc_path();
105
	if (!path)
Josef Bacik's avatar
Josef Bacik committed
106
		return -ENOMEM;
107 108 109 110 111 112 113
	path->skip_release_on_error = 1;

	if (!value) {
		di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode),
					name, name_len, -1);
		if (!di && (flags & XATTR_REPLACE))
			ret = -ENODATA;
114 115
		else if (IS_ERR(di))
			ret = PTR_ERR(di);
116 117 118 119
		else if (di)
			ret = btrfs_delete_one_dir_name(trans, root, path, di);
		goto out;
	}
Josef Bacik's avatar
Josef Bacik committed
120

121 122 123 124 125 126 127
	/*
	 * For a replace we can't just do the insert blindly.
	 * Do a lookup first (read-only btrfs_search_slot), and return if xattr
	 * doesn't exist. If it exists, fall down below to the insert/replace
	 * path - we can't race with a concurrent xattr delete, because the VFS
	 * locks the inode's i_mutex before calling setxattr or removexattr.
	 */
128
	if (flags & XATTR_REPLACE) {
Al Viro's avatar
Al Viro committed
129
		ASSERT(inode_is_locked(inode));
130 131
		di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode),
					name, name_len, 0);
132
		if (!di)
133
			ret = -ENODATA;
134 135 136
		else if (IS_ERR(di))
			ret = PTR_ERR(di);
		if (ret)
Josef Bacik's avatar
Josef Bacik committed
137
			goto out;
138
		btrfs_release_path(path);
139 140
		di = NULL;
	}
141

142 143 144
	ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
				      name, name_len, value, size);
	if (ret == -EOVERFLOW) {
145
		/*
146 147 148
		 * We have an existing item in a leaf, split_leaf couldn't
		 * expand it. That item might have or not a dir_item that
		 * matches our target xattr, so lets check.
149
		 */
150 151 152 153 154
		ret = 0;
		btrfs_assert_tree_locked(path->nodes[0]);
		di = btrfs_match_dir_item_name(root, path, name, name_len);
		if (!di && !(flags & XATTR_REPLACE)) {
			ret = -ENOSPC;
155 156
			goto out;
		}
157 158 159 160 161 162
	} else if (ret == -EEXIST) {
		ret = 0;
		di = btrfs_match_dir_item_name(root, path, name, name_len);
		ASSERT(di); /* logic error */
	} else if (ret) {
		goto out;
163
	}
Josef Bacik's avatar
Josef Bacik committed
164

165
	if (di && (flags & XATTR_CREATE)) {
166
		ret = -EEXIST;
167 168
		goto out;
	}
169

170
	if (di) {
171
		/*
172 173 174 175 176
		 * We're doing a replace, and it must be atomic, that is, at
		 * any point in time we have either the old or the new xattr
		 * value in the tree. We don't want readers (getxattr and
		 * listxattrs) to miss a value, this is specially important
		 * for ACLs.
177
		 */
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
		const int slot = path->slots[0];
		struct extent_buffer *leaf = path->nodes[0];
		const u16 old_data_len = btrfs_dir_data_len(leaf, di);
		const u32 item_size = btrfs_item_size_nr(leaf, slot);
		const u32 data_size = sizeof(*di) + name_len + size;
		struct btrfs_item *item;
		unsigned long data_ptr;
		char *ptr;

		if (size > old_data_len) {
			if (btrfs_leaf_free_space(root, leaf) <
			    (size - old_data_len)) {
				ret = -ENOSPC;
				goto out;
			}
193
		}
Josef Bacik's avatar
Josef Bacik committed
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208
		if (old_data_len + name_len + sizeof(*di) == item_size) {
			/* No other xattrs packed in the same leaf item. */
			if (size > old_data_len)
				btrfs_extend_item(root, path,
						  size - old_data_len);
			else if (size < old_data_len)
				btrfs_truncate_item(root, path, data_size, 1);
		} else {
			/* There are other xattrs packed in the same item. */
			ret = btrfs_delete_one_dir_name(trans, root, path, di);
			if (ret)
				goto out;
			btrfs_extend_item(root, path, data_size);
		}
209

210 211 212 213 214 215 216 217 218
		item = btrfs_item_nr(slot);
		ptr = btrfs_item_ptr(leaf, slot, char);
		ptr += btrfs_item_size(leaf, item) - data_size;
		di = (struct btrfs_dir_item *)ptr;
		btrfs_set_dir_data_len(leaf, di, size);
		data_ptr = ((unsigned long)(di + 1)) + name_len;
		write_extent_buffer(leaf, value, data_ptr, size);
		btrfs_mark_buffer_dirty(leaf);
	} else {
219
		/*
220 221 222
		 * Insert, and we had space for the xattr, so path->slots[0] is
		 * where our xattr dir_item is and btrfs_insert_xattr_item()
		 * filled it.
223
		 */
Josef Bacik's avatar
Josef Bacik committed
224
	}
225 226 227 228 229
out:
	btrfs_free_path(path);
	return ret;
}

230 231 232
/*
 * @value: "" makes the attribute to empty, NULL removes it
 */
233 234 235 236 237 238 239
int __btrfs_setxattr(struct btrfs_trans_handle *trans,
		     struct inode *inode, const char *name,
		     const void *value, size_t size, int flags)
{
	struct btrfs_root *root = BTRFS_I(inode)->root;
	int ret;

240 241 242
	if (btrfs_root_readonly(root))
		return -EROFS;

243 244 245
	if (trans)
		return do_setxattr(trans, inode, name, value, size, flags);

246 247 248
	trans = btrfs_start_transaction(root, 2);
	if (IS_ERR(trans))
		return PTR_ERR(trans);
Josef Bacik's avatar
Josef Bacik committed
249

250 251 252 253
	ret = do_setxattr(trans, inode, name, value, size, flags);
	if (ret)
		goto out;

254
	inode_inc_iversion(inode);
255
	inode->i_ctime = current_time(inode);
256
	set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
257 258 259
	ret = btrfs_update_inode(trans, root, inode);
	BUG_ON(ret);
out:
260
	btrfs_end_transaction(trans, root);
Josef Bacik's avatar
Josef Bacik committed
261 262 263 264 265
	return ret;
}

ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
266
	struct btrfs_key key;
267
	struct inode *inode = d_inode(dentry);
Josef Bacik's avatar
Josef Bacik committed
268 269
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_path *path;
270
	int ret = 0;
Christoph Hellwig's avatar
Christoph Hellwig committed
271
	size_t total_size = 0, size_left = size;
Josef Bacik's avatar
Josef Bacik committed
272 273 274 275 276 277

	/*
	 * ok we want all objects associated with this id.
	 * NOTE: we set key.offset = 0; because we want to start with the
	 * first xattr that we find and walk forward
	 */
278
	key.objectid = btrfs_ino(inode);
279
	key.type = BTRFS_XATTR_ITEM_KEY;
Josef Bacik's avatar
Josef Bacik committed
280 281 282 283 284
	key.offset = 0;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
285
	path->reada = READA_FORWARD;
Josef Bacik's avatar
Josef Bacik committed
286 287 288 289 290

	/* search for our xattrs */
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		goto err;
291

Josef Bacik's avatar
Josef Bacik committed
292
	while (1) {
293 294 295 296 297 298 299
		struct extent_buffer *leaf;
		int slot;
		struct btrfs_dir_item *di;
		struct btrfs_key found_key;
		u32 item_size;
		u32 cur;

Josef Bacik's avatar
Josef Bacik committed
300 301 302 303
		leaf = path->nodes[0];
		slot = path->slots[0];

		/* this is where we start walking through the path */
304
		if (slot >= btrfs_header_nritems(leaf)) {
Josef Bacik's avatar
Josef Bacik committed
305 306 307 308
			/*
			 * if we've reached the last slot in this leaf we need
			 * to go to the next leaf and reset everything
			 */
309 310 311 312 313 314
			ret = btrfs_next_leaf(root, path);
			if (ret < 0)
				goto err;
			else if (ret > 0)
				break;
			continue;
Josef Bacik's avatar
Josef Bacik committed
315 316 317 318 319 320 321
		}

		btrfs_item_key_to_cpu(leaf, &found_key, slot);

		/* check to make sure this item is what we want */
		if (found_key.objectid != key.objectid)
			break;
322
		if (found_key.type > BTRFS_XATTR_ITEM_KEY)
Josef Bacik's avatar
Josef Bacik committed
323
			break;
324
		if (found_key.type < BTRFS_XATTR_ITEM_KEY)
325
			goto next_item;
Josef Bacik's avatar
Josef Bacik committed
326 327

		di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
328 329 330 331 332 333 334 335 336 337 338 339
		item_size = btrfs_item_size_nr(leaf, slot);
		cur = 0;
		while (cur < item_size) {
			u16 name_len = btrfs_dir_name_len(leaf, di);
			u16 data_len = btrfs_dir_data_len(leaf, di);
			u32 this_len = sizeof(*di) + name_len + data_len;
			unsigned long name_ptr = (unsigned long)(di + 1);

			if (verify_dir_item(root, leaf, di)) {
				ret = -EIO;
				goto err;
			}
Josef Bacik's avatar
Josef Bacik committed
340

341 342 343 344 345 346 347
			total_size += name_len + 1;
			/*
			 * We are just looking for how big our buffer needs to
			 * be.
			 */
			if (!size)
				goto next;
Josef Bacik's avatar
Josef Bacik committed
348

349 350 351 352
			if (!buffer || (name_len + 1) > size_left) {
				ret = -ERANGE;
				goto err;
			}
Josef Bacik's avatar
Josef Bacik committed
353

354 355
			read_extent_buffer(leaf, buffer, name_ptr, name_len);
			buffer[name_len] = '\0';
Christoph Hellwig's avatar
Christoph Hellwig committed
356

357 358
			size_left -= name_len + 1;
			buffer += name_len + 1;
359
next:
360 361 362 363
			cur += this_len;
			di = (struct btrfs_dir_item *)((char *)di + this_len);
		}
next_item:
364
		path->slots[0]++;
Josef Bacik's avatar
Josef Bacik committed
365 366 367 368 369 370 371 372 373
	}
	ret = total_size;

err:
	btrfs_free_path(path);

	return ret;
}

374
static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
375 376
				   struct dentry *unused, struct inode *inode,
				   const char *name, void *buffer, size_t size)
377
{
378 379
	name = xattr_full_name(handler, name);
	return __btrfs_getxattr(inode, name, buffer, size);
380 381
}

382
static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
383 384 385
				   struct dentry *unused, struct inode *inode,
				   const char *name, const void *buffer,
				   size_t size, int flags)
386
{
387 388 389
	name = xattr_full_name(handler, name);
	return __btrfs_setxattr(NULL, inode, name, buffer, size, flags);
}
Josef Bacik's avatar
Josef Bacik committed
390

391
static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
392
					struct dentry *unused, struct inode *inode,
393 394 395 396
					const char *name, const void *value,
					size_t size, int flags)
{
	name = xattr_full_name(handler, name);
397
	return btrfs_set_prop(inode, name, value, size, flags);
398
}
Josef Bacik's avatar
Josef Bacik committed
399

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
static const struct xattr_handler btrfs_security_xattr_handler = {
	.prefix = XATTR_SECURITY_PREFIX,
	.get = btrfs_xattr_handler_get,
	.set = btrfs_xattr_handler_set,
};

static const struct xattr_handler btrfs_trusted_xattr_handler = {
	.prefix = XATTR_TRUSTED_PREFIX,
	.get = btrfs_xattr_handler_get,
	.set = btrfs_xattr_handler_set,
};

static const struct xattr_handler btrfs_user_xattr_handler = {
	.prefix = XATTR_USER_PREFIX,
	.get = btrfs_xattr_handler_get,
	.set = btrfs_xattr_handler_set,
};

static const struct xattr_handler btrfs_btrfs_xattr_handler = {
	.prefix = XATTR_BTRFS_PREFIX,
	.get = btrfs_xattr_handler_get,
	.set = btrfs_xattr_handler_set_prop,
};

const struct xattr_handler *btrfs_xattr_handlers[] = {
	&btrfs_security_xattr_handler,
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
	&posix_acl_access_xattr_handler,
	&posix_acl_default_xattr_handler,
#endif
	&btrfs_trusted_xattr_handler,
	&btrfs_user_xattr_handler,
	&btrfs_btrfs_xattr_handler,
	NULL,
};

436 437
static int btrfs_initxattrs(struct inode *inode,
			    const struct xattr *xattr_array, void *fs_info)
Jim Owens's avatar
Jim Owens committed
438
{
439 440
	const struct xattr *xattr;
	struct btrfs_trans_handle *trans = fs_info;
Jim Owens's avatar
Jim Owens committed
441
	char *name;
442
	int err = 0;
Jim Owens's avatar
Jim Owens committed
443

444 445
	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
		name = kmalloc(XATTR_SECURITY_PREFIX_LEN +
446
			       strlen(xattr->name) + 1, GFP_KERNEL);
447 448 449 450
		if (!name) {
			err = -ENOMEM;
			break;
		}
Jim Owens's avatar
Jim Owens committed
451
		strcpy(name, XATTR_SECURITY_PREFIX);
452 453 454
		strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
		err = __btrfs_setxattr(trans, inode, name,
				       xattr->value, xattr->value_len, 0);
Jim Owens's avatar
Jim Owens committed
455
		kfree(name);
456 457
		if (err < 0)
			break;
Jim Owens's avatar
Jim Owens committed
458 459 460
	}
	return err;
}
461 462 463 464 465 466 467 468

int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
			      struct inode *inode, struct inode *dir,
			      const struct qstr *qstr)
{
	return security_inode_init_security(inode, dir, qstr,
					    &btrfs_initxattrs, trans);
}