diff options
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 149 |
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. |