cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

namespaces.c (6737B)


      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}