diff options
-rw-r--r-- | fs/open.c | 24 | ||||
-rw-r--r-- | include/linux/security.h | 30 | ||||
-rw-r--r-- | security/capability.c | 13 | ||||
-rw-r--r-- | security/security.c | 15 |
4 files changed, 78 insertions, 4 deletions
@@ -616,6 +616,9 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) | |||
616 | err = mnt_want_write_file(file); | 616 | err = mnt_want_write_file(file); |
617 | if (err) | 617 | if (err) |
618 | goto out_putf; | 618 | goto out_putf; |
619 | err = security_path_chmod(dentry, file->f_vfsmnt, mode); | ||
620 | if (err) | ||
621 | goto out_drop_write; | ||
619 | mutex_lock(&inode->i_mutex); | 622 | mutex_lock(&inode->i_mutex); |
620 | if (mode == (mode_t) -1) | 623 | if (mode == (mode_t) -1) |
621 | mode = inode->i_mode; | 624 | mode = inode->i_mode; |
@@ -623,6 +626,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) | |||
623 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 626 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
624 | err = notify_change(dentry, &newattrs); | 627 | err = notify_change(dentry, &newattrs); |
625 | mutex_unlock(&inode->i_mutex); | 628 | mutex_unlock(&inode->i_mutex); |
629 | out_drop_write: | ||
626 | mnt_drop_write(file->f_path.mnt); | 630 | mnt_drop_write(file->f_path.mnt); |
627 | out_putf: | 631 | out_putf: |
628 | fput(file); | 632 | fput(file); |
@@ -645,6 +649,9 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) | |||
645 | error = mnt_want_write(path.mnt); | 649 | error = mnt_want_write(path.mnt); |
646 | if (error) | 650 | if (error) |
647 | goto dput_and_out; | 651 | goto dput_and_out; |
652 | error = security_path_chmod(path.dentry, path.mnt, mode); | ||
653 | if (error) | ||
654 | goto out_drop_write; | ||
648 | mutex_lock(&inode->i_mutex); | 655 | mutex_lock(&inode->i_mutex); |
649 | if (mode == (mode_t) -1) | 656 | if (mode == (mode_t) -1) |
650 | mode = inode->i_mode; | 657 | mode = inode->i_mode; |
@@ -652,6 +659,7 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) | |||
652 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 659 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
653 | error = notify_change(path.dentry, &newattrs); | 660 | error = notify_change(path.dentry, &newattrs); |
654 | mutex_unlock(&inode->i_mutex); | 661 | mutex_unlock(&inode->i_mutex); |
662 | out_drop_write: | ||
655 | mnt_drop_write(path.mnt); | 663 | mnt_drop_write(path.mnt); |
656 | dput_and_out: | 664 | dput_and_out: |
657 | path_put(&path); | 665 | path_put(&path); |
@@ -700,7 +708,9 @@ SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) | |||
700 | error = mnt_want_write(path.mnt); | 708 | error = mnt_want_write(path.mnt); |
701 | if (error) | 709 | if (error) |
702 | goto out_release; | 710 | goto out_release; |
703 | error = chown_common(path.dentry, user, group); | 711 | error = security_path_chown(&path, user, group); |
712 | if (!error) | ||
713 | error = chown_common(path.dentry, user, group); | ||
704 | mnt_drop_write(path.mnt); | 714 | mnt_drop_write(path.mnt); |
705 | out_release: | 715 | out_release: |
706 | path_put(&path); | 716 | path_put(&path); |
@@ -725,7 +735,9 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, | |||
725 | error = mnt_want_write(path.mnt); | 735 | error = mnt_want_write(path.mnt); |
726 | if (error) | 736 | if (error) |
727 | goto out_release; | 737 | goto out_release; |
728 | error = chown_common(path.dentry, user, group); | 738 | error = security_path_chown(&path, user, group); |
739 | if (!error) | ||
740 | error = chown_common(path.dentry, user, group); | ||
729 | mnt_drop_write(path.mnt); | 741 | mnt_drop_write(path.mnt); |
730 | out_release: | 742 | out_release: |
731 | path_put(&path); | 743 | path_put(&path); |
@@ -744,7 +756,9 @@ SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group | |||
744 | error = mnt_want_write(path.mnt); | 756 | error = mnt_want_write(path.mnt); |
745 | if (error) | 757 | if (error) |
746 | goto out_release; | 758 | goto out_release; |
747 | error = chown_common(path.dentry, user, group); | 759 | error = security_path_chown(&path, user, group); |
760 | if (!error) | ||
761 | error = chown_common(path.dentry, user, group); | ||
748 | mnt_drop_write(path.mnt); | 762 | mnt_drop_write(path.mnt); |
749 | out_release: | 763 | out_release: |
750 | path_put(&path); | 764 | path_put(&path); |
@@ -767,7 +781,9 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) | |||
767 | goto out_fput; | 781 | goto out_fput; |
768 | dentry = file->f_path.dentry; | 782 | dentry = file->f_path.dentry; |
769 | audit_inode(NULL, dentry); | 783 | audit_inode(NULL, dentry); |
770 | error = chown_common(dentry, user, group); | 784 | error = security_path_chown(&file->f_path, user, group); |
785 | if (!error) | ||
786 | error = chown_common(dentry, user, group); | ||
771 | mnt_drop_write(file->f_path.mnt); | 787 | mnt_drop_write(file->f_path.mnt); |
772 | out_fput: | 788 | out_fput: |
773 | fput(file); | 789 | fput(file); |
diff --git a/include/linux/security.h b/include/linux/security.h index 239e40d0450b..c8a584c26f7b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -447,6 +447,18 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
447 | * @new_dir contains the path structure for parent of the new link. | 447 | * @new_dir contains the path structure for parent of the new link. |
448 | * @new_dentry contains the dentry structure of the new link. | 448 | * @new_dentry contains the dentry structure of the new link. |
449 | * Return 0 if permission is granted. | 449 | * Return 0 if permission is granted. |
450 | * @path_chmod: | ||
451 | * Check for permission to change DAC's permission of a file or directory. | ||
452 | * @dentry contains the dentry structure. | ||
453 | * @mnt contains the vfsmnt structure. | ||
454 | * @mode contains DAC's mode. | ||
455 | * Return 0 if permission is granted. | ||
456 | * @path_chown: | ||
457 | * Check for permission to change owner/group of a file or directory. | ||
458 | * @path contains the path structure. | ||
459 | * @uid contains new owner's ID. | ||
460 | * @gid contains new group's ID. | ||
461 | * Return 0 if permission is granted. | ||
450 | * @inode_readlink: | 462 | * @inode_readlink: |
451 | * Check the permission to read the symbolic link. | 463 | * Check the permission to read the symbolic link. |
452 | * @dentry contains the dentry structure for the file link. | 464 | * @dentry contains the dentry structure for the file link. |
@@ -1488,6 +1500,9 @@ struct security_operations { | |||
1488 | struct dentry *new_dentry); | 1500 | struct dentry *new_dentry); |
1489 | int (*path_rename) (struct path *old_dir, struct dentry *old_dentry, | 1501 | int (*path_rename) (struct path *old_dir, struct dentry *old_dentry, |
1490 | struct path *new_dir, struct dentry *new_dentry); | 1502 | struct path *new_dir, struct dentry *new_dentry); |
1503 | int (*path_chmod) (struct dentry *dentry, struct vfsmount *mnt, | ||
1504 | mode_t mode); | ||
1505 | int (*path_chown) (struct path *path, uid_t uid, gid_t gid); | ||
1491 | #endif | 1506 | #endif |
1492 | 1507 | ||
1493 | int (*inode_alloc_security) (struct inode *inode); | 1508 | int (*inode_alloc_security) (struct inode *inode); |
@@ -2952,6 +2967,9 @@ int security_path_link(struct dentry *old_dentry, struct path *new_dir, | |||
2952 | struct dentry *new_dentry); | 2967 | struct dentry *new_dentry); |
2953 | int security_path_rename(struct path *old_dir, struct dentry *old_dentry, | 2968 | int security_path_rename(struct path *old_dir, struct dentry *old_dentry, |
2954 | struct path *new_dir, struct dentry *new_dentry); | 2969 | struct path *new_dir, struct dentry *new_dentry); |
2970 | int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | ||
2971 | mode_t mode); | ||
2972 | int security_path_chown(struct path *path, uid_t uid, gid_t gid); | ||
2955 | #else /* CONFIG_SECURITY_PATH */ | 2973 | #else /* CONFIG_SECURITY_PATH */ |
2956 | static inline int security_path_unlink(struct path *dir, struct dentry *dentry) | 2974 | static inline int security_path_unlink(struct path *dir, struct dentry *dentry) |
2957 | { | 2975 | { |
@@ -3001,6 +3019,18 @@ static inline int security_path_rename(struct path *old_dir, | |||
3001 | { | 3019 | { |
3002 | return 0; | 3020 | return 0; |
3003 | } | 3021 | } |
3022 | |||
3023 | static inline int security_path_chmod(struct dentry *dentry, | ||
3024 | struct vfsmount *mnt, | ||
3025 | mode_t mode) | ||
3026 | { | ||
3027 | return 0; | ||
3028 | } | ||
3029 | |||
3030 | static inline int security_path_chown(struct path *path, uid_t uid, gid_t gid) | ||
3031 | { | ||
3032 | return 0; | ||
3033 | } | ||
3004 | #endif /* CONFIG_SECURITY_PATH */ | 3034 | #endif /* CONFIG_SECURITY_PATH */ |
3005 | 3035 | ||
3006 | #ifdef CONFIG_KEYS | 3036 | #ifdef CONFIG_KEYS |
diff --git a/security/capability.c b/security/capability.c index fce07a7bc825..09279a8d4a14 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -308,6 +308,17 @@ static int cap_path_truncate(struct path *path, loff_t length, | |||
308 | { | 308 | { |
309 | return 0; | 309 | return 0; |
310 | } | 310 | } |
311 | |||
312 | static int cap_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | ||
313 | mode_t mode) | ||
314 | { | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int cap_path_chown(struct path *path, uid_t uid, gid_t gid) | ||
319 | { | ||
320 | return 0; | ||
321 | } | ||
311 | #endif | 322 | #endif |
312 | 323 | ||
313 | static int cap_file_permission(struct file *file, int mask) | 324 | static int cap_file_permission(struct file *file, int mask) |
@@ -977,6 +988,8 @@ void security_fixup_ops(struct security_operations *ops) | |||
977 | set_to_cap_if_null(ops, path_link); | 988 | set_to_cap_if_null(ops, path_link); |
978 | set_to_cap_if_null(ops, path_rename); | 989 | set_to_cap_if_null(ops, path_rename); |
979 | set_to_cap_if_null(ops, path_truncate); | 990 | set_to_cap_if_null(ops, path_truncate); |
991 | set_to_cap_if_null(ops, path_chmod); | ||
992 | set_to_cap_if_null(ops, path_chown); | ||
980 | #endif | 993 | #endif |
981 | set_to_cap_if_null(ops, file_permission); | 994 | set_to_cap_if_null(ops, file_permission); |
982 | set_to_cap_if_null(ops, file_alloc_security); | 995 | set_to_cap_if_null(ops, file_alloc_security); |
diff --git a/security/security.c b/security/security.c index c4c673240c1c..5259270e558f 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -434,6 +434,21 @@ int security_path_truncate(struct path *path, loff_t length, | |||
434 | return 0; | 434 | return 0; |
435 | return security_ops->path_truncate(path, length, time_attrs); | 435 | return security_ops->path_truncate(path, length, time_attrs); |
436 | } | 436 | } |
437 | |||
438 | int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt, | ||
439 | mode_t mode) | ||
440 | { | ||
441 | if (unlikely(IS_PRIVATE(dentry->d_inode))) | ||
442 | return 0; | ||
443 | return security_ops->path_chmod(dentry, mnt, mode); | ||
444 | } | ||
445 | |||
446 | int security_path_chown(struct path *path, uid_t uid, gid_t gid) | ||
447 | { | ||
448 | if (unlikely(IS_PRIVATE(path->dentry->d_inode))) | ||
449 | return 0; | ||
450 | return security_ops->path_chown(path, uid, gid); | ||
451 | } | ||
437 | #endif | 452 | #endif |
438 | 453 | ||
439 | int security_inode_create(struct inode *dir, struct dentry *dentry, int mode) | 454 | int security_inode_create(struct inode *dir, struct dentry *dentry, int mode) |