3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 // secure-mount <secure-base> <src> <dst>
21 // mounts <src> into the chroot <secure-base> at destination <dst> in a way
22 // that prevents symlink attacks
29 #define VERSION_COPYRIGHT_YEAR "2003"
30 #define VERSION_COPYRIGHT_AUTHOR "Enrico Scholz"
40 #include <sys/mount.h>
42 #include <sys/types.h>
45 #define MNTPOINT "/etc"
48 showHelp(int fd, char const *cmd, int res)
50 WRITE_MSG(fd, "Usage: ");
53 " <secure-base> <src> <dst>\n\n"
54 "Mounts <src> to <secure-base>/<dst> and assumes <secure-base>\n"
55 "as trustworthy but <dst> as hostile. Therefore, <dst> will be\n"
56 "traversed in a secure way and must not contain symlinks.\n\n"
57 "Please report bugs to " PACKAGE_BUGREPORT "\n");
66 "secure-mount " VERSION " -- secure mounting of directories\n"
67 "This program is part of " PACKAGE_STRING "\n"
68 "Copyright (C) 2003 Enrico Scholz\n"
69 VERSION_COPYRIGHT_DISCLAIMER);
74 isSameObject(struct stat const *lhs,
75 struct stat const *rhs)
77 return (lhs->st_dev==rhs->st_dev &&
78 lhs->st_ino==rhs->st_ino);
82 chdirSecure(char const *dir)
84 char tmp[strlen(dir)+1], *ptr;
88 cur = strtok_r(tmp, "/", &ptr);
90 struct stat pre_stat, post_stat;
92 if (lstat(cur, &pre_stat)==-1) return -1;
94 if (!S_ISDIR(pre_stat.st_mode)) {
98 if (S_ISLNK(pre_stat.st_mode)) {
103 if (chdir(cur)==-1) return -1;
104 if (stat(".", &post_stat)==-1) return -1;
106 if (!isSameObject(&pre_stat, &post_stat)) {
109 WRITE_MSG(2, "Possible symlink race ATTACK at '");
110 WRITE_STR(2, getcwd(dir, sizeof(dir)));
117 cur = strtok_r(0, "/", &ptr);
124 verifyPosition(char const *mntpoint, char const *dir1, char const *dir2)
126 struct stat pre_stat, post_stat;
128 if (stat(mntpoint, &pre_stat)==-1) return -1;
129 if (chroot(dir1)==-1 || chdir(dir2)==-1) return -1;
130 if (stat(".", &post_stat)==-1) return -1;
132 if (!isSameObject(&pre_stat, &post_stat)) {
135 WRITE_MSG(2, "Possible symlink race ATTACK at '");
136 WRITE_STR(2, getcwd(dir, sizeof(dir)));
137 WRITE_MSG(2, "' within '");
148 int main(int argc, char *argv[])
151 if (!strcmp(argv[1], "--help")) showHelp(1, argv[0], 0);
152 if (!strcmp(argv[1], "--version")) showVersion();
155 WRITE_MSG(2, "Bad parameter count; use --help for further information.\n");
159 if (chdir(argv[1])==-1) {
164 if (chdirSecure(argv[3])==-1) {
165 perror("chdirSecure()");
169 if (mount(argv[2], ".", "", MS_BIND, 0)==-1) {
174 // Check if directories were moved between the chdirSecure() and mount(2)
175 if (verifyPosition(argv[2], argv[1], argv[3])==-1) {
176 // TODO: what is with unmounting?