initial checkin
authorEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Thu, 16 Oct 2003 02:42:50 +0000 (02:42 +0000)
committerEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Thu, 16 Oct 2003 02:42:50 +0000 (02:42 +0000)
git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@165 94cd875c-1c1d-0410-91d2-eb244daf1a30

util-vserver/src/compat-pivot_root.h [new file with mode: 0644]
util-vserver/src/ctx-kill.c [new file with mode: 0644]
util-vserver/src/secure-umount.c [new file with mode: 0644]
util-vserver/src/stack-start.h [new file with mode: 0644]
util-vserver/src/wrappers-vserver.h [new file with mode: 0644]
util-vserver/src/wrappers.h [new file with mode: 0644]

diff --git a/util-vserver/src/compat-pivot_root.h b/util-vserver/src/compat-pivot_root.h
new file mode 100644 (file)
index 0000000..9fcdba2
--- /dev/null
@@ -0,0 +1,29 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef H_UTIL_VSERVER_SRC_COMPAT_PIVOT_ROOT_H
+#define H_UTIL_VSERVER_SRC_COMPAT_PIVOT_ROOT_H
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <errno.h>
+
+_syscall2(int,pivot_root,const char *,new_root,const char *,put_old)
+
+#endif //  H_UTIL_VSERVER_SRC_COMPAT_PIVOT_ROOT_H
diff --git a/util-vserver/src/ctx-kill.c b/util-vserver/src/ctx-kill.c
new file mode 100644 (file)
index 0000000..a8209a7
--- /dev/null
@@ -0,0 +1,341 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+#include "compat.h"
+
+#include "wrappers.h"
+#include "wrappers-vserver.h"
+#include "util.h"
+#include "stack-start.h"
+
+#include <time.h>
+#include <dirent.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sched.h>
+#include <assert.h>
+
+#ifndef CLONE_NEWNS
+#  define CLONE_NEWNS 0x00020000
+#endif
+
+#ifndef MNT_DETACH
+#  define MNT_DETACH   0x000000002
+#endif
+
+#if 0
+#  include <stdio.h>
+#  define DPRINTF(...) printf(__VA_ARGS__)
+#else
+#  define DPRINTF(...) (void)0
+#endif
+
+struct ArgInfo {
+    enum { tpUNSET, tpCTX, tpPID }     type;
+    ctx_t              ctx;
+    pid_t              pid;
+    unsigned int       interval;
+    bool               shutdown;
+    bool               omit_init;
+    size_t             argc;
+    char * const *     argv;
+};
+
+static struct option const
+CMDLINE_OPTIONS[] = {
+  { "help",     no_argument,  0, 'h' },
+  { "version",  no_argument,  0, 'v' },
+  { "all",      no_argument,       0, 'a' },
+  { "ctx",      required_argument, 0, 'c' },
+  { "pid",      required_argument, 0, 'p' },
+  { "interval", required_argument, 0, 'i' },
+  { "shutdown", no_argument,       0, 's' },
+  { 0,0,0,0 }
+};
+
+int    wrapper_exit_code = 1;
+
+static void
+showHelp(int fd, char const *cmd, int res)
+{
+  WRITE_MSG(fd, "Usage:  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " (-c|--ctx <ctx>)|(-p|--pid <pid>) [-i|--interval <msec>] [-a|--all]\n"
+           "                [-s|--shutdown] [--] <signal> [<sec> <signal>]*\n\n"
+           "Please report bugs to " PACKAGE_BUGREPORT "\n");
+  exit(res);
+}
+
+static void
+showVersion()
+{
+  WRITE_MSG(1,
+           "ctx-kill " VERSION " -- kills processes in foreign contexts\n"
+           "This program is part of " PACKAGE_STRING "\n\n"
+           "Copyright (C) 2003 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
+}
+
+static void
+iterateThroughProc(void (*fn)(pid_t pid, void *data),
+                  struct ArgInfo const * const args,
+                  void *data)
+{
+  int          grp  = getpgrp();
+  DIR          *dir;
+  struct dirent        *d;
+
+  kill(-1, SIGSTOP);
+  dir = opendir("/proc");
+  if (dir==0) {
+    perror("opendir()");
+    kill(-1, SIGCONT);
+    exit(1);
+  }
+    
+  kill(-1, SIGSTOP);
+  while ((d=readdir(dir))!=0) {
+    pid_t      pid = atoi(d->d_name);
+    if (pid==0 ||                      // not a /proc/<pid>/ entry
+       (args->omit_init && pid==1) ||
+       getpgid(pid)==grp)              // our own process-group
+      continue;
+
+    (*fn)(pid,data);
+  }
+  kill(-1, SIGCONT);
+
+  closedir(dir);
+}
+
+static void
+doKillAllSingle(pid_t pid, void *sig_ptr_v)
+{
+  register int const * const   sig_ptr = sig_ptr_v;
+  
+  DPRINTF("sending signal '%u' to process '%u'\n",
+         *sig_ptr, pid);
+  kill(pid, *sig_ptr);
+}
+
+static void
+getRemainingProcCountProc(pid_t UNUSED pid, void *cnt_v)
+{
+  register size_t * const      cnt = cnt_v;
+  
+  ++*cnt;
+}
+
+static size_t
+getRemainingProcCount(struct ArgInfo const * const args)
+{
+  size_t       cnt = 0;
+  iterateThroughProc(&getRemainingProcCountProc, args, &cnt);
+
+  return cnt;
+}
+
+static void
+doKillAll(struct ArgInfo const * const args)
+{
+  size_t       i=0;
+
+  signal(SIGSTOP, SIG_IGN);
+
+  while (i<args->argc) {
+    int                sig       = atoi(args->argv[i]);
+    time_t     next_time = time(0);
+
+    ++i;
+    if (i<args->argc)
+      next_time += atoi(args->argv[i]);
+    
+    iterateThroughProc(&doKillAllSingle, args, &sig);
+    while (time(0)<next_time && getRemainingProcCount(args)>0)
+      usleep(args->interval * 1000);
+
+    ++i;
+  }
+
+  if (args->shutdown && getRemainingProcCount(args)>0) {
+    WRITE_MSG(2, "There are processes which could not be killed\n");
+    exit(1);
+  }
+
+}
+
+static void
+doKillSingle(struct ArgInfo const * const args)
+{
+  size_t       i=0;
+
+  while (i<args->argc) {
+    int                sig       = atoi(args->argv[i]);
+    time_t     next_time = time(0);
+
+    ++i;
+    if (i<args->argc)
+      next_time += atoi(args->argv[i]);
+
+    DPRINTF("sending signal '%u' to process '%u'\n",
+           sig, args->pid);
+    kill(args->pid, sig);
+    while (time(0)<next_time &&
+          (getpgid(args->pid)!=-1 || errno!=ESRCH))
+      
+      usleep(args->interval * 1000);
+
+    ++i;
+  }
+}
+
+static int
+childFunc(void *args_v)
+{
+  struct ArgInfo *     args = args_v;
+
+  Emount("none", "/mnt", "tmpfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, "size=4k");
+  Echdir("/mnt");
+  Emkdir("proc", 0600);
+  Emkdir("old",  0600);
+  Epivot_root(".", "old");
+  Echroot(".");
+  Eumount2("old", MNT_DETACH);
+  Emkdir("old/foo",0600);
+  Emount("none", "/proc", "proc", 0, 0);
+
+    // TODO: it may be be better for ctx-shutdown to:
+    // * generate ctx with S_CTX_INFO_INIT
+    // * send kill to -1
+  Evc_new_s_context(args->ctx, ~0, S_CTX_INFO_LOCK|S_CTX_INFO_SCHED);
+
+  switch (args->type) {
+    case tpCTX :  doKillAll(args); break;
+    case tpPID :  doKillSingle(args); break;
+    default    :  assert(false); return 1;
+  }
+
+  return 0;
+}
+  
+static ctx_t
+determineContext(pid_t pid)
+{
+  int          fd[2];
+  pid_t                chld;
+  ctx_t                res;
+  
+  Epipe(fd);
+  chld = Efork();
+
+  if (chld==0) {
+    Eclose(fd[0]);
+    Evc_new_s_context(1, ~0, S_CTX_INFO_LOCK|S_CTX_INFO_SCHED);
+    res = vc_X_getctx(pid);
+    Ewrite(fd[1], &res, sizeof res);
+    Eclose(fd[1]);
+    _exit(0);
+  }
+  
+  Eclose(fd[1]);
+  if (Eread(fd[0], &res, sizeof res)!=sizeof(res)) {
+    WRITE_MSG(2, "internal communication error while determining ctx\n");
+    exit(1);
+  }
+  Eclose(fd[0]);
+  if (res==VC_NOCTX) {
+    WRITE_MSG(2, "can not determine contex for given pid\n");
+    exit(1);
+  }
+
+  return res;
+}
+
+int main(int argc, char *argv[])
+{
+  pid_t                        pid, p;
+  char                 buf[0x8000];
+  int                  status;
+  struct ArgInfo       args = {
+    .type      = tpUNSET,
+    .interval  = 500,
+    .shutdown  = false,
+    .omit_init = true };
+
+  while (1) {
+    int                c = getopt_long(argc, argv, "hvsac:p:i:", CMDLINE_OPTIONS, 0);
+    if (c==-1) break;
+
+    switch (c) {
+      case 'h'         :  showHelp(1, argv[0], 0);
+      case 'v'         :  showVersion();
+      case 'c'         :
+       args.type = tpCTX;
+       args.ctx  = atoi(optarg);
+       break;
+      case 'p'         :
+       args.type = tpPID;
+       args.pid  = atoi(optarg);
+       break;
+      case 'i'         :  args.interval  = atoi(optarg); break;
+      case 's'         :  args.shutdown  = true; break;
+      case 'a'         :  args.omit_init = false; break;
+      default          :
+       WRITE_MSG(2, "Try '");
+       WRITE_STR(2, argv[0]);
+       WRITE_MSG(2, " --help\" for more information.\n");
+       return EXIT_FAILURE;
+       break;
+    }
+  }
+
+  if (args.type==tpUNSET){
+    WRITE_MSG(2, "Please specify a context or a pid\n");
+    return EXIT_FAILURE;
+  }
+
+  if (optind==argc) {
+    WRITE_MSG(2, "No signal specified\n");
+    return EXIT_FAILURE;
+  }
+
+  if (args.type==tpPID)
+    args.ctx = determineContext(args.pid);
+  
+  args.argc = argc-optind;
+  args.argv = argv+optind;
+
+    // TODO: args.argv verification (only integers)
+
+  if (args.argc%2 != 1) {
+    WRITE_MSG(2, "Wrong count of '<signal> [<pause> <signal>]*' arguments specified.\n");
+    return EXIT_FAILURE;
+  }
+
+  pid = Eclone(childFunc, STACK_START(buf), CLONE_NEWNS|SIGCHLD, &args);
+  p   = Ewait4(pid, &status, 0,0);
+
+  if (WIFEXITED(status))   return WEXITSTATUS(status);
+  if (WIFSIGNALED(status)) return kill(getpid(), WTERMSIG(status));
+  return EXIT_FAILURE;
+}
diff --git a/util-vserver/src/secure-umount.c b/util-vserver/src/secure-umount.c
new file mode 100644 (file)
index 0000000..e2084bd
--- /dev/null
@@ -0,0 +1,74 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+#include "compat-pivot_root.h"
+
+#include "wrappers.h"
+#include "util.h"
+
+int    wrapper_exit_code = 1;
+
+static void
+showHelp(int fd, char const *cmd, int res)
+{
+  WRITE_MSG(fd, "Usage:  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           "[--help] [--version] <dir>\n\n"
+           "Please report bugs to " PACKAGE_BUGREPORT "\n");
+
+  exit(res);
+}
+
+static void
+showVersion()
+{
+  WRITE_MSG(1,
+           "secure-umount " VERSION " -- secure umounting of directories\n"
+           "This program is part of " PACKAGE_STRING "\n\n"
+           "Copyright (C) 2003 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+  char const * dir;
+
+  if (argc<2) {
+    WRITE_MSG(2, "Try '");
+    WRITE_STR(2, argv[0]);
+    WRITE_MSG(2, " --help\" for more information.\n");
+    return EXIT_FAILURE;
+  }
+
+  if (strcmp(argv[1], "--help")==0)    showHelp(1, argv[0], 0);
+  if (strcmp(argv[1], "--version")==0) showVersion();
+
+  dir = argv[1];
+  if (strcmp(dir, "--")==0 && argc>=3) dir = argv[2];
+
+  Echroot(".");
+  Echdir("/");
+
+  Eumount2(dir, 0);
+  return EXIT_SUCCESS;
+}
diff --git a/util-vserver/src/stack-start.h b/util-vserver/src/stack-start.h
new file mode 100644 (file)
index 0000000..53aa8c6
--- /dev/null
@@ -0,0 +1,28 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef H_UTIL_VSERVER_SRC_STACK_START_H
+#define H_UTIL_VSERVER_SRC_STACK_START_H
+
+#ifdef HAVE_GROWING_STACK
+#  define STACK_START(PTR)             (PTR)
+#else
+#  define STACK_START(PTR)             ((PTR)+sizeof(PTR)/sizeof(PTR[0]))
+#endif
+
+#endif //  H_UTIL_VSERVER_SRC_STACK_START_H
diff --git a/util-vserver/src/wrappers-vserver.h b/util-vserver/src/wrappers-vserver.h
new file mode 100644 (file)
index 0000000..a01eb04
--- /dev/null
@@ -0,0 +1,32 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef H_UTIL_VSERVER_SRC_WRAPPERS_VSERVER_H
+#define H_UTIL_VSERVER_SRC_WRAPPERS_VSERVER_H
+
+#include "wrappers.h"
+#include <vserver.h>
+
+inline static UNUSED void
+Evc_new_s_context(ctx_t ctx, unsigned int remove_cap, unsigned int flags)
+{
+  FatalErrnoError(vc_new_s_context(ctx,remove_cap,flags)==-1,
+                 "vc_new_s_context()");
+}
+
+#endif //  H_UTIL_VSERVER_SRC_WRAPPERS_VSERVER_H
diff --git a/util-vserver/src/wrappers.h b/util-vserver/src/wrappers.h
new file mode 100644 (file)
index 0000000..319b7c8
--- /dev/null
@@ -0,0 +1,174 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef H_UTIL_VSERVER_SRC_WRAPPERS_H
+#define H_UTIL_VSERVER_SRC_WRAPPERS_H
+
+#include "compat.h"
+#include "compat-pivot_root.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#define WRAPPER_DECL   UNUSED ALWAYSINLINE
+
+static UNUSED void 
+FatalErrnoError(bool condition, char const msg[]) /*@*/
+{
+  if (!condition)       return;
+  perror(msg);
+
+  extern int   wrapper_exit_code;
+  exit(wrapper_exit_code);
+}
+
+inline static WRAPPER_DECL void
+Eclose(int s)
+{
+  FatalErrnoError(close(s)==-1, "close()");
+}
+
+inline static WRAPPER_DECL void
+Echdir(char const path[])
+{
+  FatalErrnoError(chdir(path)==-1, "chdir()");
+}
+
+inline static WRAPPER_DECL void
+Efchdir(int fd)
+{
+  FatalErrnoError(fchdir(fd)==-1, "fchdir()");
+}
+
+inline static WRAPPER_DECL void
+Echroot(char const path[])
+{
+  FatalErrnoError(chroot(path)==-1, "chroot()");
+}
+
+inline static WRAPPER_DECL void
+Eexecv(char const *path, char *argv[])
+{
+  FatalErrnoError(execv(path,argv)==-1, "execv()");
+}
+
+inline static WRAPPER_DECL int
+Eopen(char const *fname, int flags, mode_t mode)
+{
+  int  res = open(fname, flags, mode);
+  FatalErrnoError(res==-1, "open()");
+
+  return res;
+}
+
+inline static WRAPPER_DECL void
+Eumount2(char const *path, int flag)
+{
+  FatalErrnoError(umount2(path,flag)==-1, "umount2()");
+}
+
+inline static WRAPPER_DECL void
+Emount(const char *source, const char *target,
+       const char *filesystemtype, unsigned long mountflags,
+       const void *data)
+{
+  FatalErrnoError(mount(source, target, filesystemtype,
+                       mountflags, data)==-1, "mount()");
+}
+
+inline static WRAPPER_DECL void
+Emkdir(const char *pathname, mode_t mode)
+{
+  FatalErrnoError(mkdir(pathname,mode)==-1, "mkdir()");
+}
+
+inline static WRAPPER_DECL void
+Epivot_root(const char *new_root, const char *put_old)
+{
+  FatalErrnoError(pivot_root(new_root, put_old)==-1, "pivot_root()");
+}
+
+inline static WRAPPER_DECL pid_t
+Eclone(int (*fn)(void *), void *child_stack, int flags, void *arg)
+{
+  pid_t                res;
+#ifndef __dietlibc__
+  res = clone(fn, child_stack, flags, arg);
+#else
+  res = clone((void*(*)(void*))(fn), child_stack, flags, arg);
+#endif
+  FatalErrnoError(res==-1, "clone()");
+  return res;
+}
+
+
+inline static WRAPPER_DECL pid_t
+Ewait4(pid_t pid, int *status, int options,
+       struct rusage *rusage)
+{
+  pid_t                res;
+  res = wait4(pid, status, options, rusage);
+  FatalErrnoError(res==-1, "wait4()");
+  return res;
+}
+
+inline static WRAPPER_DECL void
+Epipe(int filedes[2])
+{
+  FatalErrnoError(pipe(filedes)==-1, "pipe()");
+}
+
+inline static WRAPPER_DECL pid_t
+Efork()
+{
+  pid_t                res;
+  res = fork();
+  FatalErrnoError(res==-1, "fork()");
+  return res;
+}
+
+inline static WRAPPER_DECL size_t
+Eread(int fd, void *ptr, size_t len)
+{
+  size_t       res = read(fd, ptr, len);
+  FatalErrnoError((ssize_t)(res)==-1, "read()");
+
+  return res;
+}
+
+inline static WRAPPER_DECL size_t
+Ewrite(int fd, void const *ptr, size_t len)
+{
+  size_t       res = write(fd, ptr, len);
+  FatalErrnoError((ssize_t)(res)==-1, "write()");
+
+  return res;
+}
+
+#undef WRAPPER_DECL
+
+#endif //  H_UTIL_VSERVER_SRC_WRAPPERS_H