Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F136878345
D46284.id158917.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D46284.id158917.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D46284: Add the ability have executable jail.conf
Attached
Detach File
Event Timeline
Log In to Comment