Linux Audio

Check our new training course

Loading...
v5.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *
  4 * Copyright (C) 2017 Hari Bathini, IBM Corporation
  5 */
  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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 63int nsinfo__init(struct nsinfo *nsi)
 64{
 65	char oldns[PATH_MAX];
 66	char spath[PATH_MAX];
 67	char *newns = NULL;
 68	char *statln = NULL;
 69	struct stat old_stat;
 70	struct stat new_stat;
 71	FILE *f = NULL;
 72	size_t linesz = 0;
 73	int rv = -1;
 74
 75	if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
 76		return rv;
 77
 78	if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
 79		return rv;
 80
 81	if (stat(oldns, &old_stat) < 0)
 82		goto out;
 83
 84	if (stat(newns, &new_stat) < 0)
 85		goto out;
 86
 87	/* Check if the mount namespaces differ, if so then indicate that we
 88	 * want to switch as part of looking up dso/map data.
 89	 */
 90	if (old_stat.st_ino != new_stat.st_ino) {
 91		nsi->need_setns = true;
 92		nsi->mntns_path = newns;
 93		newns = NULL;
 94	}
 95
 96	/* If we're dealing with a process that is in a different PID namespace,
 97	 * attempt to work out the innermost tgid for the process.
 98	 */
 99	if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsi->pid) >= PATH_MAX)
100		goto out;
101
102	f = fopen(spath, "r");
103	if (f == NULL)
104		goto out;
105
106	while (getline(&statln, &linesz, f) != -1) {
107		/* Use tgid if CONFIG_PID_NS is not defined. */
108		if (strstr(statln, "Tgid:") != NULL) {
109			nsi->tgid = (pid_t)strtol(strrchr(statln, '\t'),
110						     NULL, 10);
111			nsi->nstgid = nsi->tgid;
112		}
113
114		if (strstr(statln, "NStgid:") != NULL) {
115			nsi->nstgid = (pid_t)strtol(strrchr(statln, '\t'),
116						     NULL, 10);
117			break;
118		}
119	}
120	rv = 0;
121
122out:
123	if (f != NULL)
124		(void) fclose(f);
125	free(statln);
126	free(newns);
127	return rv;
128}
129
130struct nsinfo *nsinfo__new(pid_t pid)
131{
132	struct nsinfo *nsi;
133
134	if (pid == 0)
135		return NULL;
136
137	nsi = calloc(1, sizeof(*nsi));
138	if (nsi != NULL) {
139		nsi->pid = pid;
140		nsi->tgid = pid;
141		nsi->nstgid = pid;
142		nsi->need_setns = false;
 
143		/* Init may fail if the process exits while we're trying to look
144		 * at its proc information.  In that case, save the pid but
145		 * don't try to enter the namespace.
146		 */
147		if (nsinfo__init(nsi) == -1)
148			nsi->need_setns = false;
149
150		refcount_set(&nsi->refcnt, 1);
151	}
152
153	return nsi;
154}
155
156struct nsinfo *nsinfo__copy(struct nsinfo *nsi)
157{
158	struct nsinfo *nnsi;
159
160	if (nsi == NULL)
161		return NULL;
162
163	nnsi = calloc(1, sizeof(*nnsi));
164	if (nnsi != NULL) {
165		nnsi->pid = nsi->pid;
166		nnsi->tgid = nsi->tgid;
167		nnsi->nstgid = nsi->nstgid;
168		nnsi->need_setns = nsi->need_setns;
 
169		if (nsi->mntns_path) {
170			nnsi->mntns_path = strdup(nsi->mntns_path);
171			if (!nnsi->mntns_path) {
172				free(nnsi);
173				return NULL;
174			}
175		}
176		refcount_set(&nnsi->refcnt, 1);
177	}
178
179	return nnsi;
180}
181
182void nsinfo__delete(struct nsinfo *nsi)
183{
184	zfree(&nsi->mntns_path);
185	free(nsi);
186}
187
188struct nsinfo *nsinfo__get(struct nsinfo *nsi)
189{
190	if (nsi)
191		refcount_inc(&nsi->refcnt);
192	return nsi;
193}
194
195void nsinfo__put(struct nsinfo *nsi)
196{
197	if (nsi && refcount_dec_and_test(&nsi->refcnt))
198		nsinfo__delete(nsi);
199}
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201void nsinfo__mountns_enter(struct nsinfo *nsi,
202				  struct nscookie *nc)
203{
204	char curpath[PATH_MAX];
205	int oldns = -1;
206	int newns = -1;
207	char *oldcwd = NULL;
208
209	if (nc == NULL)
210		return;
211
212	nc->oldns = -1;
213	nc->newns = -1;
214
215	if (!nsi || !nsi->need_setns)
216		return;
217
218	if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
219		return;
220
221	oldcwd = get_current_dir_name();
222	if (!oldcwd)
223		return;
224
225	oldns = open(curpath, O_RDONLY);
226	if (oldns < 0)
227		goto errout;
228
229	newns = open(nsi->mntns_path, O_RDONLY);
230	if (newns < 0)
231		goto errout;
232
233	if (setns(newns, CLONE_NEWNS) < 0)
234		goto errout;
235
236	nc->oldcwd = oldcwd;
237	nc->oldns = oldns;
238	nc->newns = newns;
239	return;
240
241errout:
242	free(oldcwd);
243	if (oldns > -1)
244		close(oldns);
245	if (newns > -1)
246		close(newns);
247}
248
249void nsinfo__mountns_exit(struct nscookie *nc)
250{
251	if (nc == NULL || nc->oldns == -1 || nc->newns == -1 || !nc->oldcwd)
252		return;
253
254	setns(nc->oldns, CLONE_NEWNS);
255
256	if (nc->oldcwd) {
257		WARN_ON_ONCE(chdir(nc->oldcwd));
258		zfree(&nc->oldcwd);
259	}
260
261	if (nc->oldns > -1) {
262		close(nc->oldns);
263		nc->oldns = -1;
264	}
265
266	if (nc->newns > -1) {
267		close(nc->newns);
268		nc->newns = -1;
269	}
270}
271
272char *nsinfo__realpath(const char *path, struct nsinfo *nsi)
273{
274	char *rpath;
275	struct nscookie nsc;
276
277	nsinfo__mountns_enter(nsi, &nsc);
278	rpath = realpath(path, NULL);
279	nsinfo__mountns_exit(&nsc);
280
281	return rpath;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282}
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *
  4 * Copyright (C) 2017 Hari Bathini, IBM Corporation
  5 */
  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(struct nsinfo *nsi, 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			nsi->tgid = (pid_t)strtol(strrchr(statln, '\t'),
 78						     NULL, 10);
 79			nsi->nstgid = nsinfo__tgid(nsi);
 80		}
 81
 82		if (strstr(statln, "NStgid:") != NULL) {
 83			nspid = strrchr(statln, '\t');
 84			nsi->nstgid = (pid_t)strtol(nspid, NULL, 10);
 85			/*
 86			 * If innermost tgid is not the first, process is in a different
 87			 * PID namespace.
 88			 */
 89			nsi->in_pidns = (statln + sizeof("NStgid:") - 1) != nspid;
 90			break;
 91		}
 92	}
 93
 94	fclose(f);
 95	free(statln);
 96	return 0;
 97}
 98
 99int nsinfo__init(struct nsinfo *nsi)
100{
101	char oldns[PATH_MAX];
102	char spath[PATH_MAX];
103	char *newns = NULL;
 
104	struct stat old_stat;
105	struct stat new_stat;
 
 
106	int rv = -1;
107
108	if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
109		return rv;
110
111	if (asprintf(&newns, "/proc/%d/ns/mnt", nsinfo__pid(nsi)) == -1)
112		return rv;
113
114	if (stat(oldns, &old_stat) < 0)
115		goto out;
116
117	if (stat(newns, &new_stat) < 0)
118		goto out;
119
120	/* Check if the mount namespaces differ, if so then indicate that we
121	 * want to switch as part of looking up dso/map data.
122	 */
123	if (old_stat.st_ino != new_stat.st_ino) {
124		nsi->need_setns = true;
125		nsi->mntns_path = newns;
126		newns = NULL;
127	}
128
129	/* If we're dealing with a process that is in a different PID namespace,
130	 * attempt to work out the innermost tgid for the process.
131	 */
132	if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsinfo__pid(nsi)) >= PATH_MAX)
 
 
 
 
133		goto out;
134
135	rv = nsinfo__get_nspid(nsi, spath);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
137out:
 
 
 
138	free(newns);
139	return rv;
140}
141
142struct nsinfo *nsinfo__new(pid_t pid)
143{
144	struct nsinfo *nsi;
145
146	if (pid == 0)
147		return NULL;
148
149	nsi = calloc(1, sizeof(*nsi));
150	if (nsi != NULL) {
151		nsi->pid = pid;
152		nsi->tgid = pid;
153		nsi->nstgid = pid;
154		nsi->need_setns = false;
155		nsi->in_pidns = false;
156		/* Init may fail if the process exits while we're trying to look
157		 * at its proc information.  In that case, save the pid but
158		 * don't try to enter the namespace.
159		 */
160		if (nsinfo__init(nsi) == -1)
161			nsi->need_setns = false;
162
163		refcount_set(&nsi->refcnt, 1);
164	}
165
166	return nsi;
167}
168
169struct nsinfo *nsinfo__copy(const struct nsinfo *nsi)
170{
171	struct nsinfo *nnsi;
172
173	if (nsi == NULL)
174		return NULL;
175
176	nnsi = calloc(1, sizeof(*nnsi));
177	if (nnsi != NULL) {
178		nnsi->pid = nsinfo__pid(nsi);
179		nnsi->tgid = nsinfo__tgid(nsi);
180		nnsi->nstgid = nsinfo__nstgid(nsi);
181		nnsi->need_setns = nsinfo__need_setns(nsi);
182		nnsi->in_pidns = nsinfo__in_pidns(nsi);
183		if (nsi->mntns_path) {
184			nnsi->mntns_path = strdup(nsi->mntns_path);
185			if (!nnsi->mntns_path) {
186				free(nnsi);
187				return NULL;
188			}
189		}
190		refcount_set(&nnsi->refcnt, 1);
191	}
192
193	return nnsi;
194}
195
196static void nsinfo__delete(struct nsinfo *nsi)
197{
198	zfree(&nsi->mntns_path);
199	free(nsi);
200}
201
202struct nsinfo *nsinfo__get(struct nsinfo *nsi)
203{
204	if (nsi)
205		refcount_inc(&nsi->refcnt);
206	return nsi;
207}
208
209void nsinfo__put(struct nsinfo *nsi)
210{
211	if (nsi && refcount_dec_and_test(&nsi->refcnt))
212		nsinfo__delete(nsi);
213}
214
215bool nsinfo__need_setns(const struct nsinfo *nsi)
216{
217        return nsi->need_setns;
218}
219
220void nsinfo__clear_need_setns(struct nsinfo *nsi)
221{
222        nsi->need_setns = false;
223}
224
225pid_t nsinfo__tgid(const struct nsinfo  *nsi)
226{
227        return nsi->tgid;
228}
229
230pid_t nsinfo__nstgid(const struct nsinfo  *nsi)
231{
232        return nsi->nstgid;
233}
234
235pid_t nsinfo__pid(const struct nsinfo  *nsi)
236{
237        return nsi->pid;
238}
239
240pid_t nsinfo__in_pidns(const struct nsinfo  *nsi)
241{
242        return nsi->in_pidns;
243}
244
245void nsinfo__mountns_enter(struct nsinfo *nsi,
246				  struct nscookie *nc)
247{
248	char curpath[PATH_MAX];
249	int oldns = -1;
250	int newns = -1;
251	char *oldcwd = NULL;
252
253	if (nc == NULL)
254		return;
255
256	nc->oldns = -1;
257	nc->newns = -1;
258
259	if (!nsi || !nsi->need_setns)
260		return;
261
262	if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
263		return;
264
265	oldcwd = get_current_dir_name();
266	if (!oldcwd)
267		return;
268
269	oldns = open(curpath, O_RDONLY);
270	if (oldns < 0)
271		goto errout;
272
273	newns = open(nsi->mntns_path, O_RDONLY);
274	if (newns < 0)
275		goto errout;
276
277	if (setns(newns, CLONE_NEWNS) < 0)
278		goto errout;
279
280	nc->oldcwd = oldcwd;
281	nc->oldns = oldns;
282	nc->newns = newns;
283	return;
284
285errout:
286	free(oldcwd);
287	if (oldns > -1)
288		close(oldns);
289	if (newns > -1)
290		close(newns);
291}
292
293void nsinfo__mountns_exit(struct nscookie *nc)
294{
295	if (nc == NULL || nc->oldns == -1 || nc->newns == -1 || !nc->oldcwd)
296		return;
297
298	setns(nc->oldns, CLONE_NEWNS);
299
300	if (nc->oldcwd) {
301		WARN_ON_ONCE(chdir(nc->oldcwd));
302		zfree(&nc->oldcwd);
303	}
304
305	if (nc->oldns > -1) {
306		close(nc->oldns);
307		nc->oldns = -1;
308	}
309
310	if (nc->newns > -1) {
311		close(nc->newns);
312		nc->newns = -1;
313	}
314}
315
316char *nsinfo__realpath(const char *path, struct nsinfo *nsi)
317{
318	char *rpath;
319	struct nscookie nsc;
320
321	nsinfo__mountns_enter(nsi, &nsc);
322	rpath = realpath(path, NULL);
323	nsinfo__mountns_exit(&nsc);
324
325	return rpath;
326}
327
328int nsinfo__stat(const char *filename, struct stat *st, struct nsinfo *nsi)
329{
330	int ret;
331	struct nscookie nsc;
332
333	nsinfo__mountns_enter(nsi, &nsc);
334	ret = stat(filename, st);
335	nsinfo__mountns_exit(&nsc);
336
337	return ret;
338}
339
340bool nsinfo__is_in_root_namespace(void)
341{
342	struct nsinfo nsi;
343
344	memset(&nsi, 0x0, sizeof(nsi));
345	nsinfo__get_nspid(&nsi, "/proc/self/status");
346	return !nsi.in_pidns;
347}