mirror of
https://github.com/Cacti/spine.git
synced 2026-11-02 18:17:27 +09:00
## Summary Consolidates the overlapping ICMP work from #555 and #619 into one review of the complete socket and resolver state machine. - add ICMPv6 echo polling and dispatch IPv6 devices to it - prefer unprivileged datagram ICMP sockets when the kernel permits them - retain bounded raw-socket fallback for IPv4 and IPv6 - give packet and socket resources one cleanup owner - leave caller-owned resolver state untouched on lookup failure - keep every retry inside one cached capability and privilege-transition decision - prevent LOCK_SETEUID retry deadlocks - validate raw and datagram reply layouts, source, sequence, identifiers, and payload - retain fuzz and unprivileged-socket integration coverage The consolidation also fixed an integration defect found locally: the controlled successful-reply test constructed only a raw IPv4 packet even when the production path selected SOCK_DGRAM. It now models the selected socket format, and IPv6 raw retries use the same privilege-safety invariant as IPv4. ## Verification - warning-enabled local build completed with MariaDB Connector/C, Net-SNMP, OpenSSL 3, and cmocka - make check: 5/5 test binaries passed - focused ping_icmp suite: 9/9 cases passed - actionlint and git diff --check passed - all commits are signed - GitHub CI is authoritative for Linux capability, sanitizer, fuzz, and unprivileged-network coverage Closes #127. Closes #250. Closes #593. Closes #611. Supersedes #555. Refs #597 and #618. --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Signed-off-by: TheWitness <copilot@users.noreply.github.com> Co-authored-by: TheWitness <thewitness@cacti.net> Co-authored-by: TheWitness <copilot@users.noreply.github.com>
51 lines
1.6 KiB
C
51 lines
1.6 KiB
C
/* libFuzzer target for the two ICMP reply classifiers.
|
|
*
|
|
* This parses a raw ICMP datagram straight off a shared SOCK_RAW socket, so
|
|
* the bytes come from any host that can reach the poller. The raw classifier
|
|
* walks the IP header length field before touching the ICMP header, which is
|
|
* exactly the shape that goes wrong; the datagram classifier is handed a
|
|
* buffer with no IP header at all. Both are driven here, chosen by an input
|
|
* byte. The real ping.c is linked, not a copy.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "common.h"
|
|
#include "spine.h"
|
|
#include "ping.h"
|
|
|
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|
const struct icmp *pkt = NULL;
|
|
spine_icmp_reply_t verdict;
|
|
uint16_t want_id, want_seq;
|
|
int dgram;
|
|
|
|
/* first byte picks the socket type, next four steer the identity check,
|
|
* the rest is the datagram */
|
|
if (size < 5) return 0;
|
|
|
|
dgram = (data[0] & 1) != 0;
|
|
want_id = (uint16_t)((data[1] << 8) | data[2]);
|
|
want_seq = (uint16_t)((data[3] << 8) | data[4]);
|
|
data += 5;
|
|
size -= 5;
|
|
|
|
if (dgram) {
|
|
verdict = spine_icmp_classify_dgram_reply(data, (ssize_t) size, want_seq, &pkt);
|
|
} else {
|
|
verdict = spine_icmp_classify_reply(data, (ssize_t) size, want_id, want_seq, &pkt);
|
|
}
|
|
|
|
/* a packet is only handed back when it was accepted, and it must then
|
|
* point inside the buffer we were given */
|
|
if (verdict == SPINE_ICMP_REPLY_OK) {
|
|
if (pkt == NULL) abort();
|
|
if ((const uint8_t *) pkt < data) abort();
|
|
if ((const uint8_t *) pkt + ICMP_HDR_SIZE > data + size) abort();
|
|
} else if (pkt != NULL) {
|
|
abort();
|
|
}
|
|
|
|
return 0;
|
|
}
|