Ejemplo n.º 1
0
Archivo: scap.c Proyecto: aledbf/sysdig
scap_t* scap_open_live_int(char *error, 
						   proc_entry_callback proc_callback,
						   void* proc_callback_context,
						   bool import_users)
{
#if !defined(HAS_CAPTURE)
	snprintf(error, SCAP_LASTERR_SIZE, "live capture not supported on %s", PLATFORM_NAME);
	return NULL;
#else
	uint32_t j;
	char filename[SCAP_MAX_PATH_SIZE];
	scap_t* handle = NULL;
	int len;
	uint32_t ndevs;
	uint32_t res;

	//
	// Allocate the handle
	//
	handle = (scap_t*)malloc(sizeof(scap_t));
	if(!handle)
	{
		snprintf(error, SCAP_LASTERR_SIZE, "error allocating the scap_t structure");
		return NULL;
	}

	//
	// Preliminary initializations
	//
	memset(handle, 0, sizeof(scap_t));

	//
	// Find out how many devices we have to open, which equals to the number of CPUs
	//
	ndevs = sysconf(_SC_NPROCESSORS_ONLN);

	//
	// Allocate the device descriptors.
	//
	len = RING_BUF_SIZE * 2;

	handle->m_devs = (scap_device*)malloc(ndevs * sizeof(scap_device));
	if(!handle->m_devs)
	{
		scap_close(handle);
		snprintf(error, SCAP_LASTERR_SIZE, "error allocating the device handles");
		return NULL;
	}

	for(j = 0; j < ndevs; j++)
	{
		handle->m_devs[j].m_buffer = (char*)MAP_FAILED;
		handle->m_devs[j].m_bufinfo = (struct ppm_ring_buffer_info*)MAP_FAILED;
	}

	handle->m_ndevs = ndevs;

	//
	// Extract machine information
	//
	handle->m_proc_callback = proc_callback;
	handle->m_proc_callback_context = proc_callback_context;
	handle->m_machine_info.num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
	handle->m_machine_info.memory_size_bytes = (uint64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
	gethostname(handle->m_machine_info.hostname, sizeof(handle->m_machine_info.hostname) / sizeof(handle->m_machine_info.hostname[0]));
	handle->m_machine_info.reserved1 = 0;
	handle->m_machine_info.reserved2 = 0;
	handle->m_machine_info.reserved3 = 0;
	handle->m_machine_info.reserved4 = 0;
	handle->m_driver_procinfo = NULL;

	//
	// Create the interface list
	//
	if(scap_create_iflist(handle) != SCAP_SUCCESS)
	{
		scap_close(handle);
		snprintf(error, SCAP_LASTERR_SIZE, "error creating the interface list");
		return NULL;
	}

	//
	// Create the user list
	//
	if(import_users)
	{
		if(scap_create_userlist(handle) != SCAP_SUCCESS)
		{
			scap_close(handle);
			snprintf(error, SCAP_LASTERR_SIZE, "error creating the interface list");
			return NULL;
		}
	}
	else
	{
		handle->m_userlist = NULL;		
	}

	handle->m_fake_kernel_proc.tid = -1;
	handle->m_fake_kernel_proc.pid = -1;
	handle->m_fake_kernel_proc.flags = 0;
	snprintf(handle->m_fake_kernel_proc.comm, SCAP_MAX_PATH_SIZE, "kernel");
	snprintf(handle->m_fake_kernel_proc.exe, SCAP_MAX_PATH_SIZE, "kernel");
	handle->m_fake_kernel_proc.args[0] = 0;

	//
	// Open and initialize all the devices
	//
	for(j = 0; j < handle->m_ndevs; j++)
	{
		//
		// Open the device
		//
		sprintf(filename, "%s/dev/sysdig%d", scap_get_host_root(), j);

		if((handle->m_devs[j].m_fd = open(filename, O_RDWR | O_SYNC)) < 0)
		{
			if(errno == EBUSY)
			{
				uint32_t curr_max_consumers = get_max_consumers();
				snprintf(error, SCAP_LASTERR_SIZE, "Too many sysdig instances attached to device %s. Current value for /sys/module/sysdig_probe/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
			}
			else
			{
				snprintf(error, SCAP_LASTERR_SIZE, "error opening device %s. Make sure you have root credentials and that the sysdig-probe module is loaded.", filename);
			}

			scap_close(handle);
			return NULL;
		}

		//
		// Map the ring buffer
		//
		handle->m_devs[j].m_buffer = (char*)mmap(0,
		                             len,
		                             PROT_READ,
		                             MAP_SHARED,
		                             handle->m_devs[j].m_fd,
		                             0);

		if(handle->m_devs[j].m_buffer == MAP_FAILED)
		{
			// we cleanup this fd and then we let scap_close() take care of the other ones
			close(handle->m_devs[j].m_fd);

			scap_close(handle);

			snprintf(error, SCAP_LASTERR_SIZE, "error mapping the ring buffer for device %s", filename);
			return NULL;
		}

		//
		// Map the ppm_ring_buffer_info that contains the buffer pointers
		//
		handle->m_devs[j].m_bufinfo = (struct ppm_ring_buffer_info*)mmap(0,
		                              sizeof(struct ppm_ring_buffer_info),
		                              PROT_READ | PROT_WRITE,
		                              MAP_SHARED,
		                              handle->m_devs[j].m_fd,
		                              0);

		if(handle->m_devs[j].m_bufinfo == MAP_FAILED)
		{
			// we cleanup this fd and then we let scap_close() take care of the other ones
			munmap(handle->m_devs[j].m_buffer, len);
			close(handle->m_devs[j].m_fd);

			scap_close(handle);

			snprintf(error, SCAP_LASTERR_SIZE, "error mapping the ring buffer info for device %s", filename);
			return NULL;
		}

		//
		// Additional initializations
		//
		handle->m_devs[j].m_lastreadsize = 0;
		handle->m_devs[j].m_sn_len = 0;
		handle->m_n_consecutive_waits = 0;
		scap_stop_dropping_mode(handle);
	}

	//
	// Create the process list
	//
	error[0] = '\0';
	snprintf(filename, sizeof(filename), "%s/proc", scap_get_host_root());
	if((res = scap_proc_scan_proc_dir(handle, filename, -1, -1, NULL, error, true)) != SCAP_SUCCESS)
	{
		scap_close(handle);
		snprintf(error, SCAP_LASTERR_SIZE, "error creating the process list. Make sure you have root credentials.");
		return NULL;
	}

	//
	// Now that sysdig has done all its /proc parsing, start the capture
	//
	scap_start_capture(handle);

	return handle;
#endif // HAS_CAPTURE
}
Ejemplo n.º 2
0
bool sinsp_container_manager::parse_docker(sinsp_container_info* container)
{
	string file = string(scap_get_host_root()) + "/var/run/docker.sock";

	int sock = socket(PF_UNIX, SOCK_STREAM, 0);
	if(sock < 0)
	{
		ASSERT(false);
		return false;
	}

	struct sockaddr_un address;
	memset(&address, 0, sizeof(struct sockaddr_un));

	address.sun_family = AF_UNIX;
	strncpy(address.sun_path, file.c_str(), sizeof(address.sun_path) - 1);
	address.sun_path[sizeof(address.sun_path) - 1]= '\0';

	if(connect(sock, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0)
	{
		return false;
	}

	string message = "GET /containers/" + container->m_id + "/json HTTP/1.0\r\n\n";
	if(write(sock, message.c_str(), message.length()) != (ssize_t) message.length())
	{
		ASSERT(false);
		close(sock);
		return false;
	}

	char buf[256];
	string json;
	ssize_t res;
	while((res = read(sock, buf, sizeof(buf))) != 0)
	{
		if(res == -1 || json.size() > MAX_JSON_SIZE_B)
		{
			ASSERT(false);
			close(sock);
			return false;
		}

		buf[res] = 0;
		json += buf;
	}

	close(sock);

	size_t pos = json.find("{");
	if(pos == string::npos)
	{
		ASSERT(false);
		return false;
	}

	Json::Value root;
	Json::Reader reader;
	bool parsingSuccessful = reader.parse(json.substr(pos), root);
	if(!parsingSuccessful)
	{
		ASSERT(false);
		return false;
	}

	const Json::Value& config_obj = root["Config"];

	container->m_image = config_obj["Image"].asString();
	container->m_name = root["Name"].asString();

	if(!container->m_name.empty() && container->m_name[0] == '/')
	{
		container->m_name = container->m_name.substr(1);
	}

	const Json::Value& net_obj = root["NetworkSettings"];

	string ip = net_obj["IPAddress"].asString();
	if(inet_pton(AF_INET, ip.c_str(), &container->m_container_ip) == -1)
	{
		ASSERT(false);
	}
	container->m_container_ip = ntohl(container->m_container_ip);

	vector<string> ports = net_obj["Ports"].getMemberNames();
	for(vector<string>::const_iterator it = ports.begin(); it != ports.end(); ++it)
	{
		size_t tcp_pos = it->find("/tcp");
		if(tcp_pos == string::npos)
		{
			continue;
		}

		uint16_t container_port = atoi(it->c_str());

		const Json::Value& v = net_obj["Ports"][*it];
		if(v.isArray())
		{
			for(uint32_t j = 0; j < v.size(); ++j)
			{	
				sinsp_container_info::container_port_mapping port_mapping;

				ip = v[j]["HostIp"].asString();
				string port = v[j]["HostPort"].asString();

				if(inet_pton(AF_INET, ip.c_str(), &port_mapping.m_host_ip) == -1)
				{
					ASSERT(false);
					continue;
				}
				port_mapping.m_host_ip = ntohl(port_mapping.m_host_ip);

				port_mapping.m_container_port = container_port;
				port_mapping.m_host_port = atoi(port.c_str());
				container->m_port_mappings.push_back(port_mapping);
			}
		}
	}

	vector<string> labels = config_obj["Labels"].getMemberNames();
	for(vector<string>::const_iterator it = labels.begin(); it != labels.end(); ++it)
	{
		string val = config_obj["Labels"][*it].asString();
		container->m_labels[*it] = val;
	}

	const Json::Value& env_vars = config_obj["Env"];
	string mesos_task_id = get_mesos_task_id(env_vars, "MESOS_TASK_ID");
	if(mesos_task_id.empty())
	{
		mesos_task_id = get_mesos_task_id(env_vars, "mesos_task_id");
	}
	if(mesos_task_id.empty())
	{
		mesos_task_id = get_mesos_task_id(env_vars, "MESOS_EXECUTOR_ID");
	}
	if(!mesos_task_id.empty())
	{
		container->m_mesos_task_id = mesos_task_id;
		g_logger.log("Mesos Docker container: [" + root["Id"].asString() + "], Mesos task ID: [" + container->m_mesos_task_id + ']', sinsp_logger::SEV_DEBUG);
	}

	return true;
}
Ejemplo n.º 3
0
bool sinsp_container_manager::parse_rkt(sinsp_container_info *container,
										const string &podid, const string &appname)
{
	bool ret = false;
	Json::Reader reader;
	Json::Value jroot;

	unordered_map<string, uint32_t> image_ports;
	char image_manifest_path[SCAP_MAX_PATH_SIZE];
	snprintf(image_manifest_path, sizeof(image_manifest_path), "%s/var/lib/rkt/pods/run/%s/appsinfo/%s/manifest", scap_get_host_root(), podid.c_str(), appname.c_str());
	ifstream image_manifest(image_manifest_path);
	if(reader.parse(image_manifest, jroot))
	{
		container->m_image = jroot["name"].asString();
		for(const auto& label_entry : jroot["labels"])
		{
			container->m_labels.emplace(label_entry["name"].asString(), label_entry["value"].asString());
		}
		auto version_label_it = container->m_labels.find("version");
		if(version_label_it != container->m_labels.end())
		{
			container->m_image += ":" + version_label_it->second;
		}
		for(const auto& image_port : jroot["app"]["ports"])
		{
			image_ports.emplace(image_port["name"].asString(), image_port["port"].asUInt());
		}
		ret = true;
	}

	char net_info_path[SCAP_MAX_PATH_SIZE];
	snprintf(net_info_path, sizeof(net_info_path), "%s/var/lib/rkt/pods/run/%s/net-info.json", scap_get_host_root(), podid.c_str());
	ifstream net_info(net_info_path);
	if(reader.parse(net_info, jroot) && jroot.size() > 0)
	{
		auto first_net = jroot[0];
		if(inet_pton(AF_INET, first_net["ip"].asCString(), &container->m_container_ip) == -1)
		{
			ASSERT(false);
		}
		container->m_container_ip = ntohl(container->m_container_ip);
	}

	char pod_manifest_path[SCAP_MAX_PATH_SIZE];
	snprintf(pod_manifest_path, sizeof(pod_manifest_path), "%s/var/lib/rkt/pods/run/%s/pod", scap_get_host_root(), podid.c_str());
	ifstream pod_manifest(pod_manifest_path);
	if(reader.parse(pod_manifest, jroot) && jroot.size() > 0)
	{
		for(const auto& jport : jroot["ports"])
		{
			auto host_port = jport["hostPort"].asUInt();
			if(host_port > 0)
			{
				sinsp_container_info::container_port_mapping port_mapping;
				port_mapping.m_host_port = host_port;
				port_mapping.m_container_port = image_ports.at(jport["name"].asString());
				container->m_port_mappings.emplace_back(move(port_mapping));
			}
		}
	}
	return ret;
}
Ejemplo n.º 4
0
bool sinsp_container_manager::resolve_container(sinsp_threadinfo* tinfo, bool query_os_for_missing_info)
{

	ASSERT(tinfo);
	bool valid_id = false;
	sinsp_container_info container_info;

	string rkt_podid, rkt_appname;
	// Start with cgroup based detection
	for(auto it = tinfo->m_cgroups.begin(); it != tinfo->m_cgroups.end(); ++it)
	{
		string cgroup = it->second;
		size_t pos;

		//
		// Non-systemd Docker
		//
		pos = cgroup.find_last_of("/");
		if(pos != string::npos)
		{
			if(cgroup.length() - pos - 1 == 64 &&
				cgroup.find_first_not_of("0123456789abcdefABCDEF", pos + 1) == string::npos)
			{
				container_info.m_type = CT_DOCKER;
				container_info.m_id = cgroup.substr(pos + 1, 12);
				valid_id = true;
				break;
			}
		}

		//
		// systemd Docker
		//
		pos = cgroup.find("docker-");
		if(pos != string::npos)
		{
			size_t pos2 = cgroup.find(".scope");
			if(pos2 != string::npos &&
				pos2 - pos - sizeof("docker-") + 1 == 64)
			{
				container_info.m_type = CT_DOCKER;
				container_info.m_id = cgroup.substr(pos + sizeof("docker-") - 1, 12);
				valid_id = true;
				break;
			}
		}

		//
		// Non-systemd libvirt-lxc
		//
		pos = cgroup.find(".libvirt-lxc");
		if(pos != string::npos &&
			pos == cgroup.length() - sizeof(".libvirt-lxc") + 1)
		{
			size_t pos2 = cgroup.find_last_of("/");
			if(pos2 != string::npos)
			{
				container_info.m_type = CT_LIBVIRT_LXC;
				container_info.m_id = cgroup.substr(pos2 + 1, pos - pos2 - 1);
				valid_id = true;
				break;
			}
		}

		//
		// systemd libvirt-lxc
		//
		pos = cgroup.find("-lxc\\x2");
		if(pos != string::npos)
		{
			size_t pos2 = cgroup.find(".scope");
			if(pos2 != string::npos &&
				pos2 == cgroup.length() - sizeof(".scope") + 1)
			{
				container_info.m_type = CT_LIBVIRT_LXC;
				container_info.m_id = cgroup.substr(pos + sizeof("-lxc\\x2"), pos2 - pos - sizeof("-lxc\\x2"));
				valid_id = true;
				break;
			}
		}

		//
		// Legacy libvirt-lxc
		//
		pos = cgroup.find("/libvirt/lxc/");
		if(pos != string::npos)
		{
			container_info.m_type = CT_LIBVIRT_LXC;
			container_info.m_id = cgroup.substr(pos + sizeof("/libvirt/lxc/") - 1);
			valid_id = true;
			break;
		}

		//
		// Non-systemd LXC
		//
		pos = cgroup.find("/lxc/");
		if(pos != string::npos)
		{
			auto id_start = pos + sizeof("/lxc/") - 1;
			auto id_end = cgroup.find('/', id_start);
			container_info.m_type = CT_LXC;
			container_info.m_id = cgroup.substr(id_start, id_end - id_start);
			valid_id = true;
			break;
		}

		//
		// Mesos
		//
		pos = cgroup.find("/mesos/");
		if(pos != string::npos)
		{
			container_info.m_type = CT_MESOS;
			container_info.m_id = cgroup.substr(pos + sizeof("/mesos/") - 1);
			// Consider a mesos container valid only if we find the mesos_task_id
			// this will exclude from the container itself the mesos-executor
			// but makes sure that we have task_id parsed properly. Otherwise what happens
			// is that we'll create a mesos container struct without a mesos_task_id
			// and for all other processes we'll use it
			valid_id = set_mesos_task_id(&container_info, tinfo);
			break;
		}

		//
		// systemd rkt
		//
		// rkt cgroups
		// 1. /system.slice/k8s_d1efb75a-ad42-458e-af65-2b378f42173f.service/system.slice/redis.service
		// 2. /machine.slice/machine-rkt\x2dc508ad4c\x2d7fa4\x2d4513\x2d9d53\x2d007628003805.scope/system.slice/redis.service
		static const string COREOS_PODID_VAR = "container_uuid=";
		static const string SYSTEMD_UUID_ARG = "--uuid=";
		static const string SERVICE_SUFFIX = ".service";
		if(cgroup.rfind(SERVICE_SUFFIX) == cgroup.size() - SERVICE_SUFFIX.size())
		{
			// check if there is a parent with pod uuid var
			sinsp_threadinfo::visitor_func_t visitor = [&rkt_podid](sinsp_threadinfo* ptinfo)
			{
				for(const auto& env_var : ptinfo->get_env())
				{
					auto container_uuid_pos = env_var.find(COREOS_PODID_VAR);
					if(container_uuid_pos == 0)
					{
						rkt_podid = env_var.substr(COREOS_PODID_VAR.size());
						return false;
					}
				}
				for(const auto& arg : ptinfo->m_args)
				{
					if(arg.find(SYSTEMD_UUID_ARG) != string::npos)
					{
						rkt_podid = arg.substr(SYSTEMD_UUID_ARG.size());
						return false;
					}
				}
				return true;
			};
			tinfo->traverse_parent_state(visitor);

			if(!rkt_podid.empty())
			{
				auto last_slash = cgroup.find_last_of("/");
				rkt_appname = cgroup.substr(last_slash + 1, cgroup.size() - last_slash - SERVICE_SUFFIX.size() - 1);
				
				char image_manifest_path[SCAP_MAX_PATH_SIZE];
				snprintf(image_manifest_path, sizeof(image_manifest_path), "%s/var/lib/rkt/pods/run/%s/appsinfo/%s/manifest", scap_get_host_root(), rkt_podid.c_str(), rkt_appname.c_str());

				// First lookup if the container exists in our table, otherwise only if we are live check if it has
				// an entry in /var/lib/rkt. In capture mode only the former will be used.
				// In live mode former will be used only if we already hit that container
				if( m_containers.find(rkt_podid + ":" + rkt_appname) != m_containers.end() ||
					(query_os_for_missing_info && access(image_manifest_path, F_OK) == 0)
					)
				{
					container_info.m_type = CT_RKT;
					container_info.m_id = rkt_podid + ":" + rkt_appname;
					container_info.m_name = rkt_appname;
					valid_id = true;
					break;
				} 
			}
		}
	}

	// If anything has been found, try proc root based detection
	// right now used for rkt
	if(!valid_id)
	{
		// Try parsing from process root,
		// Strings used to detect rkt stage1-cores pods
		// TODO: detecting stage1-coreos rkt pods in this way is deprecated
		// we can remove it in the future
		static const string COREOS_PREFIX = "/opt/stage2/";
		static const string COREOS_APP_SUFFIX = "/rootfs";
		static const string COREOS_PODID_VAR = "container_uuid=";

		auto prefix = tinfo->m_root.find(COREOS_PREFIX);
		if(prefix == 0)
		{
			auto suffix = tinfo->m_root.find(COREOS_APP_SUFFIX, prefix);
			if(suffix != string::npos)
			{
				rkt_appname = tinfo->m_root.substr(prefix + COREOS_PREFIX.size(), suffix - prefix - COREOS_PREFIX.size());
				// It is a rkt pod with stage1-coreos

				sinsp_threadinfo::visitor_func_t visitor = [&rkt_podid, &container_info, &rkt_appname, &valid_id] (sinsp_threadinfo *ptinfo)
				{
					for(const auto& env_var : ptinfo->get_env())
					{
						auto container_uuid_pos = env_var.find(COREOS_PODID_VAR);
						if(container_uuid_pos == 0)
						{
							rkt_podid = env_var.substr(COREOS_PODID_VAR.size());
							container_info.m_type = CT_RKT;
							container_info.m_id = rkt_podid + ":" + rkt_appname;
							container_info.m_name = rkt_appname;
							valid_id = true;
							return false;
						}
					}
					return true;
				};

				// Try the current thread first. visitor returns true if no coreos pid
				// info was found. In this case we traverse the parents.
				if (visitor(tinfo))
				{
					tinfo->traverse_parent_state(visitor);
				}
			}
		}
		else
		{
			// String used to detect stage1-fly pods
			static const string FLY_PREFIX = "/var/lib/rkt/pods/run/";
			static const string FLY_PODID_SUFFIX = "/stage1/rootfs/opt/stage2/";
			static const string FLY_APP_SUFFIX = "/rootfs";

			auto prefix = tinfo->m_root.find(FLY_PREFIX);
			if(prefix == 0)
			{
				auto podid_suffix = tinfo->m_root.find(FLY_PODID_SUFFIX, prefix+FLY_PREFIX.size());
				if(podid_suffix != string::npos)
				{
					rkt_podid = tinfo->m_root.substr(prefix + FLY_PREFIX.size(), podid_suffix - prefix - FLY_PREFIX.size());
					auto appname_suffix = tinfo->m_root.find(FLY_APP_SUFFIX, podid_suffix+FLY_PODID_SUFFIX.size());
					if(appname_suffix != string::npos)
					{
						rkt_appname = tinfo->m_root.substr(podid_suffix + FLY_PODID_SUFFIX.size(),
														   appname_suffix-podid_suffix-FLY_PODID_SUFFIX.size());
						container_info.m_type = CT_RKT;
						container_info.m_id = rkt_podid + ":" + rkt_appname;
						container_info.m_name = rkt_appname;
						valid_id = true;
					}
				}
			}
		}
	}

	if(!valid_id) {
		tinfo->m_container_id = "";
	}
	else
	{
		tinfo->m_container_id = container_info.m_id;

		unordered_map<string, sinsp_container_info>::const_iterator it = m_containers.find(container_info.m_id);
		if(it == m_containers.end())
		{
			switch(container_info.m_type)
			{
				case CT_DOCKER:
#ifndef _WIN32
					if(query_os_for_missing_info)
					{
						parse_docker(&container_info);
					}
#endif
					break;
				case CT_LXC:
					container_info.m_name = container_info.m_id;
					break;
				case CT_LIBVIRT_LXC:
					container_info.m_name = container_info.m_id;
					break;
				case CT_MESOS:
					container_info.m_name = container_info.m_id;
					break;
				case CT_RKT:
#ifndef _WIN32
					if(query_os_for_missing_info)
					{
						parse_rkt(&container_info, rkt_podid, rkt_appname);
					}
#endif
					break;
				default:
					ASSERT(false);
			}

			add_container(container_info);
			if(container_to_sinsp_event(container_to_json(container_info), &m_inspector->m_meta_evt))
			{
				m_inspector->m_meta_evt_pending = true;
			}
		}
	}

	return valid_id;
}