From b24003342eb707027982599a7bac485fe3b9f465 Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Fri, 8 Feb 2013 11:44:41 +0530 Subject: rpc: bring in root-squashing behavior in rpc * requests coming in as root are converted to nfsnobody * with open-behind some acl checks wont happen and nfsnobody can read the file "whose owner is root and other users do not have permission to read the file". This is becasue open-behind does not send the open to the brick and sends success to the application, thus the acl related tests on the file wont happen which would have prevented the file from being opened. Change-Id: I12a3e6b2a12884d00bb81f2779074fed09b1b2e4 BUG: 887145 Signed-off-by: Raghavendra Bhat Reviewed-on: http://review.gluster.org/4619 Tested-by: Gluster Build System Reviewed-by: Jeff Darcy --- rpc/rpc-lib/src/auth-glusterfs.c | 6 +- rpc/rpc-lib/src/rpcsvc-auth.c | 16 ++++++ rpc/rpc-lib/src/rpcsvc-common.h | 1 + rpc/rpc-lib/src/rpcsvc.h | 23 +++++++- tests/bugs/bug-887145.t | 85 +++++++++++++++++++++++++++++ xlators/mgmt/glusterd/src/glusterd-volgen.c | 1 + xlators/protocol/server/src/server.c | 9 +++ 7 files changed, 139 insertions(+), 2 deletions(-) create mode 100755 tests/bugs/bug-887145.t diff --git a/rpc/rpc-lib/src/auth-glusterfs.c b/rpc/rpc-lib/src/auth-glusterfs.c index c08871466..9c6f8385b 100644 --- a/rpc/rpc-lib/src/auth-glusterfs.c +++ b/rpc/rpc-lib/src/auth-glusterfs.c @@ -64,9 +64,9 @@ int auth_glusterfs_authenticate (rpcsvc_request_t *req, void *priv) struct auth_glusterfs_parms au = {0,}; int ret = RPCSVC_AUTH_REJECT; - int gidcount = 0; int j = 0; int i = 0; + int gidcount = 0; if (!req) return ret; @@ -99,6 +99,8 @@ int auth_glusterfs_authenticate (rpcsvc_request_t *req, void *priv) for (gidcount = 0; gidcount < au.ngrps; ++gidcount) req->auxgids[gidcount] = au.groups[gidcount]; + RPC_AUTH_ROOT_SQUASH(req); + gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth Info: pid: %u, uid: %d" ", gid: %d, owner: %s", req->pid, req->uid, req->gid, lkowner_utoa (&req->lk_owner)); @@ -207,6 +209,8 @@ int auth_glusterfs_v2_authenticate (rpcsvc_request_t *req, void *priv) for (i = 0; i < au.lk_owner.lk_owner_len; ++i) req->lk_owner.data[i] = au.lk_owner.lk_owner_val[i]; + RPC_AUTH_ROOT_SQUASH(req); + gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth Info: pid: %u, uid: %d" ", gid: %d, owner: %s", req->pid, req->uid, req->gid, lkowner_utoa (&req->lk_owner)); diff --git a/rpc/rpc-lib/src/rpcsvc-auth.c b/rpc/rpc-lib/src/rpcsvc-auth.c index 3a46cc498..907ae1ec9 100644 --- a/rpc/rpc-lib/src/rpcsvc-auth.c +++ b/rpc/rpc-lib/src/rpcsvc-auth.c @@ -203,6 +203,21 @@ rpcsvc_set_allow_insecure (rpcsvc_t *svc, dict_t *options) return 0; } +int +rpcsvc_set_root_squash (rpcsvc_t *svc, dict_t *options) +{ + GF_ASSERT (svc); + GF_ASSERT (options); + + if (dict_get_str_boolean (options, "root-squash", 0)) + svc->root_squash = _gf_true; + + if (svc->root_squash) + gf_log (GF_RPCSVC, GF_LOG_DEBUG, "root squashing enabled "); + + return 0; +} + int rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options) { @@ -212,6 +227,7 @@ rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options) return -1; (void) rpcsvc_set_allow_insecure (svc, options); + (void) rpcsvc_set_root_squash (svc, options); ret = rpcsvc_auth_add_initers (svc); if (ret == -1) { gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add initers"); diff --git a/rpc/rpc-lib/src/rpcsvc-common.h b/rpc/rpc-lib/src/rpcsvc-common.h index 81f798116..2c6f07488 100644 --- a/rpc/rpc-lib/src/rpcsvc-common.h +++ b/rpc/rpc-lib/src/rpcsvc-common.h @@ -52,6 +52,7 @@ typedef struct rpcsvc_state { /* Allow insecure ports. */ int allow_insecure; gf_boolean_t register_portmap; + gf_boolean_t root_squash; glusterfs_ctx_t *ctx; /* list of connections which will listen for incoming connections */ diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h index 7fdeaeb04..1323c8b7a 100644 --- a/rpc/rpc-lib/src/rpcsvc.h +++ b/rpc/rpc-lib/src/rpcsvc.h @@ -48,6 +48,10 @@ #define RPCSVC_POOLCOUNT_MULT 64 #define RPCSVC_CONN_READ (128 * GF_UNIT_KB) #define RPCSVC_PAGE_SIZE (128 * GF_UNIT_KB) +#define RPC_ROOT_UID 0 +#define RPC_ROOT_GID 0 +#define RPC_NOBODY_UID 65534 +#define RPC_NOBODY_GID 65534 /* RPC Record States */ #define RPCSVC_READ_FRAGHDR 1 @@ -261,7 +265,22 @@ struct rpcsvc_request { #define rpcsvc_request_vecstate(req) ((req)->vecstate) #define rpcsvc_request_transport(req) ((req)->trans) #define rpcsvc_request_transport_ref(req) (rpc_transport_ref((req)->trans)) - +#define RPC_AUTH_ROOT_SQUASH(req) \ + do { \ + int gidcount = 0; \ + if (req->svc->root_squash) { \ + if (req->uid == RPC_ROOT_UID) \ + req->uid = RPC_NOBODY_UID; \ + if (req->gid == RPC_ROOT_GID) \ + req->gid = RPC_NOBODY_GID; \ + for (gidcount = 0; gidcount < req->auxgidcount; \ + ++gidcount) { \ + if (!req->auxgids[gidcount]) \ + req->auxgids[gidcount] = \ + RPC_NOBODY_GID; \ + } \ + } \ + } while (0); #define RPCSVC_ACTOR_SUCCESS 0 #define RPCSVC_ACTOR_ERROR (-1) @@ -546,6 +565,8 @@ rpcsvc_transport_unix_options_build (dict_t **options, char *filepath); int rpcsvc_set_allow_insecure (rpcsvc_t *svc, dict_t *options); int +rpcsvc_set_root_squash (rpcsvc_t *svc, dict_t *options); +int rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen); char * rpcsvc_volume_allowed (dict_t *options, char *volname); diff --git a/tests/bugs/bug-887145.t b/tests/bugs/bug-887145.t new file mode 100755 index 000000000..8e5f03900 --- /dev/null +++ b/tests/bugs/bug-887145.t @@ -0,0 +1,85 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2}; +TEST $CLI volume set $V0 performance.open-behind off; +TEST $CLI volume start $V0 + +sleep 2; +## Mount FUSE with caching disabled +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0; + +sleep 2; + +TEST mount -t nfs -o vers=3,nolock $H0:/$V0 $N0; + +useradd tmp_user 2>/dev/null 1>/dev/null; +mkdir $M0/dir; +mkdir $M0/other; +cp /etc/passwd $M0/; +cp $M0/passwd $M0/file; +chmod 600 $M0/file; + +chown -R nfsnobody:nfsnobody $M0/dir; +chown -R tmp_user:tmp_user $M0/other; + +TEST $CLI volume set $V0 server.root-squash on; + +sleep 2; + +# create files and directories in the root of the glusterfs and nfs mount +# which is owned by root and hence the right behavior is getting EACCESS +# as the fops are executed as nfsnobody. +touch $M0/foo 2>/dev/null; +TEST [ $? -ne 0 ] +touch $N0/foo 2>/dev/null; +TEST [ $? -ne 0 ] +mkdir $M0/new 2>/dev/null; +TEST [ $? -ne 0 ] +mkdir $N0/new 2>/dev/null; +TEST [ $? -ne 0 ] +cp $M0/file $M0/tmp_file 2>/dev/null; +TEST [ $? -ne 0 ] +cp $N0/file $N0/tmp_file 2>/dev/null; +TEST [ $? -ne 0 ] +cat $M0/file 2>/dev/null; +TEST [ $? -ne 0 ] +# here read should be allowed because eventhough file "passwd" is owned +# by root, the permissions if the file allow other users to read it. +cat $M0/passwd 1>/dev/null; +TEST [ $? -eq 0 ] +cat $N0/passwd 1>/dev/null; +TEST [ $? -eq 0 ] + +# create files and directories should succeed as the fops are being executed +# inside the directory owned by nfsnobody +TEST touch $M0/dir/file; +TEST touch $N0/dir/foo; +TEST mkdir $M0/dir/new; +TEST mkdir $N0/dir/other; +TEST rm -f $M0/dir/file $M0/dir/foo; +TEST rmdir $N0/dir/*; + +# create files and directories here should fail as other directory is owned +# by tmp_user. +touch $M0/other/foo 2>/dev/null; +TEST [ $? -ne 0 ] +touch $N0/other/foo 2>/dev/null; +TEST [ $? -ne 0 ] +mkdir $M0/other/new 2>/dev/null; +TEST [ $? -ne 0 ] +mkdir $N0/other/new 2>/dev/null; +TEST [ $? -ne 0 ] + +userdel tmp_user; +rm -rf /home/tmp_user; + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup; diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index f89cd3a49..cd7ea7f62 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -191,6 +191,7 @@ static struct volopt_map_entry glusterd_volopt_map[] = { {"transport.keepalive", "protocol/server", "transport.socket.keepalive", NULL, NO_DOC, 0, 1}, {"server.allow-insecure", "protocol/server", "rpc-auth-allow-insecure", NULL, NO_DOC, 0, 1}, + {"server.root-squash", "protocol/server", "root-squash", NULL, DOC, 0, 2}, {"server.statedump-path", "protocol/server", "statedump-path", NULL, DOC, 0, 1}, {"features.lock-heal", "protocol/server", "lk-heal", NULL, NO_DOC, 0, 1}, {"features.grace-timeout", "protocol/server", "grace-timeout", NULL, NO_DOC, 0, 1}, diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c index 9e60febfb..3a5f84b1d 100644 --- a/xlators/protocol/server/src/server.c +++ b/xlators/protocol/server/src/server.c @@ -993,6 +993,7 @@ reconfigure (xlator_t *this, dict_t *options) } (void) rpcsvc_set_allow_insecure (rpc_conf, options); + (void) rpcsvc_set_root_squash (rpc_conf, options); list_for_each_entry (listeners, &(rpc_conf->listeners), list) { if (listeners->trans != NULL) { if (listeners->trans->reconfigure ) @@ -1274,6 +1275,14 @@ struct volume_options options[] = { { .key = {"rpc-auth-allow-insecure"}, .type = GF_OPTION_TYPE_BOOL, }, + { .key = {"root-squash"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + .description = "Map requests from uid/gid 0 to the anonymous " + "uid/gid. Note that this does not apply to any other" + "uids or gids that might be equally sensitive, such as" + "user bin or group staff." + }, { .key = {"statedump-path"}, .type = GF_OPTION_TYPE_PATH, .default_value = DEFAULT_VAR_RUN_DIRECTORY, -- cgit