aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/sysctl/fs.txt42
-rw-r--r--fs/namei.c122
-rw-r--r--include/linux/fs.h2
-rw-r--r--kernel/sysctl.c18
4 files changed, 184 insertions, 0 deletions
diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
index 13d6166d7a27..d4a372e75750 100644
--- a/Documentation/sysctl/fs.txt
+++ b/Documentation/sysctl/fs.txt
@@ -32,6 +32,8 @@ Currently, these files are in /proc/sys/fs:
32- nr_open 32- nr_open
33- overflowuid 33- overflowuid
34- overflowgid 34- overflowgid
35- protected_hardlinks
36- protected_symlinks
35- suid_dumpable 37- suid_dumpable
36- super-max 38- super-max
37- super-nr 39- super-nr
@@ -157,6 +159,46 @@ The default is 65534.
157 159
158============================================================== 160==============================================================
159 161
162protected_hardlinks:
163
164A long-standing class of security issues is the hardlink-based
165time-of-check-time-of-use race, most commonly seen in world-writable
166directories like /tmp. The common method of exploitation of this flaw
167is to cross privilege boundaries when following a given hardlink (i.e. a
168root process follows a hardlink created by another user). Additionally,
169on systems without separated partitions, this stops unauthorized users
170from "pinning" vulnerable setuid/setgid files against being upgraded by
171the administrator, or linking to special files.
172
173When set to "0", hardlink creation behavior is unrestricted.
174
175When set to "1" hardlinks cannot be created by users if they do not
176already own the source file, or do not have read/write access to it.
177
178This protection is based on the restrictions in Openwall and grsecurity.
179
180==============================================================
181
182protected_symlinks:
183
184A long-standing class of security issues is the symlink-based
185time-of-check-time-of-use race, most commonly seen in world-writable
186directories like /tmp. The common method of exploitation of this flaw
187is to cross privilege boundaries when following a given symlink (i.e. a
188root process follows a symlink belonging to another user). For a likely
189incomplete list of hundreds of examples across the years, please see:
190http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=/tmp
191
192When set to "0", symlink following behavior is unrestricted.
193
194When set to "1" symlinks are permitted to be followed only when outside
195a sticky world-writable directory, or when the uid of the symlink and
196follower match, or when the directory owner matches the symlink's owner.
197
198This protection is based on the restrictions in Openwall and grsecurity.
199
200==============================================================
201
160suid_dumpable: 202suid_dumpable:
161 203
162This value can be used to query and set the core dump mode for setuid 204This value can be used to query and set the core dump mode for setuid
diff --git a/fs/namei.c b/fs/namei.c
index afa087649ddb..3861d85f8488 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -650,6 +650,119 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
650 path_put(link); 650 path_put(link);
651} 651}
652 652
653int sysctl_protected_symlinks __read_mostly = 1;
654int sysctl_protected_hardlinks __read_mostly = 1;
655
656/**
657 * may_follow_link - Check symlink following for unsafe situations
658 * @link: The path of the symlink
659 *
660 * In the case of the sysctl_protected_symlinks sysctl being enabled,
661 * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is
662 * in a sticky world-writable directory. This is to protect privileged
663 * processes from failing races against path names that may change out
664 * from under them by way of other users creating malicious symlinks.
665 * It will permit symlinks to be followed only when outside a sticky
666 * world-writable directory, or when the uid of the symlink and follower
667 * match, or when the directory owner matches the symlink's owner.
668 *
669 * Returns 0 if following the symlink is allowed, -ve on error.
670 */
671static inline int may_follow_link(struct path *link, struct nameidata *nd)
672{
673 const struct inode *inode;
674 const struct inode *parent;
675
676 if (!sysctl_protected_symlinks)
677 return 0;
678
679 /* Allowed if owner and follower match. */
680 inode = link->dentry->d_inode;
681 if (current_cred()->fsuid == inode->i_uid)
682 return 0;
683
684 /* Allowed if parent directory not sticky and world-writable. */
685 parent = nd->path.dentry->d_inode;
686 if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH))
687 return 0;
688
689 /* Allowed if parent directory and link owner match. */
690 if (parent->i_uid == inode->i_uid)
691 return 0;
692
693 path_put_conditional(link, nd);
694 path_put(&nd->path);
695 return -EACCES;
696}
697
698/**
699 * safe_hardlink_source - Check for safe hardlink conditions
700 * @inode: the source inode to hardlink from
701 *
702 * Return false if at least one of the following conditions:
703 * - inode is not a regular file
704 * - inode is setuid
705 * - inode is setgid and group-exec
706 * - access failure for read and write
707 *
708 * Otherwise returns true.
709 */
710static bool safe_hardlink_source(struct inode *inode)
711{
712 umode_t mode = inode->i_mode;
713
714 /* Special files should not get pinned to the filesystem. */
715 if (!S_ISREG(mode))
716 return false;
717
718 /* Setuid files should not get pinned to the filesystem. */
719 if (mode & S_ISUID)
720 return false;
721
722 /* Executable setgid files should not get pinned to the filesystem. */
723 if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
724 return false;
725
726 /* Hardlinking to unreadable or unwritable sources is dangerous. */
727 if (inode_permission(inode, MAY_READ | MAY_WRITE))
728 return false;
729
730 return true;
731}
732
733/**
734 * may_linkat - Check permissions for creating a hardlink
735 * @link: the source to hardlink from
736 *
737 * Block hardlink when all of:
738 * - sysctl_protected_hardlinks enabled
739 * - fsuid does not match inode
740 * - hardlink source is unsafe (see safe_hardlink_source() above)
741 * - not CAP_FOWNER
742 *
743 * Returns 0 if successful, -ve on error.
744 */
745static int may_linkat(struct path *link)
746{
747 const struct cred *cred;
748 struct inode *inode;
749
750 if (!sysctl_protected_hardlinks)
751 return 0;
752
753 cred = current_cred();
754 inode = link->dentry->d_inode;
755
756 /* Source inode owner (or CAP_FOWNER) can hardlink all they like,
757 * otherwise, it must be a safe source.
758 */
759 if (cred->fsuid == inode->i_uid || safe_hardlink_source(inode) ||
760 capable(CAP_FOWNER))
761 return 0;
762
763 return -EPERM;
764}
765
653static __always_inline int 766static __always_inline int
654follow_link(struct path *link, struct nameidata *nd, void **p) 767follow_link(struct path *link, struct nameidata *nd, void **p)
655{ 768{
@@ -1818,6 +1931,9 @@ static int path_lookupat(int dfd, const char *name,
1818 while (err > 0) { 1931 while (err > 0) {
1819 void *cookie; 1932 void *cookie;
1820 struct path link = path; 1933 struct path link = path;
1934 err = may_follow_link(&link, nd);
1935 if (unlikely(err))
1936 break;
1821 nd->flags |= LOOKUP_PARENT; 1937 nd->flags |= LOOKUP_PARENT;
1822 err = follow_link(&link, nd, &cookie); 1938 err = follow_link(&link, nd, &cookie);
1823 if (err) 1939 if (err)
@@ -2778,6 +2894,9 @@ static struct file *path_openat(int dfd, const char *pathname,
2778 error = -ELOOP; 2894 error = -ELOOP;
2779 break; 2895 break;
2780 } 2896 }
2897 error = may_follow_link(&link, nd);
2898 if (unlikely(error))
2899 break;
2781 nd->flags |= LOOKUP_PARENT; 2900 nd->flags |= LOOKUP_PARENT;
2782 nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); 2901 nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
2783 error = follow_link(&link, nd, &cookie); 2902 error = follow_link(&link, nd, &cookie);
@@ -3421,6 +3540,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
3421 error = -EXDEV; 3540 error = -EXDEV;
3422 if (old_path.mnt != new_path.mnt) 3541 if (old_path.mnt != new_path.mnt)
3423 goto out_dput; 3542 goto out_dput;
3543 error = may_linkat(&old_path);
3544 if (unlikely(error))
3545 goto out_dput;
3424 error = security_path_link(old_path.dentry, &new_path, new_dentry); 3546 error = security_path_link(old_path.dentry, &new_path, new_dentry);
3425 if (error) 3547 if (error)
3426 goto out_dput; 3548 goto out_dput;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 478237844648..80c819cbe272 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -437,6 +437,8 @@ extern unsigned long get_max_files(void);
437extern int sysctl_nr_open; 437extern int sysctl_nr_open;
438extern struct inodes_stat_t inodes_stat; 438extern struct inodes_stat_t inodes_stat;
439extern int leases_enable, lease_break_time; 439extern int leases_enable, lease_break_time;
440extern int sysctl_protected_symlinks;
441extern int sysctl_protected_hardlinks;
440 442
441struct buffer_head; 443struct buffer_head;
442typedef int (get_block_t)(struct inode *inode, sector_t iblock, 444typedef int (get_block_t)(struct inode *inode, sector_t iblock,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 4ab11879aeb4..5d9a1d2b27b4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1494,6 +1494,24 @@ static struct ctl_table fs_table[] = {
1494#endif 1494#endif
1495#endif 1495#endif
1496 { 1496 {
1497 .procname = "protected_symlinks",
1498 .data = &sysctl_protected_symlinks,
1499 .maxlen = sizeof(int),
1500 .mode = 0600,
1501 .proc_handler = proc_dointvec_minmax,
1502 .extra1 = &zero,
1503 .extra2 = &one,
1504 },
1505 {
1506 .procname = "protected_hardlinks",
1507 .data = &sysctl_protected_hardlinks,
1508 .maxlen = sizeof(int),
1509 .mode = 0600,
1510 .proc_handler = proc_dointvec_minmax,
1511 .extra1 = &zero,
1512 .extra2 = &one,
1513 },
1514 {
1497 .procname = "suid_dumpable", 1515 .procname = "suid_dumpable",
1498 .data = &suid_dumpable, 1516 .data = &suid_dumpable,
1499 .maxlen = sizeof(int), 1517 .maxlen = sizeof(int),