Skip to content

Commit c008f17

Browse files
committed
fix two possible local DoS
1 parent 18d7c33 commit c008f17

2 files changed

Lines changed: 41 additions & 3 deletions

File tree

smtpd/control.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ extern const char *backend_stat;
7373

7474
static uint32_t connid = 0;
7575
static struct tree ctl_conns;
76+
static struct tree ctl_count;
7677
static struct stat_digest digest;
7778

78-
#define CONTROL_FD_RESERVE 5
79+
#define CONTROL_FD_RESERVE 5
80+
#define CONTROL_MAXCONN_PER_CLIENT 5
7981

8082
static void
8183
control_imsg(struct mproc *p, struct imsg *imsg)
@@ -282,6 +284,7 @@ control(void)
282284
signal(SIGHUP, SIG_IGN);
283285

284286
tree_init(&ctl_conns);
287+
tree_init(&ctl_count);
285288

286289
memset(&digest, 0, sizeof digest);
287290
digest.startup = time(NULL);
@@ -330,6 +333,9 @@ control_accept(int listenfd, short event, void *arg)
330333
socklen_t len;
331334
struct sockaddr_un sun;
332335
struct ctl_conn *c;
336+
size_t *count;
337+
uid_t euid;
338+
gid_t egid;
333339

334340
if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE)
335341
goto pause;
@@ -346,16 +352,30 @@ control_accept(int listenfd, short event, void *arg)
346352

347353
session_socket_blockmode(connfd, BM_NONBLOCK);
348354

349-
c = xcalloc(1, sizeof(*c), "control_accept");
350-
if (getpeereid(connfd, &c->euid, &c->egid) == -1)
355+
if (getpeereid(connfd, &euid, &egid) == -1)
351356
fatal("getpeereid");
357+
358+
count = tree_get(&ctl_count, euid);
359+
if (count == NULL)
360+
count = xcalloc(1, sizeof *count, "control_accept");
361+
362+
if (*count == CONTROL_MAXCONN_PER_CLIENT) {
363+
close(connfd);
364+
return;
365+
}
366+
(*count)++;
367+
368+
c = xcalloc(1, sizeof(*c), "control_accept");
369+
c->euid = euid;
370+
c->egid = egid;
352371
c->id = ++connid;
353372
c->mproc.proc = PROC_CLIENT;
354373
c->mproc.handler = control_dispatch_ext;
355374
c->mproc.data = c;
356375
mproc_init(&c->mproc, connfd);
357376
mproc_enable(&c->mproc);
358377
tree_xset(&ctl_conns, c->id, c);
378+
tree_set(&ctl_count, c->euid, count);
359379

360380
stat_backend->increment("control.session", 1);
361381
return;
@@ -368,6 +388,16 @@ control_accept(int listenfd, short event, void *arg)
368388
static void
369389
control_close(struct ctl_conn *c)
370390
{
391+
size_t *count;
392+
393+
count = tree_get(&ctl_count, c->euid);
394+
(*count)--;
395+
if (*count == 0) {
396+
tree_xpop(&ctl_count, c->euid);
397+
free(count);
398+
}
399+
else
400+
tree_set(&ctl_count, c->euid, count);
371401
tree_xpop(&ctl_conns, c->id);
372402
mproc_clear(&c->mproc);
373403
free(c);

smtpd/mproc.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ mproc_dispatch(int fd, short event, void *arg)
188188

189189
for (;;) {
190190
if ((n = imsg_get(&p->imsgbuf, &imsg)) == -1) {
191+
192+
if (smtpd_process == PROC_CONTROL &&
193+
p->proc == PROC_CLIENT) {
194+
log_warnx("warn: client sent invalid imsg "
195+
"over control socket");
196+
p->handler(p, NULL);
197+
return;
198+
}
191199
log_warn("fatal: %s: error in imsg_get for %s",
192200
proc_name(smtpd_process), p->name);
193201
fatalx(NULL);

0 commit comments

Comments
 (0)