CVE-2015-1334 (C, published 2015-08-12T14:59Z)
Description: value: attach.c in LXC 1.1.2 and earlier uses the proc filesystem in a container, which allows local container users to escape AppArmor or SELinux confinement by mounting a proc filesystem with a crafted (1) AppArmor profile or (2) SELinux label.
Severity: MEDIUM (CVSS v3 base score: )
Weakness: CWE-17 \u2014 DEPRECATED: Code
This entry has been deprecated.  It was originally used for organizing the Development View (CWE-699) and some other views, but it introduced unnecessary complexity and depth to the resulting tree.
Repository: https://github.com/lxc/lxc
Files changed:
src/lxc/attach.c
Commit message: CVE-2015-1334: Don't use the container's /proc during attach

A user could otherwise over-mount /proc and prevent the apparmor profile
or selinux label from being written which combined with a modified
/bin/sh or other commonly used binary would lead to unconfined code
execution.

Reported-by: Roman Fiedler
Signed-off-by: Stéphane Graber <stgraber@ubuntu.com>


Vulnerable code:
			.exec_payload = exec_payload
	if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM)) {
		int proc_mounted;
		proc_mounted = mount_proc_if_needed("/");
		if (proc_mounted == -1) {
			ERROR("Error mounting a sane /proc");
			rexit(-1);
		}
		ret = lsm_process_label_set(init_ctx->lsm_label,
				init_ctx->container->lxc_conf, 0, on_exec);
		if (proc_mounted)
			umount("/proc");
		if (ret < 0) {

Fixed code:
int lsm_set_label_at(int procfd, int on_exec, char* lsm_label) {
	int labelfd = -1;
	int ret = 0;
	const char* name;
	char* command = NULL;

	name = lsm_name();

	if (strcmp(name, "nop") == 0)
		goto out;

	if (strcmp(name, "none") == 0)
		goto out;

	/* We don't support on-exec with AppArmor */
	if (strcmp(name, "AppArmor") == 0)
		on_exec = 0;

	if (on_exec) {
		labelfd = openat(procfd, "self/attr/exec", O_RDWR);
	}
	else {
		labelfd = openat(procfd, "self/attr/current", O_RDWR);
	}

	if (labelfd < 0) {
		SYSERROR("Unable to open LSM label");
		ret = -1;
		goto out;
	}

	if (strcmp(name, "AppArmor") == 0) {
		int size;

		command = malloc(strlen(lsm_label) + strlen("changeprofile ") + 1);
		if (!command) {
			SYSERROR("Failed to write apparmor profile");
			ret = -1;
			goto out;
		}

		size = sprintf(command, "changeprofile %s", lsm_label);
		if (size < 0) {
			SYSERROR("Failed to write apparmor profile");
			ret = -1;
			goto out;
		}

		if (write(labelfd, command, size + 1) < 0) {
			SYSERROR("Unable to set LSM label");
			ret = -1;
			goto out;
		}
	}
	else if (strcmp(name, "SELinux") == 0) {
		if (write(labelfd, lsm_label, strlen(lsm_label) + 1) < 0) {
			SYSERROR("Unable to set LSM label");
			ret = -1;
			goto out;
		}
	}
	else {
		ERROR("Unable to restore label for unknown LSM: %s", name);
		ret = -1;
		goto out;
	}

out:
	free(command);

	if (labelfd != -1)
		close(labelfd);

	return ret;
}

	int procfd;
	int procfd;
	procfd = open("/proc", O_DIRECTORY | O_RDONLY);
	if (procfd < 0) {
		SYSERROR("Unable to open /proc");
		shutdown(ipc_sockets[1], SHUT_RDWR);
		rexit(-1);
	}

			.exec_payload = exec_payload,
			.procfd = procfd
	int procfd = payload->procfd;
	if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
		if (lsm_set_label_at(procfd, on_exec, init_ctx->lsm_label) < 0) {
	/* we don't need proc anymore */
	close(procfd);