inode.c 8.2 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 16 17 18 19
#include "overlayfs.h"

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

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

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

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

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

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

static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
			 struct kstat *stat)
{
	struct path realpath;
63 64
	const struct cred *old_cred;
	int err;
M
Miklos Szeredi 已提交
65 66

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

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

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

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

	return err;
M
Miklos Szeredi 已提交
104 105
}

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

113 114 115
	if (!dentry)
		return ERR_PTR(-ECHILD);

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

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

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

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

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

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

150 151 152
	if (!OVL_TYPE_UPPER(type))
		ovl_path_upper(dentry, &realpath);

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

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

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

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

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

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

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

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

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

	return res;
}

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

221
	if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode))
222 223
		return NULL;

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

	return acl;
229 230
}

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

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

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

261
	return err;
M
Miklos Szeredi 已提交
262 263
}

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

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

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

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

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

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

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

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

	return inode;
}