示例#1
0
/*
 * Given a directory path, chown it to a userid.
 * We will chown $path and try to chown $path/tasks and $path/procs.
 * if @all_children is true, then chown all files under @path.  (This
 * is for the case where the caller had the rights to mkdir the path.
 * In that case he gets to write to all files - the kernel will ensure
 * hierarhical limits)
 *
 * Return true so long as we could chown the directory itself.
 */
bool chown_cgroup_path(const char *path, uid_t uid, gid_t gid, bool all_children)
{
	int len = strlen(path), ret;
	nih_local char *fpath = NULL;

	if (chown(path, uid, gid) < 0)
		return false;
	if (all_children) {
		struct dirent dirent, *direntp;
		char fpath[MAXPATHLEN];
		DIR *d = opendir(path);
		if (len >= MAXPATHLEN)
			return true;
		strcpy(fpath, path);
		while (readdir_r(d, &dirent, &direntp) == 0 && direntp) {
			if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, ".."))
				continue;
			ret = snprintf(fpath+len, MAXPATHLEN-len, "/%s", direntp->d_name);
			if (ret < 0 || ret >= MAXPATHLEN-len)
				continue;
			if (chown(fpath, uid, gid) < 0)
				nih_info("Failed to chown file %s to %d:%d",
					fpath, (int)uid, (int)gid);
		}
		closedir(d);
	} else
		fpath = nih_sprintf(NULL, "%s/cgroup.procs", path);
		if (!fpath)
			return true;
		if (chown(fpath, uid, gid) < 0)
			nih_info("Failed to chown procs file %s", fpath);
		sprintf(fpath+len, "/tasks");
		if (chown(fpath, uid, gid) < 0)
			nih_info("Failed to chown tasks file %s", fpath);
	return true;
}
示例#2
0
int get_value_main(void *parent, const char *controller, const char *cgroup,
		const char *key, struct ucred p, struct ucred r, char **value)
{
	char path[MAXPATHLEN];

	if (!sane_cgroup(cgroup)) {
		nih_error("%s: unsafe cgroup", __func__);
		return -1;
	}

	if (!compute_pid_cgroup(r.pid, controller, cgroup, path, NULL)) {
		nih_error("%s: Could not determine the requested cgroup", __func__);
		return -1;
	}

	/* Check access rights to the cgroup directory */
	if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) {
		nih_error("%s: Pid %d may not access %s\n", __func__, r.pid, path);
		return -1;
	}

	/* append the filename */
	if (strlen(path) + strlen(key) + 2 > MAXPATHLEN) {
		nih_error("%s: filename too long for cgroup %s key %s", __func__, path, key);
		return -1;
	}

	strncat(path, "/", MAXPATHLEN-1);
	strncat(path, key, MAXPATHLEN-1);

	/* Check access rights to the file itself */
	if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) {
		nih_error("%s: Pid %d may not access %s\n", __func__, r.pid, path);
		return -1;
	}

	/* read and return the value */
	*value = file_read_string(parent, path);
	if (!*value) {
		nih_error("%s: Failed to read value from %s", __func__, path);
		return -1;
	}

	nih_info(_("Sending to client: %s"), *value);
	return 0;
}
示例#3
0
bool get_nih_io_creds(void *parent, NihIo *io, struct ucred *ucred)
{
	NihIoMessage *msg = nih_io_read_message(parent, io);
	if (!msg) {
		nih_error("failed reading msg for ucred");
		return false;
	}
	struct cmsghdr *cmsg = msg->control[0];
	if (!cmsg) {
		nih_error("cmsg null");
		return false;
	}
	if (cmsg->cmsg_level != SOL_SOCKET ||
			cmsg->cmsg_len != CMSG_LEN (sizeof(*ucred)) ||
			cmsg->cmsg_type != SCM_CREDENTIALS) {
		nih_error("Got unexpected non-scm control message");
		return false;
	}
	memcpy(ucred, CMSG_DATA(cmsg), sizeof(*ucred));
	if (ucred->pid == -1)
		return false;
	nih_info(_("got creds pid %d (%u:%u)"), ucred->pid, ucred->uid, ucred->gid);
	return true;
}
示例#4
0
int remove_main(const char *controller, const char *cgroup, struct ucred p,
		struct ucred r, int recursive, int32_t *existed)
{
	char rcgpath[MAXPATHLEN];
	size_t cgroup_len;
	nih_local char *working = NULL, *copy = NULL, *wcgroup = NULL;
	char *p1;

	*existed = 1;

	if (!sane_cgroup(cgroup)) {
		nih_error("%s: unsafe cgroup", __func__);
		return -1;
	}

	// Get r's current cgroup in rcgpath
	if (!compute_pid_cgroup(r.pid, controller, "", rcgpath, NULL)) {
		nih_error("%s: Could not determine the requested cgroup", __func__);
		return -1;
	}

	cgroup_len = strlen(cgroup);

	if (strlen(rcgpath) + cgroup_len > MAXPATHLEN) {
		nih_error("%s: Path name too long", __func__);
		return -1;
	}

	wcgroup = NIH_MUST( nih_strdup(NULL, cgroup) );
	if (!normalize_path(wcgroup))
		return -1;

	working = NIH_MUST( nih_strdup(NULL, rcgpath) );
	NIH_MUST( nih_strcat(&working, NULL, "/") );
	NIH_MUST( nih_strcat(&working, NULL, wcgroup) );

	if (!dir_exists(working)) {
		*existed = -1;
		return 0;
	}
	// must have write access to the parent dir
	copy = NIH_MUST( nih_strdup(NULL, working) );
	if (!(p1 = strrchr(copy, '/')))
		return -1;
	*p1 = '\0';
	if (!may_access(r.pid, r.uid, r.gid, copy, O_WRONLY)) {
		nih_error("%s: pid %d (%u:%u) may not remove %s", __func__,
			r.pid, r.uid, r.gid, copy);
		return -1;
	}

	if (!recursive) {
		if (rmdir(working) < 0) {
			nih_error("%s: Failed to remove %s: %s", __func__, working, strerror(errno));
			return -1;
		}
	} else if (recursive_rmdir(working) < 0)
			return -1;

	nih_info(_("Removed %s for %d (%u:%u)"), working, r.pid,
		 r.uid, r.gid);
	return 0;
}
示例#5
0
int create_main(const char *controller, const char *cgroup, struct ucred p,
		struct ucred r, int32_t *existed)
{
	int ret, depth;
	char rcgpath[MAXPATHLEN], path[MAXPATHLEN], dirpath[MAXPATHLEN];
	nih_local char *copy = NULL;
	size_t cgroup_len;
	char *p1, *p2, oldp2;

	*existed = 1;
	if (!cgroup || ! *cgroup)  // nothing to do
		return 0;

	if (!sane_cgroup(cgroup)) {
		nih_error("%s: unsafe cgroup", __func__);
		return -1;
	}

	// Get r's current cgroup in rcgpath
	if (!compute_pid_cgroup(r.pid, controller, "", rcgpath, &depth)) {
		nih_error("%s: Could not determine the requested cgroup", __func__);
		return -1;
	}

	if (depth > maxdepth) {
		nih_error("%s: Cgroup too deep: %s/%s", __func__, rcgpath, cgroup);
		return -1;
	}

	cgroup_len = strlen(cgroup);

	if (strlen(rcgpath) + cgroup_len > MAXPATHLEN) {
		nih_error("%s: Path name too long", __func__);
		return -1;
	}
	copy = NIH_MUST( nih_strndup(NULL, cgroup, cgroup_len) );

	strcpy(path, rcgpath);
	strcpy(dirpath, rcgpath);
	for (p1=copy; *p1; p1 = p2) {
		*existed = -1;
		for (p2=p1; *p2 && *p2 != '/'; p2++);
		oldp2 = *p2;
		*p2 = '\0';
		if (strcmp(p1, "..") == 0) {
			nih_error("%s: Invalid cgroup path at create: %s", __func__, p1);
			return -1;
		}
		strncat(path, "/", MAXPATHLEN-1);
		strncat(path, p1, MAXPATHLEN-1);
		if (dir_exists(path)) {
			*existed = 1;
			// TODO - properly use execute perms
			if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) {
				nih_error("%s: pid %d (uid %u gid %u) may not look under %s", __func__,
					r.pid, r.uid, r.gid, path);
				return -1;
			}
			goto next;
		}
		if (!may_access(r.pid, r.uid, r.gid, dirpath, O_RDWR)) {
			nih_error("%s: pid %d (uid %u gid %u) may not create under %s", __func__,
				r.pid, r.uid, r.gid, dirpath);
			return -1;
		}
		ret = mkdir(path, 0755);
		if (ret < 0) {  // Should we ignore EEXIST?  Ok, but don't chown.
			if (errno == EEXIST) {
				*existed = 1;
				goto next;
			}
			nih_error("%s: failed to create %s", __func__, path);
			return -1;
		}
		if (!chown_cgroup_path(path, r.uid, r.gid, true)) {
			nih_error("%s: Failed to change ownership on %s to %u:%u", __func__,
				path, r.uid, r.gid);
			rmdir(path);
			return -1;
		}
		*existed = -1;
next:
		strncat(dirpath, "/", MAXPATHLEN-1);
		strncat(dirpath, p1, MAXPATHLEN-1);
		*p2 = oldp2;
		if (*p2)
			p2++;
	}


	nih_info(_("Created %s for %d (%u:%u)"), path, r.pid,
		 r.uid, r.gid);
	return 0;
}
示例#6
0
int do_move_pid_main(const char *controller, const char *cgroup, struct ucred p,
		struct ucred r, struct ucred v, bool escape)
{
	char rcgpath[MAXPATHLEN], path[MAXPATHLEN];
	FILE *f;
	pid_t query = r.pid;

	if (!sane_cgroup(cgroup)) {
		nih_error("%s: unsafe cgroup", __func__);
		return -1;
	}

	// verify that ucred.pid may move target pid
	if (!may_move_pid(r.pid, r.uid, v.pid)) {
		nih_error("%s: %d may not move %d", __func__, r.pid, v.pid);
		return -1;
	}

	// Get r's current cgroup in rcgpath
	if (escape)
		query = p.pid;
	if (!compute_pid_cgroup(query, controller, "", rcgpath, NULL)) {
		nih_error("%s: Could not determine the requested cgroup", __func__);
		return -1;
	}

	// If the victim is not under proxy's cgroup, refuse
	if (!victim_under_proxy_cgroup(rcgpath, v.pid, controller)) {
		nih_error("%s: victim's cgroup is not under proxy's (p.uid %u)", __func__, p.uid);
		return -1;
	}

	/* rcgpath + / + cgroup + /tasks + \0 */
	if (strlen(rcgpath) + strlen(cgroup) > MAXPATHLEN - 8) {
		nih_error("%s: Path name too long", __func__);
		return -1;
	}
	strcpy(path, rcgpath);
	strncat(path, "/", MAXPATHLEN-1);
	strncat(path, cgroup, MAXPATHLEN-1);
	if (realpath_escapes(path, rcgpath)) {
		nih_error("%s: Invalid path %s", __func__, path);
		return -1;
	}
	// is r allowed to descend under the parent dir?
	if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) {
		nih_error("%s: pid %d (uid %u gid %u) may not read under %s", __func__,
			r.pid, r.uid, r.gid, path);
		return -1;
	}
	// is r allowed to write to tasks file?
	strncat(path, "/tasks", MAXPATHLEN-1);
	if (!may_access(r.pid, r.uid, r.gid, path, O_WRONLY)) {
		nih_error("%s: pid %d (uid %u gid %u) may not write to %s", __func__,
			r.pid, r.uid, r.gid, path);
		return -1;
	}
	f = fopen(path, "w");
	if (!f) {
		nih_error("%s: Failed to open %s", __func__, path);
		return -1;
	}
	if (fprintf(f, "%d\n", v.pid) < 0) {
		fclose(f);
		nih_error("%s: Failed to write %d to %s", __func__, v.pid, path);
		return -1;
	}
	if (fclose(f) != 0) {
		nih_error("%s: Failed to write %d to %s", __func__, v.pid, path);
		return -1;
	}
	nih_info(_("%d moved to %s:%s by %d's request"), v.pid,
		controller, cgroup, r.pid);
	return 0;
}
示例#7
0
/**
 * Mount the cgroup filesystems and record the information.
 * This should take configuration data from /etc.  For now,
 * Just mount all controllers, separately just as cgroup-lite
 * does, and set the use_hierarchy and clone_children options.
 *
 * Things which should go into configuration file:
 * . which controllers to mount
 * . which controllers to co-mount
 * . any mount options (per-controller)
 * . values for sane_behavior, use_hierarchy, and clone_children
 */
int setup_cgroup_mounts(void)
{
	FILE *cgf;
	int ret;
	char line[400];

	if (unshare(CLONE_NEWNS) < 0) {
		nih_fatal("Failed to unshare a private mount ns: %s", strerror(errno));
		return -1;
	}
	if (!setup_base_path()) {
		nih_fatal("Error setting up base cgroup path");
		return -1;
	}
	if ((cgf = fopen("/proc/cgroups", "r")) == NULL) {
		nih_fatal ("Error opening /proc/cgroups: %s", strerror(errno));
		return -1;
	}
	while (fgets(line, 400, cgf)) {
		char *p;
		struct controller_mounts *tmp;
		char dest[MAXPATHLEN];
		unsigned long h;

		if (line[0] == '#')
			continue;
		p = index(line, '\t');
		if (!p)
			continue;
		*p = '\0';
		h = strtoul(p+1, NULL, 10);
		if (h) {
			nih_info("%s was already mounted!", line);
#if STRICT
			ret = -1;
			goto out;
#endif
		}
		ret = snprintf(dest, MAXPATHLEN, "%s/%s", base_path, line);
		if (ret < 0 || ret >= MAXPATHLEN) {
			nih_fatal("Error calculating pathname for %s and %s", base_path, line);
			goto out;
		}
		if (mkdir(dest, 0755) < 0 && errno != EEXIST) {
			nih_fatal("Failed to create %s: %s", dest, strerror(errno));
			ret = -1;
			goto out;
		}
		if ((ret = mount(line, dest, "cgroup", 0, line)) < 0) {
			nih_fatal("Failed mounting %s: %s", line, strerror(errno));
			goto out;
		}
		ret = -1;
		tmp = realloc(all_mounts, (num_controllers+1) * sizeof(*all_mounts));
		if (!tmp) {
			nih_fatal("Out of memory mounting controllers");
			goto out;
		}
		all_mounts = tmp;
		all_mounts[num_controllers].controller = strdup(line);
		if (!all_mounts[num_controllers].controller) {
			nih_fatal("Out of memory mounting controllers");
			goto out;
		}
		all_mounts[num_controllers].options = NULL;
		all_mounts[num_controllers].path = strdup(dest);
		if (!all_mounts[num_controllers].path) {
			nih_fatal("Out of memory mounting controllers");
			goto out;
		}
		nih_info("Mounted %s onto %s",
			all_mounts[num_controllers].controller,
			all_mounts[num_controllers].path);
		if (strcmp(all_mounts[num_controllers].controller, "cpuset") == 0) {
			set_clone_children(dest); // TODO make this optional?
			nih_info("set clone_children");
		} else if (strcmp(all_mounts[num_controllers].controller, "memory") == 0) {
			set_use_hierarchy(dest);  // TODO make this optional?
			nih_info("set memory.use_hierarchy");
		}
		num_controllers++;
	}
	nih_info("mounted %d controllers", num_controllers);
	ret = 0;
out:
	fclose(cgf);
	return ret;
}