aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c149
1 files changed, 36 insertions, 113 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 4547608b46c4..f07bf8768c3a 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -70,7 +70,6 @@ xfs_setattr(
70 gid_t gid=0, igid=0; 70 gid_t gid=0, igid=0;
71 int timeflags = 0; 71 int timeflags = 0;
72 struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; 72 struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
73 int file_owner;
74 int need_iolock = 1; 73 int need_iolock = 1;
75 74
76 xfs_itrace_entry(ip); 75 xfs_itrace_entry(ip);
@@ -81,6 +80,10 @@ xfs_setattr(
81 if (XFS_FORCED_SHUTDOWN(mp)) 80 if (XFS_FORCED_SHUTDOWN(mp))
82 return XFS_ERROR(EIO); 81 return XFS_ERROR(EIO);
83 82
83 code = -inode_change_ok(inode, iattr);
84 if (code)
85 return code;
86
84 olddquot1 = olddquot2 = NULL; 87 olddquot1 = olddquot2 = NULL;
85 udqp = gdqp = NULL; 88 udqp = gdqp = NULL;
86 89
@@ -158,56 +161,6 @@ xfs_setattr(
158 161
159 xfs_ilock(ip, lock_flags); 162 xfs_ilock(ip, lock_flags);
160 163
161 /* boolean: are we the file owner? */
162 file_owner = (current_fsuid() == ip->i_d.di_uid);
163
164 /*
165 * Change various properties of a file.
166 * Only the owner or users with CAP_FOWNER
167 * capability may do these things.
168 */
169 if (mask & (ATTR_MODE|ATTR_UID|ATTR_GID)) {
170 /*
171 * CAP_FOWNER overrides the following restrictions:
172 *
173 * The user ID of the calling process must be equal
174 * to the file owner ID, except in cases where the
175 * CAP_FSETID capability is applicable.
176 */
177 if (!file_owner && !capable(CAP_FOWNER)) {
178 code = XFS_ERROR(EPERM);
179 goto error_return;
180 }
181
182 /*
183 * CAP_FSETID overrides the following restrictions:
184 *
185 * The effective user ID of the calling process shall match
186 * the file owner when setting the set-user-ID and
187 * set-group-ID bits on that file.
188 *
189 * The effective group ID or one of the supplementary group
190 * IDs of the calling process shall match the group owner of
191 * the file when setting the set-group-ID bit on that file
192 */
193 if (mask & ATTR_MODE) {
194 mode_t m = 0;
195
196 if ((iattr->ia_mode & S_ISUID) && !file_owner)
197 m |= S_ISUID;
198 if ((iattr->ia_mode & S_ISGID) &&
199 !in_group_p((gid_t)ip->i_d.di_gid))
200 m |= S_ISGID;
201#if 0
202 /* Linux allows this, Irix doesn't. */
203 if ((iattr->ia_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode))
204 m |= S_ISVTX;
205#endif
206 if (m && !capable(CAP_FSETID))
207 iattr->ia_mode &= ~m;
208 }
209 }
210
211 /* 164 /*
212 * Change file ownership. Must be the owner or privileged. 165 * Change file ownership. Must be the owner or privileged.
213 */ 166 */
@@ -224,22 +177,6 @@ xfs_setattr(
224 uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; 177 uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid;
225 178
226 /* 179 /*
227 * CAP_CHOWN overrides the following restrictions:
228 *
229 * If _POSIX_CHOWN_RESTRICTED is defined, this capability
230 * shall override the restriction that a process cannot
231 * change the user ID of a file it owns and the restriction
232 * that the group ID supplied to the chown() function
233 * shall be equal to either the group ID or one of the
234 * supplementary group IDs of the calling process.
235 */
236 if ((iuid != uid ||
237 (igid != gid && !in_group_p((gid_t)gid))) &&
238 !capable(CAP_CHOWN)) {
239 code = XFS_ERROR(EPERM);
240 goto error_return;
241 }
242 /*
243 * Do a quota reservation only if uid/gid is actually 180 * Do a quota reservation only if uid/gid is actually
244 * going to change. 181 * going to change.
245 */ 182 */
@@ -276,36 +213,22 @@ xfs_setattr(
276 code = XFS_ERROR(EINVAL); 213 code = XFS_ERROR(EINVAL);
277 goto error_return; 214 goto error_return;
278 } 215 }
216
279 /* 217 /*
280 * Make sure that the dquots are attached to the inode. 218 * Make sure that the dquots are attached to the inode.
281 */ 219 */
282 if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED))) 220 code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
221 if (code)
283 goto error_return; 222 goto error_return;
284 }
285 223
286 /* 224 /*
287 * Change file access or modified times. 225 * Now we can make the changes. Before we join the inode
288 */ 226 * to the transaction, if ATTR_SIZE is set then take care of
289 if (mask & (ATTR_ATIME|ATTR_MTIME)) { 227 * the part of the truncation that must be done without the
290 if (!file_owner) { 228 * inode lock. This needs to be done before joining the inode
291 if ((mask & (ATTR_MTIME_SET|ATTR_ATIME_SET)) && 229 * to the transaction, because the inode cannot be unlocked
292 !capable(CAP_FOWNER)) { 230 * once it is a part of the transaction.
293 code = XFS_ERROR(EPERM); 231 */
294 goto error_return;
295 }
296 }
297 }
298
299 /*
300 * Now we can make the changes. Before we join the inode
301 * to the transaction, if ATTR_SIZE is set then take care of
302 * the part of the truncation that must be done without the
303 * inode lock. This needs to be done before joining the inode
304 * to the transaction, because the inode cannot be unlocked
305 * once it is a part of the transaction.
306 */
307 if (mask & ATTR_SIZE) {
308 code = 0;
309 if (iattr->ia_size > ip->i_size) { 232 if (iattr->ia_size > ip->i_size) {
310 /* 233 /*
311 * Do the first part of growing a file: zero any data 234 * Do the first part of growing a file: zero any data
@@ -360,17 +283,10 @@ xfs_setattr(
360 } 283 }
361 commit_flags = XFS_TRANS_RELEASE_LOG_RES; 284 commit_flags = XFS_TRANS_RELEASE_LOG_RES;
362 xfs_ilock(ip, XFS_ILOCK_EXCL); 285 xfs_ilock(ip, XFS_ILOCK_EXCL);
363 }
364 286
365 if (tp) {
366 xfs_trans_ijoin(tp, ip, lock_flags); 287 xfs_trans_ijoin(tp, ip, lock_flags);
367 xfs_trans_ihold(tp, ip); 288 xfs_trans_ihold(tp, ip);
368 }
369 289
370 /*
371 * Truncate file. Must have write permission and not be a directory.
372 */
373 if (mask & ATTR_SIZE) {
374 /* 290 /*
375 * Only change the c/mtime if we are changing the size 291 * Only change the c/mtime if we are changing the size
376 * or we are explicitly asked to change it. This handles 292 * or we are explicitly asked to change it. This handles
@@ -410,20 +326,9 @@ xfs_setattr(
410 */ 326 */
411 xfs_iflags_set(ip, XFS_ITRUNCATED); 327 xfs_iflags_set(ip, XFS_ITRUNCATED);
412 } 328 }
413 } 329 } else if (tp) {
414 330 xfs_trans_ijoin(tp, ip, lock_flags);
415 /* 331 xfs_trans_ihold(tp, ip);
416 * Change file access modes.
417 */
418 if (mask & ATTR_MODE) {
419 ip->i_d.di_mode &= S_IFMT;
420 ip->i_d.di_mode |= iattr->ia_mode & ~S_IFMT;
421
422 inode->i_mode &= S_IFMT;
423 inode->i_mode |= iattr->ia_mode & ~S_IFMT;
424
425 xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
426 timeflags |= XFS_ICHGTIME_CHG;
427 } 332 }
428 333
429 /* 334 /*
@@ -471,6 +376,24 @@ xfs_setattr(
471 timeflags |= XFS_ICHGTIME_CHG; 376 timeflags |= XFS_ICHGTIME_CHG;
472 } 377 }
473 378
379 /*
380 * Change file access modes.
381 */
382 if (mask & ATTR_MODE) {
383 umode_t mode = iattr->ia_mode;
384
385 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
386 mode &= ~S_ISGID;
387
388 ip->i_d.di_mode &= S_IFMT;
389 ip->i_d.di_mode |= mode & ~S_IFMT;
390
391 inode->i_mode &= S_IFMT;
392 inode->i_mode |= mode & ~S_IFMT;
393
394 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
395 timeflags |= XFS_ICHGTIME_CHG;
396 }
474 397
475 /* 398 /*
476 * Change file access or modified times. 399 * Change file access or modified times.