Exemple #1
0
int main(int argc, char **argv)
{
	int err;
	char *c;
	unsigned long bounds_dir_entry;
	int pid;

	printf("mpx-dig starting...\n");
	err = sscanf(argv[1], "%d", &pid);
	printf("parsing: '%s', err: %d\n", argv[1], err);
	if (err != 1)
		mpx_dig_abort();

	err = sscanf(argv[2], "%lx", &bounds_dir_global);
	printf("parsing: '%s': %d\n", argv[2], err);
	if (err != 1)
		mpx_dig_abort();

	proc_pid_mem_fd = open_proc(pid, "mem");
	if (proc_pid_mem_fd < 0)
		mpx_dig_abort();

	inspect_pid(pid);
	return 0;
}
Exemple #2
0
int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s)
{
	char *tok, *p;
	int fd;
	int n;

	fd = open_proc(pid, "stat");
	if (fd < 0)
		return -1;

	n = read(fd, buf, BUF_SIZE);
	if (n < 1) {
		pr_err("stat for %d is corrupted\n", pid);
		close(fd);
		return -1;
	}
	close(fd);

	memset(s, 0, sizeof(*s));

	tok = strchr(buf, ' ');
	if (!tok)
		goto err;
	*tok++ = '\0';
	if (*tok != '(')
		goto err;

	s->pid = atoi(buf);

	p = strrchr(tok + 1, ')');
	if (!p)
		goto err;
	*tok = '\0';
	*p = '\0';

	strncpy(s->comm, tok + 1, sizeof(s->comm));

	n = sscanf(p + 1, " %c %d %d %d", &s->state, &s->ppid, &s->pgid, &s->sid);
	if (n < 4)
		goto err;

	return 0;

err:
	pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
	return -1;
}
Exemple #3
0
static int check_fcntl(void)
{
	u32 v[2];
	int fd;

	fd = open_proc(PROC_SELF, "comm");
	if (fd < 0)
		return -1;

	if (fcntl(fd, F_GETOWNER_UIDS, (long)v)) {
		pr_perror("Can'r fetch file owner UIDs");
		close(fd);
		return -1;
	}

	close(fd);
	return 0;
}
Exemple #4
0
int __pid_load_vaddrs(int pid)
{
	int ret = 0;
	int proc_maps_fd = open_proc(pid, "maps");
	char linebuf[10000];
	unsigned long start;
	unsigned long end;
	char rest[1000];
	FILE *f = fdopen(proc_maps_fd, "r");

	if (!f)
		mpx_dig_abort();
	nr_ranges_populated = 0;
	while (!feof(f)) {
		char *readret = fgets(linebuf, sizeof(linebuf), f);
		int parsed;

		if (readret == NULL) {
			if (feof(f))
				break;
			mpx_dig_abort();
		}

		parsed = sscanf(linebuf, "%lx-%lx%s", &start, &end, rest);
		if (parsed != 3)
			mpx_dig_abort();

		dprintf4("result[%d]: %lx-%lx<->%s\n", parsed, start, end, rest);
		if (nr_ranges_populated >= nr_ranges_allocated) {
			ret = -E2BIG;
			break;
		}
		ranges[nr_ranges_populated].start = start;
		ranges[nr_ranges_populated].end = end;
		nr_ranges_populated++;
	}
	last_range = -1;
	fclose(f);
	close(proc_maps_fd);
	return ret;
}
Exemple #5
0
int switch_ns(int pid, struct ns_desc *nd, int *rst)
{
	char buf[32];
	int nsfd;
	int ret = -1;

	nsfd = open_proc(pid, "ns/%s", nd->str);
	if (nsfd < 0) {
		pr_perror("Can't open ns file");
		goto err_ns;
	}

	if (rst) {
		snprintf(buf, sizeof(buf), "/proc/self/ns/%s", nd->str);
		*rst = open(buf, O_RDONLY);
		if (*rst < 0) {
			pr_perror("Can't open ns file");
			goto err_rst;
		}
	}

	ret = setns(nsfd, nd->cflag);
	if (ret < 0) {
		pr_perror("Can't setns %d/%s", pid, nd->str);
		goto err_set;
	}

	close(nsfd);
	return 0;

err_set:
	if (rst)
		close(*rst);
err_rst:
	close(nsfd);
err_ns:
	return -1;
}
Exemple #6
0
static int dump_one_shmem(struct shmem_info_dump *si)
{
	struct iovec *iovs;
	struct page_pipe *pp;
	struct page_xfer xfer;
	int err, ret = -1, fd;
	unsigned char *map = NULL;
	void *addr = NULL;
	unsigned long pfn, nrpages;

	pr_info("Dumping shared memory %ld\n", si->shmid);

	nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE;
	map = xmalloc(nrpages * sizeof(*map));
	if (!map)
		goto err;

	fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end);
	if (fd < 0)
		goto err;

	addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0);
	close(fd);
	if (addr == MAP_FAILED) {
		pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n",
				si->shmid, si->start, si->end);
		goto err;
	}

	/*
	 * We can't use pagemap here, because this vma is
	 * not mapped to us at all, but mincore reports the
	 * pagecache status of a file, which is correct in
	 * this case.
	 */

	err = mincore(addr, si->size, map);
	if (err)
		goto err_unmap;

	iovs = xmalloc(((nrpages + 1) / 2) * sizeof(struct iovec));
	if (!iovs)
		goto err_unmap;

	pp = create_page_pipe((nrpages + 1) / 2, iovs, true);
	if (!pp)
		goto err_iovs;

	err = open_page_xfer(&xfer, CR_FD_SHMEM_PAGEMAP, si->shmid);
	if (err)
		goto err_pp;

	for (pfn = 0; pfn < nrpages; pfn++) {
		if (!(map[pfn] & PAGE_RSS))
			continue;
again:
		ret = page_pipe_add_page(pp, (unsigned long)addr + pfn * PAGE_SIZE);
		if (ret == -EAGAIN) {
			ret = dump_pages(pp, &xfer, addr);
			if (ret)
				goto err_xfer;
			page_pipe_reinit(pp);
			goto again;
		} else if (ret)
			goto err_xfer;
	}

	ret = dump_pages(pp, &xfer, addr);

err_xfer:
	xfer.close(&xfer);
err_pp:
	destroy_page_pipe(pp);
err_iovs:
	xfree(iovs);
err_unmap:
	munmap(addr,  si->size);
err:
	xfree(map);
	return ret;
}
Exemple #7
0
static int dump_one_shmem(struct shmem_info_dump *si)
{
	struct iovec *iovs;
	struct page_pipe *pp;
	struct page_pipe_buf *ppb;
	struct page_xfer xfer;
	int err, ret = -1, fd;
	unsigned char *map = NULL;
	void *addr = NULL;
	unsigned long pfn, nrpages;

	pr_info("Dumping shared memory %ld\n", si->shmid);

	nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE;
	map = xmalloc(nrpages * sizeof(*map));
	if (!map)
		goto err;

	fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end);
	if (fd < 0)
		goto err;

	addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0);
	close(fd);
	if (addr == MAP_FAILED) {
		pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n",
				si->shmid, si->start, si->end);
		goto err;
	}

	/*
	 * We can't use pagemap here, because this vma is
	 * not mapped to us at all, but mincore reports the
	 * pagecache status of a file, which is correct in
	 * this case.
	 */

	err = mincore(addr, si->size, map);
	if (err)
		goto err_unmap;

	iovs = xmalloc(((nrpages + 1) / 2) * sizeof(struct iovec));
	if (!iovs)
		goto err_unmap;

	pp = create_page_pipe((nrpages + 1) / 2, iovs);
	if (!pp)
		goto err_iovs;

	for (pfn = 0; pfn < nrpages; pfn++) {
		if (!(map[pfn] & PAGE_RSS))
			continue;

		if (page_pipe_add_page(pp, (unsigned long)addr + pfn * PAGE_SIZE))
			goto err_pp;
	}

	list_for_each_entry(ppb, &pp->bufs, l)
		if (vmsplice(ppb->p[1], ppb->iov, ppb->nr_segs,
					SPLICE_F_GIFT | SPLICE_F_NONBLOCK) !=
				ppb->pages_in * PAGE_SIZE) {
			pr_perror("Can't get shmem into page-pipe");
			goto err_pp;
		}

	err = open_page_xfer(&xfer, CR_FD_SHMEM_PAGEMAP, si->shmid);
	if (err)
		goto err_pp;

	ret = page_xfer_dump_pages(&xfer, pp, (unsigned long)addr);

	xfer.close(&xfer);
err_pp:
	destroy_page_pipe(pp);
err_iovs:
	xfree(iovs);
err_unmap:
	munmap(addr,  si->size);
err:
	xfree(map);
	return ret;
}
Exemple #8
0
int parse_pid_status(pid_t pid, struct proc_status_creds *cr)
{
	struct bfd f;
	int done = 0;
	int ret = -1;
	char *str;

	f.fd = open_proc(pid, "status");
	if (f.fd < 0) {
		pr_perror("Can't open proc status");
		return -1;
	}

	if (bfdopenr(&f))
		return -1;

	while (done < 9) {
		str = breadline(&f);
		if (str == NULL)
			break;
		if (IS_ERR(str))
			goto err_parse;

		if (!strncmp(str, "State:", 6)) {
			cr->state = str[7];
			done++;
		}

		if (!strncmp(str, "PPid:", 5)) {
			if (sscanf(str, "PPid:\t%d", &cr->ppid) != 1) {
				pr_err("Unable to parse: %s\n", str);
				goto err_parse;
			}
			done++;
		}

		if (!strncmp(str, "Uid:", 4)) {
			if (ids_parse(str + 5, cr->uids))
				goto err_parse;

			done++;
		}

		if (!strncmp(str, "Gid:", 4)) {
			if (ids_parse(str + 5, cr->gids))
				goto err_parse;

			done++;
		}

		if (!strncmp(str, "CapInh:", 7)) {
			if (cap_parse(str + 8, cr->cap_inh))
				goto err_parse;

			done++;
		}

		if (!strncmp(str, "CapEff:", 7)) {
			if (cap_parse(str + 8, cr->cap_eff))
				goto err_parse;

			done++;
		}

		if (!strncmp(str, "CapPrm:", 7)) {
			if (cap_parse(str + 8, cr->cap_prm))
				goto err_parse;

			done++;
		}

		if (!strncmp(str, "CapBnd:", 7)) {
			if (cap_parse(str + 8, cr->cap_bnd))
				goto err_parse;

			done++;
		}

		if (!strncmp(str, "Seccomp:", 8)) {
			if (sscanf(str + 9, "%d", &cr->seccomp_mode) != 1) {
				goto err_parse;
			}

			if (cr->seccomp_mode == SECCOMP_MODE_FILTER) {
				pr_err("SECCOMP_MODE_FILTER not currently supported\n");
				goto err_parse;
			}

			done++;
		}
	}

	if (done >= 8)
		ret = 0;

err_parse:
	if (ret)
		pr_err("Error parsing proc status file\n");
	bclose(&f);
	return ret;
}
Exemple #9
0
int parse_pid_stat(pid_t pid, struct proc_pid_stat *s)
{
	char *tok, *p;
	int fd;
	int n;

	fd = open_proc(pid, "stat");
	if (fd < 0)
		return -1;

	n = read(fd, buf, BUF_SIZE);
	close(fd);
	if (n < 1) {
		pr_err("stat for %d is corrupted\n", pid);
		return -1;
	}

	memset(s, 0, sizeof(*s));

	tok = strchr(buf, ' ');
	if (!tok)
		goto err;
	*tok++ = '\0';
	if (*tok != '(')
		goto err;

	s->pid = atoi(buf);

	p = strrchr(tok + 1, ')');
	if (!p)
		goto err;
	*tok = '\0';
	*p = '\0';

	strlcpy(s->comm, tok + 1, sizeof(s->comm));

	n = sscanf(p + 1,
	       " %c %d %d %d %d %d %u %lu %lu %lu %lu "
	       "%lu %lu %ld %ld %ld %ld %d %d %llu %lu %ld %lu %lu %lu %lu "
	       "%lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld "
	       "%lu %lu %lu %lu %lu %lu %lu %d",
		&s->state,
		&s->ppid,
		&s->pgid,
		&s->sid,
		&s->tty_nr,
		&s->tty_pgrp,
		&s->flags,
		&s->min_flt,
		&s->cmin_flt,
		&s->maj_flt,
		&s->cmaj_flt,
		&s->utime,
		&s->stime,
		&s->cutime,
		&s->cstime,
		&s->priority,
		&s->nice,
		&s->num_threads,
		&s->zero0,
		&s->start_time,
		&s->vsize,
		&s->mm_rss,
		&s->rsslim,
		&s->start_code,
		&s->end_code,
		&s->start_stack,
		&s->esp,
		&s->eip,
		&s->sig_pending,
		&s->sig_blocked,
		&s->sig_ignored,
		&s->sig_handled,
		&s->wchan,
		&s->zero1,
		&s->zero2,
		&s->exit_signal,
		&s->task_cpu,
		&s->rt_priority,
		&s->policy,
		&s->delayacct_blkio_ticks,
		&s->gtime,
		&s->cgtime,
		&s->start_data,
		&s->end_data,
		&s->start_brk,
		&s->arg_start,
		&s->arg_end,
		&s->env_start,
		&s->env_end,
		&s->exit_code);
	if (n < 50)
		goto err;

	return 0;

err:
	pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
	return -1;
}
Exemple #10
0
int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list)
{
	struct vma_area *vma_area = NULL;
	unsigned long start, end, pgoff, prev_end = 0;
	char r, w, x, s;
	int ret = -1;
	struct vma_file_info vfi;
	struct vma_file_info prev_vfi = {};

	DIR *map_files_dir = NULL;
	struct bfd f;

	vma_area_list->nr = 0;
	vma_area_list->nr_aios = 0;
	vma_area_list->longest = 0;
	vma_area_list->priv_size = 0;
	INIT_LIST_HEAD(&vma_area_list->h);

	f.fd = open_proc(pid, "smaps");
	if (f.fd < 0)
		goto err_n;

	if (bfdopenr(&f))
		goto err_n;

	map_files_dir = opendir_proc(pid, "map_files");
	if (!map_files_dir) /* old kernel? */
		goto err;

	while (1) {
		int num;
		char file_path[32];
		bool eof;
		char *str;

		str = breadline(&f);
		if (IS_ERR(str))
			goto err;
		eof = (str == NULL);

		if (!eof && !is_vma_range_fmt(str)) {
			if (!strncmp(str, "Nonlinear", 9)) {
				BUG_ON(!vma_area);
				pr_err("Nonlinear mapping found %016"PRIx64"-%016"PRIx64"\n",
				       vma_area->e->start, vma_area->e->end);
				/*
				 * VMA is already on list and will be
				 * freed later as list get destroyed.
				 */
				vma_area = NULL;
				goto err;
			} else if (!strncmp(str, "VmFlags: ", 9)) {
				BUG_ON(!vma_area);
				if (parse_vmflags(&str[9], vma_area))
					goto err;
				continue;
			} else
				continue;
		}

		if (vma_area && vma_list_add(vma_area, vma_area_list,
						&prev_end, &vfi, &prev_vfi))
			goto err;

		if (eof)
			break;

		vma_area = alloc_vma_area();
		if (!vma_area)
			goto err;

		memzero(file_path, sizeof(file_path));
		num = sscanf(str, "%lx-%lx %c%c%c%c %lx %x:%x %lu %31s",
			     &start, &end, &r, &w, &x, &s, &pgoff,
			     &vfi.dev_maj, &vfi.dev_min, &vfi.ino, file_path);
		if (num < 10) {
			pr_err("Can't parse: %s\n", str);
			goto err;
		}

		vma_area->e->start	= start;
		vma_area->e->end	= end;
		vma_area->e->pgoff	= pgoff;
		vma_area->e->prot	= PROT_NONE;

		if (r == 'r')
			vma_area->e->prot |= PROT_READ;
		if (w == 'w')
			vma_area->e->prot |= PROT_WRITE;
		if (x == 'x')
			vma_area->e->prot |= PROT_EXEC;

		if (s == 's')
			vma_area->e->flags = MAP_SHARED;
		else if (s == 'p')
			vma_area->e->flags = MAP_PRIVATE;
		else {
			pr_err("Unexpected VMA met (%c)\n", s);
			goto err;
		}

		if (handle_vma(pid, vma_area, file_path, map_files_dir,
					&vfi, &prev_vfi, vma_area_list))
			goto err;
	}

	vma_area = NULL;
	ret = 0;

err:
	bclose(&f);
err_n:
	if (map_files_dir)
		closedir(map_files_dir);

	xfree(vma_area);
	return ret;

}
Exemple #11
0
int sysctl_op(struct sysctl_req *req, size_t nr_req, int op, unsigned int ns)
{
	int i, fd, ret;
	struct sysctl_userns_req *userns_req;
	struct sysctl_req *cur;

	if (nr_req == 0)
		return 0;

	if (ns & ~KNOWN_NS_MASK) {
		pr_err("don't know how to restore some namespaces in %u\n", ns);
		return -1;
	}

	/* The way sysctl files behave on open/write depends on the namespace
	 * they correspond to. If we don't want to interact with something in a
	 * namespace (e.g. kernel/cap_last_cap is global), we can do this from
	 * the current process. Similarly, if we're accessing net namespaces,
	 * we can just do the operation from our current process, since
	 * anything with CAP_NET_ADMIN can write to the net/ sysctls, and we
	 * still have that even when restoring in a user ns.
	 *
	 * For IPC/UTS, we restore them as described above.
	 *
	 * For read operations, we need to copy the values back to return.
	 * Fortunately, we only do read on dump (or global reads on restore),
	 * so we can do those in process as well.
	 */
	if (!ns || ns & CLONE_NEWNET || op == CTL_READ)
		return __nonuserns_sysctl_op(req, nr_req, op);

	/*
	 * In order to avoid lots of opening of /proc/sys for each struct sysctl_req,
	 * we encode each array of sysctl_reqs into one contiguous region of memory so
	 * it can be passed via userns_call if necessary. It looks like this:
	 *
	 *  struct sysctl_userns_req    struct sysctl_req       name        arg
	 * ---------------------------------------------------------------------------
	 * |  op  |  nr_req  |  reqs  | <fields> | name | arg | "the name" | "the arg" ...
	 * ---------------------------------------------------------------------------
	 *                       |____^             |______|__^            ^
	 *                                                 |_______________|
	 */
	userns_req = alloca(MAX_UNSFD_MSG_SIZE);
	userns_req->op = op;
	userns_req->nr_req = nr_req;
	userns_req->ns = ns;
	userns_req->reqs = (struct sysctl_req *) (&userns_req[1]);

	cur = userns_req->reqs;
	for (i = 0; i < nr_req; i++) {
		int arg_len = sysctl_userns_arg_size(req[i].type);
		int name_len = strlen(req[i].name) + 1;
		int total_len = sizeof(*cur) + arg_len + name_len;

		if (((char *) cur) + total_len >= ((char *) userns_req) + MAX_UNSFD_MSG_SIZE) {
			pr_err("sysctl msg %s too big: %d\n", req[i].name, total_len);
			return -1;
		}

		/* copy over the non-pointer fields */
		cur->type = req[i].type;
		cur->flags = req[i].flags;

		cur->name = (char *) &cur[1];
		strcpy(cur->name, req[i].name);

		cur->arg = cur->name + name_len;
		memcpy(cur->arg, req[i].arg, arg_len);

		cur = (struct sysctl_req *) (((char *) cur) + total_len);
	}

	fd = open_proc(PROC_SELF, "ns");
	if (fd < 0)
		return -1;

	ret = userns_call(__userns_sysctl_op, 0, userns_req, MAX_UNSFD_MSG_SIZE, fd);
	close(fd);
	return ret;
}