1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-01 03:22:48 -05:00

Build SSH agent reply messages in a BinarySink.

This gets rid of yet another huge pile of beating around the bush with
length-counting. Also, this time, the BinarySink in question is a
little more interesting than just being a strbuf every time: on
Windows, where the shared-memory Pageant IPC system imposes a hard
limit on the size of message we can return, I've written a custom
BinarySink implementation that collects up to that much data and then
gives up and sets an overflow flag rather than continue to allocate
memory.

So the main Pageant code no longer has to worry about checking
AGENT_MAX_MSGLEN all the time - and better still, the Unix version of
Pageant is no longer _limited_ by AGENT_MAX_MSGLEN in its outgoing
messages, i.e. it could store a really extra large number of keys if
it needed to. That limitation is now a local feature of Windows
Pageant rather than intrinsic to the whole code base.

(AGENT_MAX_MSGLEN is still used to check incoming agent messages for
sanity, however. Mostly that's because I feel I ought to check them
against _some_ limit, and this one seems sensible enough. Incoming
agent messages are more bounded anyway - they generally don't hold
more than _one_ private key.)
This commit is contained in:
Simon Tatham
2018-05-24 13:23:17 +01:00
parent 0c44fa85df
commit b6cbad89fc
3 changed files with 234 additions and 237 deletions

View File

@ -376,22 +376,46 @@ void keylist_update(void)
}
}
struct PageantReply {
char buf[AGENT_MAX_MSGLEN - 4];
int len, overflowed;
BinarySink_IMPLEMENTATION;
};
static void pageant_reply_BinarySink_write(
BinarySink *bs, const void *data, size_t len)
{
struct PageantReply *rep = BinarySink_DOWNCAST(bs, struct PageantReply);
if (!rep->overflowed && len <= sizeof(rep->buf) - rep->len) {
memcpy(rep->buf + rep->len, data, len);
rep->len += len;
} else {
rep->overflowed = TRUE;
}
}
static void answer_msg(void *msgv)
{
unsigned char *msg = (unsigned char *)msgv;
unsigned msglen;
void *reply;
int replylen;
struct PageantReply reply;
reply.len = 0;
reply.overflowed = FALSE;
BinarySink_INIT(&reply, pageant_reply_BinarySink_write);
msglen = GET_32BIT(msg);
if (msglen > AGENT_MAX_MSGLEN) {
reply = pageant_failure_msg(&replylen);
pageant_failure_msg(BinarySink_UPCAST(&reply),
"incoming length field too large", NULL, NULL);
} else {
reply = pageant_handle_msg(msg + 4, msglen, &replylen, NULL, NULL);
if (replylen > AGENT_MAX_MSGLEN) {
smemclr(reply, replylen);
sfree(reply);
reply = pageant_failure_msg(&replylen);
pageant_handle_msg(BinarySink_UPCAST(&reply),
msg + 4, msglen, NULL, NULL);
if (reply.len > AGENT_MAX_MSGLEN) {
reply.len = 0;
reply.overflowed = FALSE;
pageant_failure_msg(BinarySink_UPCAST(&reply),
"output would exceed max msglen", NULL, NULL);
}
}
@ -399,9 +423,10 @@ static void answer_msg(void *msgv)
* Windows Pageant answers messages in place, by overwriting the
* input message buffer.
*/
memcpy(msg, reply, replylen);
smemclr(reply, replylen);
sfree(reply);
assert(4 + reply.len <= AGENT_MAX_MSGLEN);
PUT_32BIT(msg, reply.len);
memcpy(msg + 4, reply.buf, reply.len);
smemclr(reply.buf, sizeof(reply.buf));
}
static void win_add_keyfile(Filename *filename)