brintos

brintos / linux-shallow public Read only

0
0
Text · 7.5 KiB · cb185c5 Raw
377 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 * Copyright (C) 2017 Hari Bathini, IBM Corporation5 */6 7#include "namespaces.h"8#include "event.h"9#include "get_current_dir_name.h"10#include <sys/types.h>11#include <sys/stat.h>12#include <fcntl.h>13#include <limits.h>14#include <sched.h>15#include <stdlib.h>16#include <stdio.h>17#include <string.h>18#include <unistd.h>19#include <asm/bug.h>20#include <linux/kernel.h>21#include <linux/zalloc.h>22 23static const char *perf_ns__names[] = {24	[NET_NS_INDEX]		= "net",25	[UTS_NS_INDEX]		= "uts",26	[IPC_NS_INDEX]		= "ipc",27	[PID_NS_INDEX]		= "pid",28	[USER_NS_INDEX]		= "user",29	[MNT_NS_INDEX]		= "mnt",30	[CGROUP_NS_INDEX]	= "cgroup",31};32 33const char *perf_ns__name(unsigned int id)34{35	if (id >= ARRAY_SIZE(perf_ns__names))36		return "UNKNOWN";37	return perf_ns__names[id];38}39 40struct namespaces *namespaces__new(struct perf_record_namespaces *event)41{42	struct namespaces *namespaces;43	u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *44			      sizeof(struct perf_ns_link_info));45 46	namespaces = zalloc(sizeof(struct namespaces) + link_info_size);47	if (!namespaces)48		return NULL;49 50	namespaces->end_time = -1;51 52	if (event)53		memcpy(namespaces->link_info, event->link_info, link_info_size);54 55	return namespaces;56}57 58void namespaces__free(struct namespaces *namespaces)59{60	free(namespaces);61}62 63static int nsinfo__get_nspid(pid_t *tgid, pid_t *nstgid, bool *in_pidns, const char *path)64{65	FILE *f = NULL;66	char *statln = NULL;67	size_t linesz = 0;68	char *nspid;69 70	f = fopen(path, "r");71	if (f == NULL)72		return -1;73 74	while (getline(&statln, &linesz, f) != -1) {75		/* Use tgid if CONFIG_PID_NS is not defined. */76		if (strstr(statln, "Tgid:") != NULL) {77			*tgid = (pid_t)strtol(strrchr(statln, '\t'), NULL, 10);78			*nstgid = *tgid;79		}80 81		if (strstr(statln, "NStgid:") != NULL) {82			nspid = strrchr(statln, '\t');83			*nstgid = (pid_t)strtol(nspid, NULL, 10);84			/*85			 * If innermost tgid is not the first, process is in a different86			 * PID namespace.87			 */88			*in_pidns = (statln + sizeof("NStgid:") - 1) != nspid;89			break;90		}91	}92 93	fclose(f);94	free(statln);95	return 0;96}97 98int nsinfo__init(struct nsinfo *nsi)99{100	char oldns[PATH_MAX];101	char spath[PATH_MAX];102	char *newns = NULL;103	struct stat old_stat;104	struct stat new_stat;105	int rv = -1;106 107	if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)108		return rv;109 110	if (asprintf(&newns, "/proc/%d/ns/mnt", nsinfo__pid(nsi)) == -1)111		return rv;112 113	if (stat(oldns, &old_stat) < 0)114		goto out;115 116	if (stat(newns, &new_stat) < 0)117		goto out;118 119	/* Check if the mount namespaces differ, if so then indicate that we120	 * want to switch as part of looking up dso/map data.121	 */122	if (old_stat.st_ino != new_stat.st_ino) {123		RC_CHK_ACCESS(nsi)->need_setns = true;124		RC_CHK_ACCESS(nsi)->mntns_path = newns;125		newns = NULL;126	}127 128	/* If we're dealing with a process that is in a different PID namespace,129	 * attempt to work out the innermost tgid for the process.130	 */131	if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsinfo__pid(nsi)) >= PATH_MAX)132		goto out;133 134	rv = nsinfo__get_nspid(&RC_CHK_ACCESS(nsi)->tgid, &RC_CHK_ACCESS(nsi)->nstgid,135			       &RC_CHK_ACCESS(nsi)->in_pidns, spath);136 137out:138	free(newns);139	return rv;140}141 142static struct nsinfo *nsinfo__alloc(void)143{144	struct nsinfo *res;145	RC_STRUCT(nsinfo) *nsi;146 147	nsi = calloc(1, sizeof(*nsi));148	if (ADD_RC_CHK(res, nsi))149		refcount_set(&nsi->refcnt, 1);150 151	return res;152}153 154struct nsinfo *nsinfo__new(pid_t pid)155{156	struct nsinfo *nsi;157 158	if (pid == 0)159		return NULL;160 161	nsi = nsinfo__alloc();162	if (!nsi)163		return NULL;164 165	RC_CHK_ACCESS(nsi)->pid = pid;166	RC_CHK_ACCESS(nsi)->tgid = pid;167	RC_CHK_ACCESS(nsi)->nstgid = pid;168	nsinfo__clear_need_setns(nsi);169	RC_CHK_ACCESS(nsi)->in_pidns = false;170	/* Init may fail if the process exits while we're trying to look at its171	 * proc information. In that case, save the pid but don't try to enter172	 * the namespace.173	 */174	if (nsinfo__init(nsi) == -1)175		nsinfo__clear_need_setns(nsi);176 177	return nsi;178}179 180static const char *nsinfo__mntns_path(const struct nsinfo *nsi)181{182	return RC_CHK_ACCESS(nsi)->mntns_path;183}184 185struct nsinfo *nsinfo__copy(const struct nsinfo *nsi)186{187	struct nsinfo *nnsi;188 189	if (nsi == NULL)190		return NULL;191 192	nnsi = nsinfo__alloc();193	if (!nnsi)194		return NULL;195 196	RC_CHK_ACCESS(nnsi)->pid = nsinfo__pid(nsi);197	RC_CHK_ACCESS(nnsi)->tgid = nsinfo__tgid(nsi);198	RC_CHK_ACCESS(nnsi)->nstgid = nsinfo__nstgid(nsi);199	RC_CHK_ACCESS(nnsi)->need_setns = nsinfo__need_setns(nsi);200	RC_CHK_ACCESS(nnsi)->in_pidns = nsinfo__in_pidns(nsi);201	if (nsinfo__mntns_path(nsi)) {202		RC_CHK_ACCESS(nnsi)->mntns_path = strdup(nsinfo__mntns_path(nsi));203		if (!RC_CHK_ACCESS(nnsi)->mntns_path) {204			nsinfo__put(nnsi);205			return NULL;206		}207	}208 209	return nnsi;210}211 212static refcount_t *nsinfo__refcnt(struct nsinfo *nsi)213{214	return &RC_CHK_ACCESS(nsi)->refcnt;215}216 217static void nsinfo__delete(struct nsinfo *nsi)218{219	if (nsi) {220		WARN_ONCE(refcount_read(nsinfo__refcnt(nsi)) != 0, "nsinfo refcnt unbalanced\n");221		zfree(&RC_CHK_ACCESS(nsi)->mntns_path);222		RC_CHK_FREE(nsi);223	}224}225 226struct nsinfo *nsinfo__get(struct nsinfo *nsi)227{228	struct nsinfo *result;229 230	if (RC_CHK_GET(result, nsi))231		refcount_inc(nsinfo__refcnt(nsi));232 233	return result;234}235 236void nsinfo__put(struct nsinfo *nsi)237{238	if (nsi && refcount_dec_and_test(nsinfo__refcnt(nsi)))239		nsinfo__delete(nsi);240	else241		RC_CHK_PUT(nsi);242}243 244bool nsinfo__need_setns(const struct nsinfo *nsi)245{246	return RC_CHK_ACCESS(nsi)->need_setns;247}248 249void nsinfo__clear_need_setns(struct nsinfo *nsi)250{251	RC_CHK_ACCESS(nsi)->need_setns = false;252}253 254pid_t nsinfo__tgid(const struct nsinfo  *nsi)255{256	return RC_CHK_ACCESS(nsi)->tgid;257}258 259pid_t nsinfo__nstgid(const struct nsinfo  *nsi)260{261	return RC_CHK_ACCESS(nsi)->nstgid;262}263 264pid_t nsinfo__pid(const struct nsinfo  *nsi)265{266	return RC_CHK_ACCESS(nsi)->pid;267}268 269pid_t nsinfo__in_pidns(const struct nsinfo  *nsi)270{271	return RC_CHK_ACCESS(nsi)->in_pidns;272}273 274void nsinfo__mountns_enter(struct nsinfo *nsi,275				  struct nscookie *nc)276{277	char curpath[PATH_MAX];278	int oldns = -1;279	int newns = -1;280	char *oldcwd = NULL;281 282	if (nc == NULL)283		return;284 285	nc->oldns = -1;286	nc->newns = -1;287 288	if (!nsi || !nsinfo__need_setns(nsi))289		return;290 291	if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)292		return;293 294	oldcwd = get_current_dir_name();295	if (!oldcwd)296		return;297 298	oldns = open(curpath, O_RDONLY);299	if (oldns < 0)300		goto errout;301 302	newns = open(nsinfo__mntns_path(nsi), O_RDONLY);303	if (newns < 0)304		goto errout;305 306	if (setns(newns, CLONE_NEWNS) < 0)307		goto errout;308 309	nc->oldcwd = oldcwd;310	nc->oldns = oldns;311	nc->newns = newns;312	return;313 314errout:315	free(oldcwd);316	if (oldns > -1)317		close(oldns);318	if (newns > -1)319		close(newns);320}321 322void nsinfo__mountns_exit(struct nscookie *nc)323{324	if (nc == NULL || nc->oldns == -1 || nc->newns == -1 || !nc->oldcwd)325		return;326 327	setns(nc->oldns, CLONE_NEWNS);328 329	if (nc->oldcwd) {330		WARN_ON_ONCE(chdir(nc->oldcwd));331		zfree(&nc->oldcwd);332	}333 334	if (nc->oldns > -1) {335		close(nc->oldns);336		nc->oldns = -1;337	}338 339	if (nc->newns > -1) {340		close(nc->newns);341		nc->newns = -1;342	}343}344 345char *nsinfo__realpath(const char *path, struct nsinfo *nsi)346{347	char *rpath;348	struct nscookie nsc;349 350	nsinfo__mountns_enter(nsi, &nsc);351	rpath = realpath(path, NULL);352	nsinfo__mountns_exit(&nsc);353 354	return rpath;355}356 357int nsinfo__stat(const char *filename, struct stat *st, struct nsinfo *nsi)358{359	int ret;360	struct nscookie nsc;361 362	nsinfo__mountns_enter(nsi, &nsc);363	ret = stat(filename, st);364	nsinfo__mountns_exit(&nsc);365 366	return ret;367}368 369bool nsinfo__is_in_root_namespace(void)370{371	pid_t tgid = 0, nstgid = 0;372	bool in_pidns = false;373 374	nsinfo__get_nspid(&tgid, &nstgid, &in_pidns, "/proc/self/status");375	return !in_pidns;376}377