inode.c 8.3 KB
Newer Older
M
Miklos Szeredi 已提交
1 2 3 4 5 6 7 8 9 10 11
/*
 *
 * 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>
12
#include <linux/cred.h>
M
Miklos Szeredi 已提交
13
#include <linux/xattr.h>
14
#include <linux/posix_acl.h>
M
Miklos Szeredi 已提交
15 16 17 18 19 20
#include "overlayfs.h"

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

23 24 25 26 27 28 29 30 31
	/*
	 * 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).
	 */
32
	err = setattr_prepare(dentry, attr);
33 34 35
	if (err)
		return err;

M
Miklos Szeredi 已提交
36 37 38 39
	err = ovl_want_write(dentry);
	if (err)
		goto out;

40 41 42 43
	err = ovl_copy_up(dentry);
	if (!err) {
		upperdentry = ovl_dentry_upper(dentry);

M
Miklos Szeredi 已提交
44 45 46
		if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
			attr->ia_valid &= ~ATTR_MODE;

A
Al Viro 已提交
47
		inode_lock(upperdentry->d_inode);
48
		old_cred = ovl_override_creds(dentry->d_sb);
M
Miklos Szeredi 已提交
49
		err = notify_change(upperdentry, attr, NULL);
50
		revert_creds(old_cred);
51 52
		if (!err)
			ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
A
Al Viro 已提交
53
		inode_unlock(upperdentry->d_inode);
M
Miklos Szeredi 已提交
54 55 56 57 58 59
	}
	ovl_drop_write(dentry);
out:
	return err;
}

60 61
static int ovl_getattr(const struct path *path, struct kstat *stat,
		       u32 request_mask, unsigned int flags)
M
Miklos Szeredi 已提交
62
{
63
	struct dentry *dentry = path->dentry;
M
Miklos Szeredi 已提交
64
	struct path realpath;
65 66
	const struct cred *old_cred;
	int err;
M
Miklos Szeredi 已提交
67 68

	ovl_path_real(dentry, &realpath);
69
	old_cred = ovl_override_creds(dentry->d_sb);
70
	err = vfs_getattr(&realpath, stat, request_mask, flags);
71 72
	revert_creds(old_cred);
	return err;
M
Miklos Szeredi 已提交
73 74 75 76 77
}

int ovl_permission(struct inode *inode, int mask)
{
	bool is_upper;
78
	struct inode *realinode = ovl_inode_real(inode, &is_upper);
79
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
80 81 82 83 84
	int err;

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

88 89 90 91 92 93 94 95 96
	/*
	 * 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);
97
	if (!is_upper && !special_file(realinode->i_mode) && mask & MAY_WRITE) {
98
		mask &= ~(MAY_WRITE | MAY_APPEND);
99 100 101
		/* Make sure mounter can read file for copy up later */
		mask |= MAY_READ;
	}
102
	err = inode_permission(realinode, mask);
103 104 105
	revert_creds(old_cred);

	return err;
M
Miklos Szeredi 已提交
106 107
}

108
static const char *ovl_get_link(struct dentry *dentry,
109 110
				struct inode *inode,
				struct delayed_call *done)
M
Miklos Szeredi 已提交
111
{
112 113
	const struct cred *old_cred;
	const char *p;
M
Miklos Szeredi 已提交
114

115 116 117
	if (!dentry)
		return ERR_PTR(-ECHILD);

118
	old_cred = ovl_override_creds(dentry->d_sb);
M
Miklos Szeredi 已提交
119
	p = vfs_get_link(ovl_dentry_real(dentry), done);
120 121
	revert_creds(old_cred);
	return p;
M
Miklos Szeredi 已提交
122 123
}

M
Miklos Szeredi 已提交
124
bool ovl_is_private_xattr(const char *name)
M
Miklos Szeredi 已提交
125
{
A
Andreas Gruenbacher 已提交
126 127
	return strncmp(name, OVL_XATTR_PREFIX,
		       sizeof(OVL_XATTR_PREFIX) - 1) == 0;
M
Miklos Szeredi 已提交
128 129
}

130 131
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
		  size_t size, int flags)
M
Miklos Szeredi 已提交
132 133
{
	int err;
134 135
	struct path realpath;
	enum ovl_path_type type = ovl_path_real(dentry, &realpath);
136
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
137 138 139 140 141

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

142 143 144 145 146 147
	if (!value && !OVL_TYPE_UPPER(type)) {
		err = vfs_getxattr(realpath.dentry, name, NULL, 0);
		if (err < 0)
			goto out_drop_write;
	}

M
Miklos Szeredi 已提交
148 149 150 151
	err = ovl_copy_up(dentry);
	if (err)
		goto out_drop_write;

152 153 154
	if (!OVL_TYPE_UPPER(type))
		ovl_path_upper(dentry, &realpath);

155
	old_cred = ovl_override_creds(dentry->d_sb);
156 157 158 159 160 161
	if (value)
		err = vfs_setxattr(realpath.dentry, name, value, size, flags);
	else {
		WARN_ON(flags != XATTR_REPLACE);
		err = vfs_removexattr(realpath.dentry, name);
	}
162
	revert_creds(old_cred);
M
Miklos Szeredi 已提交
163 164 165 166 167 168 169

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

170 171
int ovl_xattr_get(struct dentry *dentry, const char *name,
		  void *value, size_t size)
M
Miklos Szeredi 已提交
172
{
M
Miklos Szeredi 已提交
173
	struct dentry *realdentry = ovl_dentry_real(dentry);
174 175
	ssize_t res;
	const struct cred *old_cred;
176

177 178 179 180
	old_cred = ovl_override_creds(dentry->d_sb);
	res = vfs_getxattr(realdentry, name, value, size);
	revert_creds(old_cred);
	return res;
M
Miklos Szeredi 已提交
181 182 183 184
}

ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
{
M
Miklos Szeredi 已提交
185
	struct dentry *realdentry = ovl_dentry_real(dentry);
M
Miklos Szeredi 已提交
186
	ssize_t res;
M
Miklos Szeredi 已提交
187 188
	size_t len;
	char *s;
189
	const struct cred *old_cred;
M
Miklos Szeredi 已提交
190

191
	old_cred = ovl_override_creds(dentry->d_sb);
M
Miklos Szeredi 已提交
192
	res = vfs_listxattr(realdentry, list, size);
193
	revert_creds(old_cred);
M
Miklos Szeredi 已提交
194 195 196 197
	if (res <= 0 || size == 0)
		return res;

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

M
Miklos Szeredi 已提交
201 202 203
		/* underlying fs providing us with an broken xattr list? */
		if (WARN_ON(slen > len))
			return -EIO;
M
Miklos Szeredi 已提交
204

M
Miklos Szeredi 已提交
205
		len -= slen;
M
Miklos Szeredi 已提交
206 207
		if (ovl_is_private_xattr(s)) {
			res -= slen;
M
Miklos Szeredi 已提交
208
			memmove(s, s + slen, len);
M
Miklos Szeredi 已提交
209
		} else {
M
Miklos Szeredi 已提交
210
			s += slen;
M
Miklos Szeredi 已提交
211 212 213 214 215 216
		}
	}

	return res;
}

217 218
struct posix_acl *ovl_get_acl(struct inode *inode, int type)
{
219
	struct inode *realinode = ovl_inode_real(inode, NULL);
220 221
	const struct cred *old_cred;
	struct posix_acl *acl;
222

223
	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode))
224 225
		return NULL;

226
	old_cred = ovl_override_creds(inode->i_sb);
227
	acl = get_acl(realinode, type);
228 229 230
	revert_creds(old_cred);

	return acl;
231 232
}

M
Miklos Szeredi 已提交
233 234 235
static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
				  struct dentry *realdentry)
{
M
Miklos Szeredi 已提交
236
	if (OVL_TYPE_UPPER(type))
M
Miklos Szeredi 已提交
237 238 239 240 241 242 243 244 245 246 247
		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;
}

248
int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags)
M
Miklos Szeredi 已提交
249
{
250
	int err = 0;
M
Miklos Szeredi 已提交
251 252 253 254
	struct path realpath;
	enum ovl_path_type type;

	type = ovl_path_real(dentry, &realpath);
255
	if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) {
M
Miklos Szeredi 已提交
256
		err = ovl_want_write(dentry);
257
		if (!err) {
258
			err = ovl_copy_up_flags(dentry, file_flags);
259 260
			ovl_drop_write(dentry);
		}
M
Miklos Szeredi 已提交
261 262
	}

263
	return err;
M
Miklos Szeredi 已提交
264 265
}

M
Miklos Szeredi 已提交
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
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 已提交
289 290 291 292 293
static const struct inode_operations ovl_file_inode_operations = {
	.setattr	= ovl_setattr,
	.permission	= ovl_permission,
	.getattr	= ovl_getattr,
	.listxattr	= ovl_listxattr,
294
	.get_acl	= ovl_get_acl,
M
Miklos Szeredi 已提交
295
	.update_time	= ovl_update_time,
M
Miklos Szeredi 已提交
296 297 298 299
};

static const struct inode_operations ovl_symlink_inode_operations = {
	.setattr	= ovl_setattr,
300
	.get_link	= ovl_get_link,
M
Miklos Szeredi 已提交
301 302
	.getattr	= ovl_getattr,
	.listxattr	= ovl_listxattr,
M
Miklos Szeredi 已提交
303
	.update_time	= ovl_update_time,
M
Miklos Szeredi 已提交
304 305
};

306
static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev)
M
Miklos Szeredi 已提交
307 308 309
{
	inode->i_ino = get_next_ino();
	inode->i_mode = mode;
M
Miklos Szeredi 已提交
310
	inode->i_flags |= S_NOCMTIME;
311 312 313
#ifdef CONFIG_FS_POSIX_ACL
	inode->i_acl = inode->i_default_acl = ACL_DONT_CACHE;
#endif
M
Miklos Szeredi 已提交
314

315 316 317 318 319
	switch (mode & S_IFMT) {
	case S_IFREG:
		inode->i_op = &ovl_file_inode_operations;
		break;

M
Miklos Szeredi 已提交
320 321 322 323 324 325 326 327 328
	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 已提交
329
	default:
M
Miklos Szeredi 已提交
330
		inode->i_op = &ovl_file_inode_operations;
331
		init_special_inode(inode, mode, rdev);
M
Miklos Szeredi 已提交
332
		break;
M
Miklos Szeredi 已提交
333 334
	}
}
M
Miklos Szeredi 已提交
335

336
struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, dev_t rdev)
M
Miklos Szeredi 已提交
337 338 339 340 341
{
	struct inode *inode;

	inode = new_inode(sb);
	if (inode)
342
		ovl_fill_inode(inode, mode, rdev);
M
Miklos Szeredi 已提交
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365

	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) {
366
		ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
M
Miklos Szeredi 已提交
367 368
		set_nlink(inode, realinode->i_nlink);
		unlock_new_inode(inode);
M
Miklos Szeredi 已提交
369 370 371 372
	}

	return inode;
}