Page MenuHomeFreeBSD

D46284.id158917.diff
No OneTemporary

D46284.id158917.diff

diff --git a/usr.sbin/jail/config.c b/usr.sbin/jail/config.c
--- a/usr.sbin/jail/config.c
+++ b/usr.sbin/jail/config.c
@@ -29,14 +29,19 @@
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/sysctl.h>
+#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <err.h>
+#include <fcntl.h>
#include <glob.h>
+#include <libgen.h>
#include <netdb.h>
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -306,10 +311,107 @@
--depth;
}
+extern char **environ;
+
+static FILE *
+open_config(const char *cfname, pid_t pid[static 1])
+{
+
+ int read_fd, write_fd, exec_fd, pipes[2];
+ FILE *file;
+
+ /* Invalidate the child PID. */
+ *pid = -1;
+
+ /* The configuration must be readable. */
+ read_fd = open(cfname, O_RDONLY|O_CLOEXEC);
+ if (read_fd < 0)
+ err(1, "open(): %s", cfname);
+
+ /* Try to open the configuration for execution (to parse its standard output config instead). */
+ exec_fd = openat(read_fd, "", O_EMPTY_PATH|O_EXEC);
+ if (exec_fd < 0) {
+ if (errno != EACCES)
+ err(1, "openat(): %s", cfname);
+ } else if (!xflag) {
+ errx(1, "invoke jail with -x to execute jail.conf");
+ } else {
+ const size_t cfname_size = strlen(cfname) + 1;
+ char dir_buf[PATH_MAX], base_buf[PATH_MAX];
+ if (cfname_size > PATH_MAX) {
+ errno = ENAMETOOLONG;
+ err(1, "open_config(): %s", cfname);
+ }
+
+ /* Set the argument list: <jail_conf> <jail_conf> <jail_dir> <jail_base> <jail_name>. */
+ const struct cfjail *const current_jail = TAILQ_LAST(&cfjails, cfjails);
+ char *const jail_conf = __DECONST(char *, cfname);
+ char *const jail_dir = dirname(memcpy(dir_buf, cfname, cfname_size));
+ char *const jail_base = basename(memcpy(base_buf, cfname, cfname_size));
+ char *const jail_name = current_jail && current_jail->name ? current_jail->name : __DECONST(char *, "");
+ char *argv[] = { jail_conf, jail_conf, jail_dir, jail_base, jail_name, NULL };
+
+ /* Read from the pipe instead of the configuration. */
+ close(read_fd);
+ if (pipe(pipes))
+ err(1, "pipe(): %s", cfname);
+ read_fd = pipes[0];
+ write_fd = pipes[1];
+
+ /* Run the configuration as child process. */
+ switch ((*pid = fork())) {
+
+ /* Failed to fork(). */
+ case -1:
+ err(1, "fork(): %s", cfname);
+ break;
+
+ /* After successful fork() inside the child process. */
+ case 0:
+ /* Export the arguments to the executable configuration. */
+ if (setenv("JAIL_CONF", cfname, 1))
+ err(1, "setenv(\"JAIL_CONF\", \"%s\"): %s", cfname, cfname);
+ if (setenv("JAIL_DIR", jail_dir, 1))
+ err(1, "setenv(\"JAIL_DIR\", \"%s\"): %s", jail_dir, cfname);
+ if (setenv("JAIL_BASE", jail_base, 1))
+ err(1, "setenv(\"JAIL_BASE\", \"%s\"): %s", jail_base, cfname);
+ if (setenv("JAIL_NAME", jail_name, 1))
+ err(1, "setenv(\"JAIL_NAME\", \"%s\"): %s", jail_name, cfname);
+
+ /* Redirect the child's standard output into the pipe. */
+ if (write_fd != STDOUT_FILENO) {
+ if (dup2(write_fd, STDOUT_FILENO) != STDOUT_FILENO)
+ err(1, "dup2(): %s", cfname);
+ close(write_fd);
+ }
+
+ /* Replace the forked child with the configuration command. */
+ fexecve(exec_fd, argv, environ);
+ err(1, "fexecve(): %s", cfname);
+ break;
+
+ /* After successful fork() inside the parent process. */
+ default:
+ /* Close the write end of the pipe and the executable file descriptor in the parent. */
+ close(write_fd); write_fd = -1;
+ close(exec_fd); exec_fd = -1;
+ break;
+ }
+ }
+
+ /* Wrap a FILE handle around the read-only file descriptor. */
+ file = fdopen(read_fd, "r");
+ if (file == NULL)
+ err(1, "fdopen(): %s", cfname);
+
+ return file;
+}
+
static void
parse_config(const char *cfname, int is_stdin)
{
struct cflex cflex = {.cfname = cfname, .error = 0};
+ pid_t child = -1;
void *scanner;
yylex_init_extra(&cflex, &scanner);
@@ -317,7 +419,7 @@
cflex.cfname = "STDIN";
yyset_in(stdin, scanner);
} else {
- FILE *yfp = fopen(cfname, "r");
+ FILE *yfp = open_config(cfname, &child);
if (!yfp)
err(1, "%s", cfname);
yyset_in(yfp, scanner);
@@ -325,6 +427,16 @@
if (yyparse(scanner) || cflex.error)
exit(1);
yylex_destroy(scanner);
+ if (child > 0) {
+ pid_t exited;
+ int status;
+ do {
+ exited = waitpid(child, &status, 0);
+ } while (exited < 0 || errno == EINTR);
+ status = WEXITSTATUS(status);
+ if (status != 0)
+ errx(status, "Config child failed (exit code = %i): %s", status, cfname);
+ }
}
/*
diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8
--- a/usr.sbin/jail/jail.8
+++ b/usr.sbin/jail/jail.8
@@ -33,7 +33,7 @@
.Ss From Configuration File
.Nm
.Op Fl cm
-.Op Fl Cdqv
+.Op Fl Cdqvx
.Op Fl f Ar conf_file
.Op Fl p Ar limit
.Op Ar jail
@@ -214,6 +214,13 @@
.It Fl v
Print a message on every operation, such as running commands and
mounting filesystems.
+.It Fl x
+Allow executable jail configuration file(s).
+An executable jail configuration runs during configuration parsing.
+It must write valid
+.Xr jail.conf 5
+to standard output.
+A non-zero exit status is treated like a syntax error.
.It Fl d
This is deprecated and is equivalent to the
.Va allow.dying
diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c
--- a/usr.sbin/jail/jail.c
+++ b/usr.sbin/jail/jail.c
@@ -54,6 +54,7 @@
};
int iflag;
+int xflag;
int note_remove;
int verbose;
const char *separator = "\t";
@@ -180,12 +181,12 @@
#endif
op = 0;
- dflag = eflag = Rflag = 0;
+ dflag = eflag = Rflag = xflag = 0;
docf = 1;
cfname = CONF_FILE;
JidFile = NULL;
- while ((ch = getopt(argc, argv, "cCde:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) {
+ while ((ch = getopt(argc, argv, "cCdxe:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) {
switch (ch) {
case 'c':
op |= JF_START;
@@ -196,6 +197,9 @@
case 'd':
dflag = 1;
break;
+ case 'x':
+ xflag = 1;
+ break;
case 'e':
eflag = 1;
separator = optarg;
diff --git a/usr.sbin/jail/jailp.h b/usr.sbin/jail/jailp.h
--- a/usr.sbin/jail/jailp.h
+++ b/usr.sbin/jail/jailp.h
@@ -249,6 +249,7 @@
extern struct cfjails ready;
extern struct cfjails depend;
extern int iflag;
+extern int xflag;
extern int note_remove;
extern int paralimit;
extern int verbose;

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 21, 8:39 AM (4 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25757574
Default Alt Text
D46284.id158917.diff (6 KB)

Event Timeline