harden ipc and frontend recovery
This commit is contained in:
186
ipc.c
Normal file
186
ipc.c
Normal file
@@ -0,0 +1,186 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include "ipc.h"
|
||||
|
||||
#if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE)
|
||||
#error "ipcsend requires MSG_NOSIGNAL or SO_NOSIGPIPE"
|
||||
#endif
|
||||
|
||||
static void
|
||||
putlen(unsigned char p[Ipclensz], size_t n)
|
||||
{
|
||||
p[0] = n;
|
||||
p[1] = n >> 8;
|
||||
}
|
||||
|
||||
static size_t
|
||||
getlen(const unsigned char p[Ipclensz])
|
||||
{
|
||||
return p[0] | (p[1] << 8);
|
||||
}
|
||||
|
||||
void
|
||||
ipcpackreq(unsigned char req[Ipcreqsz], int want, unsigned int mod,
|
||||
unsigned int key)
|
||||
{
|
||||
req[0] = want != 0;
|
||||
req[1] = mod;
|
||||
req[2] = key;
|
||||
req[3] = key >> 8;
|
||||
req[4] = key >> 16;
|
||||
req[5] = key >> 24;
|
||||
}
|
||||
|
||||
void
|
||||
ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, unsigned int *mod,
|
||||
unsigned int *key)
|
||||
{
|
||||
*want = req[0] != 0;
|
||||
*mod = req[1];
|
||||
*key = (unsigned int)req[2] |
|
||||
((unsigned int)req[3] << 8) |
|
||||
((unsigned int)req[4] << 16) |
|
||||
((unsigned int)req[5] << 24);
|
||||
}
|
||||
|
||||
int
|
||||
ipcpackresp(unsigned char *dst, size_t cap, int eaten,
|
||||
const char *commit, size_t ncommit, const char *preedit, size_t npreedit,
|
||||
int want)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
if(ncommit > Ipcfieldmax || npreedit > Ipcfieldmax)
|
||||
return -1;
|
||||
if((ncommit > 0 && commit == NULL) ||
|
||||
(want && npreedit > 0 && preedit == NULL))
|
||||
return -1;
|
||||
n = Ipcresphdrsz + ncommit + (want ? Ipclensz + npreedit : 0);
|
||||
if(dst == NULL || cap < n)
|
||||
return -1;
|
||||
dst[0] = eaten != 0;
|
||||
putlen(dst + 1, ncommit);
|
||||
if(ncommit > 0)
|
||||
memcpy(dst + Ipcresphdrsz, commit, ncommit);
|
||||
if(want){
|
||||
putlen(dst + Ipcresphdrsz + ncommit, npreedit);
|
||||
if(npreedit > 0)
|
||||
memcpy(dst + Ipcresphdrsz + ncommit + Ipclensz,
|
||||
preedit, npreedit);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
ipcreadn(int fd, void *buf, size_t n)
|
||||
{
|
||||
unsigned char *p;
|
||||
ssize_t r;
|
||||
|
||||
p = buf;
|
||||
while(n > 0){
|
||||
r = read(fd, p, n);
|
||||
if(r < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(r <= 0)
|
||||
return -1;
|
||||
p += r;
|
||||
n -= r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipcsend(int fd, const void *buf, size_t n)
|
||||
{
|
||||
const unsigned char *p;
|
||||
ssize_t r;
|
||||
int flags;
|
||||
#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
|
||||
int one, sr;
|
||||
#endif
|
||||
|
||||
p = buf;
|
||||
#ifdef MSG_NOSIGNAL
|
||||
flags = MSG_NOSIGNAL;
|
||||
#else
|
||||
flags = 0;
|
||||
#ifdef SO_NOSIGPIPE
|
||||
one = 1;
|
||||
do
|
||||
sr = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof one);
|
||||
while(sr < 0 && errno == EINTR);
|
||||
if(sr < 0)
|
||||
return -1;
|
||||
#endif
|
||||
#endif
|
||||
while(n > 0){
|
||||
r = send(fd, p, n, flags);
|
||||
if(r < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(r <= 0)
|
||||
return -1;
|
||||
p += r;
|
||||
n -= r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
readfield(int fd, size_t n, char *dst, size_t cap)
|
||||
{
|
||||
unsigned char discard[128];
|
||||
size_t keep, part;
|
||||
|
||||
if(cap > 0 && dst == NULL)
|
||||
return -1;
|
||||
keep = 0;
|
||||
if(cap > 0)
|
||||
keep = n >= cap ? cap - 1 : n;
|
||||
if(keep > 0 && ipcreadn(fd, dst, keep) < 0)
|
||||
return -1;
|
||||
if(cap > 0)
|
||||
dst[keep] = '\0';
|
||||
n -= keep;
|
||||
while(n > 0){
|
||||
part = n < sizeof discard ? n : sizeof discard;
|
||||
if(ipcreadn(fd, discard, part) < 0)
|
||||
return -1;
|
||||
n -= part;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipcreadresp(int fd, int want, char *commit, size_t ccap,
|
||||
char *preedit, size_t pcap, Ipcresp *resp)
|
||||
{
|
||||
unsigned char hdr[Ipcresphdrsz], npreedit[Ipclensz];
|
||||
|
||||
if(resp == NULL || (ccap > 0 && commit == NULL) ||
|
||||
(pcap > 0 && preedit == NULL))
|
||||
return -1;
|
||||
if(ccap > 0)
|
||||
commit[0] = '\0';
|
||||
if(pcap > 0)
|
||||
preedit[0] = '\0';
|
||||
memset(resp, 0, sizeof *resp);
|
||||
if(ipcreadn(fd, hdr, sizeof hdr) < 0)
|
||||
return -1;
|
||||
resp->eaten = hdr[0] != 0;
|
||||
resp->ncommit = getlen(hdr + 1);
|
||||
if(resp->ncommit > Ipcfieldmax)
|
||||
return -1;
|
||||
if(readfield(fd, resp->ncommit, commit, ccap) < 0)
|
||||
return -1;
|
||||
if(!want)
|
||||
return 0;
|
||||
if(ipcreadn(fd, npreedit, sizeof npreedit) < 0)
|
||||
return -1;
|
||||
resp->npreedit = getlen(npreedit);
|
||||
if(resp->npreedit > Ipcfieldmax)
|
||||
return -1;
|
||||
return readfield(fd, resp->npreedit, preedit, pcap);
|
||||
}
|
||||
Reference in New Issue
Block a user