aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Zaborski <oshogbo@FreeBSD.org>2021-06-09 21:46:51 +0000
committerMark Johnston <markj@FreeBSD.org>2021-06-29 17:08:28 +0000
commit3d2c68f5378391e4edba9f1a9b0c9a994ba09f6e (patch)
treec76b26755055ffed5e772c189c53c0c52978b7a8
parent53de482ad419a777e3353fcc91865badf4ec062c (diff)
downloadsrc-3d2c68f5378391e4edba9f1a9b0c9a994ba09f6e.tar.gz
src-3d2c68f5378391e4edba9f1a9b0c9a994ba09f6e.zip
libcasper: fix descriptors numbers
Casper services expect that the first 3 descriptors (stdin/stdout/stderr) will point to /dev/null. Which Casper will ensure later. The Casper services are forked from the original process. If the initial process closes one of those descriptors, Casper may reuse one of them for it on purpose. If this is the case, then renumarate the descriptors used by Casper to higher numbers. This is done already after the fork, so it doesn't break the parent process. Approved by: so Security: EN-21:19.libcasper PR: 255339 Reported by: Borja Marcos <borjam (at) sarenet.es> Tested by: jkim@ (cherry picked from commit aa310ebfba3d49a0b6b03a103b969731a8136a73) (cherry picked from commit 6c0a51837f4ba242ea723a887c3b6120d9335c8f)
-rw-r--r--lib/libcasper/libcasper/libcasper_impl.c27
-rw-r--r--lib/libcasper/libcasper/libcasper_impl.h1
-rw-r--r--lib/libcasper/libcasper/service.c23
-rw-r--r--lib/libcasper/libcasper/zygote.c15
4 files changed, 50 insertions, 16 deletions
diff --git a/lib/libcasper/libcasper/libcasper_impl.c b/lib/libcasper/libcasper/libcasper_impl.c
index 57d489943252..f58bd44d2039 100644
--- a/lib/libcasper/libcasper/libcasper_impl.c
+++ b/lib/libcasper/libcasper/libcasper_impl.c
@@ -30,8 +30,10 @@
* $FreeBSD$
*/
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <paths.h>
#include <stdlib.h>
#include "libcasper_impl.h"
@@ -42,3 +44,28 @@ fd_is_valid(int fd)
return (fcntl(fd, F_GETFL) != -1 || errno != EBADF);
}
+
+void
+fd_fix_environment(int *fdp)
+{
+ int nullfd, nfd;
+
+ if (*fdp > STDERR_FILENO)
+ return;
+
+ nullfd = open(_PATH_DEVNULL, O_RDWR);
+ if (nullfd == -1)
+ errx(1, "Unable to open %s", _PATH_DEVNULL);
+
+ while (*fdp <= STDERR_FILENO) {
+ nfd = dup(*fdp);
+ if (nfd == -1)
+ errx(1, "Unable to secure fd");
+ if (dup2(nullfd, *fdp) == -1)
+ errx(1, "Unable to secure fd");
+ *fdp = nfd;
+ }
+
+ close(nullfd);
+}
+
diff --git a/lib/libcasper/libcasper/libcasper_impl.h b/lib/libcasper/libcasper/libcasper_impl.h
index 89f244d0b87d..01dbd234e3ff 100644
--- a/lib/libcasper/libcasper/libcasper_impl.h
+++ b/lib/libcasper/libcasper/libcasper_impl.h
@@ -42,6 +42,7 @@ struct service;
struct service_connection;
bool fd_is_valid(int fd);
+void fd_fix_environment(int *fdp);
/* Private service functions. */
struct service *service_alloc(const char *name,
diff --git a/lib/libcasper/libcasper/service.c b/lib/libcasper/libcasper/service.c
index cc53d0d630ae..b3d2d2f05ea3 100644
--- a/lib/libcasper/libcasper/service.c
+++ b/lib/libcasper/libcasper/service.c
@@ -365,24 +365,27 @@ stdnull(void)
}
static void
-service_clean(int sock, int procfd, uint64_t flags)
+service_clean(int *sockp, int *procfdp, uint64_t flags)
{
int fd, maxfd, minfd;
- assert(sock > STDERR_FILENO);
- assert(procfd > STDERR_FILENO);
- assert(sock != procfd);
+ fd_fix_environment(sockp);
+ fd_fix_environment(procfdp);
+
+ assert(*sockp > STDERR_FILENO);
+ assert(*procfdp > STDERR_FILENO);
+ assert(*sockp != *procfdp);
if ((flags & CASPER_SERVICE_STDIO) == 0)
stdnull();
if ((flags & CASPER_SERVICE_FD) == 0) {
- if (procfd > sock) {
- maxfd = procfd;
- minfd = sock;
+ if (*procfdp > *sockp) {
+ maxfd = *procfdp;
+ minfd = *sockp;
} else {
- maxfd = sock;
- minfd = procfd;
+ maxfd = *sockp;
+ minfd = *procfdp;
}
for (fd = STDERR_FILENO + 1; fd < maxfd; fd++) {
@@ -403,7 +406,7 @@ service_start(struct service *service, int sock, int procfd)
assert(service != NULL);
assert(service->s_magic == SERVICE_MAGIC);
setproctitle("%s", service->s_name);
- service_clean(sock, procfd, service->s_flags);
+ service_clean(&sock, &procfd, service->s_flags);
if (service_connection_add(service, sock, NULL) == NULL)
exit(1);
diff --git a/lib/libcasper/libcasper/zygote.c b/lib/libcasper/libcasper/zygote.c
index feeb1537af87..ef0032ddf58d 100644
--- a/lib/libcasper/libcasper/zygote.c
+++ b/lib/libcasper/libcasper/zygote.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <strings.h>
#include <unistd.h>
+#include "libcasper_impl.h"
#include "zygote.h"
/* Zygote info. */
@@ -88,7 +89,7 @@ zygote_clone(zygote_func_t *func, int *chanfdp, int *procfdp)
* between sandbox and its owner.
*/
static void
-zygote_main(int sock)
+zygote_main(int *sockp)
{
int error, procfd;
int chanfd[2];
@@ -96,12 +97,14 @@ zygote_main(int sock)
zygote_func_t *func;
pid_t pid;
- assert(sock > STDERR_FILENO);
+ fd_fix_environment(sockp);
+
+ assert(*sockp > STDERR_FILENO);
setproctitle("zygote");
for (;;) {
- nvlin = nvlist_recv(sock, 0);
+ nvlin = nvlist_recv(*sockp, 0);
if (nvlin == NULL) {
if (errno == ENOTCONN) {
/* Casper exited. */
@@ -133,7 +136,7 @@ zygote_main(int sock)
break;
case 0:
/* Child. */
- close(sock);
+ close(*sockp);
close(chanfd[0]);
func(chanfd[1]);
/* NOTREACHED */
@@ -155,7 +158,7 @@ send:
nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]);
nvlist_move_descriptor(nvlout, "procfd", procfd);
}
- (void)nvlist_send(sock, nvlout);
+ (void)nvlist_send(*sockp, nvlout);
nvlist_destroy(nvlout);
}
/* NOTREACHED */
@@ -182,7 +185,7 @@ zygote_init(void)
case 0:
/* Child. */
close(sp[0]);
- zygote_main(sp[1]);
+ zygote_main(&sp[1]);
/* NOTREACHED */
abort();
default: