diff options
| author | Kevin Vigor <kvigor@fb.com> | 2017-05-22 10:27:14 -0700 | 
|---|---|---|
| committer | Shreyas Siravara <sshreyas@fb.com> | 2017-09-09 00:36:15 +0000 | 
| commit | 0f0d00e8a53e0220b2eb81ad159b12e475ea2afb (patch) | |
| tree | 0f5d071a3416903c4abf6afc975432241b032467 | |
| parent | 8250b0bf29d5423bf6014b45b43a22c6aace5576 (diff) | |
posix-acl: Add assume-permissive option for EACCES debugging / rug-sweeping.
Summary:
Add assume-permissive option for EACCES debugging / rug-sweeping.
Re-fetch permissions when needed if they're absent.
This is a port of D5104707 & D5131597 to 3.8
Change-Id: I900fc66876ec8e73b04049f844c428b3d225d4ad
Reviewed-on: https://review.gluster.org/18249
Reviewed-by: Shreyas Siravara <sshreyas@fb.com>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Smoke: Gluster Build System <jenkins@build.gluster.org>
| -rw-r--r-- | libglusterfs/src/glusterfs-acl.h | 14 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volume-set.c | 8 | ||||
| -rw-r--r-- | xlators/system/posix-acl/src/posix-acl.c | 158 | 
3 files changed, 177 insertions, 3 deletions
diff --git a/libglusterfs/src/glusterfs-acl.h b/libglusterfs/src/glusterfs-acl.h index 55f94ff0509..aa591fa4417 100644 --- a/libglusterfs/src/glusterfs-acl.h +++ b/libglusterfs/src/glusterfs-acl.h @@ -97,6 +97,7 @@ struct posix_acl {  };  struct posix_acl_ctx { +        gf_boolean_t      was_set;          uid_t             uid;          gid_t             gid;          mode_t            perm; @@ -104,10 +105,23 @@ struct posix_acl_ctx {          struct posix_acl *acl_default;  }; +enum liberal_permissions_mode_t { +        CONSERVATIVE = 0,       // Do nothing. +        LOGGING = 1,            // Log interesting events. +        INIT_PERMS = 2,         // Initialize perms to 777. +        IGNORE_ZERO_PERMS = 3,  // Ignore any zero perms. +        IGNORE_ALL_PERMS = 4,   // Ignore all perms. +}; +  struct posix_acl_conf {          gf_lock_t         acl_lock;          uid_t             super_uid;          struct posix_acl *minimal_acl; +        // 'liberal_permissions_mode' is used for debugging/ papering over +        // EACCES problems. +        // +        // Value should be one of liberal_permissions_mode_t. +        uint32_t          liberal_permissions_mode;  }; diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c index 857c494e039..94ae212bc27 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c @@ -2600,6 +2600,14 @@ struct volopt_map_entry glusterd_volopt_map[] = {            .voltype     = "storage/posix",            .op_version  = 2,          }, +        { .key         = "storage.liberal-perms-mode", +          /* +           * This is really storage/posix but for some ancient historical (and +           * probably no longer operative) reason we call it something else. +           */ +          .voltype     = "features/access-control", +          .op_version  = GD_OP_VERSION_3_6_0, +        },          { .key         = "storage.bd-aio",            .voltype     = "storage/bd",            .op_version  = 3 diff --git a/xlators/system/posix-acl/src/posix-acl.c b/xlators/system/posix-acl/src/posix-acl.c index 1c82e8b2239..c1370610958 100644 --- a/xlators/system/posix-acl/src/posix-acl.c +++ b/xlators/system/posix-acl/src/posix-acl.c @@ -22,6 +22,46 @@  #define PTR(num) ((void *)((long)(num))) +static char PE_TYPE_NOT_SET[]   = "not set"; +static char PE_TYPE_SET_ZERO[]  = "set to zero"; + +typedef struct { +        char            *type; +        int             filter; +        gf_boolean_t    log_caller; +} pe_ctx_t; + + +static void +maybe_log_perm_error (xlator_t *this, inode_t *inode, pe_ctx_t *pe_ctx) +{ +        struct posix_acl_conf *conf = this->private; + +        if (__is_root_gfid (inode->gfid)) { +                return; +        } + +        if (conf && conf->liberal_permissions_mode < LOGGING) { +                return; +        } + +        if (pe_ctx->filter == 0) { +                if (pe_ctx->log_caller) { +                        gf_log_callingfn (this->name, GF_LOG_INFO, +                                "perm error: %s on %s", pe_ctx->type, +                                uuid_utoa (inode->gfid)); +                        pe_ctx->log_caller = _gf_false; +                } else { +                        gf_log (this->name, GF_LOG_INFO, +                                "perm error: %s on %s", pe_ctx->type, +                                uuid_utoa (inode->gfid)); +                } +        } + +        pe_ctx->filter = (pe_ctx->filter + 1) % 100; +} + +  int32_t  mem_acct_init (xlator_t *this)  { @@ -151,6 +191,7 @@ posix_acl_access_set_mode (struct posix_acl *acl, struct posix_acl_ctx *ctx)  out:          ctx->perm = (ctx->perm & ~mask) | mode; +        ctx->was_set = _gf_true;          return mode;  } @@ -186,6 +227,74 @@ sticky_permits (call_frame_t *frame, inode_t *parent, inode_t *inode)  } +static int32_t +refresh_perms_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                   int32_t op_ret, int32_t op_errno, struct iatt *buf, +                   dict_t *xdata) +{ +        struct posix_acl_ctx    *ctx    = cookie; + +        if (op_ret < 0) { +                gf_log (this->name, GF_LOG_WARNING, +                        "perm refresh failed (%d)", op_errno); +                return 0; +        } + +        ctx->perm = st_mode_from_ia (buf->ia_prot, buf->ia_type); +        ctx->was_set = _gf_true; +        gf_log (this->name, GF_LOG_INFO, +                "refreshed perms = 0%o", ctx->perm); + +        STACK_DESTROY (frame->root); +        return 0; +} + + +static void +refresh_perms (call_frame_t *frame, inode_t *inode, struct posix_acl_ctx *ctx) +{ +        xlator_t        *this           = frame->this; +        xlator_t        *child          = FIRST_CHILD (this); +        call_frame_t    *newframe; +        loc_t           loc             = {NULL, }; + +        newframe = create_frame (this, this->ctx->pool); +        if (!newframe) { +                gf_log (this->name, GF_LOG_ERROR, "failed to allocate frame"); +                return; +        } + +        /* +         * WARNING: sharp edges +         * +         * Normally, continuing after STACK_WIND like this is a terrible idea +         * because we have no guarantee that the callback has executed by then. +         * That's why we have syncops and stubs, but syncops are going to muck +         * with our thread context and adding a stub for every single op is way +         * too invasive when we *do* happen to know that posix_stat will always +         * complete synchronously.  So this one time we can do the easy thing, +         * but it would be unwise to follow this example in less constrained +         * circumstances. +         */ +        gf_uuid_copy (loc.gfid, inode->gfid); +        STACK_WIND_COOKIE (newframe, refresh_perms_cbk, ctx, +                           child, child->fops->stat, &loc, NULL); + +        /* +         * If our assumption above was false and posix_stat didn't complete +         * synchronously (or someone foolishly put a delay-inducing translator +         * between us and them), we're probably still safe in terms of the +         * callback trying to access resources after we've continued from here +         * and freed them.  However, it would still be nice to know that perms +         * were in fact not updated. +         */ +        if (!ctx->was_set) { +                gf_log (this->name, GF_LOG_WARNING, +                        "perms were not refreshed before return"); +        } +} + +  static int  acl_permits (call_frame_t *frame, inode_t *inode, int want)  { @@ -198,6 +307,7 @@ acl_permits (call_frame_t *frame, inode_t *inode, int want)          int                     perm = 0;          int                     found = 0;          int                     acl_present = 0; +        static pe_ctx_t         pe_ctx = {PE_TYPE_NOT_SET, 0, _gf_true};          conf = frame->this->private; @@ -252,9 +362,15 @@ acl_permits (call_frame_t *frame, inode_t *inode, int want)                  case POSIX_ACL_MASK:                          break;                  case POSIX_ACL_OTHER: -                        perm = (ctx->perm & S_IRWXO); -                        if (!found) +                        if (!found) { +                                if (!ctx->was_set) { +                                        maybe_log_perm_error (frame->this, +                                                              inode, &pe_ctx); +                                        refresh_perms (frame, inode, ctx); +                                } +                                perm = (ctx->perm & S_IRWXO);                                  goto perm_check; +                        }                          /* fall through */                  default:                          goto red; @@ -276,6 +392,12 @@ mask_check:          }  perm_check: +        if (conf->liberal_permissions_mode >= IGNORE_ZERO_PERMS && perm == 0) { +                gf_log (frame->this->name, GF_LOG_INFO, +                        "ignoring zero perms on %s due to liberal-perms-mode", +                        uuid_utoa (inode->gfid)); +                goto green; +        }          if ((perm & want) == want) {                  goto green;          } else { @@ -286,7 +408,14 @@ green:          verdict = 1;          goto out;  red: -        verdict = 0; +        if (conf->liberal_permissions_mode >= IGNORE_ALL_PERMS) { +                gf_log (frame->this->name, GF_LOG_INFO, +                        "ignoring all perms on %s due to liberal-perms-mode", +                        uuid_utoa (inode->gfid)); +                 verdict = 1; +        } else { +                verdict = 0; +        }  out:          if (acl)                  posix_acl_unref (frame->this, acl); @@ -301,6 +430,7 @@ __posix_acl_ctx_get (inode_t *inode, xlator_t *this, gf_boolean_t create)          struct posix_acl_ctx *ctx = NULL;          uint64_t              int_ctx = 0;          int                   ret = 0; +        struct posix_acl_conf *conf = this->private;          ret = __inode_ctx_get (inode, this, &int_ctx);          if ((ret == 0) && (int_ctx)) @@ -313,6 +443,10 @@ __posix_acl_ctx_get (inode_t *inode, xlator_t *this, gf_boolean_t create)          if (!ctx)                  return NULL; +        if (conf->liberal_permissions_mode >= INIT_PERMS) { +                ctx->perm = 0777; +        } +          ret = __inode_ctx_put (inode, this, UINT64 (ctx));          return ctx; @@ -670,6 +804,7 @@ posix_acl_inherit (xlator_t *this, loc_t *loc, dict_t *params, mode_t mode,          mode_t                 retmode = 0;          int16_t                tmp_mode = 0;          mode_t                 client_umask = 0; +        static pe_ctx_t        pe_ctx = {PE_TYPE_SET_ZERO, 0, _gf_true};          retmode = mode;          client_umask = umask; @@ -701,6 +836,10 @@ posix_acl_inherit (xlator_t *this, loc_t *loc, dict_t *params, mode_t mode,          client_umask = 0; // No umask if we inherit an ACL          retmode = posix_acl_inherit_mode (acl_access, retmode);          ctx->perm = retmode; +        if (ctx->perm == 0) { +                maybe_log_perm_error (this, loc->inode, &pe_ctx); +        } +        ctx->was_set = _gf_true;          size_access = posix_acl_to_xattr (this, acl_access, NULL, 0);          xattr_access = GF_CALLOC (1, size_access, gf_posix_acl_mt_char); @@ -809,6 +948,7 @@ posix_acl_ctx_update (inode_t *inode, xlator_t *this, struct iatt *buf)                  ctx->uid   = buf->ia_uid;                  ctx->gid   = buf->ia_gid;                  ctx->perm  = st_mode_from_ia (buf->ia_prot, buf->ia_type); +                ctx->was_set = _gf_true;  		acl = ctx->acl_access;  		if (!acl || !(acl->count > POSIX_ACL_MINIMAL_ACE_COUNT)) @@ -1977,6 +2117,7 @@ posix_acl_setxattr_update (xlator_t *this, inode_t *inode, dict_t *xattr)          struct posix_acl     *old_default = NULL;          struct posix_acl_ctx *ctx = NULL;          int                   ret = 0; +        static pe_ctx_t       pe_ctx = {PE_TYPE_SET_ZERO, 0, _gf_true};          ctx = posix_acl_ctx_get (inode, this);          if (!ctx) @@ -1996,6 +2137,9 @@ posix_acl_setxattr_update (xlator_t *this, inode_t *inode, dict_t *xattr)          if (acl_access && acl_access != old_access) {                  posix_acl_access_set_mode (acl_access, ctx); +                if (ctx->perm == 0) { +                        maybe_log_perm_error (this, inode, &pe_ctx); +                }          }          if (acl_access) @@ -2292,6 +2436,8 @@ reconfigure (xlator_t *this, dict_t *options)          conf = this->private;          GF_OPTION_RECONF ("super-uid", conf->super_uid, options, uint32, err); +        GF_OPTION_RECONF ("liberal-perms-mode", conf->liberal_permissions_mode, options, +                          uint32, err);          return 0;  err: @@ -2329,6 +2475,7 @@ init (xlator_t *this)          conf->minimal_acl = minacl;          GF_OPTION_INIT ("super-uid", conf->super_uid, uint32, err); +        GF_OPTION_INIT ("liberal-perms-mode", conf->liberal_permissions_mode, uint32, err);          return 0;  err: @@ -2407,5 +2554,10 @@ struct volume_options options[] = {            .default_value = "0",            .description = "UID to be treated as super user's id instead of 0",          }, +        { .key = {"liberal-perms-mode"}, +          .type = GF_OPTION_TYPE_INT, +          .default_value = "0", +          .description = "assume liberal permissions if none have been set", +        },          { .key = {NULL} },  };  | 
