Re: vmd 3/5: add size checks for control imsg

2017-02-27 Thread Gilles Chehade
On Mon, Feb 27, 2017 at 10:52:14AM +0100, Reyk Floeter wrote:
> Reminder: using IMSG_SIZE_CHECK() in user-facing imsg handlers is a
> bad thing as an invalid imsg would kill the daemon (via fatal).
> 
> OK?
> 
> Add size checks for imsg received over the control socket.
> 
> Additionally, make sure that vmd never fatal()s when receiving an
> invalid imsg from an arbitrary user over the control socket.
> 

ok gilles@


> diff --git usr.sbin/vmd/control.c usr.sbin/vmd/control.c
> index 5e0141f..cda7df9 100644
> --- usr.sbin/vmd/control.c
> +++ usr.sbin/vmd/control.c
> @@ -286,11 +286,13 @@ control_close(int fd, struct control_sock *cs)
>  void
>  control_dispatch_imsg(int fd, short event, void *arg)
>  {
> - struct control_sock *cs = arg;
> - struct privsep  *ps = cs->cs_env;
> - struct ctl_conn *c;
> - struct imsg  imsg;
> - int  n, v, ret = 0;
> + struct control_sock *cs = arg;
> + struct privsep  *ps = cs->cs_env;
> + struct ctl_conn *c;
> + struct imsg  imsg;
> + struct vmop_create_paramsvmc;
> + struct vmop_id   vid;
> + int  n, v, ret = 0;
>  
>   if ((c = control_connbyfd(fd)) == NULL) {
>   log_warn("%s: fd %d: not found", __func__, fd);
> @@ -347,7 +349,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
>   c->flags |= CTL_CONN_NOTIFY;
>   break;
>   case IMSG_CTL_VERBOSE:
> - IMSG_SIZE_CHECK(, );
> + if (IMSG_DATA_SIZE() < sizeof(v))
> + goto fail;
>  
>   memcpy(, imsg.data, sizeof(v));
>   log_setverbose(v);
> @@ -355,17 +358,34 @@ control_dispatch_imsg(int fd, short event, void *arg)
>   proc_forward_imsg(ps, , PROC_PARENT, -1);
>   break;
>   case IMSG_VMDOP_START_VM_REQUEST:
> + if (IMSG_DATA_SIZE() < sizeof(vmc))
> + goto fail;
> + if (proc_compose_imsg(ps, PROC_PARENT, -1,
> + imsg.hdr.type, fd, -1,
> + imsg.data, IMSG_DATA_SIZE()) == -1) {
> + control_close(fd, cs);
> + return;
> + }
> + break;
>   case IMSG_VMDOP_TERMINATE_VM_REQUEST:
> - case IMSG_VMDOP_GET_INFO_VM_REQUEST:
> - imsg.hdr.peerid = fd;
> -
> + if (IMSG_DATA_SIZE() < sizeof(vid))
> + goto fail;
>   if (proc_compose_imsg(ps, PROC_PARENT, -1,
> - imsg.hdr.type, imsg.hdr.peerid, -1,
> + imsg.hdr.type, fd, -1,
>   imsg.data, IMSG_DATA_SIZE()) == -1) {
>   control_close(fd, cs);
>   return;
>   }
>   break;
> + case IMSG_VMDOP_GET_INFO_VM_REQUEST:
> + if (IMSG_DATA_SIZE() != 0)
> + goto fail;
> + if (proc_compose_imsg(ps, PROC_PARENT, -1,
> + imsg.hdr.type, fd, -1, NULL, 0) == -1) {
> + control_close(fd, cs);
> + return;
> + }
> + break;
>   case IMSG_VMDOP_LOAD:
>   case IMSG_VMDOP_RELOAD:
>   case IMSG_CTL_RESET:
> @@ -384,6 +404,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
>   return;
>  
>   fail:
> + if (ret == 0)
> + ret = EINVAL;
>   imsg_compose_event(>iev, IMSG_CTL_FAIL,
>   0, 0, -1, , sizeof(ret));
>   imsg_flush(>iev.ibuf);
> 

-- 
Gilles Chehade

https://www.poolp.org  @poolpOrg



vmd 3/5: add size checks for control imsg

2017-02-27 Thread Reyk Floeter
Reminder: using IMSG_SIZE_CHECK() in user-facing imsg handlers is a
bad thing as an invalid imsg would kill the daemon (via fatal).

OK?

Add size checks for imsg received over the control socket.

Additionally, make sure that vmd never fatal()s when receiving an
invalid imsg from an arbitrary user over the control socket.

diff --git usr.sbin/vmd/control.c usr.sbin/vmd/control.c
index 5e0141f..cda7df9 100644
--- usr.sbin/vmd/control.c
+++ usr.sbin/vmd/control.c
@@ -286,11 +286,13 @@ control_close(int fd, struct control_sock *cs)
 void
 control_dispatch_imsg(int fd, short event, void *arg)
 {
-   struct control_sock *cs = arg;
-   struct privsep  *ps = cs->cs_env;
-   struct ctl_conn *c;
-   struct imsg  imsg;
-   int  n, v, ret = 0;
+   struct control_sock *cs = arg;
+   struct privsep  *ps = cs->cs_env;
+   struct ctl_conn *c;
+   struct imsg  imsg;
+   struct vmop_create_paramsvmc;
+   struct vmop_id   vid;
+   int  n, v, ret = 0;
 
if ((c = control_connbyfd(fd)) == NULL) {
log_warn("%s: fd %d: not found", __func__, fd);
@@ -347,7 +349,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
c->flags |= CTL_CONN_NOTIFY;
break;
case IMSG_CTL_VERBOSE:
-   IMSG_SIZE_CHECK(, );
+   if (IMSG_DATA_SIZE() < sizeof(v))
+   goto fail;
 
memcpy(, imsg.data, sizeof(v));
log_setverbose(v);
@@ -355,17 +358,34 @@ control_dispatch_imsg(int fd, short event, void *arg)
proc_forward_imsg(ps, , PROC_PARENT, -1);
break;
case IMSG_VMDOP_START_VM_REQUEST:
+   if (IMSG_DATA_SIZE() < sizeof(vmc))
+   goto fail;
+   if (proc_compose_imsg(ps, PROC_PARENT, -1,
+   imsg.hdr.type, fd, -1,
+   imsg.data, IMSG_DATA_SIZE()) == -1) {
+   control_close(fd, cs);
+   return;
+   }
+   break;
case IMSG_VMDOP_TERMINATE_VM_REQUEST:
-   case IMSG_VMDOP_GET_INFO_VM_REQUEST:
-   imsg.hdr.peerid = fd;
-
+   if (IMSG_DATA_SIZE() < sizeof(vid))
+   goto fail;
if (proc_compose_imsg(ps, PROC_PARENT, -1,
-   imsg.hdr.type, imsg.hdr.peerid, -1,
+   imsg.hdr.type, fd, -1,
imsg.data, IMSG_DATA_SIZE()) == -1) {
control_close(fd, cs);
return;
}
break;
+   case IMSG_VMDOP_GET_INFO_VM_REQUEST:
+   if (IMSG_DATA_SIZE() != 0)
+   goto fail;
+   if (proc_compose_imsg(ps, PROC_PARENT, -1,
+   imsg.hdr.type, fd, -1, NULL, 0) == -1) {
+   control_close(fd, cs);
+   return;
+   }
+   break;
case IMSG_VMDOP_LOAD:
case IMSG_VMDOP_RELOAD:
case IMSG_CTL_RESET:
@@ -384,6 +404,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
return;
 
  fail:
+   if (ret == 0)
+   ret = EINVAL;
imsg_compose_event(>iev, IMSG_CTL_FAIL,
0, 0, -1, , sizeof(ret));
imsg_flush(>iev.ibuf);