Ejemplo n.º 1
0
/*
 * Parses the list of buffers of a xreadv or xwritev call, and pushes the size
 * (and optionally the data) to the ring.
 */
int32_t parse_readv_writev_bufs(struct event_filler_arguments *args, const struct iovec __user *iovsrc, unsigned long iovcnt, int64_t retval, int flags)
{
	int32_t res;
	const struct iovec *iov;
	u32 copylen;
	u32 j;
	uint64_t size = 0;
	unsigned long bufsize;
	char *targetbuf = args->str_storage;

	copylen = iovcnt * sizeof(struct iovec);

	if (unlikely(copylen >= STR_STORAGE_SIZE))
		return PPM_FAILURE_BUFFER_FULL;

	if (unlikely(ppm_copy_from_user(targetbuf, iovsrc, copylen)))
		return PPM_FAILURE_INVALID_USER_MEMORY;

	iov = (const struct iovec *)targetbuf;

	/*
	 * Size
	 */
	if (flags & PRB_FLAG_PUSH_SIZE) {
		for (j = 0; j < iovcnt; j++)
			size += iov[j].iov_len;

		res = val_to_ring(args, size, 0, false, 0);
		if (unlikely(res != PPM_SUCCESS))
			return res;
	}

	/*
	 * data
	 * NOTE: for the moment, we limit our data copy to the first buffer.
	 * We assume that in the vast majority of the cases g_snaplen is much smaller
	 * than iov[0].iov_len, and therefore we don't bother complicvating the code.
	 */
	if (flags & PRB_FLAG_PUSH_DATA) {
		if (retval > 0 && iovcnt > 0) {
			bufsize = min_t(int64_t, retval, (int64_t)iov[0].iov_len);

			res = val_to_ring(args,
				(unsigned long)iov[0].iov_base,
				min(bufsize, (unsigned long)g_snaplen),
				true,
				0);
			if (unlikely(res != PPM_SUCCESS))
				return res;
		} else {
			res = val_to_ring(args, 0, 0, false, 0);
			if (unlikely(res != PPM_SUCCESS))
				return res;
		}
	}

	return PPM_SUCCESS;
}
Ejemplo n.º 2
0
int addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr)
{
	if (unlikely(ulen < 0 || ulen > sizeof(struct sockaddr_storage)))
		return -EINVAL;

	if (unlikely(ulen == 0))
		return 0;

	if (unlikely(ppm_copy_from_user(kaddr, uaddr, ulen)))
		return -EFAULT;

	return 0;
}
Ejemplo n.º 3
0
/*
 * NOTES:
 * - val_len is ignored for everything other than PT_BYTEBUF.
 * - fromuser is ignored for numeric types
 */
inline int val_to_ring(struct event_filler_arguments *args, uint64_t val, u16 val_len, bool fromuser)
{
	int len = -1;
	u16 *psize = (u16 *)(args->buffer + args->curarg * sizeof(u16));

	if (unlikely(args->curarg >= args->nargs)) {
		pr_info("(%u)val_to_ring: too many arguments for event #%u, type=%u, curarg=%u, nargs=%u tid:%u\n",
		       smp_processor_id(),
		       args->nevents,
		       (u32)args->event_type,
		       args->curarg,
		       args->nargs,
		       current->pid);
		memory_dump(args->buffer - sizeof(struct ppm_evt_hdr), 32);
		ASSERT(0);
		return PPM_FAILURE_BUG;
	}

	switch (g_event_info[args->event_type].params[args->curarg].type) {
	case PT_CHARBUF:
	case PT_FSPATH:
		if (likely(val != 0)) {
			if (fromuser) {
				len = ppm_strncpy_from_user(args->buffer + args->arg_data_offset,
					(const char __user *)(unsigned long)val, args->arg_data_size);

				if (unlikely(len < 0))
					return PPM_FAILURE_INVALID_USER_MEMORY;
			} else {
				char *dest = strncpy(args->buffer + args->arg_data_offset,
								(const char *)(unsigned long)val,
								args->arg_data_size);

				dest[args->arg_data_size - 1] = 0;
				len = strlen(dest) + 1;
			}

			/*
			 * Make sure the string is null-terminated
			 */
			*(char *)(args->buffer + args->arg_data_offset + len) = 0;
		} else {
			/*
			 * Handle NULL pointers
			 */
			char *dest = strncpy(args->buffer + args->arg_data_offset,
			       "(NULL)",
			       args->arg_data_size);

			dest[args->arg_data_size - 1] = 0;
			len = strlen(dest) + 1;
		}

		break;
	case PT_BYTEBUF:
	case PT_SOCKADDR:
	case PT_SOCKTUPLE:
	case PT_FDLIST:
		if (likely(val != 0)) {
			if (unlikely(val_len >= args->arg_data_size)) {
				return PPM_FAILURE_BUFFER_FULL;
			} else {
				if (fromuser) {
					len = (int)ppm_copy_from_user(args->buffer + args->arg_data_offset,
							(const void __user *)(unsigned long)val,
							val_len);

					if (unlikely(len != 0))
						return PPM_FAILURE_INVALID_USER_MEMORY;

					len = val_len;
				} else {
					memcpy(args->buffer + args->arg_data_offset,
						(void *)(unsigned long)val, val_len);

					len = val_len;
				}
			}
		} else {
			/*
			 * Handle NULL pointers
			 */
			len = 0;
		}

		break;
	case PT_FLAGS8:
	case PT_UINT8:
	case PT_SIGTYPE:
		if (likely(args->arg_data_size >= sizeof(u8)))	{
			*(u8 *)(args->buffer + args->arg_data_offset) = (u8)val;
			len = sizeof(u8);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_FLAGS16:
	case PT_UINT16:
	case PT_SYSCALLID:
		if (likely(args->arg_data_size >= sizeof(u16))) {
			*(u16 *)(args->buffer + args->arg_data_offset) = (u16)val;
			len = sizeof(u16);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_FLAGS32:
	case PT_UINT32:
		if (likely(args->arg_data_size >= sizeof(u32))) {
			*(u32 *)(args->buffer + args->arg_data_offset) = (u32)val;
			len = sizeof(u32);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_RELTIME:
	case PT_ABSTIME:
	case PT_UINT64:
		if (likely(args->arg_data_size >= sizeof(u64))) {
			*(u64 *)(args->buffer + args->arg_data_offset) = (u64)val;
			len = sizeof(u64);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT8:
		if (likely(args->arg_data_size >= sizeof(s8))) {
			*(s8 *)(args->buffer + args->arg_data_offset) = (s8)(long)val;
			len = sizeof(s8);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT16:
		if (likely(args->arg_data_size >= sizeof(s16))) {
			*(s16 *)(args->buffer + args->arg_data_offset) = (s16)(long)val;
			len = sizeof(s16);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT32:
		if (likely(args->arg_data_size >= sizeof(s32))) {
			*(s32 *)(args->buffer + args->arg_data_offset) = (s32)(long)val;
			len = sizeof(s32);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT64:
	case PT_ERRNO:
	case PT_FD:
	case PT_PID:
		if (likely(args->arg_data_size >= sizeof(s64))) {
			*(s64 *)(args->buffer + args->arg_data_offset) = (s64)(long)val;
			len = sizeof(s64);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	default:
		ASSERT(0);
		pr_info("val_to_ring: invalid argument type %d. Event %u (%s) might have less parameters than what has been declared in nparams\n",
		       (int)g_event_info[args->event_type].params[args->curarg].type,
		       (u32)args->event_type,
		       g_event_info[args->event_type].name);
		return PPM_FAILURE_BUG;
	}

	ASSERT(len <= 65535);
	ASSERT(len <= args->arg_data_size);

	*psize = (u16)len;
	args->curarg++;
	args->arg_data_offset += len;
	args->arg_data_size -= len;

	return PPM_SUCCESS;
}
Ejemplo n.º 4
0
/*
 * NOTES:
 * - val_len is ignored for everything other than PT_BYTEBUF.
 * - fromuser is ignored for numeric types
 * - dyn_idx is ignored for everything other than PT_DYN
 */
int val_to_ring(struct event_filler_arguments *args, uint64_t val, u16 val_len, bool fromuser, u8 dyn_idx)
{
	const struct ppm_param_info *param_info;
	int len = -1;
	u16 *psize = (u16 *)(args->buffer + args->curarg * sizeof(u16));

	if (unlikely(args->curarg >= args->nargs)) {
		pr_err("(%u)val_to_ring: too many arguments for event #%u, type=%u, curarg=%u, nargs=%u tid:%u\n",
			smp_processor_id(),
			args->nevents,
			(u32)args->event_type,
			args->curarg,
			args->nargs,
			current->pid);
		memory_dump(args->buffer - sizeof(struct ppm_evt_hdr), 32);
		ASSERT(0);
		return PPM_FAILURE_BUG;
	}

	if (unlikely(args->arg_data_size == 0))
		return PPM_FAILURE_BUFFER_FULL;

	param_info = &(g_event_info[args->event_type].params[args->curarg]);
	if (param_info->type == PT_DYN && param_info->info != NULL) {
		const struct ppm_param_info *dyn_params;

		if (unlikely(dyn_idx >= param_info->ninfo)) {
			ASSERT(0);
			return PPM_FAILURE_BUG;
		}

		dyn_params = (const struct ppm_param_info *)param_info->info;

		param_info = &dyn_params[dyn_idx];
		if (likely(args->arg_data_size >= sizeof(u8)))	{
			*(u8 *)(args->buffer + args->arg_data_offset) = dyn_idx;
			len = sizeof(u8);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}
		args->arg_data_offset += len;
		args->arg_data_size -= len;
		*psize = (u16)len;
	} else {
		*psize = 0;
	}

	switch (param_info->type) {
	case PT_CHARBUF:
	case PT_FSPATH:
		if (likely(val != 0)) {
			if (fromuser) {
				len = ppm_strncpy_from_user(args->buffer + args->arg_data_offset,
					(const char __user *)(unsigned long)val, args->arg_data_size);

				if (unlikely(len < 0))
					return PPM_FAILURE_INVALID_USER_MEMORY;
			} else {
				len = strlcpy(args->buffer + args->arg_data_offset,
								(const char *)(unsigned long)val,
								args->arg_data_size);

				if (++len > args->arg_data_size)
					len = args->arg_data_size;
			}

			/*
			 * Make sure the string is null-terminated
			 */
			*(char *)(args->buffer + args->arg_data_offset + len) = 0;
		} else {
			/*
			 * Handle NULL pointers
			 */
			len = strlcpy(args->buffer + args->arg_data_offset,
				"(NULL)",
				args->arg_data_size);

			if (++len > args->arg_data_size)
				len = args->arg_data_size;
		}

		break;
	case PT_BYTEBUF:
		if (likely(val != 0)) {
			if (fromuser) {
				/*
				 * Copy the lookahead portion of the buffer that we will use DPI-based
				 * snaplen calculation
				 */
				u32 dpi_lookahead_size = DPI_LOOKAHED_SIZE;

				if (dpi_lookahead_size > val_len)
					dpi_lookahead_size = val_len;

				if (unlikely(dpi_lookahead_size >= args->arg_data_size))
					return PPM_FAILURE_BUFFER_FULL;

				len = (int)ppm_copy_from_user(args->buffer + args->arg_data_offset,
						(const void __user *)(unsigned long)val,
						dpi_lookahead_size);

				if (unlikely(len != 0))
					return PPM_FAILURE_INVALID_USER_MEMORY;

				/*
				 * Check if there's more to copy
				 */
				if (likely((dpi_lookahead_size != val_len))) {
					/*
					 * Calculate the snaplen
					 */
					if (likely(args->enforce_snaplen)) {
						u32 sl = args->consumer->snaplen;

						sl = compute_snaplen(args, args->buffer + args->arg_data_offset, dpi_lookahead_size);

						if (val_len > sl)
							val_len = sl;
					}

					if (unlikely((val_len) >= args->arg_data_size))
						val_len = args->arg_data_size;

					if (val_len > dpi_lookahead_size) {
						len = (int)ppm_copy_from_user(args->buffer + args->arg_data_offset + dpi_lookahead_size,
								(const void __user *)(unsigned long)val + dpi_lookahead_size,
								val_len - dpi_lookahead_size);

						if (unlikely(len != 0))
							return PPM_FAILURE_INVALID_USER_MEMORY;
					}
				}

				len = val_len;
			} else {
				if (likely(args->enforce_snaplen)) {
					u32 sl = compute_snaplen(args, (char *)(unsigned long)val, val_len);

					if (val_len > sl)
						val_len = sl;
				}

				if (unlikely(val_len >= args->arg_data_size))
					return PPM_FAILURE_BUFFER_FULL;

				memcpy(args->buffer + args->arg_data_offset,
					(void *)(unsigned long)val, val_len);

				len = val_len;
			}
		} else {
			/*
			 * Handle NULL pointers
			 */
			len = 0;
		}

		break;
	case PT_SOCKADDR:
	case PT_SOCKTUPLE:
	case PT_FDLIST:
		if (likely(val != 0)) {
			if (unlikely(val_len >= args->arg_data_size))
				return PPM_FAILURE_BUFFER_FULL;

			if (fromuser) {
				len = (int)ppm_copy_from_user(args->buffer + args->arg_data_offset,
						(const void __user *)(unsigned long)val,
						val_len);

				if (unlikely(len != 0))
					return PPM_FAILURE_INVALID_USER_MEMORY;

				len = val_len;
			} else {
				memcpy(args->buffer + args->arg_data_offset,
					(void *)(unsigned long)val, val_len);

				len = val_len;
			}
		} else {
			/*
			 * Handle NULL pointers
			 */
			len = 0;
		}

		break;
	case PT_FLAGS8:
	case PT_UINT8:
	case PT_SIGTYPE:
		if (likely(args->arg_data_size >= sizeof(u8)))	{
			*(u8 *)(args->buffer + args->arg_data_offset) = (u8)val;
			len = sizeof(u8);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_FLAGS16:
	case PT_UINT16:
	case PT_SYSCALLID:
		if (likely(args->arg_data_size >= sizeof(u16))) {
			*(u16 *)(args->buffer + args->arg_data_offset) = (u16)val;
			len = sizeof(u16);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_FLAGS32:
	case PT_UINT32:
	case PT_UID:
	case PT_GID:
	case PT_SIGSET:
		if (likely(args->arg_data_size >= sizeof(u32))) {
			*(u32 *)(args->buffer + args->arg_data_offset) = (u32)val;
			len = sizeof(u32);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_RELTIME:
	case PT_ABSTIME:
	case PT_UINT64:
		if (likely(args->arg_data_size >= sizeof(u64))) {
			*(u64 *)(args->buffer + args->arg_data_offset) = (u64)val;
			len = sizeof(u64);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT8:
		if (likely(args->arg_data_size >= sizeof(s8))) {
			*(s8 *)(args->buffer + args->arg_data_offset) = (s8)(long)val;
			len = sizeof(s8);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT16:
		if (likely(args->arg_data_size >= sizeof(s16))) {
			*(s16 *)(args->buffer + args->arg_data_offset) = (s16)(long)val;
			len = sizeof(s16);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT32:
		if (likely(args->arg_data_size >= sizeof(s32))) {
			*(s32 *)(args->buffer + args->arg_data_offset) = (s32)(long)val;
			len = sizeof(s32);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	case PT_INT64:
	case PT_ERRNO:
	case PT_FD:
	case PT_PID:
		if (likely(args->arg_data_size >= sizeof(s64))) {
			*(s64 *)(args->buffer + args->arg_data_offset) = (s64)(long)val;
			len = sizeof(s64);
		} else {
			return PPM_FAILURE_BUFFER_FULL;
		}

		break;
	default:
		ASSERT(0);
		pr_err("val_to_ring: invalid argument type %d. Event %u (%s) might have less parameters than what has been declared in nparams\n",
			(int)g_event_info[args->event_type].params[args->curarg].type,
			(u32)args->event_type,
			g_event_info[args->event_type].name);
		return PPM_FAILURE_BUG;
	}

	ASSERT(len <= 65535);
	ASSERT(len <= args->arg_data_size);

	*psize += (u16)len;
	args->curarg++;
	args->arg_data_offset += len;
	args->arg_data_size -= len;

	return PPM_SUCCESS;
}
Ejemplo n.º 5
0
/*
 * Parses the list of buffers of a xreadv or xwritev call, and pushes the size
 * (and optionally the data) to the ring.
 */
int32_t compat_parse_readv_writev_bufs(struct event_filler_arguments *args, const struct compat_iovec __user *iovsrc, unsigned long iovcnt, int64_t retval, int flags)
{
	int32_t res;
	const struct compat_iovec *iov;
	u32 copylen;
	u32 j;
	u64 size = 0;
	unsigned long bufsize;
	char *targetbuf = args->str_storage;
	u32 targetbuflen = STR_STORAGE_SIZE;
	unsigned long val;
	u32 notcopied_len;
	compat_size_t tocopy_len;

	copylen = iovcnt * sizeof(struct compat_iovec);

	if (unlikely(copylen >= STR_STORAGE_SIZE))
		return PPM_FAILURE_BUFFER_FULL;

	if (unlikely(ppm_copy_from_user(args->str_storage, iovsrc, copylen)))
		return PPM_FAILURE_INVALID_USER_MEMORY;

	iov = (const struct compat_iovec *)(args->str_storage);

	targetbuf += copylen;
	targetbuflen -= copylen;

	/*
	 * Size
	 */
	if (flags & PRB_FLAG_PUSH_SIZE) {
		for (j = 0; j < iovcnt; j++)
			size += iov[j].iov_len;

		/*
		 * Size is the total size of the buffers provided by the user. The number of
		 * received bytes can be smaller
		 */
		if ((flags & PRB_FLAG_IS_WRITE) == 0)
			if (size > retval)
				size = retval;

		res = val_to_ring(args, size, 0, false, 0);
		if (unlikely(res != PPM_SUCCESS))
			return res;
	}

	/*
	 * data
	 */
	if (flags & PRB_FLAG_PUSH_DATA) {
		if (retval > 0 && iovcnt > 0) {
			/*
			 * Retrieve the FD. It will be used for dynamic snaplen calculation.
			 */
			syscall_get_arguments(current, args->regs, 0, 1, &val);
			args->fd = (int)val;

			/*
			 * Merge the buffers
			 */
			bufsize = 0;

			for (j = 0; j < iovcnt; j++) {
				if ((flags & PRB_FLAG_IS_WRITE) == 0) {
					if (bufsize >= retval) {
						ASSERT(bufsize >= retval);

						/*
						 * Copied all the data even if we haven't reached the
						 * end of the buffer.
						 * Copy must stop here.
						 */
						break;
					}

					tocopy_len = min(iov[j].iov_len, (compat_size_t)((size_t)retval - bufsize));
					tocopy_len = min(tocopy_len, (compat_size_t)(targetbuflen - bufsize - 1));
				} else {
					tocopy_len = min(iov[j].iov_len, (compat_size_t)(targetbuflen - bufsize - 1));
				}

				notcopied_len = (int)ppm_copy_from_user(targetbuf + bufsize,
									compat_ptr(iov[j].iov_base),
						tocopy_len);

				if (unlikely(notcopied_len != 0)) {
					/*
					 * This means we had a page fault. Skip this event.
					 */
					return PPM_FAILURE_INVALID_USER_MEMORY;
				}

				bufsize += tocopy_len;

				if (tocopy_len != iov[j].iov_len) {
					/*
					 * No space left in the args->str_storage buffer.
					 * Copy must stop here.
					 */
					break;
				}
			}

			args->enforce_snaplen = true;

			res = val_to_ring(args,
				(unsigned long)targetbuf,
				bufsize,
				false,
				0);
			if (unlikely(res != PPM_SUCCESS))
				return res;
		} else {
			res = val_to_ring(args, 0, 0, false, 0);
			if (unlikely(res != PPM_SUCCESS))
				return res;
		}
	}

	return PPM_SUCCESS;
}