From d4e14f9eb0cc0c5708d3bb8acde58263d37bc54e Mon Sep 17 00:00:00 2001 From: Christiano Haesbaert Date: Fri, 9 May 2025 15:00:12 +0200 Subject: [PATCH 1/2] Implement entity_id. Issue #155 This implements the 12 byte entity id as defined in https://www.elastic.co/docs/reference/ecs/ecs-process#field-process-entity-id We can't depend on dynamic linking of md or openssl, so include a standlone MIT licensed sha256 implementation from https://github.com/ilvn/SHA256, they claim to be formally verified, so that's something. We now also have to link against resolv so we can get the base64 functions, that's ok, beats already links against it. Musl doesn't have b64_ntop so we include a replacement guarded by NO_B64. This is a WIP as I want to make sure we compute the very same entity_id as gosysinfo and friends. --- Makefile | 14 ++- base64.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++ compat.h | 17 +++ quark.c | 87 +++++++++++++++ quark.h | 3 + sha256.c | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ sha256.h | 52 +++++++++ 7 files changed, 806 insertions(+), 2 deletions(-) create mode 100644 base64.c create mode 100644 sha256.c create mode 100644 sha256.h diff --git a/Makefile b/Makefile index 9efbde9..affe811 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,9 @@ CPPFLAGS?= -D_GNU_SOURCE ifndef SYSLIB CPPFLAGS+= -Iinclude/usr/include endif +ifdef NO_B64 +CPPFLAGS+= -DNO_B64 +endif CDIAGFLAGS+= -Wall CDIAGFLAGS+= -Wextra @@ -90,13 +93,15 @@ LIBQUARK_DEPS+= $(EEBPF_FILES) include endif LIBQUARK_DEPS:= $(filter-out manpages.h, $(LIBQUARK_DEPS)) LIBQUARK_SRCS:= \ + base64.c \ bpf_queue.c \ btf.c \ btfhub.c \ compat.c \ kprobe_queue.c \ quark.c \ - qutil.c + qutil.c \ + sha256.c LIBQUARK_OBJS:= $(patsubst %.c,%.o,$(LIBQUARK_SRCS)) LIBQUARK_STATIC:= libquark.a LIBQUARK_STATIC_BIG:= libquark_big.a @@ -109,6 +114,11 @@ LIBQUARK_TARGET=$(LIBQUARK_STATIC) EXTRA_LDFLAGS+= -lbpf endif +# for b64_ntop() +ifndef NO_B64 +EXTRA_LDFLAGS+= -lresolv +endif + # ZLIB ZLIB_SRC:= zlib ZLIB_FILES:= $(shell find $(ZLIB_SRC) \(\ @@ -287,7 +297,7 @@ alpine: alpine-image clean-all $(call msg,ALPINE-DOCKER-RUN,Dockerfile) $(Q)$(DOCKER) run \ $(ALPINE_RUN_ARGS) $(SHELL) \ - -c "make -C $(PWD) all initramfs.gz EXTRA_LDFLAGS=-lfts" + -c "make -C $(PWD) all initramfs.gz EXTRA_LDFLAGS=-lfts NO_B64=y" alpine-image: clean-all $(call msg,ALPINE-IMAGE,Dockerfile.alpine) diff --git a/base64.c b/base64.c new file mode 100644 index 0000000..1c2c8eb --- /dev/null +++ b/base64.c @@ -0,0 +1,307 @@ +/* $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* OPENBSD ORIGINAL: lib/libc/net/base64.c */ + +#ifdef NO_B64 + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "compat.h" + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int +b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + u_int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(char const *src, u_char *target, size_t targsize) +{ + u_int tarindex, state; + int ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +#endif /* NO_B64 */ diff --git a/compat.h b/compat.h index 0fcbe59..0a3bfab 100644 --- a/compat.h +++ b/compat.h @@ -70,4 +70,21 @@ long long strtonum(const char *, long long, long long, const char **); */ void sshbuf_dump_data(const void *, size_t, FILE *); +/* + * Musl + */ +#ifdef NO_B64 +int b64_ntop(u_char const *src, size_t srclength, char *target, + size_t targsize); +int b64_pton(char const *src, u_char *target, size_t targsize); +#else +#include +#endif /* NO_B64 */ + +/* + * Linkining with the one billion versions of openssl is a pain, we need sha256 + * for a dozen bytes only. + */ +#include "sha256.h" + #endif /* _COMPAT_H */ diff --git a/quark.c b/quark.c index 34d14f1..90d09f2 100644 --- a/quark.c +++ b/quark.c @@ -62,6 +62,7 @@ RB_GENERATE(raw_event_by_pidtime, raw_event, struct quark { unsigned int hz; u64 boottime; + char machine_id[1024]; } quark; struct raw_event * @@ -447,6 +448,43 @@ process_by_pid_cmp(struct quark_process *a, struct quark_process *b) return (0); } +static void +process_entity_id(struct quark_queue *qq, struct quark_process *qp) +{ + sha256_context ctx; + u64 pid64_le, start_le; + u8 digest[SHA256_SIZE_BYTES]; + char digest_p[45]; + size_t machine_len; + + /* No proc_time_boot, bail */ + if ((qp->flags & QUARK_F_PROC) == 0) + return; + /* Already known, bail */ + if (qp->flags & QUARK_F_ENTITYID) + return; + /* No machine_id, bail */ + if ((machine_len = strlen(quark.machine_id)) == 0) + return; + + /* Historically little endian */ + pid64_le = htole64(qp->pid); + start_le = htole64(qp->proc_time_boot); + + sha256_init(&ctx); + sha256_hash(&ctx, quark.machine_id, machine_len); + sha256_hash(&ctx, &pid64_le, sizeof(pid64_le)); + sha256_hash(&ctx, &start_le, sizeof(start_le)); + sha256_done(&ctx, digest); + + b64_ntop(digest, sizeof(digest), digest_p, sizeof(digest_p)); + digest_p[sizeof(digest_p) - 1] = 0; + + /* Let it truncate, entity_id is only 12 bytes */ + (void)strlcpy(qp->entity_id, digest_p, sizeof(qp->entity_id)); + qp->flags |= QUARK_F_ENTITYID; +} + /* * Socket stuff */ @@ -585,6 +623,8 @@ event_flag_str(u64 flag) return "CWD"; case QUARK_F_CGROUP: return "CGRP"; + case QUARK_F_ENTITYID: + return "EID"; default: return "?"; } @@ -1017,6 +1057,10 @@ quark_event_dump(const struct quark_event *qev, FILE *f) entry_leader_type_str(qp->proc_entry_leader_type), qp->proc_entry_leader); } + if (qp->flags & QUARK_F_ENTITYID) { + flagname = event_flag_str(QUARK_F_ENTITYID); + P(" %.4s\tentity_id=%s\n", flagname, qp->entity_id); + } if (qp->flags & QUARK_F_CWD) { flagname = event_flag_str(QUARK_F_CWD); P(" %.4s\tcwd=%s\n", flagname, qp->cwd); @@ -1268,12 +1312,16 @@ raw_event_process(struct quark_queue *qq, struct raw_event *src) /* Don't set cwd as it's not valid on exit */ comm = raw_task->comm; + if (raw_task->cgroup != NULL) { qp->flags |= QUARK_F_CGROUP; free(qp->cgroup); qp->cgroup = raw_task->cgroup; raw_task->cgroup = NULL; } + + /* Depends on QUARK_F_PROC, idempotent */ + process_entity_id(qq, qp); } if (raw_comm != NULL) comm = raw_comm->comm; /* raw_comm always overrides */ @@ -2036,6 +2084,39 @@ fetch_boottime(void) return (btime * NS_PER_S); } +static int +fetch_machine_id(char *buf, size_t len) +{ + int fd; + char *id; + const char **path, *all_paths[] = { + "/etc/machine-id", + "/var/lib/dbus/machine-id", + "/var/db/dbus/machine-id", + NULL + }; + + for (fd = -1, path = all_paths; *path != NULL; path++) { + fd = open("/etc/machine-id", O_RDONLY); + if (fd != -1) + break; + } + if (fd == -1) + return (-1); + /* Historically the final newline is included, so keep it. */ + if ((id = load_file_nostat(fd, NULL)) == NULL) { + close(fd); + warnx("can't load machine_id"); + return (-1); + } + close(fd); + + if (strlcpy(buf, id, len) >= len) + warnx("machine_id truncated, ignoring"); + + return (0); +} + /* * Aggregation is a relationship between a parent event and a child event. In a * fork+exec cenario, fork is the parent, exec is the child. @@ -2096,6 +2177,12 @@ quark_init(void) qwarn("can't fetch btime"); return (-1); } + if (fetch_machine_id(quark.machine_id, + sizeof(quark.machine_id)) == -1) { + qwarn("can't fetch machine id, ignoring"); + quark.machine_id[0] = 0; + } + quark.hz = hz; quark.boottime = boottime; diff --git a/quark.h b/quark.h index 7b15a5e..afda8d6 100644 --- a/quark.h +++ b/quark.h @@ -384,6 +384,7 @@ struct quark_process { #define QUARK_F_CMDLINE (1 << 4) #define QUARK_F_CWD (1 << 5) #define QUARK_F_CGROUP (1 << 6) +#define QUARK_F_ENTITYID (1 << 7) u64 flags; /* QUARK_F_PROC */ @@ -424,6 +425,8 @@ struct quark_process { char *cwd; /* QUARK_F_CGROUP */ char *cgroup; + /* QUARK_F_ENTITY_ID */ + char entity_id[13]; }; struct quark_process_iter { diff --git a/sha256.c b/sha256.c new file mode 100644 index 0000000..9f7bf2f --- /dev/null +++ b/sha256.c @@ -0,0 +1,328 @@ +//usr/bin/env clang -Ofast -Wall -Wextra -pedantic ${0} -o ${0%%.c*} $* ;exit $? +// +// SHA-256 implementation, Mark 2 +// +// Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +#include "sha256.h" + +#ifndef _cbmc_ +#define __CPROVER_assume(...) do {} while(0) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define FN_ static inline __attribute__((const)) + +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + + +// ----------------------------------------------------------------------------- +FN_ uint8_t _shb(uint32_t x, uint32_t n) +{ + return ((x >> (n & 31)) & 0xff); +} // _shb + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _shw(uint32_t x, uint32_t n) +{ + return ((x << (n & 31)) & 0xffffffff); +} // _shw + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _r(uint32_t x, uint8_t n) +{ + return ((x >> n) | _shw(x, 32 - n)); +} // _r + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _Ch(uint32_t x, uint32_t y, uint32_t z) +{ + return ((x & y) ^ ((~x) & z)); +} // _Ch + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _Ma(uint32_t x, uint32_t y, uint32_t z) +{ + return ((x & y) ^ (x & z) ^ (y & z)); +} // _Ma + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _S0(uint32_t x) +{ + return (_r(x, 2) ^ _r(x, 13) ^ _r(x, 22)); +} // _S0 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _S1(uint32_t x) +{ + return (_r(x, 6) ^ _r(x, 11) ^ _r(x, 25)); +} // _S1 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _G0(uint32_t x) +{ + return (_r(x, 7) ^ _r(x, 18) ^ (x >> 3)); +} // _G0 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _G1(uint32_t x) +{ + return (_r(x, 17) ^ _r(x, 19) ^ (x >> 10)); +} // _G1 + + +// ----------------------------------------------------------------------------- +FN_ uint32_t _word(uint8_t *c) +{ + return (_shw(c[0], 24) | _shw(c[1], 16) | _shw(c[2], 8) | (c[3])); +} // _word + + +// ----------------------------------------------------------------------------- +static void _addbits(sha256_context *ctx, uint32_t n) +{ + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + + if (ctx->bits[0] > (0xffffffff - n)) { + ctx->bits[1] = (ctx->bits[1] + 1) & 0xFFFFFFFF; + } + ctx->bits[0] = (ctx->bits[0] + n) & 0xFFFFFFFF; +} // _addbits + + +// ----------------------------------------------------------------------------- +static void _hash(sha256_context *ctx) +{ + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + + register uint32_t a, b, c, d, e, f, g, h; + uint32_t t[2]; + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + f = ctx->hash[5]; + g = ctx->hash[6]; + h = ctx->hash[7]; + + for (uint32_t i = 0; i < 64; i++) { + if (i < 16) { + ctx->W[i] = _word(&ctx->buf[_shw(i, 2)]); + } else { + ctx->W[i] = _G1(ctx->W[i - 2]) + ctx->W[i - 7] + + _G0(ctx->W[i - 15]) + ctx->W[i - 16]; + } + + t[0] = h + _S1(e) + _Ch(e, f, g) + K[i] + ctx->W[i]; + t[1] = _S0(a) + _Ma(a, b, c); + h = g; + g = f; + f = e; + e = d + t[0]; + d = c; + c = b; + b = a; + a = t[0] + t[1]; + } + + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; + ctx->hash[5] += f; + ctx->hash[6] += g; + ctx->hash[7] += h; +} // _hash + + +// ----------------------------------------------------------------------------- +void sha256_init(sha256_context *ctx) +{ + if (ctx != NULL) { + ctx->bits[0] = ctx->bits[1] = ctx->len = 0; + ctx->hash[0] = 0x6a09e667; + ctx->hash[1] = 0xbb67ae85; + ctx->hash[2] = 0x3c6ef372; + ctx->hash[3] = 0xa54ff53a; + ctx->hash[4] = 0x510e527f; + ctx->hash[5] = 0x9b05688c; + ctx->hash[6] = 0x1f83d9ab; + ctx->hash[7] = 0x5be0cd19; + } +} // sha256_init + + +// ----------------------------------------------------------------------------- +void sha256_hash(sha256_context *ctx, const void *data, size_t len) +{ + const uint8_t *bytes = (const uint8_t *)data; + + if ((ctx != NULL) && (bytes != NULL) && (ctx->len < sizeof(ctx->buf))) { + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(bytes)); + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + for (size_t i = 0; i < len; i++) { + ctx->buf[ctx->len++] = bytes[i]; + if (ctx->len == sizeof(ctx->buf)) { + _hash(ctx); + _addbits(ctx, sizeof(ctx->buf) * 8); + ctx->len = 0; + } + } + } +} // sha256_hash + + +// ----------------------------------------------------------------------------- +void sha256_done(sha256_context *ctx, uint8_t *hash) +{ + register uint32_t i, j; + + if (ctx != NULL) { + j = ctx->len % sizeof(ctx->buf); + ctx->buf[j] = 0x80; + for (i = j + 1; i < sizeof(ctx->buf); i++) { + ctx->buf[i] = 0x00; + } + + if (ctx->len > 55) { + _hash(ctx); + for (j = 0; j < sizeof(ctx->buf); j++) { + ctx->buf[j] = 0x00; + } + } + + _addbits(ctx, ctx->len * 8); + ctx->buf[63] = _shb(ctx->bits[0], 0); + ctx->buf[62] = _shb(ctx->bits[0], 8); + ctx->buf[61] = _shb(ctx->bits[0], 16); + ctx->buf[60] = _shb(ctx->bits[0], 24); + ctx->buf[59] = _shb(ctx->bits[1], 0); + ctx->buf[58] = _shb(ctx->bits[1], 8); + ctx->buf[57] = _shb(ctx->bits[1], 16); + ctx->buf[56] = _shb(ctx->bits[1], 24); + _hash(ctx); + + if (hash != NULL) { + for (i = 0, j = 24; i < 4; i++, j -= 8) { + hash[i + 0] = _shb(ctx->hash[0], j); + hash[i + 4] = _shb(ctx->hash[1], j); + hash[i + 8] = _shb(ctx->hash[2], j); + hash[i + 12] = _shb(ctx->hash[3], j); + hash[i + 16] = _shb(ctx->hash[4], j); + hash[i + 20] = _shb(ctx->hash[5], j); + hash[i + 24] = _shb(ctx->hash[6], j); + hash[i + 28] = _shb(ctx->hash[7], j); + } + } + } +} // sha256_done + + +// ----------------------------------------------------------------------------- +void sha256(const void *data, size_t len, uint8_t *hash) +{ + sha256_context ctx; + + sha256_init(&ctx); + sha256_hash(&ctx, data, len); + sha256_done(&ctx, hash); +} // sha256 + + +#if 0 +#pragma mark - Self Test +#endif +#ifdef SHA256_SELF_TEST__ +#include +#include + +int main(void) +{ + char *buf[] = { + "", + "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855", + + "abc", + "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad", + + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1", + + "The quick brown fox jumps over the lazy dog", + "d7a8fbb3 07d78094 69ca9abc b0082e4f 8d5651e4 6d3cdb76 2d02d0bf 37c9e592", + + "The quick brown fox jumps over the lazy cog", // avalanche effect test + "e4c4d8f3 bf76b692 de791a17 3e053211 50f7a345 b46484fe 427f6acc 7ecc81be", + + "bhn5bjmoniertqea40wro2upyflkydsibsk8ylkmgbvwi420t44cq034eou1szc1k0mk46oeb7ktzmlxqkbte2sy", + "9085df2f 02e0cc45 5928d0f5 1b27b4bf 1d9cd260 a66ed1fd a11b0a3f f5756d99" + }; + const size_t tests_total = sizeof(buf) / sizeof(buf[0]); + uint8_t hash[SHA256_SIZE_BYTES]; + + if (0 != (tests_total % 2)) { + return printf("invalid tests\n"); + } + + for (size_t i = 0; i < tests_total; i += 2) { + sha256(buf[i], strlen(buf[i]), hash); + printf("input = '%s'\ndigest: %s\nresult: ", buf[i], buf[i + 1]); + for (size_t j = 0; j < SHA256_SIZE_BYTES; j++) { + printf("%02x%s", hash[j], ((j % 4) == 3) ? " " : ""); + } + printf("\n\n"); + } + + return 0; +} // main + +#endif // def SHA256_SELF_TEST__ + +#ifdef __cplusplus +} +#endif diff --git a/sha256.h b/sha256.h new file mode 100644 index 0000000..6df116b --- /dev/null +++ b/sha256.h @@ -0,0 +1,52 @@ +// +// SHA-256 implementation, Mark 2 +// +// Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +#ifndef SHA256_H_ +#define SHA256_H_ + +#include +#include + +#define SHA256_SIZE_BYTES (32) + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct { + uint8_t buf[64]; + uint32_t hash[8]; + uint32_t bits[2]; + uint32_t len; + uint32_t rfu__; + uint32_t W[64]; +} sha256_context; + +void sha256_init(sha256_context *ctx); +void sha256_hash(sha256_context *ctx, const void *data, size_t len); +void sha256_done(sha256_context *ctx, uint8_t *hash); + +void sha256(const void *data, size_t len, uint8_t *hash); + +#ifdef __cplusplus +} +#endif + +#endif From ce7d3f3a9960b7e03d12398064130b831989dbfc Mon Sep 17 00:00:00 2001 From: Christiano Haesbaert Date: Wed, 18 Jun 2025 23:21:35 +0200 Subject: [PATCH 2/2] Kill precision --- quark.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/quark.c b/quark.c index 90d09f2..f50e4a1 100644 --- a/quark.c +++ b/quark.c @@ -452,7 +452,7 @@ static void process_entity_id(struct quark_queue *qq, struct quark_process *qp) { sha256_context ctx; - u64 pid64_le, start_le; + u64 pid64_le, start_le, ns; u8 digest[SHA256_SIZE_BYTES]; char digest_p[45]; size_t machine_len; @@ -467,9 +467,15 @@ process_entity_id(struct quark_queue *qq, struct quark_process *qp) if ((machine_len = strlen(quark.machine_id)) == 0) return; + /* + * Kill precision + */ + ns = qp->proc_time_boot; + ns -= ns % ((NS_PER_S) / quark.hz); + /* Historically little endian */ pid64_le = htole64(qp->pid); - start_le = htole64(qp->proc_time_boot); + start_le = htole64(ns); sha256_init(&ctx); sha256_hash(&ctx, quark.machine_id, machine_len);