diff options
| author | Jeff Darcy <jdarcy@redhat.com> | 2013-02-07 13:57:42 -0500 | 
|---|---|---|
| committer | Anand Avati <avati@redhat.com> | 2013-02-17 12:04:48 -0800 | 
| commit | fcc230c99dd7318c2bee54beaa152b5a8c66f186 (patch) | |
| tree | b8734e799d7610be989b692ef0021100fc847f9f /xlators/features/protect/src | |
| parent | 614529c59123d3f2a20a6ee9a99d362a7d35e5b1 (diff) | |
features: add a directory-protection translator
This is useful to find all calls that remove a file from the protected
directory, including renames and internal calls.  Such calls will cause
a stack trace to be logged.  There's a filter script to add the needed
translators, and then the new functionality can be invoked with one of
the following commands.
	setfattr -n trusted.glusterfs.protect -v log $dir
	setfattr -n trusted.glusterfs.protect -v reject $dir
	setfattr -n trusted.glusterfs.protect -v anything_else $dir
The first logs calls, but still allows them.  The second rejects them
with EPERM.  The third turns off protection for that directory.
Change-Id: Iee4baaf8e837106be2b4099542cb7dcaae40428c
BUG: 888072
Signed-off-by: Jeff Darcy <jdarcy@redhat.com>
Reviewed-on: http://review.gluster.org/4496
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'xlators/features/protect/src')
| -rw-r--r-- | xlators/features/protect/src/Makefile.am | 21 | ||||
| -rw-r--r-- | xlators/features/protect/src/prot_client.c | 215 | ||||
| -rw-r--r-- | xlators/features/protect/src/prot_dht.c | 168 | ||||
| -rw-r--r-- | xlators/features/protect/src/prot_server.c | 51 | 
4 files changed, 455 insertions, 0 deletions
diff --git a/xlators/features/protect/src/Makefile.am b/xlators/features/protect/src/Makefile.am new file mode 100644 index 00000000000..7eb93f32e11 --- /dev/null +++ b/xlators/features/protect/src/Makefile.am @@ -0,0 +1,21 @@ +xlator_LTLIBRARIES = prot_dht.la prot_client.la prot_server.la + +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features + +prot_dht_la_LDFLAGS = -module -avoidversion +prot_dht_la_SOURCES = prot_dht.c +prot_dht_la_LIBADD  = $(top_builddir)/libglusterfs/src/libglusterfs.la + +prot_client_la_LDFLAGS = -module -avoidversion +prot_client_la_SOURCES = prot_client.c +prot_client_la_LIBADD  = $(top_builddir)/libglusterfs/src/libglusterfs.la + +prot_server_la_LDFLAGS = -module -avoidversion +prot_server_la_SOURCES = prot_server.c +prot_server_la_LIBADD  = $(top_builddir)/libglusterfs/src/libglusterfs.la + +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src +AM_CFLAGS = -Wall $(GF_CFLAGS) + +CLEANFILES =  + diff --git a/xlators/features/protect/src/prot_client.c b/xlators/features/protect/src/prot_client.c new file mode 100644 index 00000000000..a27216d0aff --- /dev/null +++ b/xlators/features/protect/src/prot_client.c @@ -0,0 +1,215 @@ +/* +   Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +   This file is part of GlusterFS. + +   This file is licensed to you under your choice of the GNU Lesser +   General Public License, version 3 or any later version (LGPLv3 or +   later), or the GNU General Public License, version 2 (GPLv2), in all +   cases as published by the Free Software Foundation. +*/ +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "defaults.h" + +#include <execinfo.h> + +#define NUM_FRAMES 20 + +static char PROTECT_KEY[] = "trusted.glusterfs.protect"; + +enum { +        PROT_ACT_NONE = 0, +        PROT_ACT_LOG, +        PROT_ACT_REJECT, +}; + +void +pcli_print_trace (char *name, call_frame_t *frame) +{ +        void    *frames[NUM_FRAMES]; +        char    **symbols; +        int     size; +        int     i; + +        gf_log (name, GF_LOG_INFO, "Translator stack:"); +        while (frame) { +                gf_log (name, GF_LOG_INFO, "%s (%s)", +                        frame->wind_from, frame->this->name); +                frame = frame->next; +        } + +        size = backtrace(frames,NUM_FRAMES); +        if (size <= 0) { +                return; +        } +        symbols = backtrace_symbols(frames,size); +        if (!symbols) { +                return; +        } + +        gf_log(name, GF_LOG_INFO, "Processor stack:"); +        for (i = 0; i < size; ++i) { +                gf_log (name, GF_LOG_INFO, "%s", symbols[i]); +        } +        free(symbols); +} + +int32_t +pcli_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, +                loc_t *newloc, dict_t *xdata) +{ +        uint64_t        value; + +        if (newloc->parent == oldloc->parent) { +                gf_log (this->name, GF_LOG_DEBUG, "rename in same directory"); +                goto simple_unwind; +        } +        if (!oldloc->parent) { +                goto simple_unwind; +        } +        if (inode_ctx_get(oldloc->parent,this,&value) != 0) { +                goto simple_unwind; +        } + +        if (value != PROT_ACT_NONE) { +                gf_log (this->name, GF_LOG_WARNING, +                        "got rename for protected %s", oldloc->path); +                pcli_print_trace(this->name,frame->next); +                if (value == PROT_ACT_REJECT) { +                        STACK_UNWIND_STRICT (rename, frame, -1, EPERM, +                                             NULL, NULL, NULL, NULL, NULL, +                                             xdata); +                        return 0; +                } +        } + +simple_unwind: +        STACK_WIND_TAIL (frame, FIRST_CHILD(this), +                         FIRST_CHILD(this)->fops->rename, oldloc, newloc, +                         xdata); +        return 0; +} + +int32_t +pcli_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, +               int32_t flags, dict_t *xdata) +{ +        data_t          *data; +        uint64_t        value; + +        /* +         * We can't use dict_get_str and strcmp here, because the value comes +         * directly from the user and might not be NUL-terminated (it would +         * be if we had set it ourselves. +         */ + +        data = dict_get(dict,PROTECT_KEY); +        if (!data) { +                goto simple_wind; +        } + +        if (dict->count > 1) { +                gf_log (this->name, GF_LOG_WARNING, +                        "attempted to mix %s with other keys", PROTECT_KEY); +                goto simple_wind; +        } + +        gf_log (this->name, GF_LOG_DEBUG, "got %s request", PROTECT_KEY); +        if (!strncmp(data->data,"log",data->len)) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "logging removals on %s", loc->path); +                value = PROT_ACT_LOG; +        } +        else if (!strncmp(data->data,"reject",data->len)) { +                gf_log (this->name, GF_LOG_DEBUG, +                        "rejecting removals on %s", loc->path); +                value = PROT_ACT_REJECT; +        } +        else { +                gf_log (this->name, GF_LOG_DEBUG, +                        "removing protection on %s", loc->path); +                value = PROT_ACT_NONE; +        } +        /* Right now the value doesn't matter - just the presence. */ +        if (inode_ctx_set(loc->inode,this,&value) != 0) { +                gf_log (this->name, GF_LOG_WARNING, +                        "failed to set protection status for %s", loc->path); +        } +        STACK_UNWIND_STRICT (setxattr, frame, 0, 0, NULL); +        return 0; + +simple_wind: +        STACK_WIND_TAIL (frame, +                         FIRST_CHILD(this), FIRST_CHILD(this)->fops->setxattr, +                         loc, dict, flags, xdata); +        return 0; +} + +int32_t +pcli_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, +             dict_t *xdata) +{ +        uint64_t        value; + +        if (!loc->parent || (inode_ctx_get(loc->parent,this,&value) != 0)) { +                goto simple_unwind; +        } + +        if (value != PROT_ACT_NONE) { +                gf_log (this->name, GF_LOG_WARNING, +                        "got unlink for protected %s", loc->path); +                pcli_print_trace(this->name,frame->next); +                if (value == PROT_ACT_REJECT) { +                        STACK_UNWIND_STRICT (unlink, frame, -1, EPERM, +                                             NULL, NULL, NULL); +                        return 0; +                } +        } + +simple_unwind: +        STACK_WIND_TAIL (frame, FIRST_CHILD(this), +                         FIRST_CHILD(this)->fops->unlink, loc, xflag, xdata); +        return 0; +} + +int32_t +init (xlator_t *this) +{ +	if (!this->children || this->children->next) { +		gf_log (this->name, GF_LOG_ERROR, +			"translator not configured with exactly one child"); +		return -1; +	} + +	if (!this->parents) { +		gf_log (this->name, GF_LOG_WARNING, +			"dangling volume. check volfile "); +	} + +	return 0; +} + + +void +fini (xlator_t *this) +{ +	return; +} + + +struct xlator_fops fops = { +        .rename         = pcli_rename, +        .setxattr       = pcli_setxattr, +        .unlink         = pcli_unlink, +}; + +struct xlator_cbks cbks = { +}; + +struct volume_options options[] = { +	{ .key = {NULL} }, +}; diff --git a/xlators/features/protect/src/prot_dht.c b/xlators/features/protect/src/prot_dht.c new file mode 100644 index 00000000000..feec6ffd69c --- /dev/null +++ b/xlators/features/protect/src/prot_dht.c @@ -0,0 +1,168 @@ +/* +   Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +   This file is part of GlusterFS. + +   This file is licensed to you under your choice of the GNU Lesser +   General Public License, version 3 or any later version (LGPLv3 or +   later), or the GNU General Public License, version 2 (GPLv2), in all +   cases as published by the Free Software Foundation. +*/ +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "defaults.h" + +enum gf_pdht_mem_types_ { +        gf_pdht_mt_coord_t = gf_common_mt_end + 1, +        gf_pdht_mt_end +}; + +typedef struct { +        pthread_mutex_t         lock; +        uint16_t                refs; +        int32_t                 op_ret; +        int32_t                 op_errno; +        dict_t                  *xdata; +} pdht_coord_t; + +static char PROTECT_KEY[] = "trusted.glusterfs.protect"; + +void +pdht_unref_and_unlock (call_frame_t *frame, xlator_t *this, +                       pdht_coord_t *coord) +{ +        gf_boolean_t    should_unwind; + +        should_unwind = (--(coord->refs) == 0); +        pthread_mutex_unlock(&coord->lock); + +        if (should_unwind) { +                STACK_UNWIND_STRICT (setxattr, frame,  +                                     coord->op_ret, coord->op_errno, +                                     coord->xdata); +                if (coord->xdata) { +                        dict_unref(coord->xdata); +                } +                GF_FREE(coord); +        } +} + +int32_t +pdht_recurse_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                  int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ +        pdht_coord_t    *coord = cookie; + +        pthread_mutex_lock(&coord->lock); +        if (op_ret) { +                coord->op_ret = op_ret; +                coord->op_errno = op_errno; +        } +        if (xdata) { +                if (coord->xdata) { +                        dict_unref(coord->xdata); +                } +                coord->xdata = dict_ref(xdata); +        } +        pdht_unref_and_unlock(frame,this,coord); +                 +        return 0; +} + +void +pdht_recurse (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, +              int32_t flags, dict_t *xdata, xlator_t *xl, pdht_coord_t *coord) +{ +        xlator_list_t   *iter; + +        if (!strcmp(xl->type,"features/prot_client")) { +                pthread_mutex_lock(&coord->lock); +                ++(coord->refs); +                pthread_mutex_unlock(&coord->lock); +                STACK_WIND_COOKIE (frame, pdht_recurse_cbk, coord, xl, +                                   xl->fops->setxattr, loc, dict, flags, xdata); +        } + +        else for (iter = xl->children; iter; iter = iter->next) { +                pdht_recurse (frame, this, loc, dict, flags, xdata, +                              iter->xlator, coord); +        } +} + +int32_t +pdht_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, +               int32_t flags, dict_t *xdata) +{ +        pdht_coord_t    *coord; + +        if (!dict_get(dict,PROTECT_KEY)) { +                goto simple_wind; +        } + +        if (dict->count > 1) { +                gf_log (this->name, GF_LOG_WARNING, +                        "attempted to mix %s with other keys", PROTECT_KEY); +                goto simple_wind; +        } + +        coord = GF_CALLOC(1,sizeof(*coord),gf_pdht_mt_coord_t); +        if (!coord) { +                gf_log (this->name, GF_LOG_WARNING, "allocation failed"); +                goto simple_wind; +        } + +        pthread_mutex_init(&coord->lock,NULL); +        coord->refs = 1; +        coord->op_ret = 0; +        coord->xdata = NULL; + +        pdht_recurse(frame,this,loc,dict,flags,xdata,this,coord); +        pthread_mutex_lock(&coord->lock); +        pdht_unref_and_unlock(frame,this,coord); + +        return 0; + +simple_wind: +        STACK_WIND_TAIL (frame, +                         FIRST_CHILD(this), FIRST_CHILD(this)->fops->setxattr, +                         loc, dict, flags, xdata); +        return 0; +} + +int32_t +init (xlator_t *this) +{ +	if (!this->children || this->children->next) { +		gf_log (this->name, GF_LOG_ERROR, +			"translator not configured with exactly one child"); +		return -1; +	} + +	if (!this->parents) { +		gf_log (this->name, GF_LOG_WARNING, +			"dangling volume. check volfile "); +	} + +	return 0; +} + + +void +fini (xlator_t *this) +{ +	return; +} + +struct xlator_fops fops = { +        .setxattr = pdht_setxattr, +}; + +struct xlator_cbks cbks = { +}; + +struct volume_options options[] = { +	{ .key = {NULL} }, +}; diff --git a/xlators/features/protect/src/prot_server.c b/xlators/features/protect/src/prot_server.c new file mode 100644 index 00000000000..beaee0889b7 --- /dev/null +++ b/xlators/features/protect/src/prot_server.c @@ -0,0 +1,51 @@ +/* +   Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +   This file is part of GlusterFS. + +   This file is licensed to you under your choice of the GNU Lesser +   General Public License, version 3 or any later version (LGPLv3 or +   later), or the GNU General Public License, version 2 (GPLv2), in all +   cases as published by the Free Software Foundation. +*/ +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "xlator.h" +#include "defaults.h" + +int32_t +init (xlator_t *this) +{ +	if (!this->children || this->children->next) { +		gf_log (this->name, GF_LOG_ERROR, +			"translator not configured with exactly one child"); +		return -1; +	} + +	if (!this->parents) { +		gf_log (this->name, GF_LOG_WARNING, +			"dangling volume. check volfile "); +	} + +	return 0; +} + + +void +fini (xlator_t *this) +{ +	return; +} + + +struct xlator_fops fops = { +}; + +struct xlator_cbks cbks = { +}; + +struct volume_options options[] = { +	{ .key = {NULL} }, +};  | 
