release-request-a2143a0f-bf92-4fa8-ad68-7346e7505126-for-git_oc-dr1-release-4067638 snap-temp-L84900000070511178

Change-Id: Ic7d369a9e23fc14bcf59e4f8e694921319a64721
diff --git a/libminijail.c b/libminijail.c
index 1da4e19..81cea4b 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -106,6 +106,7 @@
 		int skip_remount_private : 1;
 		int pids : 1;
 		int ipc : 1;
+		int uts : 1;
 		int net : 1;
 		int enter_net : 1;
 		int ns_cgroups : 1;
@@ -144,6 +145,7 @@
 	char *pid_file_path;
 	char *uidmap;
 	char *gidmap;
+	char *hostname;
 	size_t filter_len;
 	struct sock_fprog *filter_prog;
 	char *alt_syscall_table;
@@ -439,6 +441,22 @@
 	j->flags.ipc = 1;
 }
 
+void API minijail_namespace_uts(struct minijail *j)
+{
+	j->flags.uts = 1;
+}
+
+int API minijail_namespace_set_hostname(struct minijail *j, const char *name)
+{
+	if (j->hostname)
+		return -EINVAL;
+	minijail_namespace_uts(j);
+	j->hostname = strdup(name);
+	if (!j->hostname)
+		return -ENOMEM;
+	return 0;
+}
+
 void API minijail_namespace_net(struct minijail *j)
 {
 	j->flags.net = 1;
@@ -869,6 +887,8 @@
 	}
 	if (j->chrootdir)
 		marshal_append(state, j->chrootdir, strlen(j->chrootdir) + 1);
+	if (j->hostname)
+		marshal_append(state, j->hostname, strlen(j->hostname) + 1);
 	if (j->alt_syscall_table) {
 		marshal_append(state, j->alt_syscall_table,
 			       strlen(j->alt_syscall_table) + 1);
@@ -956,6 +976,15 @@
 			goto bad_chrootdir;
 	}
 
+	if (j->hostname) {	/* stale pointer */
+		char *hostname = consumestr(&serialized, &length);
+		if (!hostname)
+			goto bad_hostname;
+		j->hostname = strdup(hostname);
+		if (!j->hostname)
+			goto bad_hostname;
+	}
+
 	if (j->alt_syscall_table) {	/* stale pointer */
 		char *alt_syscall_table = consumestr(&serialized, &length);
 		if (!alt_syscall_table)
@@ -1062,6 +1091,9 @@
 	if (j->chrootdir)
 		free(j->chrootdir);
 bad_chrootdir:
+	if (j->hostname)
+		free(j->hostname);
+bad_hostname:
 	if (j->suppl_gid_list)
 		free(j->suppl_gid_list);
 bad_gid_list:
@@ -1071,6 +1103,7 @@
 	j->user = NULL;
 	j->suppl_gid_list = NULL;
 	j->chrootdir = NULL;
+	j->hostname = NULL;
 	j->alt_syscall_table = NULL;
 	j->cgroup_count = 0;
 out:
@@ -1594,6 +1627,14 @@
 		pdie("unshare(CLONE_NEWIPC) failed");
 	}
 
+	if (j->flags.uts) {
+		if (unshare(CLONE_NEWUTS))
+			pdie("unshare(CLONE_NEWUTS) failed");
+
+		if (j->hostname && sethostname(j->hostname, strlen(j->hostname)))
+			pdie("sethostname(%s) failed", j->hostname);
+	}
+
 	if (j->flags.enter_net) {
 		if (setns(j->netns_fd, CLONE_NEWNET))
 			pdie("setns(CLONE_NEWNET) failed");
@@ -2345,6 +2386,8 @@
 		free(j->uidmap);
 	if (j->gidmap)
 		free(j->gidmap);
+	if (j->hostname)
+		free(j->hostname);
 	if (j->alt_syscall_table)
 		free(j->alt_syscall_table);
 	for (i = 0; i < j->cgroup_count; ++i)
diff --git a/libminijail.h b/libminijail.h
index a1f2f74..08fdf2b 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -71,6 +71,8 @@
  */
 void minijail_skip_remount_private(struct minijail *j);
 void minijail_namespace_ipc(struct minijail *j);
+void minijail_namespace_uts(struct minijail *j);
+int minijail_namespace_set_hostname(struct minijail *j, const char *name);
 void minijail_namespace_net(struct minijail *j);
 void minijail_namespace_enter_net(struct minijail *j, const char *ns_path);
 void minijail_namespace_cgroups(struct minijail *j);
diff --git a/minijail0.1 b/minijail0.1
index e186fef..11579c2 100644
--- a/minijail0.1
+++ b/minijail0.1
@@ -147,6 +147,10 @@
 .TP
 \fB-Y\fR
 Synchronize seccomp filters across thread group.
+.TP
+\fB--uts[=hostname]\fR
+Create a new UTS/hostname namespace, and optionally set the hostname in the new
+namespace to \fIhostname\fR.
 .SH IMPLEMENTATION
 This program is broken up into two parts: \fBminijail0\fR (the frontend) and a helper
 library called \fBlibminijailpreload\fR. Some jailings can only be achieved from
diff --git a/minijail0.c b/minijail0.c
index b9f4e5a..72353f6 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -118,32 +118,32 @@
 	       "  [-m[<uid> <loweruid> <count>]*] [-M[<gid> <lowergid> <count>]*]\n"
 	       "  [-S <file>] [-t[size]] [-T <type>] [-u <user>] [-V <file>]\n"
 	       "  <program> [args...]\n"
-	       "  -a <table>: Use alternate syscall table <table>.\n"
-	       "  -b:         Bind <src> to <dest> in chroot.\n"
-	       "              Multiple instances allowed.\n"
-	       "  -k:         Mount <src> at <dest> in chroot.\n"
-	       "              <flags> and <data> can be specified as in mount(2).\n"
-	       "              Multiple instances allowed.\n"
-	       "  -c <caps>:  Restrict caps to <caps>.\n"
-	       "  -C <dir>:   chroot(2) to <dir>.\n"
-	       "              Not compatible with -P.\n"
-	       "  -P <dir>:   pivot_root(2) to <dir> (implies -v).\n"
-	       "              Not compatible with -C.\n"
-	       "  -e[file]:   Enter new network namespace, or existing one if |file| is provided.\n"
-	       "  -f <file>:  Write the pid of the jailed process to <file>.\n"
-	       "  -g <group>: Change gid to <group>.\n"
-	       "  -G:         Inherit supplementary groups from uid.\n"
-	       "              Not compatible with -y.\n"
-	       "  -y:         Keep uid's supplementary groups.\n"
-	       "              Not compatible with -G.\n"
-	       "  -h:         Help (this message).\n"
-	       "  -H:         Seccomp filter help message.\n"
-	       "  -i:         Exit immediately after fork (do not act as init).\n"
-	       "  -I:         Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
-	       "  -K:         Don't mark all existing mounts as MS_PRIVATE.\n"
-	       "  -l:         Enter new IPC namespace.\n"
-	       "  -L:         Report blocked syscalls to syslog when using seccomp filter.\n"
-	       "              Forces the following syscalls to be allowed:\n"
+	       "  -a <table>:   Use alternate syscall table <table>.\n"
+	       "  -b:           Bind <src> to <dest> in chroot.\n"
+	       "                Multiple instances allowed.\n"
+	       "  -k:           Mount <src> at <dest> in chroot.\n"
+	       "                <flags> and <data> can be specified as in mount(2).\n"
+	       "                Multiple instances allowed.\n"
+	       "  -c <caps>:    Restrict caps to <caps>.\n"
+	       "  -C <dir>:     chroot(2) to <dir>.\n"
+	       "                Not compatible with -P.\n"
+	       "  -P <dir>:     pivot_root(2) to <dir> (implies -v).\n"
+	       "                Not compatible with -C.\n"
+	       "  -e[file]:     Enter new network namespace, or existing one if |file| is provided.\n"
+	       "  -f <file>:    Write the pid of the jailed process to <file>.\n"
+	       "  -g <group>:   Change gid to <group>.\n"
+	       "  -G:           Inherit supplementary groups from uid.\n"
+	       "                Not compatible with -y.\n"
+	       "  -y:           Keep uid's supplementary groups.\n"
+	       "                Not compatible with -G.\n"
+	       "  -h:           Help (this message).\n"
+	       "  -H:           Seccomp filter help message.\n"
+	       "  -i:           Exit immediately after fork (do not act as init).\n"
+	       "  -I:           Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
+	       "  -K:           Don't mark all existing mounts as MS_PRIVATE.\n"
+	       "  -l:           Enter new IPC namespace.\n"
+	       "  -L:           Report blocked syscalls to syslog when using seccomp filter.\n"
+	       "                Forces the following syscalls to be allowed:\n"
 	       "                  ", progn);
 	/* clang-format on */
 	for (i = 0; i < log_syscalls_len; i++)
@@ -151,34 +151,35 @@
 
 	/* clang-format off */
 	printf("\n"
-	       "  -m[map]:    Set the uid map of a user namespace (implies -pU).\n"
-	       "              Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
-	       "              With no mapping, map the current uid to root inside the user namespace.\n"
-	       "              Not compatible with -b without the 'writable' option.\n"
-	       "  -M[map]:    Set the gid map of a user namespace (implies -pU).\n"
-	       "              Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
-	       "              With no mapping, map the current gid to root inside the user namespace.\n"
-	       "              Not compatible with -b without the 'writable' option.\n"
-	       "  -n:         Set no_new_privs.\n"
-	       "  -N:         Enter a new cgroup namespace.\n"
-	       "  -p:         Enter new pid namespace (implies -vr).\n"
-	       "  -r:         Remount /proc read-only (implies -v).\n"
-	       "  -s:         Use seccomp.\n"
-	       "  -S <file>:  Set seccomp filter using <file>.\n"
-	       "              E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
-	       "              Requires -n when not running as root.\n"
-	       "  -t[size]:   Mount tmpfs at /tmp (implies -v).\n"
-	       "              Optional argument specifies size (default \"64M\").\n"
-	       "  -T <type>:  Don't access <program> before execve(2), assume <type> ELF binary.\n"
-	       "              <type> must be 'static' or 'dynamic'.\n"
-	       "  -u <user>:  Change uid to <user>.\n"
-	       "  -U:         Enter new user namespace (implies -p).\n"
-	       "  -v:         Enter new mount namespace.\n"
-	       "  -V <file>:  Enter specified mount namespace.\n"
-	       "  -w:         Create and join a new anonymous session keyring.\n"
-	       "  -Y:         Synchronize seccomp filters across thread group.\n"
-	       "  -z:         Don't forward signals to jailed process.\n"
-	       "  --ambient:  Raise ambient capabilities. Requires -c.\n");
+	       "  -m[map]:      Set the uid map of a user namespace (implies -pU).\n"
+	       "                Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
+	       "                With no mapping, map the current uid to root inside the user namespace.\n"
+	       "                Not compatible with -b without the 'writable' option.\n"
+	       "  -M[map]:      Set the gid map of a user namespace (implies -pU).\n"
+	       "                Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
+	       "                With no mapping, map the current gid to root inside the user namespace.\n"
+	       "                Not compatible with -b without the 'writable' option.\n"
+	       "  -n:           Set no_new_privs.\n"
+	       "  -N:           Enter a new cgroup namespace.\n"
+	       "  -p:           Enter new pid namespace (implies -vr).\n"
+	       "  -r:           Remount /proc read-only (implies -v).\n"
+	       "  -s:           Use seccomp.\n"
+	       "  -S <file>:    Set seccomp filter using <file>.\n"
+	       "                E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
+	       "                Requires -n when not running as root.\n"
+	       "  -t[size]:     Mount tmpfs at /tmp (implies -v).\n"
+	       "                Optional argument specifies size (default \"64M\").\n"
+	       "  -T <type>:    Don't access <program> before execve(2), assume <type> ELF binary.\n"
+	       "                <type> must be 'static' or 'dynamic'.\n"
+	       "  -u <user>:    Change uid to <user>.\n"
+	       "  -U:           Enter new user namespace (implies -p).\n"
+	       "  -v:           Enter new mount namespace.\n"
+	       "  -V <file>:    Enter specified mount namespace.\n"
+	       "  -w:           Create and join a new anonymous session keyring.\n"
+	       "  -Y:           Synchronize seccomp filters across thread group.\n"
+	       "  -z:           Don't forward signals to jailed process.\n"
+	       "  --ambient:    Raise ambient capabilities. Requires -c.\n"
+	       "  --uts[=name]: Enter a new UTS namespace (and set hostname).\n");
 	/* clang-format on */
 }
 
@@ -217,6 +218,7 @@
 	/* clang-format off */
 	const struct option long_options[] = {
 		{"ambient", no_argument, 0, 128},
+		{"uts", optional_argument, 0, 129},
 		{0, 0, 0, 0},
 	};
 	/* clang-format on */
@@ -444,6 +446,11 @@
 			ambient_caps = 1;
 			minijail_set_ambient_caps(j);
 			break;
+		case 129: /* UTS/hostname namespace. */
+			minijail_namespace_uts(j);
+			if (optarg)
+				minijail_namespace_set_hostname(j, optarg);
+			break;
 		default:
 			usage(argv[0]);
 			exit(1);