From 7e04913aa6f4ddb45e95099ef648564bf90da0b3 Mon Sep 17 00:00:00 2001 From: Csaba Henk Date: Tue, 13 Sep 2011 13:12:38 +0200 Subject: gsyncd: control rsync target - require/perform rsync invocation with unprotected args (so that target is revealed to gateway program) - make use of some procfs wizardry to find gsyncd sibling and match rsync target against its working directory Change-Id: Iae1e39b0e61f22563c0f2a2e0605567e0d1902df BUG: 2825 Reviewed-on: http://review.gluster.com/461 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- xlators/features/marker/utils/src/Makefile.am | 4 +- xlators/features/marker/utils/src/gsyncd.c | 122 +++++++++++++++++--- xlators/features/marker/utils/src/procdiggy.c | 124 +++++++++++++++++++++ xlators/features/marker/utils/src/procdiggy.h | 26 +++++ xlators/features/marker/utils/syncdaemon/gsyncd.py | 2 +- 5 files changed, 258 insertions(+), 20 deletions(-) create mode 100644 xlators/features/marker/utils/src/procdiggy.c create mode 100644 xlators/features/marker/utils/src/procdiggy.h (limited to 'xlators/features') diff --git a/xlators/features/marker/utils/src/Makefile.am b/xlators/features/marker/utils/src/Makefile.am index 74e2b3ef516..73c99cb76d8 100644 --- a/xlators/features/marker/utils/src/Makefile.am +++ b/xlators/features/marker/utils/src/Makefile.am @@ -2,12 +2,14 @@ gsyncddir = $(libexecdir)/glusterfs gsyncd_PROGRAMS = gsyncd -gsyncd_SOURCES = gsyncd.c +gsyncd_SOURCES = gsyncd.c procdiggy.c gsyncd_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la gsyncd_LDFLAGS = $(GF_LDFLAGS) $(GF_GLUSTERFS_LDFLAGS) +noinst_HEADERS = procdiggy.h + AM_CFLAGS = -fPIC -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS)\ -I$(top_srcdir)/libglusterfs/src\ -DGSYNCD_PREFIX=\"$(libexecdir)/glusterfs\"\ diff --git a/xlators/features/marker/utils/src/gsyncd.c b/xlators/features/marker/utils/src/gsyncd.c index cebca1aeaae..d3fa2d325a6 100644 --- a/xlators/features/marker/utils/src/gsyncd.c +++ b/xlators/features/marker/utils/src/gsyncd.c @@ -30,10 +30,12 @@ #include "common-utils.h" #include "run.h" +#include "procdiggy.h" #define _GLUSTERD_CALLED_ "_GLUSTERD_CALLED_" #define _GSYNCD_DISPATCHED_ "_GSYNCD_DISPATCHED_" #define GSYNCD_CONF "geo-replication/gsyncd.conf" +#define GSYNCD_PY "gsyncd.py" #define RSYNC "rsync" int restricted = 0; @@ -128,9 +130,12 @@ invoke_gsyncd (int argc, char **argv) goto error; } + if (chdir ("/") == -1) + goto error; + j = 0; nargv[j++] = PYTHON; - nargv[j++] = GSYNCD_PREFIX"/python/syncdaemon/gsyncd.py"; + nargv[j++] = GSYNCD_PREFIX"/python/syncdaemon/"GSYNCD_PY; for (i = 1; i < argc; i++) nargv[j++] = argv[i]; if (config_file[0]) { @@ -149,10 +154,72 @@ invoke_gsyncd (int argc, char **argv) return 1; } + +static int +find_gsyncd (pid_t pid, pid_t ppid, char *name, void *data) +{ + char buf[NAME_MAX * 2] = {0,}; + char *p = NULL; + int zeros = 0; + int ret = 0; + int fd = -1; + pid_t *pida = (pid_t *)data; + + if (ppid != pida[0]) + return 0; + + ret = gf_asprintf (&p, PROC"/%d/cmdline", pid); + if (ret == -1) { + fprintf (stderr, "out of memory\n"); + return -1; + } + + fd = open (p, O_RDONLY); + if (fd == -1) + return 0; + ret = read (fd, buf, sizeof (buf)); + close (fd); + if (ret == -1) + return 0; + for (zeros = 0, p = buf; zeros < 2 && p < buf + ret; p++) + zeros += !*p; + + ret = 0; + switch (zeros) { + case 2: + if ((strcmp (basename (buf), basename (PYTHON)) || + strcmp (basename (buf + strlen (buf) + 1), GSYNCD_PY)) == 0) { + ret = 1; + break; + } + /* fallthrough */ + case 1: + if (strcmp (basename (buf), GSYNCD_PY) == 0) + ret = 1; + } + + if (ret == 1) { + if (pida[1] != -1) { + fprintf (stderr, GSYNCD_PY" sibling is not unique"); + return -1; + } + pida[1] = pid; + } + + return 0; +} + static int invoke_rsync (int argc, char **argv) { - int i = 0; + int i = 0; + char *p = NULL; + pid_t pid = -1; + pid_t ppid = -1; + pid_t pida[] = {-1, -1}; + char *name = NULL; + char buf[PATH_MAX + 1] = {0,}; + int ret = 0; assert (argv[argc] == NULL); @@ -161,24 +228,42 @@ invoke_rsync (int argc, char **argv) for (i = 2; i < argc && argv[i][0] == '-'; i++); - if (!(i == argc || - (i == argc - 2 && strcmp (argv[i], ".") == 0 && argv[i + 1][0] == '/'))) + if (!(i == argc - 2 && strcmp (argv[i], ".") == 0 && argv[i + 1][0] == '/')) { + fprintf (stderr, "need an rsync invocation without protected args\n"); goto error; + } - /* XXX a proper check would involve the following: - * - require rsync to not protect args (ie. pass target in command line) - * - find out proper synchronization target by: - * - looking up sshd process we origin from - * - within its children, find the gsyncd process - * that maintains the aux mount - * - find out mount directory by checking the working directory - * of the gsyncd process - * - demand that rsync target equals to sync target - * - * As of now, what we implement is dispatching rsync invocation to - * our system rsync, that handles the cardinal issue of controlling - * remote-requested command invocations. - */ + /* look up sshd we are spawned from */ + for (pid = getpid () ;; pid = ppid) { + ppid = pidinfo (pid, &name); + if (ppid < 0) { + fprintf (stderr, "sshd ancestor not found\n"); + goto error; + } + if (strcmp (name, "sshd") == 0) + break; + } + /* look up "ssh-sibling" gsyncd */ + pida[0] = pid; + ret = prociter (find_gsyncd, pida); + if (ret == -1 || pida[1] == -1) { + fprintf (stderr, "gsyncd sibling not found\n"); + goto error; + } + /* check if rsync target matches gsyncd target */ + if (gf_asprintf (&p, PROC"/%d/cwd", pida[1]) == -1) { + fprintf (stderr, "out of memory\n"); + goto error; + } + ret = readlink (p, buf, sizeof (buf)); + if (ret == -1 || ret == sizeof (buf)) + goto error; + if (strcmp (argv[argc - 1], "/") == 0 /* root dir cannot be a target */ || + (strcmp (argv[argc - 1], p) /* match against gluster target */ && + strcmp (argv[argc - 1], buf) /* match against file target */) != 0) { + fprintf (stderr, "rsync target does not match "GEOREP" session\n"); + goto error; + } argv[0] = RSYNC; @@ -192,6 +277,7 @@ invoke_rsync (int argc, char **argv) return 1; } + struct invocable { char *name; int (*invoker) (int argc, char **argv); diff --git a/xlators/features/marker/utils/src/procdiggy.c b/xlators/features/marker/utils/src/procdiggy.c new file mode 100644 index 00000000000..fc0f97999d6 --- /dev/null +++ b/xlators/features/marker/utils/src/procdiggy.c @@ -0,0 +1,124 @@ +/* + Copyright (c) 2011 Gluster, Inc. + This file is part of GlusterFS. + + GlusterFS 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; either version 3 of the License, + or (at your option) any later version. + + GlusterFS 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, see + . +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "common-utils.h" +#include "procdiggy.h" + +pid_t +pidinfo (pid_t pid, char **name) +{ + char buf[NAME_MAX * 2] = {0,}; + FILE *f = NULL; + char *p = NULL; + int ret = 0; + + ret = gf_asprintf (&p, PROC"/%d/status", pid); + if (ret == -1) + goto oom; + + f = fopen (p, "r"); + if (!f) + return -1; + + if (name) + *name = NULL; + for (;;) { + memset (buf, 0, sizeof (buf)); + if (fgets (buf, sizeof (buf), f) == NULL || + buf[strlen (buf) - 1] != '\n') { + pid = -1; + goto out; + } + buf[strlen (buf) -1] = '\0'; + + if (name && !*name) { + p = strtail (buf, "Name:"); + if (p) { + while (isspace (*++p)); + *name = gf_strdup (p); + if (!*name) + goto oom; + continue; + } + } + + p = strtail (buf, "PPid:"); + if (p) + break; + } + + while (isspace (*++p)); + ret = gf_string2int (p, &pid); + if (ret == -1) + pid = -1; + + out: + fclose (f); + return pid; + + oom: + fclose (f); + fprintf (stderr, "out of memory\n"); + return -2; +} + +int +prociter (int (*proch) (pid_t pid, pid_t ppid, char *name, void *data), + void *data) +{ + char *name = NULL; + DIR *d = NULL; + struct dirent *de = NULL; + pid_t pid = -1; + pid_t ppid = -1; + int ret = 0; + + d = opendir (PROC); + while (errno = 0, de = readdir (d)) { + if (gf_string2int (de->d_name, &pid) != -1 && pid >= 0) { + ppid = pidinfo (pid, &name); + switch (ppid) { + case -1: continue; + case -2: return -1; + } + ret = proch (pid, ppid, name, data); + if (ret) + return ret; + } + } + if (errno) { + fprintf (stderr, "failed to traverse "PROC" (%s)\n", + strerror (errno)); + return -1; + } + + return 0; +} diff --git a/xlators/features/marker/utils/src/procdiggy.h b/xlators/features/marker/utils/src/procdiggy.h new file mode 100644 index 00000000000..f4586de6c67 --- /dev/null +++ b/xlators/features/marker/utils/src/procdiggy.h @@ -0,0 +1,26 @@ +/* + Copyright (c) 2011 Gluster, Inc. + This file is part of GlusterFS. + + GlusterFS 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; either version 3 of the License, + or (at your option) any later version. + + GlusterFS 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, see + . +*/ + +#define PROC "/proc" + +pid_t pidinfo (pid_t pid, char **name); + +int prociter (int (*proch) (pid_t pid, pid_t ppid, char *name, void *data), + void *data); + diff --git a/xlators/features/marker/utils/syncdaemon/gsyncd.py b/xlators/features/marker/utils/syncdaemon/gsyncd.py index 6747acbce6f..9771822dcea 100644 --- a/xlators/features/marker/utils/syncdaemon/gsyncd.py +++ b/xlators/features/marker/utils/syncdaemon/gsyncd.py @@ -155,7 +155,7 @@ def main_i(): op.add_option('--session-owner', metavar='ID') op.add_option('-s', '--ssh-command', metavar='CMD', default='ssh') op.add_option('--rsync-command', metavar='CMD', default='rsync') - op.add_option('--rsync-extra', metavar='ARGS', default='-sS', help=SUPPRESS_HELP) + op.add_option('--rsync-extra', metavar='ARGS', default='-S', help=SUPPRESS_HELP) op.add_option('--timeout', metavar='SEC', type=int, default=120) op.add_option('--sync-jobs', metavar='N', type=int, default=3) op.add_option('--turns', metavar='N', type=int, default=0, help=SUPPRESS_HELP) -- cgit