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 @@ -23,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 17, 2024 +.Dd March 16, 2024 .Dt JAIL 8 .Os .Sh NAME @@ -33,13 +33,13 @@ .Ss From Configuration File .Nm .Op Fl cm -.Op Fl dqv +.Op Fl Cdqv .Op Fl f Ar conf_file .Op Fl p Ar limit .Op Ar jail .Nm .Op Fl r -.Op Fl qv +.Op Fl Cqv .Op Fl f Ar conf_file .Op Fl p Ar limit .Op Cm * | Ar jail ... @@ -144,6 +144,9 @@ .Pp Other available options are: .Bl -tag -width indent +.It Fl C +Clean up after an already-removed jail, running commands and operations +that are typically run following jail removal. .It Fl f Ar conf_file Use configuration file .Ar conf_file 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 @@ -128,6 +128,24 @@ IP__NULL }; +static const enum intparam cleancommands[] = { + IP__NULL, + IP_EXEC_POSTSTOP, + IP_MOUNT_PROCFS, + IP_MOUNT_FDESCFS, + IP_MOUNT_DEVFS, + IP__MOUNT_FROM_FSTAB, + IP_MOUNT, +#ifdef INET6 + IP__IP6_IFADDR, +#endif +#ifdef INET + IP__IP4_IFADDR, +#endif + IP_EXEC_RELEASE, + IP__NULL +}; + int main(int argc, char **argv) { @@ -153,11 +171,14 @@ cfname = CONF_FILE; JidFile = NULL; - while ((ch = getopt(argc, argv, "cde:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) { + while ((ch = getopt(argc, argv, "cCde:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) { switch (ch) { case 'c': op |= JF_START; break; + case 'C': + op |= JF_CLEANUP; + break; case 'd': dflag = 1; break; @@ -305,7 +326,7 @@ note_remove = docf || argc > 1 || wild_jail_name(argv[0]); } else if (argc > 1 || (argc == 1 && strchr(argv[0], '='))) { /* Single jail specified on the command line */ - if (Rflag) + if (Rflag || (op & JF_CLEANUP)) usage(); docf = 0; for (i = 0; i < argc; i++) { @@ -355,7 +376,7 @@ /* Find out which jails will be run. */ dep_setup(docf); error = 0; - if (op == JF_STOP) { + if ((op & JF_OP_MASK) == JF_STOP) { for (i = 0; i < argc; i++) if (start_state(argv[i], docf, op, Rflag) < 0) error = 1; @@ -415,22 +436,24 @@ * depending on the jail's current status. */ case JF_START_SET: - j->flags = j->jid < 0 ? JF_START : JF_SET; + j->flags = j->jid < 0 + ? (j->flags & JF_CLEANUP) | JF_START : JF_SET; break; case JF_SET_RESTART: - if (j->jid < 0) { + if (j->jid < 0 && !(j->flags & JF_CLEANUP)) { jail_quoted_warnx(j, "not found", "no jail specified"); failed(j); continue; } - j->flags = rdtun_params(j, 0) ? JF_RESTART : JF_SET; + j->flags = rdtun_params(j, 0) + ? (j->flags & JF_CLEANUP) | JF_RESTART : JF_SET; if (j->flags == JF_RESTART) dep_reset(j); break; case JF_START_SET_RESTART: - j->flags = j->jid < 0 ? JF_START - : rdtun_params(j, 0) ? JF_RESTART : JF_SET; + j->flags = j->jid < 0 ? JF_START : rdtun_params(j, 0) + ? (j->flags & JF_CLEANUP) | JF_RESTART : JF_SET; if (j->flags == JF_RESTART) dep_reset(j); } @@ -449,11 +472,18 @@ continue; if (j->jid > 0) goto jail_create_done; + if (j->flags & JF_CLEANUP) { + j->flags |= JF_STOP; + j->comparam = cleancommands; + } else + j->comparam = startcommands; j->comparam = startcommands; j->comstring = NULL; } if (next_command(j)) continue; + if (j->flags & JF_STOP) + goto jail_remove_done; jail_create_done: clear_persist(j); if (jfp != NULL) @@ -485,7 +515,10 @@ if (j->comparam == NULL) { if (dep_check(j)) continue; - if (j->jid < 0) { + if (j->flags & JF_CLEANUP) { + j->comparam = j->jid < 0 + ? cleancommands : stopcommands; + } else if (j->jid < 0) { if (!(j->flags & (JF_DEPEND|JF_WILD))) { if (verbose >= 0) jail_quoted_warnx(j, @@ -494,7 +527,8 @@ } goto jail_remove_done; } - j->comparam = stopcommands; + else + j->comparam = stopcommands; j->comstring = NULL; } else if ((j->flags & JF_FAILED) && j->jid > 0) goto jail_remove_done; @@ -504,7 +538,7 @@ dep_done(j, 0); if ((j->flags & (JF_START | JF_FAILED)) == JF_START) { j->comparam = NULL; - j->flags &= ~JF_STOP; + j->flags &= ~(JF_STOP | JF_CLEANUP); dep_reset(j); requeue(j, j->ndeps ? &depend : &ready); } 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 @@ -67,6 +67,7 @@ #define JF_TIMEOUT 0x0200 /* A command (or process kill) timed out */ #define JF_SLEEPQ 0x0400 /* Waiting on a command and/or timeout */ #define JF_FROM_RUNQ 0x0800 /* Has already been on the run queue */ +#define JF_CLEANUP 0x1000 /* -C Run post-removal commands */ #define JF_OP_MASK (JF_START | JF_SET | JF_STOP) #define JF_RESTART (JF_START | JF_STOP) diff --git a/usr.sbin/jail/state.c b/usr.sbin/jail/state.c --- a/usr.sbin/jail/state.c +++ b/usr.sbin/jail/state.c @@ -306,7 +306,7 @@ int jid; char namebuf[MAXHOSTNAMELEN]; - if (!target || (!docf && state != JF_STOP) || + if (!target || (!docf && (state & JF_OP_MASK) != JF_STOP) || (!running && !strcmp(target, "*"))) { /* * For a global wildcard (including no target specified), @@ -365,7 +365,7 @@ } } else { j = find_jail(target); - if (j == NULL && state == JF_STOP) { + if (j == NULL && (state & JF_OP_MASK) == JF_STOP) { /* Allow -[rR] to specify a currently running jail. */ j = running_jail(target, JAIL_DYING); }