aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2014-06-27 12:24:39 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2014-06-27 12:24:39 +0200
commita6ae999b3b30ad522272325bac4c69b153150108 (patch)
tree0af61697af6661c9d45c28025f2404c522436278
parent5f8daefb835687e428215f90d26fdf1f0206149d (diff)
downloadbusybox-w32-a6ae999b3b30ad522272325bac4c69b153150108.tar.gz
busybox-w32-a6ae999b3b30ad522272325bac4c69b153150108.tar.bz2
busybox-w32-a6ae999b3b30ad522272325bac4c69b153150108.zip
ftpd: escape chroot prior to re-executing ls helper
When we merely chdir to saved "real" root fd, exec("proc/self/exe") works for static executables but not for dynamic ones (they can't find their interpreter). With this patch, we also *chroot* to real root. As a bonus, this gives us proper usernames, timezone conversion etc. function old new delta popen_ls 203 259 +56 ftpd_main 2362 2366 +4 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--networking/ftpd.c53
1 files changed, 21 insertions, 32 deletions
diff --git a/networking/ftpd.c b/networking/ftpd.c
index e724734df..839a85d73 100644
--- a/networking/ftpd.c
+++ b/networking/ftpd.c
@@ -620,16 +620,12 @@ popen_ls(const char *opt)
620 const char *argv[5]; 620 const char *argv[5];
621 struct fd_pair outfd; 621 struct fd_pair outfd;
622 pid_t pid; 622 pid_t pid;
623 623#if !BB_MMU
624 int cur_fd = xopen(".", O_RDONLY | O_DIRECTORY);
625#endif
624 argv[0] = "ftpd"; 626 argv[0] = "ftpd";
625 argv[1] = opt; /* "-l" or "-1" */ 627 argv[1] = opt; /* "-l" or "-1" */
626#if BB_MMU
627 argv[2] = "--"; 628 argv[2] = "--";
628#else
629 /* NOMMU ftpd ls helper chdirs to argv[2],
630 * preventing peer from seeing real root. */
631 argv[2] = xrealloc_getcwd_or_warn(NULL);
632#endif
633 argv[3] = G.ftp_arg; 629 argv[3] = G.ftp_arg;
634 argv[4] = NULL; 630 argv[4] = NULL;
635 631
@@ -651,16 +647,6 @@ popen_ls(const char *opt)
651 pid = BB_MMU ? xfork() : xvfork(); 647 pid = BB_MMU ? xfork() : xvfork();
652 if (pid == 0) { 648 if (pid == 0) {
653 /* child */ 649 /* child */
654#if !BB_MMU
655 /* On NOMMU, we want to execute a child - copy of ourself.
656 * In chroot we usually can't do it. Thus we chdir
657 * out of the chroot back to original root,
658 * and (see later below) execute bb_busybox_exec_path
659 * relative to current directory */
660 if (fchdir(G.root_fd) != 0)
661 _exit(127);
662 /*close(G.root_fd); - close_on_exec_on() took care of this */
663#endif
664 /* NB: close _first_, then move fd! */ 650 /* NB: close _first_, then move fd! */
665 close(outfd.rd); 651 close(outfd.rd);
666 xmove_fd(outfd.wr, STDOUT_FILENO); 652 xmove_fd(outfd.wr, STDOUT_FILENO);
@@ -674,19 +660,25 @@ popen_ls(const char *opt)
674 /* memset(&G, 0, sizeof(G)); - ls_main does it */ 660 /* memset(&G, 0, sizeof(G)); - ls_main does it */
675 exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv)); 661 exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv));
676#else 662#else
677 /* + 1: we must use relative path here if in chroot. 663 /* On NOMMU, we want to execute a child - copy of ourself
678 * For example, execv("/proc/self/exe") will fail, since 664 * in order to unblock parent after vfork.
679 * it looks for "/proc/self/exe" _relative to chroot!_ */ 665 * In chroot we usually can't re-exec. Thus we escape
680 execv(bb_busybox_exec_path + 1, (char**) argv); 666 * out of the chroot back to original root.
667 */
668 if (G.root_fd >= 0) {
669 if (fchdir(G.root_fd) != 0 || chroot(".") != 0)
670 _exit(127);
671 /*close(G.root_fd); - close_on_exec_on() took care of this */
672 }
673 /* Child expects directory to list on fd #3 */
674 xmove_fd(cur_fd, 3);
675 execv(bb_busybox_exec_path, (char**) argv);
681 _exit(127); 676 _exit(127);
682#endif 677#endif
683 } 678 }
684 679
685 /* parent */ 680 /* parent */
686 close(outfd.wr); 681 close(outfd.wr);
687#if !BB_MMU
688 free((char*)argv[2]);
689#endif
690 return outfd.rd; 682 return outfd.rd;
691} 683}
692 684
@@ -705,8 +697,6 @@ handle_dir_common(int opts)
705 if (!(opts & USE_CTRL_CONN) && !port_or_pasv_was_seen()) 697 if (!(opts & USE_CTRL_CONN) && !port_or_pasv_was_seen())
706 return; /* port_or_pasv_was_seen emitted error response */ 698 return; /* port_or_pasv_was_seen emitted error response */
707 699
708 /* -n prevents user/groupname display,
709 * which can be problematic in chroot */
710 ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1"); 700 ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1");
711 ls_fp = xfdopen_for_read(ls_fd); 701 ls_fp = xfdopen_for_read(ls_fd);
712/* FIXME: filenames with embedded newlines are mishandled */ 702/* FIXME: filenames with embedded newlines are mishandled */
@@ -1139,11 +1129,10 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1139 opts = getopt32(argv, "l1vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); 1129 opts = getopt32(argv, "l1vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S);
1140 if (opts & (OPT_l|OPT_1)) { 1130 if (opts & (OPT_l|OPT_1)) {
1141 /* Our secret backdoor to ls */ 1131 /* Our secret backdoor to ls */
1142/* TODO: pass -n? It prevents user/group resolution, which may not work in chroot anyway */
1143/* TODO: pass -A? It shows dot files */ 1132/* TODO: pass -A? It shows dot files */
1144/* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */ 1133/* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */
1145 xchdir(argv[2]); 1134 if (fchdir(3) != 0)
1146 argv[2] = (char*)"--"; 1135 _exit(127);
1147 /* memset(&G, 0, sizeof(G)); - ls_main does it */ 1136 /* memset(&G, 0, sizeof(G)); - ls_main does it */
1148 return ls_main(argc, argv); 1137 return ls_main(argc, argv);
1149 } 1138 }
@@ -1185,9 +1174,9 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv)
1185 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); 1174 G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY);
1186 close_on_exec_on(G.root_fd); 1175 close_on_exec_on(G.root_fd);
1187#endif 1176#endif
1188 1177 argv += optind;
1189 if (argv[optind]) { 1178 if (argv[0]) {
1190 xchroot(argv[optind]); 1179 xchroot(argv[0]);
1191 } 1180 }
1192 1181
1193 //umask(077); - admin can set umask before starting us 1182 //umask(077); - admin can set umask before starting us