In libcasper, prefer to send a function index or service name over the IPC

channel to a zygote process, rather than sending a function pointer or
service pointer.  This avoids transfering pointers between address spaces,
which while robust in this case (due to the zygote being forked() from the
parent) is not generally a good idea, especially in the presence of
increasingly popular control-flow integrity and pointer protection
mitigation schemes.  With this change, ping(8) and other sandboxed tools
using libcasper for DNS resolution now work on architectures with tagged
memory again.

Reviewed by:	oshogbo
MFC after:	1 week
Sponsored by:	DARPA, AFRL
This commit is contained in:
rwatson 2017-03-23 14:35:21 +00:00
parent 63254ceea6
commit a78ff3f4f3
3 changed files with 51 additions and 12 deletions

View File

@ -1,11 +1,16 @@
/*-
* Copyright (c) 2012 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* Copyright (c) 2017 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -130,18 +135,25 @@ casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
return (0);
}
static void
void
service_execute(int chanfd)
{
struct casper_service *casserv;
struct service *service;
const char *servname;
nvlist_t *nvl;
int procfd;
nvl = nvlist_recv(chanfd, 0);
if (nvl == NULL)
exit(1);
service = (struct service *)(uintptr_t)nvlist_take_number(nvl,
"service");
if (!nvlist_exists_string(nvl, "service"))
exit(1);
servname = nvlist_get_string(nvl, "service");
casserv = service_find(servname);
if (casserv == NULL)
exit(1);
service = casserv->cs_service;
procfd = nvlist_take_descriptor(nvl, "procfd");
nvlist_destroy(nvl);
@ -172,12 +184,11 @@ casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
if (!casper_allowed_service(limits, servname))
return (ENOTCAPABLE);
if (zygote_clone(service_execute, &chanfd, &procfd) == -1)
if (zygote_clone_service_execute(&chanfd, &procfd) == -1)
return (errno);
nvl = nvlist_create(0);
nvlist_add_number(nvl, "service",
(uint64_t)(uintptr_t)casserv->cs_service);
nvlist_add_string(nvl, "service", servname);
nvlist_move_descriptor(nvl, "procfd", procfd);
if (nvlist_send(chanfd, nvl) == -1) {
error = errno;

View File

@ -1,11 +1,16 @@
/*-
* Copyright (c) 2012 The FreeBSD Foundation
* Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
* Copyright (c) 2017 Robert N. M. Watson
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* All rights reserved.
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -50,8 +55,10 @@ __FBSDID("$FreeBSD$");
/* Zygote info. */
static int zygote_sock = -1;
#define ZYGOTE_SERVICE_EXECUTE 1
int
zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp)
zygote_clone(uint64_t funcidx, int *chanfdp, int *procfdp)
{
nvlist_t *nvl;
int error;
@ -63,7 +70,7 @@ zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp)
}
nvl = nvlist_create(0);
nvlist_add_number(nvl, "func", (uint64_t)(uintptr_t)func);
nvlist_add_number(nvl, "funcidx", funcidx);
nvl = nvlist_xfer(zygote_sock, nvl, 0);
if (nvl == NULL)
return (-1);
@ -81,6 +88,13 @@ zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp)
return (0);
}
int
zygote_clone_service_execute(int *chanfdp, int *procfdp)
{
return (zygote_clone(ZYGOTE_SERVICE_EXECUTE, chanfdp, procfdp));
}
/*
* This function creates sandboxes on-demand whoever has access to it via
* 'sock' socket. Function sends two descriptors to the caller: process
@ -93,6 +107,7 @@ zygote_main(int sock)
int error, procfd;
int chanfd[2];
nvlist_t *nvlin, *nvlout;
uint64_t funcidx;
zygote_func_t *func;
pid_t pid;
@ -109,10 +124,17 @@ zygote_main(int sock)
}
continue;
}
func = (zygote_func_t *)(uintptr_t)nvlist_get_number(nvlin,
"func");
funcidx = nvlist_get_number(nvlin, "funcidx");
nvlist_destroy(nvlin);
switch (funcidx) {
case ZYGOTE_SERVICE_EXECUTE:
func = service_execute;
break;
default:
exit(0);
}
/*
* Someone is requesting a new process, create one.
*/

View File

@ -36,6 +36,12 @@
typedef void zygote_func_t(int);
int zygote_init(void);
int zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp);
int zygote_clone(uint64_t funcidx, int *chanfdp, int *procfdp);
int zygote_clone_service_execute(int *chanfdp, int *procfdp);
/*
* Functions reachable via zygote_clone().
*/
zygote_func_t service_execute;
#endif /* !_ZYGOTE_H_ */