Anatomy of a Clients v3 RPC Call Header
Frank Sorensen recently noted that the Linux Client’s v3 size allocations for some operations may be incorrect. If that is the case, we’d expect to have reports of crashes, as this code is old. Let’s figure out what’s going on..
The question is why hasn’t anyone seen an overflow from req->rq_callsize:
1763 static void
1764 call_allocate(struct rpc_task *task)
1765 {
...
1784 /*
1785 * Calculate the size (in quads) of the RPC call
1786 * and reply headers, and convert both values
1787 * to byte sizes.
1788 */
1789 req->rq_callsize = RPC_CALLHDRSIZE + (auth->au_cslack << 1) +
1790 proc->p_arglen;
1791 req->rq_callsize <<= 2;
1792 /*
RPC_CALLHDRSIZE is 6 quad words. This should cover:
- unsigned int xid: 1
- enum msg_type: 1
- unsigned int rpcvers: 1
- unsigned int prog: 1
- unsigned int vers: 1
- unsigned int proc: 1
After this, the client adds auth->au_cslack, which for AUTH_SYS is set as UNX_CALLSLACK:
include/linux/sunrpc/auth.h:#define UNX_CALLSLACK (21 + XDR_QUADLEN(UNX_MAXNODENAME))
UNX_MAXNODENAME is __NEW_UTS_LEN is 64, which XDR_QUADLEN will take down to 16, so we have au_cslack of 37.
So, what are those 37 words? We now have an opaque_auth cred:
- unsigned int flavor: 1
- unsigned int length: 1
.. and then the AUTH_SYS cred body:
- unsigned int stamp: 1
- string machinename<255>: (linux only sends 64 bytes, so max here is 17):
- unsigned int length: 1
- body: 16
- unsigned int uid: 1
- unsigned int gid: 1
- unsigned int gids<16>: 17
for up to 39 words, then the opaque_auth verifier:
- auth_flavor: 1
- length: 1
We ought then to be up to 41 words needed in au_cslack for AUTH_SYS, not 37. We are saved from having a problem by the fact that the current code left-shifts our 37 into 74. This is likely the reason why our miscalculations in procedure are not causing crashes.