aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2008-12-09 04:47:34 -0500
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2008-12-10 21:15:10 -0500
commitc4cd747ee6c3ba1e7727878e3fce482d0d8c0136 (patch)
tree2232d0b923fdd2095abed5cfa4ea8b7222026b74 /fs/xfs/xfs_vnodeops.c
parent4d4be482a4d78ca906f45e99fd9fdb91e907f5ad (diff)
[XFS] use inode_change_ok for setattr permission checking
Instead of implementing our own checks use inode_change_ok to check for necessary permission in setattr. There is a slight change in behaviour as inode_change_ok doesn't allow i_mode updates to add the suid or sgid without superuser privilegues while the old XFS code just stripped away those bits from the file mode. (First sent on Semptember 29th) Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
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.