summaryrefslogtreecommitdiffstats
path: root/rpc/rpc-lib/src/rpc-clnt.c
diff options
context:
space:
mode:
authorNiels de Vos <ndevos@redhat.com>2014-05-11 22:51:15 -0300
committerNiels de Vos <ndevos@redhat.com>2014-05-22 06:02:21 -0700
commit57ec16e7f6d08b9a1c07f8ece3db630b08557372 (patch)
tree3e09ed682dc989fbe7741c6c4cc0ea40318ddc42 /rpc/rpc-lib/src/rpc-clnt.c
parent0ba8c6113058ae2ab2a2e38e11a2c95d75056a3b (diff)
rpc: warn and truncate grouplist if RPC/AUTH can not hold everything
The GlusterFS protocol currently uses AUTH_GLUSTERFS_V2 in the RPC/AUTH header. This header contains the uid, gid and auxiliary groups of the user/process that accesses the Gluster Volume. The AUTH_GLUSTERFS_V2 structure allows up to 65535 auxiliary groups to be passed on. Unfortunately, the RPC/AUTH header is limited to 400 bytes by the RPC specification: http://tools.ietf.org/html/rfc5531#section-8.2 In order to not cause complete failures on the client-side when trying to encode a AUTH_GLUSTERFS_V2 that would result in more than 400 bytes, we can calculate the expected size of the other elements: 1 | pid 1 | uid 1 | gid 1 | groups_len XX | groups_val (GF_MAX_AUX_GROUPS=65535) 1 | lk_owner_len YY | lk_owner_val (GF_MAX_LOCK_OWNER_LEN=1024) ----+------------------------------------------- 5 | total xdr-units one XDR-unit is defined as BYTES_PER_XDR_UNIT = 4 bytes MAX_AUTH_BYTES = 400 is the maximum, this is 100 xdr-units. XX + YY can be 95 to fill the 100 xdr-units. Note that the on-wire protocol has tighter requirements than the internal structures. It is possible for xlators to use more groups and a bigger lk_owner than that can be sent by a GlusterFS-client. This change prevents overflows when allocating the RPC/AUTH header. Two new macros are introduced to calculate the number of groups that fit in the RPC/AUTH header, when taking the size of the lk_owner in account. In case the list of groups exceeds the maximum possible, only the first groups are passed over the RPC/GlusterFS protocol to the bricks. A warning is added to the logs, so that most system administrators will get informed. The reducing of the number of groups is not a new inventions. The RPC/AUTH header (AUTH_SYS or AUTH_UNIX) that NFS uses has a limit of 16 groups. Most, if not all, NFS-clients will reduce any bigger number of groups to 16. (nfs.server-aux-gids can be used to workaround the limit of 16 groups, but the Gluster NFS-server will be limited to a maximum of 93 groups, or fewer in case the lk_owner structure contains more items.) Cherry picked from commit 8235de189845986a535d676b1fd2c894b9c02e52: > BUG: 1053579 > Signed-off-by: Niels de Vos <ndevos@redhat.com> > Reviewed-on: http://review.gluster.org/7202 > Tested-by: Gluster Build System <jenkins@build.gluster.com> > Reviewed-by: Harshavardhana <harsha@harshavardhana.net> > Reviewed-by: Santosh Pradhan <spradhan@redhat.com> > Reviewed-by: Vijay Bellur <vbellur@redhat.com> Change-Id: I8410e59d0fd246d601b54b961d3ae9cb5a858c10 BUG: 1096425 Signed-off-by: Niels de Vos <ndevos@redhat.com> Reviewed-on: http://review.gluster.org/7829 Reviewed-by: Lalatendu Mohanty <lmohanty@redhat.com> Tested-by: Gluster Build System <jenkins@build.gluster.com>
Diffstat (limited to 'rpc/rpc-lib/src/rpc-clnt.c')
-rw-r--r--rpc/rpc-lib/src/rpc-clnt.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/rpc/rpc-lib/src/rpc-clnt.c b/rpc/rpc-lib/src/rpc-clnt.c
index 1e9f307be40..ff3231d7f8d 100644
--- a/rpc/rpc-lib/src/rpc-clnt.c
+++ b/rpc/rpc-lib/src/rpc-clnt.c
@@ -1095,17 +1095,34 @@ rpc_clnt_register_notify (struct rpc_clnt *rpc, rpc_clnt_notify_t fn,
return 0;
}
+/* used for GF_LOG_OCCASIONALLY() */
+static int gf_auth_max_groups_log = 0;
+
ssize_t
xdr_serialize_glusterfs_auth (char *dest, struct auth_glusterfs_parms_v2 *au)
{
ssize_t ret = -1;
XDR xdr;
+ uint64_t ngroups = 0;
+ int max_groups = 0;
if ((!dest) || (!au))
return -1;
+ max_groups = GF_AUTH_GLUSTERFS_MAX_GROUPS (au->lk_owner.lk_owner_len);
+
xdrmem_create (&xdr, dest, GF_MAX_AUTH_BYTES, XDR_ENCODE);
+ if (au->groups.groups_len > max_groups) {
+ ngroups = au->groups.groups_len;
+ au->groups.groups_len = max_groups;
+
+ GF_LOG_OCCASIONALLY (gf_auth_max_groups_log,
+ THIS->name, GF_LOG_WARNING,
+ "too many groups, reducing %ld -> %d",
+ ngroups, max_groups);
+ }
+
if (!xdr_auth_glusterfs_parms_v2 (&xdr, au)) {
gf_log (THIS->name, GF_LOG_WARNING,
"failed to encode auth glusterfs elements");
@@ -1116,6 +1133,9 @@ xdr_serialize_glusterfs_auth (char *dest, struct auth_glusterfs_parms_v2 *au)
ret = (((size_t)(&xdr)->x_private) - ((size_t)(&xdr)->x_base));
ret:
+ if (ngroups)
+ au->groups.groups_len = ngroups;
+
return ret;
}
@@ -1281,6 +1301,8 @@ rpc_clnt_record (struct rpc_clnt *clnt, call_frame_t *call_frame,
struct auth_glusterfs_parms_v2 au = {0, };
struct iobuf *request_iob = NULL;
char owner[4] = {0,};
+ int max_groups = 0;
+ int max_lkowner_len = 0;
if (!prog || !rpchdr || !call_frame) {
goto out;
@@ -1307,6 +1329,28 @@ rpc_clnt_record (struct rpc_clnt *clnt, call_frame_t *call_frame,
au.lk_owner.lk_owner_len = 4;
}
+ /* The number of groups and the size of lk_owner depend on oneother.
+ * We can truncate the groups, but should not touch the lk_owner. */
+ max_groups = GF_AUTH_GLUSTERFS_MAX_GROUPS (au.lk_owner.lk_owner_len);
+ if (au.groups.groups_len > max_groups) {
+ GF_LOG_OCCASIONALLY (gf_auth_max_groups_log,
+ clnt->conn.trans->name,
+ GF_LOG_WARNING, "truncating grouplist "
+ "from %d to %d", au.groups.groups_len,
+ max_groups);
+
+ au.groups.groups_len = max_groups;
+ }
+
+ max_lkowner_len = GF_AUTH_GLUSTERFS_MAX_LKOWNER (au.groups.groups_len);
+ if (au.lk_owner.lk_owner_len > max_lkowner_len) {
+ gf_log (clnt->conn.trans->name, GF_LOG_ERROR, "lkowner field "
+ "is too big (%d), it does not fit in the rpc-header",
+ au.lk_owner.lk_owner_len);
+ errno = E2BIG;
+ goto out;
+ }
+
gf_log (clnt->conn.trans->name, GF_LOG_TRACE, "Auth Info: pid: %u, uid: %d"
", gid: %d, owner: %s", au.pid, au.uid, au.gid,
lkowner_utoa (&call_frame->root->lk_owner));