inode.c 9.7 KB
Newer Older
M
Miklos Szeredi 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/*
 *
 * Copyright (C) 2011 Novell Inc.
 *
 * 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.
 */

#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/xattr.h>
13
#include <linux/posix_acl.h>
M
Miklos Szeredi 已提交
14 15
#include "overlayfs.h"

16
static int ovl_copy_up_truncate(struct dentry *dentry)
M
Miklos Szeredi 已提交
17 18 19 20 21
{
	int err;
	struct dentry *parent;
	struct kstat stat;
	struct path lowerpath;
22
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
23 24 25 26 27 28 29 30

	parent = dget_parent(dentry);
	err = ovl_copy_up(parent);
	if (err)
		goto out_dput_parent;

	ovl_path_lower(dentry, &lowerpath);

31 32 33 34 35 36 37
	old_cred = ovl_override_creds(dentry->d_sb);
	err = vfs_getattr(&lowerpath, &stat);
	if (!err) {
		stat.size = 0;
		err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
	}
	revert_creds(old_cred);
M
Miklos Szeredi 已提交
38 39 40 41 42 43 44 45 46 47

out_dput_parent:
	dput(parent);
	return err;
}

int ovl_setattr(struct dentry *dentry, struct iattr *attr)
{
	int err;
	struct dentry *upperdentry;
48
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
49

50 51 52 53 54 55 56 57 58 59 60 61 62
	/*
	 * Check for permissions before trying to copy-up.  This is redundant
	 * since it will be rechecked later by ->setattr() on upper dentry.  But
	 * without this, copy-up can be triggered by just about anybody.
	 *
	 * We don't initialize inode->size, which just means that
	 * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
	 * check for a swapfile (which this won't be anyway).
	 */
	err = inode_change_ok(dentry->d_inode, attr);
	if (err)
		return err;

M
Miklos Szeredi 已提交
63 64 65 66
	err = ovl_want_write(dentry);
	if (err)
		goto out;

67 68 69 70 71 72 73 74
	if (attr->ia_valid & ATTR_SIZE) {
		struct inode *realinode = d_inode(ovl_dentry_real(dentry));

		err = -ETXTBSY;
		if (atomic_read(&realinode->i_writecount) < 0)
			goto out_drop_write;
	}

75 76
	err = ovl_copy_up(dentry);
	if (!err) {
77 78
		struct inode *winode = NULL;

79 80
		upperdentry = ovl_dentry_upper(dentry);

81 82 83 84 85 86 87
		if (attr->ia_valid & ATTR_SIZE) {
			winode = d_inode(upperdentry);
			err = get_write_access(winode);
			if (err)
				goto out_drop_write;
		}

M
Miklos Szeredi 已提交
88 89 90
		if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
			attr->ia_valid &= ~ATTR_MODE;

A
Al Viro 已提交
91
		inode_lock(upperdentry->d_inode);
92
		old_cred = ovl_override_creds(dentry->d_sb);
M
Miklos Szeredi 已提交
93
		err = notify_change(upperdentry, attr, NULL);
94
		revert_creds(old_cred);
95 96
		if (!err)
			ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
A
Al Viro 已提交
97
		inode_unlock(upperdentry->d_inode);
98 99 100

		if (winode)
			put_write_access(winode);
M
Miklos Szeredi 已提交
101
	}
102
out_drop_write:
M
Miklos Szeredi 已提交
103 104 105 106 107 108 109 110 111
	ovl_drop_write(dentry);
out:
	return err;
}

static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
			 struct kstat *stat)
{
	struct path realpath;
112 113
	const struct cred *old_cred;
	int err;
M
Miklos Szeredi 已提交
114 115

	ovl_path_real(dentry, &realpath);
116 117 118 119
	old_cred = ovl_override_creds(dentry->d_sb);
	err = vfs_getattr(&realpath, stat);
	revert_creds(old_cred);
	return err;
M
Miklos Szeredi 已提交
120 121 122 123 124
}

int ovl_permission(struct inode *inode, int mask)
{
	bool is_upper;
125
	struct inode *realinode = ovl_inode_real(inode, &is_upper);
126
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
127 128 129 130 131
	int err;

	/* Careful in RCU walk mode */
	if (!realinode) {
		WARN_ON(!(mask & MAY_NOT_BLOCK));
132
		return -ECHILD;
M
Miklos Szeredi 已提交
133 134
	}

135 136 137 138 139 140 141 142 143
	/*
	 * Check overlay inode with the creds of task and underlying inode
	 * with creds of mounter
	 */
	err = generic_permission(inode, mask);
	if (err)
		return err;

	old_cred = ovl_override_creds(inode->i_sb);
144
	if (!is_upper && !special_file(realinode->i_mode) && mask & MAY_WRITE) {
145
		mask &= ~(MAY_WRITE | MAY_APPEND);
146 147 148
		/* Make sure mounter can read file for copy up later */
		mask |= MAY_READ;
	}
149
	err = inode_permission(realinode, mask);
150 151 152
	revert_creds(old_cred);

	return err;
M
Miklos Szeredi 已提交
153 154
}

155
static const char *ovl_get_link(struct dentry *dentry,
156 157
				struct inode *inode,
				struct delayed_call *done)
M
Miklos Szeredi 已提交
158 159 160
{
	struct dentry *realdentry;
	struct inode *realinode;
161 162
	const struct cred *old_cred;
	const char *p;
M
Miklos Szeredi 已提交
163

164 165 166
	if (!dentry)
		return ERR_PTR(-ECHILD);

M
Miklos Szeredi 已提交
167 168 169
	realdentry = ovl_dentry_real(dentry);
	realinode = realdentry->d_inode;

170
	if (WARN_ON(!realinode->i_op->get_link))
M
Miklos Szeredi 已提交
171 172
		return ERR_PTR(-EPERM);

173 174 175 176
	old_cred = ovl_override_creds(dentry->d_sb);
	p = realinode->i_op->get_link(realdentry, realinode, done);
	revert_creds(old_cred);
	return p;
M
Miklos Szeredi 已提交
177 178
}

M
Miklos Szeredi 已提交
179
bool ovl_is_private_xattr(const char *name)
M
Miklos Szeredi 已提交
180
{
A
Andreas Gruenbacher 已提交
181 182
	return strncmp(name, OVL_XATTR_PREFIX,
		       sizeof(OVL_XATTR_PREFIX) - 1) == 0;
M
Miklos Szeredi 已提交
183 184
}

185 186
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
		  size_t size, int flags)
M
Miklos Szeredi 已提交
187 188
{
	int err;
189 190
	struct path realpath;
	enum ovl_path_type type = ovl_path_real(dentry, &realpath);
191
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
192 193 194 195 196

	err = ovl_want_write(dentry);
	if (err)
		goto out;

197 198 199 200 201 202
	if (!value && !OVL_TYPE_UPPER(type)) {
		err = vfs_getxattr(realpath.dentry, name, NULL, 0);
		if (err < 0)
			goto out_drop_write;
	}

M
Miklos Szeredi 已提交
203 204 205 206
	err = ovl_copy_up(dentry);
	if (err)
		goto out_drop_write;

207 208 209
	if (!OVL_TYPE_UPPER(type))
		ovl_path_upper(dentry, &realpath);

210
	old_cred = ovl_override_creds(dentry->d_sb);
211 212 213 214 215 216
	if (value)
		err = vfs_setxattr(realpath.dentry, name, value, size, flags);
	else {
		WARN_ON(flags != XATTR_REPLACE);
		err = vfs_removexattr(realpath.dentry, name);
	}
217
	revert_creds(old_cred);
M
Miklos Szeredi 已提交
218 219 220 221 222 223 224

out_drop_write:
	ovl_drop_write(dentry);
out:
	return err;
}

225 226
int ovl_xattr_get(struct dentry *dentry, const char *name,
		  void *value, size_t size)
M
Miklos Szeredi 已提交
227
{
M
Miklos Szeredi 已提交
228
	struct dentry *realdentry = ovl_dentry_real(dentry);
229 230
	ssize_t res;
	const struct cred *old_cred;
231

232 233 234 235
	old_cred = ovl_override_creds(dentry->d_sb);
	res = vfs_getxattr(realdentry, name, value, size);
	revert_creds(old_cred);
	return res;
M
Miklos Szeredi 已提交
236 237 238 239
}

ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
{
M
Miklos Szeredi 已提交
240
	struct dentry *realdentry = ovl_dentry_real(dentry);
M
Miklos Szeredi 已提交
241
	ssize_t res;
M
Miklos Szeredi 已提交
242 243
	size_t len;
	char *s;
244
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
245

246
	old_cred = ovl_override_creds(dentry->d_sb);
M
Miklos Szeredi 已提交
247
	res = vfs_listxattr(realdentry, list, size);
248
	revert_creds(old_cred);
M
Miklos Szeredi 已提交
249 250 251 252
	if (res <= 0 || size == 0)
		return res;

	/* filter out private xattrs */
M
Miklos Szeredi 已提交
253 254
	for (s = list, len = res; len;) {
		size_t slen = strnlen(s, len) + 1;
M
Miklos Szeredi 已提交
255

M
Miklos Szeredi 已提交
256 257 258
		/* underlying fs providing us with an broken xattr list? */
		if (WARN_ON(slen > len))
			return -EIO;
M
Miklos Szeredi 已提交
259

M
Miklos Szeredi 已提交
260
		len -= slen;
M
Miklos Szeredi 已提交
261 262
		if (ovl_is_private_xattr(s)) {
			res -= slen;
M
Miklos Szeredi 已提交
263
			memmove(s, s + slen, len);
M
Miklos Szeredi 已提交
264
		} else {
M
Miklos Szeredi 已提交
265
			s += slen;
M
Miklos Szeredi 已提交
266 267 268 269 270 271
		}
	}

	return res;
}

272 273
struct posix_acl *ovl_get_acl(struct inode *inode, int type)
{
274
	struct inode *realinode = ovl_inode_real(inode, NULL);
275 276
	const struct cred *old_cred;
	struct posix_acl *acl;
277

278
	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode))
279 280 281 282 283
		return NULL;

	if (!realinode->i_op->get_acl)
		return NULL;

284
	old_cred = ovl_override_creds(inode->i_sb);
285
	acl = get_acl(realinode, type);
286 287 288
	revert_creds(old_cred);

	return acl;
289 290
}

M
Miklos Szeredi 已提交
291 292 293
static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
				  struct dentry *realdentry)
{
M
Miklos Szeredi 已提交
294
	if (OVL_TYPE_UPPER(type))
M
Miklos Szeredi 已提交
295 296 297 298 299 300 301 302 303 304 305
		return false;

	if (special_file(realdentry->d_inode->i_mode))
		return false;

	if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC))
		return false;

	return true;
}

306
int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
M
Miklos Szeredi 已提交
307
{
308
	int err = 0;
M
Miklos Szeredi 已提交
309 310 311 312
	struct path realpath;
	enum ovl_path_type type;

	type = ovl_path_real(dentry, &realpath);
313
	if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) {
M
Miklos Szeredi 已提交
314
		err = ovl_want_write(dentry);
315 316 317 318 319 320 321
		if (!err) {
			if (file_flags & O_TRUNC)
				err = ovl_copy_up_truncate(dentry);
			else
				err = ovl_copy_up(dentry);
			ovl_drop_write(dentry);
		}
M
Miklos Szeredi 已提交
322 323
	}

324
	return err;
M
Miklos Szeredi 已提交
325 326
}

M
Miklos Szeredi 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
int ovl_update_time(struct inode *inode, struct timespec *ts, int flags)
{
	struct dentry *alias;
	struct path upperpath;

	if (!(flags & S_ATIME))
		return 0;

	alias = d_find_any_alias(inode);
	if (!alias)
		return 0;

	ovl_path_upper(alias, &upperpath);
	if (upperpath.dentry) {
		touch_atime(&upperpath);
		inode->i_atime = d_inode(upperpath.dentry)->i_atime;
	}

	dput(alias);

	return 0;
}

M
Miklos Szeredi 已提交
350 351 352 353
static const struct inode_operations ovl_file_inode_operations = {
	.setattr	= ovl_setattr,
	.permission	= ovl_permission,
	.getattr	= ovl_getattr,
M
Miklos Szeredi 已提交
354
	.setxattr	= generic_setxattr,
355
	.getxattr	= generic_getxattr,
M
Miklos Szeredi 已提交
356
	.listxattr	= ovl_listxattr,
357
	.removexattr	= generic_removexattr,
358
	.get_acl	= ovl_get_acl,
M
Miklos Szeredi 已提交
359
	.update_time	= ovl_update_time,
M
Miklos Szeredi 已提交
360 361 362 363
};

static const struct inode_operations ovl_symlink_inode_operations = {
	.setattr	= ovl_setattr,
364
	.get_link	= ovl_get_link,
M
Miklos Szeredi 已提交
365
	.readlink	= generic_readlink,
M
Miklos Szeredi 已提交
366
	.getattr	= ovl_getattr,
M
Miklos Szeredi 已提交
367
	.setxattr	= generic_setxattr,
368
	.getxattr	= generic_getxattr,
M
Miklos Szeredi 已提交
369
	.listxattr	= ovl_listxattr,
370
	.removexattr	= generic_removexattr,
M
Miklos Szeredi 已提交
371
	.update_time	= ovl_update_time,
M
Miklos Szeredi 已提交
372 373
};

M
Miklos Szeredi 已提交
374
static void ovl_fill_inode(struct inode *inode, umode_t mode)
M
Miklos Szeredi 已提交
375 376 377
{
	inode->i_ino = get_next_ino();
	inode->i_mode = mode;
M
Miklos Szeredi 已提交
378
	inode->i_flags |= S_NOCMTIME;
379 380 381
#ifdef CONFIG_FS_POSIX_ACL
	inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE;
#endif
M
Miklos Szeredi 已提交
382

383
	mode &= S_IFMT;
M
Miklos Szeredi 已提交
384 385 386 387 388 389 390 391 392 393
	switch (mode) {
	case S_IFDIR:
		inode->i_op = &ovl_dir_inode_operations;
		inode->i_fop = &ovl_dir_operations;
		break;

	case S_IFLNK:
		inode->i_op = &ovl_symlink_inode_operations;
		break;

M
Miklos Szeredi 已提交
394 395 396 397
	default:
		WARN(1, "illegal file type: %i\n", mode);
		/* Fall through */

M
Miklos Szeredi 已提交
398 399 400 401 402 403 404
	case S_IFREG:
	case S_IFSOCK:
	case S_IFBLK:
	case S_IFCHR:
	case S_IFIFO:
		inode->i_op = &ovl_file_inode_operations;
		break;
M
Miklos Szeredi 已提交
405 406
	}
}
M
Miklos Szeredi 已提交
407

M
Miklos Szeredi 已提交
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 436 437 438 439 440
struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
{
	struct inode *inode;

	inode = new_inode(sb);
	if (inode)
		ovl_fill_inode(inode, mode);

	return inode;
}

static int ovl_inode_test(struct inode *inode, void *data)
{
	return ovl_inode_real(inode, NULL) == data;
}

static int ovl_inode_set(struct inode *inode, void *data)
{
	inode->i_private = (void *) (((unsigned long) data) | OVL_ISUPPER_MASK);
	return 0;
}

struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode)

{
	struct inode *inode;

	inode = iget5_locked(sb, (unsigned long) realinode,
			     ovl_inode_test, ovl_inode_set, realinode);
	if (inode && inode->i_state & I_NEW) {
		ovl_fill_inode(inode, realinode->i_mode);
		set_nlink(inode, realinode->i_nlink);
		unlock_new_inode(inode);
M
Miklos Szeredi 已提交
441 442 443 444
	}

	return inode;
}