Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
Loading...
v4.17
 
  1/*
  2 * This program is free software; you can redistribute it and/or modify
  3 * it under the terms of the GNU General Public License, version 2, as
  4 * published by the Free Software Foundation.
  5 *
  6 * Copyright (C) 2017 Hari Bathini, IBM Corporation
  7 */
  8
  9#include "namespaces.h"
 10#include "util.h"
 11#include "event.h"
 
 12#include <sys/types.h>
 13#include <sys/stat.h>
 14#include <fcntl.h>
 15#include <limits.h>
 16#include <sched.h>
 17#include <stdlib.h>
 18#include <stdio.h>
 19#include <string.h>
 20#include <unistd.h>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 21
 22struct namespaces *namespaces__new(struct namespaces_event *event)
 23{
 24	struct namespaces *namespaces;
 25	u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) *
 26			      sizeof(struct perf_ns_link_info));
 27
 28	namespaces = zalloc(sizeof(struct namespaces) + link_info_size);
 29	if (!namespaces)
 30		return NULL;
 31
 32	namespaces->end_time = -1;
 33
 34	if (event)
 35		memcpy(namespaces->link_info, event->link_info, link_info_size);
 36
 37	return namespaces;
 38}
 39
 40void namespaces__free(struct namespaces *namespaces)
 41{
 42	free(namespaces);
 43}
 44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 45int nsinfo__init(struct nsinfo *nsi)
 46{
 47	char oldns[PATH_MAX];
 48	char spath[PATH_MAX];
 49	char *newns = NULL;
 50	char *statln = NULL;
 51	struct stat old_stat;
 52	struct stat new_stat;
 53	FILE *f = NULL;
 54	size_t linesz = 0;
 55	int rv = -1;
 56
 57	if (snprintf(oldns, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
 58		return rv;
 59
 60	if (asprintf(&newns, "/proc/%d/ns/mnt", nsi->pid) == -1)
 61		return rv;
 62
 63	if (stat(oldns, &old_stat) < 0)
 64		goto out;
 65
 66	if (stat(newns, &new_stat) < 0)
 67		goto out;
 68
 69	/* Check if the mount namespaces differ, if so then indicate that we
 70	 * want to switch as part of looking up dso/map data.
 71	 */
 72	if (old_stat.st_ino != new_stat.st_ino) {
 73		nsi->need_setns = true;
 74		nsi->mntns_path = newns;
 75		newns = NULL;
 76	}
 77
 78	/* If we're dealing with a process that is in a different PID namespace,
 79	 * attempt to work out the innermost tgid for the process.
 80	 */
 81	if (snprintf(spath, PATH_MAX, "/proc/%d/status", nsi->pid) >= PATH_MAX)
 82		goto out;
 83
 84	f = fopen(spath, "r");
 85	if (f == NULL)
 86		goto out;
 87
 88	while (getline(&statln, &linesz, f) != -1) {
 89		/* Use tgid if CONFIG_PID_NS is not defined. */
 90		if (strstr(statln, "Tgid:") != NULL) {
 91			nsi->tgid = (pid_t)strtol(strrchr(statln, '\t'),
 92						     NULL, 10);
 93			nsi->nstgid = nsi->tgid;
 94		}
 95
 96		if (strstr(statln, "NStgid:") != NULL) {
 97			nsi->nstgid = (pid_t)strtol(strrchr(statln, '\t'),
 98						     NULL, 10);
 99			break;
100		}
101	}
102	rv = 0;
103
104out:
105	if (f != NULL)
106		(void) fclose(f);
107	free(statln);
108	free(newns);
109	return rv;
110}
111
112struct nsinfo *nsinfo__new(pid_t pid)
113{
114	struct nsinfo *nsi;
115
116	if (pid == 0)
117		return NULL;
118
119	nsi = calloc(1, sizeof(*nsi));
120	if (nsi != NULL) {
121		nsi->pid = pid;
122		nsi->tgid = pid;
123		nsi->nstgid = pid;
124		nsi->need_setns = false;
 
125		/* Init may fail if the process exits while we're trying to look
126		 * at its proc information.  In that case, save the pid but
127		 * don't try to enter the namespace.
128		 */
129		if (nsinfo__init(nsi) == -1)
130			nsi->need_setns = false;
131
132		refcount_set(&nsi->refcnt, 1);
133	}
134
135	return nsi;
136}
137
138struct nsinfo *nsinfo__copy(struct nsinfo *nsi)
139{
140	struct nsinfo *nnsi;
141
 
 
 
142	nnsi = calloc(1, sizeof(*nnsi));
143	if (nnsi != NULL) {
144		nnsi->pid = nsi->pid;
145		nnsi->tgid = nsi->tgid;
146		nnsi->nstgid = nsi->nstgid;
147		nnsi->need_setns = nsi->need_setns;
 
148		if (nsi->mntns_path) {
149			nnsi->mntns_path = strdup(nsi->mntns_path);
150			if (!nnsi->mntns_path) {
151				free(nnsi);
152				return NULL;
153			}
154		}
155		refcount_set(&nnsi->refcnt, 1);
156	}
157
158	return nnsi;
159}
160
161void nsinfo__delete(struct nsinfo *nsi)
162{
163	zfree(&nsi->mntns_path);
164	free(nsi);
165}
166
167struct nsinfo *nsinfo__get(struct nsinfo *nsi)
168{
169	if (nsi)
170		refcount_inc(&nsi->refcnt);
171	return nsi;
172}
173
174void nsinfo__put(struct nsinfo *nsi)
175{
176	if (nsi && refcount_dec_and_test(&nsi->refcnt))
177		nsinfo__delete(nsi);
178}
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180void nsinfo__mountns_enter(struct nsinfo *nsi,
181				  struct nscookie *nc)
182{
183	char curpath[PATH_MAX];
184	int oldns = -1;
185	int newns = -1;
 
186
187	if (nc == NULL)
188		return;
189
190	nc->oldns = -1;
191	nc->newns = -1;
192
193	if (!nsi || !nsi->need_setns)
194		return;
195
196	if (snprintf(curpath, PATH_MAX, "/proc/self/ns/mnt") >= PATH_MAX)
197		return;
198
 
 
 
 
199	oldns = open(curpath, O_RDONLY);
200	if (oldns < 0)
201		return;
202
203	newns = open(nsi->mntns_path, O_RDONLY);
204	if (newns < 0)
205		goto errout;
206
207	if (setns(newns, CLONE_NEWNS) < 0)
208		goto errout;
209
 
210	nc->oldns = oldns;
211	nc->newns = newns;
212	return;
213
214errout:
 
215	if (oldns > -1)
216		close(oldns);
217	if (newns > -1)
218		close(newns);
219}
220
221void nsinfo__mountns_exit(struct nscookie *nc)
222{
223	if (nc == NULL || nc->oldns == -1 || nc->newns == -1)
224		return;
225
226	setns(nc->oldns, CLONE_NEWNS);
227
 
 
 
 
 
228	if (nc->oldns > -1) {
229		close(nc->oldns);
230		nc->oldns = -1;
231	}
232
233	if (nc->newns > -1) {
234		close(nc->newns);
235		nc->newns = -1;
236	}
237}
238
239char *nsinfo__realpath(const char *path, struct nsinfo *nsi)
240{
241	char *rpath;
242	struct nscookie nsc;
243
244	nsinfo__mountns_enter(nsi, &nsc);
245	rpath = realpath(path, NULL);
246	nsinfo__mountns_exit(&nsc);
247
248	return rpath;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249}
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}