diff options
author | Niels de Vos <ndevos@redhat.com> | 2014-03-20 18:13:49 +0100 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-04-08 10:50:52 -0700 |
commit | 8235de189845986a535d676b1fd2c894b9c02e52 (patch) | |
tree | 6f5ea06d6b0b9b3f8091e0b9e7b34a7158afe3d1 /rpc/rpc-lib/src/rpc-clnt.c | |
parent | 07df69edc8165d875edd42a4080a494e09b98de5 (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.)
Change-Id: I8410e59d0fd246d601b54b961d3ae9cb5a858c10
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>
Diffstat (limited to 'rpc/rpc-lib/src/rpc-clnt.c')
-rw-r--r-- | rpc/rpc-lib/src/rpc-clnt.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/rpc/rpc-lib/src/rpc-clnt.c b/rpc/rpc-lib/src/rpc-clnt.c index 22513b789d6..e095c55b3d9 100644 --- a/rpc/rpc-lib/src/rpc-clnt.c +++ b/rpc/rpc-lib/src/rpc-clnt.c @@ -1133,17 +1133,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"); @@ -1154,6 +1171,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; } @@ -1319,6 +1339,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; @@ -1345,6 +1367,27 @@ 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.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.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.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)); |