aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/open.c24
-rw-r--r--include/linux/security.h30
-rw-r--r--security/capability.c13
-rw-r--r--security/security.c15
4 files changed, 78 insertions, 4 deletions
diff --git a/fs/open.c b/fs/open.c
index 4f01e06227c6..b5c294d35bd1 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -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);
629out_drop_write:
626 mnt_drop_write(file->f_path.mnt); 630 mnt_drop_write(file->f_path.mnt);
627out_putf: 631out_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);
662out_drop_write:
655 mnt_drop_write(path.mnt); 663 mnt_drop_write(path.mnt);
656dput_and_out: 664dput_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);
705out_release: 715out_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);
730out_release: 742out_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);
749out_release: 763out_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);
772out_fput: 788out_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);
2953int security_path_rename(struct path *old_dir, struct dentry *old_dentry, 2968int 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);
2970int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
2971 mode_t mode);
2972int security_path_chown(struct path *path, uid_t uid, gid_t gid);
2955#else /* CONFIG_SECURITY_PATH */ 2973#else /* CONFIG_SECURITY_PATH */
2956static inline int security_path_unlink(struct path *dir, struct dentry *dentry) 2974static 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
3023static inline int security_path_chmod(struct dentry *dentry,
3024 struct vfsmount *mnt,
3025 mode_t mode)
3026{
3027 return 0;
3028}
3029
3030static 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
312static int cap_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
313 mode_t mode)
314{
315 return 0;
316}
317
318static int cap_path_chown(struct path *path, uid_t uid, gid_t gid)
319{
320 return 0;
321}
311#endif 322#endif
312 323
313static int cap_file_permission(struct file *file, int mask) 324static 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
438int 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
446int 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
439int security_inode_create(struct inode *dir, struct dentry *dentry, int mode) 454int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)