From bb708111833e23cafda1a5dd377e13400fa1e452 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Fri, 25 Mar 2022 13:02:47 +0100 Subject: treewide: Packet abstraction with mandatory boundary checks Implement a packet abstraction providing boundary and size checks based on packet descriptors: packets stored in a buffer can be queued into a pool (without storage of its own), and data can be retrieved referring to an index in the pool, specifying offset and length. Checks ensure data is not read outside the boundaries of buffer and descriptors, and that packets added to a pool are within the buffer range with valid offset and indices. This implies a wider rework: usage of the "queueing" part of the abstraction mostly affects tap_handler_{passt,pasta}() functions and their callees, while the "fetching" part affects all the guest or tap facing implementations: TCP, UDP, ICMP, ARP, NDP, DHCP and DHCPv6 handlers. Suggested-by: Stefan Hajnoczi Signed-off-by: Stefano Brivio --- packet.h | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 packet.h (limited to 'packet.h') diff --git a/packet.h b/packet.h new file mode 100644 index 0000000..0ef8849 --- /dev/null +++ b/packet.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: AGPL-3.0-or-later + * Copyright (c) 2022 Red Hat GmbH + * Author: Stefano Brivio + */ + +#ifndef PACKET_H +#define PACKET_H + +/** + * struct desc - Generic offset-based descriptor within buffer + * @offset: Offset of descriptor relative to buffer start, 32-bit limit + * @len: Length of descriptor, host order, 16-bit limit + */ +struct desc { + uint32_t offset; + uint16_t len; +}; + +/** + * struct pool - Generic pool of packets stored in a buffer + * @buf: Buffer storing packet descriptors + * @buf_size: Total size of buffer + * @size: Number of usable descriptors for the pool + * @count: Number of used descriptors for the pool + * @pkt: Descriptors: see macros below + */ +struct pool { + char *buf; + size_t buf_size; + size_t size; + size_t count; + struct desc pkt[1]; +}; + +void packet_add_do(struct pool *p, size_t len, const char *start, + const char *func, const int line); +void *packet_get_do(struct pool *p, size_t index, size_t offset, size_t len, + size_t *left, const char *func, const int line); +void pool_flush(struct pool *p); + +#define packet_add(p, len, start) \ + packet_add_do(p, len, start, __func__, __LINE__); + +#define packet_get(p, index, offset, len, left) \ + packet_get_do(p, index, offset, len, left, __func__, __LINE__); + +#define packet_get_try(p, index, offset, len, left) \ + packet_get_do(p, index, offset, len, left, NULL, 0) + +#define PACKET_POOL_DECL(_name, _size, _buf) \ +struct _name ## _t { \ + char *buf; \ + size_t buf_size; \ + size_t size; \ + size_t count; \ + struct desc pkt[_size]; \ +} + +#define PACKET_POOL_INIT_NOCAST(_size, _buf, _buf_size) \ +{ \ + .buf_size = _buf_size, \ + .buf = _buf, \ + .size = _size, \ +} + +#define PACKET_POOL(name, size, buf, buf_size) \ + PACKET_POOL_DECL(name, size, buf) name = \ + PACKET_POOL_INIT_NOCAST(size, buf, buf_size) + +#define PACKET_INIT(name, size, buf, buf_size) \ + (struct name ## _t) PACKET_POOL_INIT_NOCAST(size, buf, buf_size) + +#define PACKET_POOL_NOINIT(name, size, buf) \ + PACKET_POOL_DECL(name, size, buf) name ## _storage; \ + static struct pool *name = (struct pool *)&name ## _storage + +#define PACKET_POOL_P(name, size, buf, buf_size) \ + PACKET_POOL(name ## _storage, size, buf, buf_size); \ + struct pool *name = (struct pool *)&name ## _storage + +#endif /* PACKET_H */ -- cgit v1.2.3