git: d50685b303e3 - main - jail: add the -C flag to clean up after a partially removed jail

From: Jamie Gritton <jamie_at_FreeBSD.org>
Date: Sun, 17 Mar 2024 05:12:41 UTC
The branch main has been updated by jamie:

URL: https://cgit.FreeBSD.org/src/commit/?id=d50685b303e3353aa1aeaea022a80f31e3732a29

commit d50685b303e3353aa1aeaea022a80f31e3732a29
Author:     Jamie Gritton <jamie@FreeBSD.org>
AuthorDate: 2024-03-17 05:11:14 +0000
Commit:     Jamie Gritton <jamie@FreeBSD.org>
CommitDate: 2024-03-17 05:11:14 +0000

    jail: add the -C flag to clean up after a partially removed jail
    
    Differential Revision:  https://reviews.freebsd.org/D42670
---
 usr.sbin/jail/jail.8  |  9 ++++++---
 usr.sbin/jail/jail.c  | 56 +++++++++++++++++++++++++++++++++++++++++----------
 usr.sbin/jail/jailp.h |  1 +
 usr.sbin/jail/state.c |  4 ++--
 4 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8
index e49c3fe95e7f..d58192623952 100644
--- 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 @@ jail if it does exist.
 .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
index df0a32321794..53e05870ff26 100644
--- a/usr.sbin/jail/jail.c
+++ b/usr.sbin/jail/jail.c
@@ -128,6 +128,24 @@ static const enum intparam stopcommands[] = {
     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 @@ main(int argc, char **argv)
 	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 @@ main(int argc, char **argv)
 		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 @@ main(int argc, char **argv)
 	/* 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 @@ main(int argc, char **argv)
 			 * 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 @@ main(int argc, char **argv)
 					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 @@ main(int argc, char **argv)
 			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 @@ main(int argc, char **argv)
 					}
 					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 @@ main(int argc, char **argv)
 			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
index 74ef2a8acab8..ccd96f5f247e 100644
--- 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
index 6cbe879acc55..1d200beacef9 100644
--- a/usr.sbin/jail/state.c
+++ b/usr.sbin/jail/state.c
@@ -306,7 +306,7 @@ start_state(const char *target, int docf, unsigned state, int running)
 	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 @@ start_state(const char *target, int docf, unsigned state, int running)
 		}
 	} 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);
 		}