X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=util-vserver%2Fsrc%2Fsecure-mount.c;h=4e35a321fb464300f0cc53b5f227eb564a1c4cda;hb=f56384040472bbb428daea122330746a7ca09569;hp=f75228353fc39110890a5e9b562cc618e2d3898b;hpb=3dcc7b50a90ff6c51c5d6bbcead198d73bd44475;p=util-vserver.git diff --git a/util-vserver/src/secure-mount.c b/util-vserver/src/secure-mount.c index f752283..4e35a32 100644 --- a/util-vserver/src/secure-mount.c +++ b/util-vserver/src/secure-mount.c @@ -31,12 +31,15 @@ #include "util.h" #include "pathconfig.h" +#include + #include #include #include #include #include #include +#include #include #include #include @@ -51,16 +54,20 @@ #include #define ENSC_WRAPPERS_FCNTL 1 +#define ENSC_WRAPPERS_UNISTD 1 #include #define MNTPOINT "/etc" +typedef enum { rfsYES, rfsNO, rfsONLY } RootFsOption; + struct MountInfo { char const * src; char const * dst; char const * type; unsigned long flag; unsigned long xflag; + unsigned long mask; char * data; }; @@ -70,6 +77,7 @@ struct Options { bool do_chroot; bool ignore_mtab; bool mount_all; + RootFsOption rootfs; int cur_dir_fd; int cur_rootdir_fd; @@ -82,6 +90,7 @@ struct Options { #define OPTION_CHROOT 1028 #define OPTION_SECURE 1029 #define OPTION_RBIND 1030 +#define OPTION_ROOTFS 1031 #define XFLAG_NOAUTO 0x01 @@ -93,6 +102,7 @@ CMDLINE_OPTIONS[] = { { "move", no_argument, 0, OPTION_MOVE }, { "mtab", required_argument, 0, OPTION_MTAB }, { "fstab", required_argument, 0, OPTION_FSTAB }, + { "rootfs", required_argument, 0, OPTION_ROOTFS }, { "chroot", no_argument, 0, OPTION_CHROOT }, { "secure", no_argument, 0, OPTION_SECURE }, { "rbind", no_argument, 0, OPTION_RBIND }, @@ -153,13 +163,39 @@ showHelp(int fd, char const *cmd, int res) WRITE_MSG(fd, "Usage: "); WRITE_STR(fd, cmd); WRITE_MSG(fd, - " [--help] [--version] [--bind] [--move] [--rbind] [-t ] [-n]\n" - " [--mtab ] [--fstab ] [--chroot] \n" - " -a|([-o ] [--] )\n\n" + " [--help] [--version] [--bind] [--move] [--rbind] [-t ] [--chroot]\n" + " [--mtab ] [--fstab ] [--rootfs yes|no|only]\n" + " [-n] -a|([-o ] [--] )\n\n" "Executes mount-operations under the current directory: it assumes sources in\n" "the current root-dir while destinations are expected in the chroot environment.\n\n" "For non-trivial mount-operations it uses the external 'mount' program which\n" "can be overridden by the $MOUNT environment variable.\n\n" + "Options:\n" + " --bind|move|rbind ... set the correspond flags; with this options\n" + " the mount will be executed internally without\n" + " calling an external mount program.\n" + " -t ... assume the given filesystem type\n" + " -o ... set additional options; see mount(2) for details\n" + " -n ... do not update the mtab-file\n" + " --mtab ... use as an alternative mtab file\n" + " [default: /etc/mtab]\n" + " --chroot ... chroot into the current directory before\n" + " mounting the filesystem\n" + " --fstab ... use as an alternative fstab file;\n" + " this option has an effect only with the '-a'\n" + " option [default: /etc/fstab]\n" + " --rootfs yes|no|only ... specifies how to handle an entry for a rootfs\n" + " ('/') when processing an fstab file. 'yes' will\n" + " mount it among the other entries, 'only' will\n" + " mount only the rootfs entry, and 'no' will ignore\n" + " it and mount only the other entries [default: yes]\n" + " -a ... mount everything listed in the fstab-file\n\n" + " ... the source-filesystem; this path is absolute\n" + " to the current root-filesystem. Only valid\n" + " without the '-a' option.\n" + " ... the destination mount-point; when used with\n" + " '--chroot', this path is relative to the current\n" + " directory. Only valid without the '-a' option\n\n" "Please report bugs to " PACKAGE_BUGREPORT "\n"); exit(res); @@ -282,11 +318,20 @@ callExternalMount(struct MountInfo const *mnt) if (mnt->flag & MS_BIND) argv[idx++] = "--bind"; else if (mnt->flag & MS_MOVE) argv[idx++] = "--move"; - if (mnt->data && + argv[idx++] = "-o"; + if (mnt->data && *mnt->data && strcmp(mnt->data, "defaults")!=0) { - argv[idx++] = "-o"; - argv[idx++] = mnt->data; + if (mnt->mask & MS_NODEV) + argv[idx++] = mnt->data; + else { + char * tmp = alloca(strlen(mnt->data) + sizeof("nodev,")); + strcpy(tmp, "nodev,"); + strcat(tmp, mnt->data); + argv[idx++] = tmp; + } } + else + argv[idx++] = "nodev"; if (mnt->type) { argv[idx++] = "-t"; @@ -362,9 +407,12 @@ mountSingle(struct MountInfo const *mnt, struct Options const *opt) return false; if (mnt->flag & (MS_BIND|MS_MOVE)) { + unsigned long flag = mnt->flag; + if ((flag & MS_NODEV)==0) flag |= MS_NODEV; + if (mount(mnt->src, ".", mnt->type ? mnt->type : "", - mnt->flag, mnt->data)==-1) { + flag, mnt->data)==-1) { perror("secure-mount: mount()"); return false; } @@ -392,7 +440,7 @@ searchOption(char const *opt, size_t len) } static bool -transformOptionList(struct MountInfo *info) +transformOptionList(struct MountInfo *info, size_t UNUSED *col) { char const * ptr = info->data; @@ -406,6 +454,7 @@ transformOptionList(struct MountInfo *info) if (opt!=0) { info->flag &= ~opt->mask; info->flag |= opt->flag; + info->mask |= opt->mask; info->xflag |= opt->xflag; } @@ -421,13 +470,17 @@ transformOptionList(struct MountInfo *info) #define MOVE_TO_NEXT_FIELD(PTR,ALLOW_EOL) \ while (!isspace(*PTR) && *PTR!='\0') ++PTR; \ + if (col) *col = buf-start_buf+1; \ if (!(ALLOW_EOL) && *PTR=='\0') return prFAIL; \ *PTR++ = '\0'; \ while (isspace(*PTR)) ++PTR static enum {prDOIT, prFAIL, prIGNORE} -parseFstabLine(struct MountInfo *info, char *buf) + parseFstabLine(struct MountInfo *info, char *buf, size_t *col) { + char const * const start_buf = buf; + size_t err_col; + while (isspace(*buf)) ++buf; if (*buf=='#' || *buf=='\0') return prIGNORE; @@ -437,22 +490,41 @@ parseFstabLine(struct MountInfo *info, char *buf) MOVE_TO_NEXT_FIELD(buf, false); info->type = buf; MOVE_TO_NEXT_FIELD(buf, false); + err_col = buf-start_buf+1; info->data = buf; MOVE_TO_NEXT_FIELD(buf, true); - if (strcmp(info->type, "swap")==0) return prIGNORE; - if (strcmp(info->type, "none")==0) info->type = 0; + info->flag = MS_NODEV; + info->mask = 0; + info->xflag = 0; + + if (strcmp(info->type, "swap") ==0) return prIGNORE; + else if (strcmp(info->type, "none") ==0) info->type = 0; + else if (strcmp(info->type, "devpts")==0) info->mask |= MS_NODEV; - info->flag = 0; - info->xflag = 0; - if (!transformOptionList(info)) return prFAIL; - if (info->xflag & XFLAG_NOAUTO) return prIGNORE; + if (col) *col = err_col; + if (!transformOptionList(info,col)) return prFAIL; + if (info->xflag & XFLAG_NOAUTO) return prIGNORE; return prDOIT; } #undef MOVE_TO_NEXT_FIELD +static void +showFstabPosition(int fd, char const *fname, size_t line_nr, size_t col_nr) +{ + char buf[3*sizeof(line_nr)*2 + 4]; + size_t len = utilvserver_fmt_uint(buf+1, line_nr)+1; + + buf[0] = ':'; + buf[len++] = ':'; + len += utilvserver_fmt_uint(buf+len, col_nr); + WRITE_STR(fd, fname); + Vwrite(fd, buf, len); +} + + static bool mountFstab(struct Options const *opt) { @@ -467,7 +539,7 @@ mountFstab(struct Options const *opt) goto err0; } - len = lseek(fd, 0, SEEK_END); + len = lseek(fd, 0, SEEK_END); if (len==-1 || lseek(fd, 0, SEEK_SET)==-1) { perror("secure-mount: lseek()"); @@ -477,6 +549,7 @@ mountFstab(struct Options const *opt) { char buf[len+2]; char *ptr, *ptrptr; + size_t line_nr=0, col_nr; if (read(fd, buf, len+1)!=len) { perror("secure-mount: read()"); @@ -485,33 +558,33 @@ mountFstab(struct Options const *opt) buf[len] = '#'; // workaround for broken dietlibc strtok_r() // implementation buf[len+1] = '\0'; + ptrptr = buf; - ptr = strtok_r(buf, "\n", &ptrptr); - while (ptr) { + while ((ptr=strsep(&ptrptr, "\n")) != 0) { struct MountInfo mnt; - char * new_ptr = strtok_r(0, "\n", &ptrptr); + ++line_nr; - switch (parseFstabLine(&mnt, ptr)) { + switch (parseFstabLine(&mnt, ptr, &col_nr)) { case prFAIL : - WRITE_MSG(2, "Failed to parse fstab-line beginning with '"); - WRITE_STR(2, ptr); - WRITE_MSG(2, "'\n"); + showFstabPosition(2, opt->fstab, line_nr, col_nr); + WRITE_MSG(2, ": syntax error\n"); goto err1; case prIGNORE : break; - case prDOIT : - chdir("/"); - if (!mountSingle(&mnt, opt)) { - WRITE_MSG(2, "Failed to mount fstab-line beginning with '"); - WRITE_STR(2, ptr); - WRITE_MSG(2, "'\n"); + case prDOIT : { + bool is_rootfs = (strcmp(mnt.dst, "/")==0); + Echdir("/"); + if (( is_rootfs && opt->rootfs==rfsNO) || + (!is_rootfs && opt->rootfs==rfsONLY)) { /* ignore the entry */ } + else if (!mountSingle(&mnt, opt)) { + showFstabPosition(2, opt->fstab, line_nr, 1); + WRITE_MSG(2, ": failed to mount fstab-entry\n"); } break; + } default : assert(false); } - - ptr = new_ptr; } } @@ -531,6 +604,20 @@ initFDs(struct Options *opt) Efcntl(opt->cur_rootdir_fd, F_SETFD, FD_CLOEXEC); } +static RootFsOption +parseRootFS(char const *str) +{ + if (strcasecmp(str, "yes")==0) return rfsYES; + else if (strcasecmp(str, "no")==0) return rfsNO; + else if (strcasecmp(str, "only")==0) return rfsONLY; + else { + WRITE_MSG(2, "secure-mount: invalid option for '--rootfs': '"); + WRITE_STR(2, str); + WRITE_MSG(2, "'\n"); + exit(wrapper_exit_code); + } +} + int main(int argc, char *argv[]) { struct MountInfo mnt = { @@ -549,7 +636,8 @@ int main(int argc, char *argv[]) .ignore_mtab = false, .mount_all = false, .cur_dir_fd = -1, - .cur_rootdir_fd = -1 + .cur_rootdir_fd = -1, + .rootfs = rfsYES }; while (1) { @@ -569,6 +657,7 @@ int main(int argc, char *argv[]) case OPTION_MTAB : opt.mtab = optarg; break; case OPTION_FSTAB : opt.fstab = optarg; break; case OPTION_CHROOT: opt.do_chroot = true; break; + case OPTION_ROOTFS: opt.rootfs = parseRootFS(optarg); break; case OPTION_SECURE: WRITE_MSG(2, "secure-mount: The '--secure' option is deprecated...\n"); break; @@ -602,7 +691,7 @@ int main(int argc, char *argv[]) if (mnt.data) { mnt.data = strdup(mnt.data); - if (!transformOptionList(&mnt)) { + if (!transformOptionList(&mnt, 0)) { WRITE_MSG(2, "Invalid options specified\n"); return EXIT_FAILURE; }