attr.c 9.68 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
Linus Torvalds's avatar
Linus Torvalds committed
2
3
4
5
6
7
8
/*
 *  linux/fs/attr.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *  changes by Thomas Schoebel-Theuer
 */

9
#include <linux/export.h>
Linus Torvalds's avatar
Linus Torvalds committed
10
11
12
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/string.h>
13
#include <linux/sched/signal.h>
14
#include <linux/capability.h>
Robert Love's avatar
Robert Love committed
15
#include <linux/fsnotify.h>
Linus Torvalds's avatar
Linus Torvalds committed
16
17
#include <linux/fcntl.h>
#include <linux/security.h>
Mimi Zohar's avatar
Mimi Zohar committed
18
#include <linux/evm.h>
Mimi Zohar's avatar
Mimi Zohar committed
19
#include <linux/ima.h>
Linus Torvalds's avatar
Linus Torvalds committed
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
static bool chown_ok(const struct inode *inode, kuid_t uid)
{
	if (uid_eq(current_fsuid(), inode->i_uid) &&
	    uid_eq(uid, inode->i_uid))
		return true;
	if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
		return true;
	if (uid_eq(inode->i_uid, INVALID_UID) &&
	    ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
		return true;
	return false;
}

static bool chgrp_ok(const struct inode *inode, kgid_t gid)
{
	if (uid_eq(current_fsuid(), inode->i_uid) &&
	    (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
		return true;
	if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
		return true;
	if (gid_eq(inode->i_gid, INVALID_GID) &&
	    ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
		return true;
	return false;
}

47
/**
48
49
 * setattr_prepare - check if attribute changes to a dentry are allowed
 * @dentry:	dentry to check
50
51
52
 * @attr:	attributes to change
 *
 * Check if we are allowed to change the attributes contained in @attr
53
54
55
56
 * in the given dentry.  This includes the normal unix access permission
 * checks, as well as checks for rlimits and others. The function also clears
 * SGID bit from mode if user is not allowed to set it. Also file capabilities
 * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
57
58
59
60
 *
 * Should be called as the first thing in ->setattr implementations,
 * possibly after taking additional locks.
 */
61
int setattr_prepare(struct dentry *dentry, struct iattr *attr)
Linus Torvalds's avatar
Linus Torvalds committed
62
{
63
	struct inode *inode = d_inode(dentry);
Linus Torvalds's avatar
Linus Torvalds committed
64
65
	unsigned int ia_valid = attr->ia_valid;

66
67
68
69
70
71
72
73
74
75
	/*
	 * First check size constraints.  These can't be overriden using
	 * ATTR_FORCE.
	 */
	if (ia_valid & ATTR_SIZE) {
		int error = inode_newsize_ok(inode, attr->ia_size);
		if (error)
			return error;
	}

Linus Torvalds's avatar
Linus Torvalds committed
76
77
	/* If force is set do it anyway. */
	if (ia_valid & ATTR_FORCE)
78
		goto kill_priv;
Linus Torvalds's avatar
Linus Torvalds committed
79
80

	/* Make sure a caller can chown. */
81
	if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid))
82
		return -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
83
84

	/* Make sure caller can chgrp. */
85
	if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid))
86
		return -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
87
88
89

	/* Make sure a caller can chmod. */
	if (ia_valid & ATTR_MODE) {
90
		if (!inode_owner_or_capable(inode))
91
			return -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
92
93
		/* Also check the setgid bit! */
		if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
94
				inode->i_gid) &&
95
		    !capable_wrt_inode_uidgid(inode, CAP_FSETID))
Linus Torvalds's avatar
Linus Torvalds committed
96
97
98
99
			attr->ia_mode &= ~S_ISGID;
	}

	/* Check for setting the inode time. */
100
	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
101
		if (!inode_owner_or_capable(inode))
102
			return -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
103
	}
104

105
106
107
108
109
110
111
112
113
114
kill_priv:
	/* User has permission for the change */
	if (ia_valid & ATTR_KILL_PRIV) {
		int error;

		error = security_inode_killpriv(dentry);
		if (error)
			return error;
	}

115
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
116
}
117
EXPORT_SYMBOL(setattr_prepare);
Linus Torvalds's avatar
Linus Torvalds committed
118

npiggin@suse.de's avatar
npiggin@suse.de committed
119
120
121
122
123
124
/**
 * inode_newsize_ok - may this inode be truncated to a given size
 * @inode:	the inode to be truncated
 * @offset:	the new size to assign to the inode
 * @Returns:	0 on success, -ve errno on failure
 *
125
126
 * inode_newsize_ok must be called with i_mutex held.
 *
npiggin@suse.de's avatar
npiggin@suse.de committed
127
128
129
130
131
132
133
134
135
136
137
138
 * inode_newsize_ok will check filesystem limits and ulimits to check that the
 * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ
 * when necessary. Caller must not proceed with inode size change if failure is
 * returned. @inode must be a file (not directory), with appropriate
 * permissions to allow truncate (inode_newsize_ok does NOT check these
 * conditions).
 */
int inode_newsize_ok(const struct inode *inode, loff_t offset)
{
	if (inode->i_size < offset) {
		unsigned long limit;

Jiri Slaby's avatar
Jiri Slaby committed
139
		limit = rlimit(RLIMIT_FSIZE);
npiggin@suse.de's avatar
npiggin@suse.de committed
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
		if (limit != RLIM_INFINITY && offset > limit)
			goto out_sig;
		if (offset > inode->i_sb->s_maxbytes)
			goto out_big;
	} else {
		/*
		 * truncation of in-use swapfiles is disallowed - it would
		 * cause subsequent swapout to scribble on the now-freed
		 * blocks.
		 */
		if (IS_SWAPFILE(inode))
			return -ETXTBSY;
	}

	return 0;
out_sig:
	send_sig(SIGXFSZ, current, 0);
out_big:
	return -EFBIG;
}
EXPORT_SYMBOL(inode_newsize_ok);

162
/**
Christoph Hellwig's avatar
Christoph Hellwig committed
163
 * setattr_copy - copy simple metadata updates into the generic inode
164
165
166
 * @inode:	the inode to be updated
 * @attr:	the new attributes
 *
Christoph Hellwig's avatar
Christoph Hellwig committed
167
 * setattr_copy must be called with i_mutex held.
168
 *
Christoph Hellwig's avatar
Christoph Hellwig committed
169
 * setattr_copy updates the inode's metadata with that specified
Lucas De Marchi's avatar
Lucas De Marchi committed
170
 * in attr. Noticeably missing is inode size update, which is more complex
171
 * as it requires pagecache updates.
172
173
174
175
176
 *
 * The inode is not marked as dirty after this operation. The rationale is
 * that for "simple" filesystems, the struct inode is the inode storage.
 * The caller is free to mark the inode dirty afterwards if needed.
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
177
void setattr_copy(struct inode *inode, const struct iattr *attr)
Linus Torvalds's avatar
Linus Torvalds committed
178
179
{
	unsigned int ia_valid = attr->ia_valid;
180

Linus Torvalds's avatar
Linus Torvalds committed
181
182
183
184
185
	if (ia_valid & ATTR_UID)
		inode->i_uid = attr->ia_uid;
	if (ia_valid & ATTR_GID)
		inode->i_gid = attr->ia_gid;
	if (ia_valid & ATTR_ATIME)
186
187
		inode->i_atime = timespec64_trunc(attr->ia_atime,
						  inode->i_sb->s_time_gran);
Linus Torvalds's avatar
Linus Torvalds committed
188
	if (ia_valid & ATTR_MTIME)
189
190
		inode->i_mtime = timespec64_trunc(attr->ia_mtime,
						  inode->i_sb->s_time_gran);
Linus Torvalds's avatar
Linus Torvalds committed
191
	if (ia_valid & ATTR_CTIME)
192
193
		inode->i_ctime = timespec64_trunc(attr->ia_ctime,
						  inode->i_sb->s_time_gran);
Linus Torvalds's avatar
Linus Torvalds committed
194
195
196
	if (ia_valid & ATTR_MODE) {
		umode_t mode = attr->ia_mode;

197
		if (!in_group_p(inode->i_gid) &&
198
		    !capable_wrt_inode_uidgid(inode, CAP_FSETID))
Linus Torvalds's avatar
Linus Torvalds committed
199
200
201
			mode &= ~S_ISGID;
		inode->i_mode = mode;
	}
202
}
Christoph Hellwig's avatar
Christoph Hellwig committed
203
EXPORT_SYMBOL(setattr_copy);
204

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/**
 * notify_change - modify attributes of a filesytem object
 * @dentry:	object affected
 * @iattr:	new attributes
 * @delegated_inode: returns inode, if the inode is delegated
 *
 * The caller must hold the i_mutex on the affected object.
 *
 * If notify_change discovers a delegation in need of breaking,
 * it will return -EWOULDBLOCK and return a reference to the inode in
 * delegated_inode.  The caller should then break the delegation and
 * retry.  Because breaking a delegation may take a long time, the
 * caller should drop the i_mutex before doing so.
 *
 * Alternatively, a caller may pass NULL for delegated_inode.  This may
 * be appropriate for callers that expect the underlying filesystem not
 * to be NFS exported.  Also, passing NULL is fine for callers holding
 * the file open for write, as there can be no conflicting delegation in
 * that case.
 */
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
Linus Torvalds's avatar
Linus Torvalds committed
226
227
{
	struct inode *inode = dentry->d_inode;
Al Viro's avatar
Al Viro committed
228
	umode_t mode = inode->i_mode;
Linus Torvalds's avatar
Linus Torvalds committed
229
	int error;
230
	struct timespec64 now;
Linus Torvalds's avatar
Linus Torvalds committed
231
232
	unsigned int ia_valid = attr->ia_valid;

Al Viro's avatar
Al Viro committed
233
	WARN_ON_ONCE(!inode_is_locked(inode));
234

235
236
237
238
239
	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
		if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
			return -EPERM;
	}

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	/*
	 * If utimes(2) and friends are called with times == NULL (or both
	 * times are UTIME_NOW), then we need to check for write permission
	 */
	if (ia_valid & ATTR_TOUCH) {
		if (IS_IMMUTABLE(inode))
			return -EPERM;

		if (!inode_owner_or_capable(inode)) {
			error = inode_permission(inode, MAY_WRITE);
			if (error)
				return error;
		}
	}

255
	if ((ia_valid & ATTR_MODE)) {
Al Viro's avatar
Al Viro committed
256
		umode_t amode = attr->ia_mode;
257
258
259
260
261
		/* Flag setting protected by i_mutex */
		if (is_sxid(amode))
			inode->i_flags &= ~S_NOSEC;
	}

262
	now = current_time(inode);
Linus Torvalds's avatar
Linus Torvalds committed
263
264
265
266
267
268

	attr->ia_ctime = now;
	if (!(ia_valid & ATTR_ATIME_SET))
		attr->ia_atime = now;
	if (!(ia_valid & ATTR_MTIME_SET))
		attr->ia_mtime = now;
269
270
	if (ia_valid & ATTR_KILL_PRIV) {
		error = security_inode_need_killpriv(dentry);
271
		if (error < 0)
272
			return error;
273
274
		if (error == 0)
			ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
275
	}
276
277
278
279
280
281
282
283
284
285
286
287

	/*
	 * We now pass ATTR_KILL_S*ID to the lower level setattr function so
	 * that the function has the ability to reinterpret a mode change
	 * that's due to these bits. This adds an implicit restriction that
	 * no function will ever call notify_change with both ATTR_MODE and
	 * ATTR_KILL_S*ID set.
	 */
	if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) &&
	    (ia_valid & ATTR_MODE))
		BUG();

Linus Torvalds's avatar
Linus Torvalds committed
288
289
	if (ia_valid & ATTR_KILL_SUID) {
		if (mode & S_ISUID) {
290
291
			ia_valid = attr->ia_valid |= ATTR_MODE;
			attr->ia_mode = (inode->i_mode & ~S_ISUID);
Linus Torvalds's avatar
Linus Torvalds committed
292
293
294
295
296
297
298
299
300
301
302
		}
	}
	if (ia_valid & ATTR_KILL_SGID) {
		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
			if (!(ia_valid & ATTR_MODE)) {
				ia_valid = attr->ia_valid |= ATTR_MODE;
				attr->ia_mode = inode->i_mode;
			}
			attr->ia_mode &= ~S_ISGID;
		}
	}
303
	if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
Linus Torvalds's avatar
Linus Torvalds committed
304
305
		return 0;

306
307
308
309
310
311
312
313
314
315
316
	/*
	 * Verify that uid/gid changes are valid in the target
	 * namespace of the superblock.
	 */
	if (ia_valid & ATTR_UID &&
	    !kuid_has_mapping(inode->i_sb->s_user_ns, attr->ia_uid))
		return -EOVERFLOW;
	if (ia_valid & ATTR_GID &&
	    !kgid_has_mapping(inode->i_sb->s_user_ns, attr->ia_gid))
		return -EOVERFLOW;

317
318
319
320
321
322
323
324
	/* Don't allow modifications of files with invalid uids or
	 * gids unless those uids & gids are being made valid.
	 */
	if (!(ia_valid & ATTR_UID) && !uid_valid(inode->i_uid))
		return -EOVERFLOW;
	if (!(ia_valid & ATTR_GID) && !gid_valid(inode->i_gid))
		return -EOVERFLOW;

325
	error = security_inode_setattr(dentry, attr);
326
327
328
	if (error)
		return error;
	error = try_break_deleg(inode, delegated_inode);
329
330
331
	if (error)
		return error;

Christoph Hellwig's avatar
Christoph Hellwig committed
332
	if (inode->i_op->setattr)
333
		error = inode->i_op->setattr(dentry, attr);
Christoph Hellwig's avatar
Christoph Hellwig committed
334
335
	else
		error = simple_setattr(dentry, attr);
Linus Torvalds's avatar
Linus Torvalds committed
336

Mimi Zohar's avatar
Mimi Zohar committed
337
	if (!error) {
Robert Love's avatar
Robert Love committed
338
		fsnotify_change(dentry, ia_valid);
Mimi Zohar's avatar
Mimi Zohar committed
339
		ima_inode_post_setattr(dentry);
Mimi Zohar's avatar
Mimi Zohar committed
340
341
		evm_inode_post_setattr(dentry, ia_valid);
	}
Robert Love's avatar
Robert Love committed
342

Linus Torvalds's avatar
Linus Torvalds committed
343
344
345
	return error;
}
EXPORT_SYMBOL(notify_change);