diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 78 |
1 files changed, 28 insertions, 50 deletions
@@ -446,74 +446,52 @@ out: | |||
446 | return error; | 446 | return error; |
447 | } | 447 | } |
448 | 448 | ||
449 | SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) | 449 | static int chmod_common(struct path *path, umode_t mode) |
450 | { | 450 | { |
451 | struct inode * inode; | 451 | struct inode *inode = path->dentry->d_inode; |
452 | struct dentry * dentry; | ||
453 | struct file * file; | ||
454 | int err = -EBADF; | ||
455 | struct iattr newattrs; | 452 | struct iattr newattrs; |
453 | int error; | ||
456 | 454 | ||
457 | file = fget(fd); | 455 | error = mnt_want_write(path->mnt); |
458 | if (!file) | 456 | if (error) |
459 | goto out; | 457 | return error; |
460 | |||
461 | dentry = file->f_path.dentry; | ||
462 | inode = dentry->d_inode; | ||
463 | |||
464 | audit_inode(NULL, dentry); | ||
465 | |||
466 | err = mnt_want_write_file(file); | ||
467 | if (err) | ||
468 | goto out_putf; | ||
469 | mutex_lock(&inode->i_mutex); | 458 | mutex_lock(&inode->i_mutex); |
470 | err = security_path_chmod(dentry, file->f_vfsmnt, mode); | 459 | error = security_path_chmod(path->dentry, path->mnt, mode); |
471 | if (err) | 460 | if (error) |
472 | goto out_unlock; | 461 | goto out_unlock; |
473 | if (mode == (mode_t) -1) | ||
474 | mode = inode->i_mode; | ||
475 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 462 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); |
476 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 463 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
477 | err = notify_change(dentry, &newattrs); | 464 | error = notify_change(path->dentry, &newattrs); |
478 | out_unlock: | 465 | out_unlock: |
479 | mutex_unlock(&inode->i_mutex); | 466 | mutex_unlock(&inode->i_mutex); |
480 | mnt_drop_write(file->f_path.mnt); | 467 | mnt_drop_write(path->mnt); |
481 | out_putf: | 468 | return error; |
482 | fput(file); | 469 | } |
483 | out: | 470 | |
471 | SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) | ||
472 | { | ||
473 | struct file * file; | ||
474 | int err = -EBADF; | ||
475 | |||
476 | file = fget(fd); | ||
477 | if (file) { | ||
478 | audit_inode(NULL, file->f_path.dentry); | ||
479 | err = chmod_common(&file->f_path, mode); | ||
480 | fput(file); | ||
481 | } | ||
484 | return err; | 482 | return err; |
485 | } | 483 | } |
486 | 484 | ||
487 | SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) | 485 | SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) |
488 | { | 486 | { |
489 | struct path path; | 487 | struct path path; |
490 | struct inode *inode; | ||
491 | int error; | 488 | int error; |
492 | struct iattr newattrs; | ||
493 | 489 | ||
494 | error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); | 490 | error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); |
495 | if (error) | 491 | if (!error) { |
496 | goto out; | 492 | error = chmod_common(&path, mode); |
497 | inode = path.dentry->d_inode; | 493 | path_put(&path); |
498 | 494 | } | |
499 | error = mnt_want_write(path.mnt); | ||
500 | if (error) | ||
501 | goto dput_and_out; | ||
502 | mutex_lock(&inode->i_mutex); | ||
503 | error = security_path_chmod(path.dentry, path.mnt, mode); | ||
504 | if (error) | ||
505 | goto out_unlock; | ||
506 | if (mode == (mode_t) -1) | ||
507 | mode = inode->i_mode; | ||
508 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | ||
509 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
510 | error = notify_change(path.dentry, &newattrs); | ||
511 | out_unlock: | ||
512 | mutex_unlock(&inode->i_mutex); | ||
513 | mnt_drop_write(path.mnt); | ||
514 | dput_and_out: | ||
515 | path_put(&path); | ||
516 | out: | ||
517 | return error; | 495 | return error; |
518 | } | 496 | } |
519 | 497 | ||