$NetBSD: patch-ab,v 1.1.1.1 2004/11/19 18:07:42 daprice Exp $ --- chrsh.c.orig Thu Jul 10 11:55:31 2003 +++ chrsh.c @@ -80,6 +80,7 @@ /* The chroot jail main directory must be owned and permissioned thus */ #define JAILDIRUID 0 #define JAILDIRGID 0 +#define JAILMNT MNT_RDONLY #define JAILDIRMODE 0555 /* The jailed user's chrooted home directory must be this mode */ @@ -116,6 +117,7 @@ # error "You MUST define either LOG_USESYSLOG or LOG_USEFILE (not both)!" #endif +#include #include #include #include @@ -126,6 +128,7 @@ #include #include #include +#include #include #include #include @@ -255,8 +258,9 @@ void clean_exit(int exitcode) { * are world writable, race conditions and worse WILL almost CERTAINLY * end up in a root compromise. */ -int checkjailed(char *item, uid_t uid, gid_t gid, int isdir, mode_t mode) { +int checkjailed(char *item, uid_t uid, gid_t gid, int isdir, int fs_flags, mode_t mode) { struct stat statinfo; + struct statfs statfsinfo; char *type; type = isdir ? "subdirectory" : "file"; @@ -265,6 +269,10 @@ int checkjailed(char *item, uid_t uid, g do_log(LOG_WARNING, "Unable to stat %s %s of the jail.", item, type); return 1; } + if (statfs(item, &statfsinfo)) { + do_log(LOG_WARNING, "Unable to statfs %s %s of the jail.", item, type); + return 1; + } if ((!(statinfo.st_mode & S_IFDIR) && isdir) || (!(statinfo.st_mode & S_IFREG) && !isdir)) { do_log(LOG_WARNING, "Jailed %s %s is not a %s.", item, type, (isdir ? "directory" : "regular file")); return 2; @@ -273,9 +281,12 @@ int checkjailed(char *item, uid_t uid, g do_log(LOG_WARNING, "Jailed %s %s is world writable.", item, type); return 3; } - if ((statinfo.st_mode & ALLPERMS) != mode) { - do_log(LOG_WARNING, "Jailed %s %s mode does not match expected mode %lo.", item, type, mode); - return 4; + if ((statfsinfo.f_flags & fs_flags) == 0) { + if ((statinfo.st_mode & ALLPERMS) != mode) { + do_log(LOG_WARNING, "Jailed %s %s mode does not match expected mode %lo.", item, type, mode); + return 4; + } + } if (statinfo.st_uid != uid) { do_log(LOG_WARNING, "Jailed %s %s is not owned by expected UID %ld.", item, type, uid); @@ -310,6 +321,7 @@ int main(int argc, char *argv[], char *e struct passwd *pw; struct group *gr; struct stat statinfo; + struct statfs statfsinfo; struct sockaddr sock; int m, i; int logfd = -1; @@ -558,13 +570,19 @@ int main(int argc, char *argv[], char *e do_log(LOG_WARNING, "Unable to stat the jail directory: %s", jail); clean_exit(185); } + if (statfs(jail, &statfsinfo)) { + do_log(LOG_WARNING, "Unable to statfs the jail directory: %s", jail); + clean_exit(185); + } if (statinfo.st_mode & (S_IWGRP | S_IWOTH)) { do_log(LOG_WARNING, "Jail directory is world writable."); clean_exit(186); } - if ((statinfo.st_mode & ALLPERMS) != JAILDIRMODE) { - do_log(LOG_WARNING, "Jail directory mode does not match expected mode %lo.", JAILDIRMODE); - clean_exit(187); + if ((statfsinfo.f_flags & JAILMNT) == 0) { + if ((statinfo.st_mode & ALLPERMS) != JAILDIRMODE) { + do_log(LOG_WARNING, "Jail directory mode does not match expected mode %lo.", JAILDIRMODE); + clean_exit(187); + } } if (statinfo.st_uid != JAILDIRUID) { do_log(LOG_WARNING, "Jail directory is not owned by expected UID %ld.", JAILDIRUID); @@ -587,17 +605,17 @@ int main(int argc, char *argv[], char *e /* * Now look for and check out /bin and /etc in the jail... */ - if ((m = checkjailed("/etc", JAILDIRUID, JAILDIRGID, 1, JAILDIRMODE)) != 0) { + if ((m = checkjailed("/etc", JAILDIRUID, JAILDIRGID, 1, JAILMNT, JAILDIRMODE)) != 0) { clean_exit(m+200); } - if ((m = checkjailed("/bin", JAILDIRUID, JAILDIRGID, 1, JAILDIRMODE)) != 0) { + if ((m = checkjailed("/bin", JAILDIRUID, JAILDIRGID, 1, JAILMNT, JAILDIRMODE)) != 0) { clean_exit(m+210); } /* * Check out the user's home subdir in the jail... */ - if ((m = checkjailed(home, uid, gid, 1, HOMEDIRMODE)) != 0) { + if ((m = checkjailed(home, uid, gid, 1, JAILMNT, HOMEDIRMODE)) != 0) { clean_exit(m+220); } @@ -644,7 +662,7 @@ int main(int argc, char *argv[], char *e do_log(LOG_WARNING, "Unable to allocate space for user's jailed shell \"%s\".", pw->pw_shell); clean_exit(241); } - if ((m = checkjailed(shell, SHELLUID, SHELLGID, 0, SHELLMODE)) != 0) { + if ((m = checkjailed(shell, SHELLUID, SHELLGID, 0, JAILMNT, SHELLMODE)) != 0) { clean_exit(242+m); }