Be more robust against misbehaving clients, prompted by deraadt based on

a report from sai02 at student dot ubc dot ca.
This commit is contained in:
nicm
2025-08-26 07:00:22 +00:00
parent 94bafa5aaf
commit 3520e833a4

View File

@ -61,9 +61,9 @@ static void server_client_set_path(struct client *);
static void server_client_reset_state(struct client *);
static void server_client_update_latest(struct client *);
static void server_client_dispatch(struct imsg *, void *);
static void server_client_dispatch_command(struct client *, struct imsg *);
static void server_client_dispatch_identify(struct client *, struct imsg *);
static void server_client_dispatch_shell(struct client *);
static int server_client_dispatch_command(struct client *, struct imsg *);
static int server_client_dispatch_identify(struct client *, struct imsg *);
static int server_client_dispatch_shell(struct client *);
static void server_client_report_theme(struct client *, enum client_theme);
/* Compare client windows. */
@ -3343,14 +3343,16 @@ server_client_dispatch(struct imsg *imsg, void *arg)
case MSG_IDENTIFY_TERMINFO:
case MSG_IDENTIFY_TTYNAME:
case MSG_IDENTIFY_DONE:
server_client_dispatch_identify(c, imsg);
if (server_client_dispatch_identify(c, imsg) != 0)
goto bad;
break;
case MSG_COMMAND:
server_client_dispatch_command(c, imsg);
if (server_client_dispatch_command(c, imsg) != 0)
goto bad;
break;
case MSG_RESIZE:
if (datalen != 0)
fatalx("bad MSG_RESIZE size");
goto bad;
if (c->flags & CLIENT_CONTROL)
break;
@ -3368,7 +3370,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
break;
case MSG_EXITING:
if (datalen != 0)
fatalx("bad MSG_EXITING size");
goto bad;
server_client_set_session(c, NULL);
recalculate_sizes();
tty_close(&c->tty);
@ -3377,7 +3379,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
case MSG_WAKEUP:
case MSG_UNLOCK:
if (datalen != 0)
fatalx("bad MSG_WAKEUP size");
goto bad;
if (!(c->flags & CLIENT_SUSPENDED))
break;
@ -3399,9 +3401,9 @@ server_client_dispatch(struct imsg *imsg, void *arg)
break;
case MSG_SHELL:
if (datalen != 0)
fatalx("bad MSG_SHELL size");
server_client_dispatch_shell(c);
goto bad;
if (server_client_dispatch_shell(c) != 0)
goto bad;
break;
case MSG_WRITE_READY:
file_write_ready(&c->files, imsg);
@ -3413,6 +3415,12 @@ server_client_dispatch(struct imsg *imsg, void *arg)
file_read_done(&c->files, imsg);
break;
}
return;
bad:
log_debug("client %p invalid message type %d", c, imsg->hdr.type);
proc_kill_peer(c->peer);
}
/* Callback when command is not allowed. */
@ -3440,7 +3448,7 @@ server_client_command_done(struct cmdq_item *item, __unused void *data)
}
/* Handle command message. */
static void
static int
server_client_dispatch_command(struct client *c, struct imsg *imsg)
{
struct msg_command data;
@ -3454,16 +3462,16 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
struct cmd_list *cmdlist;
if (c->flags & CLIENT_EXIT)
return;
return (0);
if (imsg->hdr.len - IMSG_HEADER_SIZE < sizeof data)
fatalx("bad MSG_COMMAND size");
return (-1);
memcpy(&data, imsg->data, sizeof data);
buf = (char *)imsg->data + sizeof data;
len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data;
len = imsg->hdr.len - IMSG_HEADER_SIZE - sizeof data;
if (len > 0 && buf[len - 1] != '\0')
fatalx("bad MSG_COMMAND string");
return (-1);
if (cmd_unpack_argv(buf, len, data.argc, &argv) != 0) {
cause = xstrdup("command too long");
@ -3499,7 +3507,7 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg)
cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL));
cmd_list_free(cmdlist);
return;
return (0);
error:
cmd_free_argv(argc, argv);
@ -3508,10 +3516,11 @@ error:
free(cause);
c->flags |= CLIENT_EXIT;
return (0);
}
/* Handle identify message. */
static void
static int
server_client_dispatch_identify(struct client *c, struct imsg *imsg)
{
const char *data, *home;
@ -3521,7 +3530,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
char *name;
if (c->flags & CLIENT_IDENTIFIED)
fatalx("out-of-order identify message");
return (-1);
data = imsg->data;
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
@ -3529,7 +3538,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
switch (imsg->hdr.type) {
case MSG_IDENTIFY_FEATURES:
if (datalen != sizeof feat)
fatalx("bad MSG_IDENTIFY_FEATURES size");
return (-1);
memcpy(&feat, data, sizeof feat);
c->term_features |= feat;
log_debug("client %p IDENTIFY_FEATURES %s", c,
@ -3537,14 +3546,14 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
break;
case MSG_IDENTIFY_FLAGS:
if (datalen != sizeof flags)
fatalx("bad MSG_IDENTIFY_FLAGS size");
return (-1);
memcpy(&flags, data, sizeof flags);
c->flags |= flags;
log_debug("client %p IDENTIFY_FLAGS %#x", c, flags);
break;
case MSG_IDENTIFY_LONGFLAGS:
if (datalen != sizeof longflags)
fatalx("bad MSG_IDENTIFY_LONGFLAGS size");
return (-1);
memcpy(&longflags, data, sizeof longflags);
c->flags |= longflags;
log_debug("client %p IDENTIFY_LONGFLAGS %#llx", c,
@ -3552,16 +3561,13 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
break;
case MSG_IDENTIFY_TERM:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_TERM string");
if (*data == '\0')
c->term_name = xstrdup("unknown");
else
c->term_name = xstrdup(data);
return (-1);
c->term_name = xstrdup(data);
log_debug("client %p IDENTIFY_TERM %s", c, data);
break;
case MSG_IDENTIFY_TERMINFO:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_TERMINFO string");
return (-1);
c->term_caps = xreallocarray(c->term_caps, c->term_ncaps + 1,
sizeof *c->term_caps);
c->term_caps[c->term_ncaps++] = xstrdup(data);
@ -3569,13 +3575,13 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
break;
case MSG_IDENTIFY_TTYNAME:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_TTYNAME string");
return (-1);
c->ttyname = xstrdup(data);
log_debug("client %p IDENTIFY_TTYNAME %s", c, data);
break;
case MSG_IDENTIFY_CWD:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_CWD string");
return (-1);
if (access(data, X_OK) == 0)
c->cwd = xstrdup(data);
else if ((home = find_home()) != NULL)
@ -3586,26 +3592,26 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
break;
case MSG_IDENTIFY_STDIN:
if (datalen != 0)
fatalx("bad MSG_IDENTIFY_STDIN size");
return (-1);
c->fd = imsg_get_fd(imsg);
log_debug("client %p IDENTIFY_STDIN %d", c, c->fd);
break;
case MSG_IDENTIFY_STDOUT:
if (datalen != 0)
fatalx("bad MSG_IDENTIFY_STDOUT size");
return (-1);
c->out_fd = imsg_get_fd(imsg);
log_debug("client %p IDENTIFY_STDOUT %d", c, c->out_fd);
break;
case MSG_IDENTIFY_ENVIRON:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_ENVIRON string");
return (-1);
if (strchr(data, '=') != NULL)
environ_put(c->environ, data, 0);
log_debug("client %p IDENTIFY_ENVIRON %s", c, data);
break;
case MSG_IDENTIFY_CLIENTPID:
if (datalen != sizeof c->pid)
fatalx("bad MSG_IDENTIFY_CLIENTPID size");
return (-1);
memcpy(&c->pid, data, sizeof c->pid);
log_debug("client %p IDENTIFY_CLIENTPID %ld", c, (long)c->pid);
break;
@ -3614,10 +3620,15 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
}
if (imsg->hdr.type != MSG_IDENTIFY_DONE)
return;
return (0);
c->flags |= CLIENT_IDENTIFIED;
if (*c->ttyname != '\0')
if (c->term_name == NULL || *c->term_name == '\0') {
free(c->term_name);
c->term_name = xstrdup("unknown");
}
if (c->ttyname == NULL || *c->ttyname != '\0')
name = xstrdup(c->ttyname);
else
xasprintf(&name, "client-%ld", (long)c->pid);
@ -3634,7 +3645,8 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
tty_resize(&c->tty);
c->flags |= CLIENT_TERMINAL;
}
close(c->out_fd);
if (c->out_fd != -1)
close(c->out_fd);
c->out_fd = -1;
}
@ -3647,10 +3659,12 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
!cfg_finished &&
c == TAILQ_FIRST(&clients))
start_cfg();
return (0);
}
/* Handle shell message. */
static void
static int
server_client_dispatch_shell(struct client *c)
{
const char *shell;
@ -3661,6 +3675,7 @@ server_client_dispatch_shell(struct client *c)
proc_send(c->peer, MSG_SHELL, -1, shell, strlen(shell) + 1);
proc_kill_peer(c->peer);
return (0);
}
/* Get client working directory. */