From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on sa.local.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.1 X-MC-Unique: 6NuOjvNYMZy3SmOzvrxY6A-1 From: Alexey Gladkov To: ALT Devel discussion list Date: Tue, 27 Oct 2020 12:33:51 +0100 Message-Id: <20201027113351.3373843-7-legion@altlinux.ru> In-Reply-To: <20201027113351.3373843-1-legion@altlinux.ru> References: <20201027113351.3373843-1-legion@altlinux.ru> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: altlinux.ru Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=WINDOWS-1252 Subject: [devel] [PATCH 6/6] syslogd: implement checksum chains for log entries X-BeenThere: devel@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: ALT Linux Team development discussions List-Id: ALT Linux Team development discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Oct 2020 11:34:13 -0000 Archived-At: List-Archive: List-Post: This is a mechanism for detecting intrusion into log files. Each time the server starts, it starts creating a checksum chain for each log file. On restart, the chain starts with an empty checksum. A mismatch between the checkum and the server restart is a possible intrusion and the reason for investigation. Each entry is accompanied by a checksum of this entry with the previous checksum. So, to check the checksum of the current record, you need to have a previous checksum. Signed-off-by: Alexey Gladkov --- Makefile | 14 +- block/bswap.h | 217 +++++++++++++++++++++++++++++++ block/sha256.c | 202 ++++++++++++++++++++++++++++ block/sha256.h | 24 ++++ hash.h | 66 ++++++++++ syslogd.c | 41 ++++++ tests/log-hashes/.gitignore | 5 + tests/log-hashes/check | 28 ++++ tests/log-hashes/check-hashes.sh | 28 ++++ 9 files changed, 622 insertions(+), 3 deletions(-) create mode 100644 block/bswap.h create mode 100644 block/sha256.c create mode 100644 block/sha256.h create mode 100644 hash.h create mode 100644 tests/log-hashes/.gitignore create mode 100755 tests/log-hashes/check create mode 100755 tests/log-hashes/check-hashes.sh diff --git a/Makefile b/Makefile index b46969f..27c415b 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,10 @@ MANDIR =3D $(prefix)/usr/share/man # file system standard. FSSTND =3D -DFSSTND =20 +# The following define determines whether the syslogd should create checks= um +# chains for log entries. +USE_CHECKSUMS =3D -DUSE_CHECKSUMS + # The following define establishes ownership for the man pages. # Avery tells me that there is a difference between Debian and # Slackware. Rather than choose sides I am leaving it up to the user. @@ -67,8 +71,8 @@ MAN_PERMS =3D 644 # ballot below. SYSLOGD_PIDNAME =3D -DSYSLOGD_PIDNAME=3D\"syslogd.pid\" =20 -SYSLOGD_FLAGS=3D -DSYSLOG_INET -DSYSLOG_UNIXAF -DINET6 -DNO_SCCS ${FSSTND}= \ -=09${SYSLOGD_PIDNAME} +SYSLOGD_FLAGS=3D -DSYSLOG_INET -DSYSLOG_UNIXAF -DINET6 -DNO_SCCS \ +=09${USE_CHECKSUMS} ${FSSTND} ${SYSLOGD_PIDNAME} SYSLOG_FLAGS=3D -DALLOW_KERNEL_LOGGING KLOGD_FLAGS =3D ${FSSTND} ${KLOGD_START_DELAY} DEB =3D @@ -80,6 +84,10 @@ TESTS =3D \ =09priority-exclamation \ =09named-pipes =20 +ifneq (${USE_CHECKSUMS},) +TESTS +=3D log-hashes +endif + all: syslogd klogd =20 test: @@ -98,7 +106,7 @@ test: =20 install: install_man install_exec =20 -syslogd: syslogd.o pidfile.o +syslogd: syslogd.o pidfile.o block/sha256.o =09${CC} ${LDFLAGS} -o $@ $^ ${LIBS} =20 klogd:=09klogd.o syslog.o pidfile.o diff --git a/block/bswap.h b/block/bswap.h new file mode 100644 index 0000000..e4e2573 --- /dev/null +++ b/block/bswap.h @@ -0,0 +1,217 @@ +#ifndef COMPAT_BSWAP_H +#define COMPAT_BSWAP_H + +/* + * Let's make sure we always have a sane definition for ntohl()/htonl(). + * Some libraries define those as a function call, just to perform byte + * shifting, bringing significant overhead to what should be a simple + * operation. + */ + +/* + * Default version that the compiler ought to optimize properly with + * constant values. + */ +static inline uint32_t default_swab32(uint32_t val) +{ +=09return (((val & 0xff000000) >> 24) | +=09=09((val & 0x00ff0000) >> 8) | +=09=09((val & 0x0000ff00) << 8) | +=09=09((val & 0x000000ff) << 24)); +} + +static inline uint64_t default_bswap64(uint64_t val) +{ +=09return (((val & (uint64_t)0x00000000000000ffULL) << 56) | +=09=09((val & (uint64_t)0x000000000000ff00ULL) << 40) | +=09=09((val & (uint64_t)0x0000000000ff0000ULL) << 24) | +=09=09((val & (uint64_t)0x00000000ff000000ULL) << 8) | +=09=09((val & (uint64_t)0x000000ff00000000ULL) >> 8) | +=09=09((val & (uint64_t)0x0000ff0000000000ULL) >> 24) | +=09=09((val & (uint64_t)0x00ff000000000000ULL) >> 40) | +=09=09((val & (uint64_t)0xff00000000000000ULL) >> 56)); +} + +#undef bswap32 +#undef bswap64 + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#define bswap32 git_bswap32 +static inline uint32_t git_bswap32(uint32_t x) +{ +=09uint32_t result; +=09if (__builtin_constant_p(x)) +=09=09result =3D default_swab32(x); +=09else +=09=09__asm__("bswap %0" : "=3Dr" (result) : "0" (x)); +=09return result; +} + +#define bswap64 git_bswap64 +#if defined(__x86_64__) +static inline uint64_t git_bswap64(uint64_t x) +{ +=09uint64_t result; +=09if (__builtin_constant_p(x)) +=09=09result =3D default_bswap64(x); +=09else +=09=09__asm__("bswap %q0" : "=3Dr" (result) : "0" (x)); +=09return result; +} +#else +static inline uint64_t git_bswap64(uint64_t x) +{ +=09union { uint64_t i64; uint32_t i32[2]; } tmp, result; +=09if (__builtin_constant_p(x)) +=09=09result.i64 =3D default_bswap64(x); +=09else { +=09=09tmp.i64 =3D x; +=09=09result.i32[0] =3D git_bswap32(tmp.i32[1]); +=09=09result.i32[1] =3D git_bswap32(tmp.i32[0]); +=09} +=09return result.i64; +} +#endif + +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + +#include + +#define bswap32(x) _byteswap_ulong(x) +#define bswap64(x) _byteswap_uint64(x) + +#endif + +#if defined(bswap32) + +#undef ntohl +#undef htonl +#define ntohl(x) bswap32(x) +#define htonl(x) bswap32(x) + +#endif + +#if defined(bswap64) + +#undef ntohll +#undef htonll +#define ntohll(x) bswap64(x) +#define htonll(x) bswap64(x) + +#else + +#undef ntohll +#undef htonll + +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_END= IAN) + +# define GIT_BYTE_ORDER __BYTE_ORDER +# define GIT_LITTLE_ENDIAN __LITTLE_ENDIAN +# define GIT_BIG_ENDIAN __BIG_ENDIAN + +#elif defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) + +# define GIT_BYTE_ORDER BYTE_ORDER +# define GIT_LITTLE_ENDIAN LITTLE_ENDIAN +# define GIT_BIG_ENDIAN BIG_ENDIAN + +#else + +# define GIT_BIG_ENDIAN 4321 +# define GIT_LITTLE_ENDIAN 1234 + +# if defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# define GIT_BYTE_ORDER GIT_BIG_ENDIAN +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN +# elif defined(__THW_BIG_ENDIAN__) && !defined(__THW_LITTLE_ENDIAN__) +# define GIT_BYTE_ORDER GIT_BIG_ENDIAN +# elif defined(__THW_LITTLE_ENDIAN__) && !defined(__THW_BIG_ENDIAN__) +# define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN +# else +# error "Cannot determine endianness" +# endif + +#endif + +#if GIT_BYTE_ORDER =3D=3D GIT_BIG_ENDIAN +# define ntohll(n) (n) +# define htonll(n) (n) +#else +# define ntohll(n) default_bswap64(n) +# define htonll(n) default_bswap64(n) +#endif + +#endif + +/* + * Performance might be improved if the CPU architecture is OK with + * unaligned 32-bit loads and a fast ntohl() is available. + * Otherwise fall back to byte loads and shifts which is portable, + * and is faster on architectures with memory alignment issues. + */ + +#if !defined(NO_UNALIGNED_LOADS) && ( \ + defined(__i386__) || defined(__x86_64__) || \ + defined(_M_IX86) || defined(_M_X64) || \ + defined(__ppc__) || defined(__ppc64__) || \ + defined(__powerpc__) || defined(__powerpc64__) || \ + defined(__s390__) || defined(__s390x__)) + +#define get_be16(p)=09ntohs(*(unsigned short *)(p)) +#define get_be32(p)=09ntohl(*(unsigned int *)(p)) +#define get_be64(p)=09ntohll(*(uint64_t *)(p)) +#define put_be32(p, v)=09do { *(unsigned int *)(p) =3D htonl(v); } while (= 0) +#define put_be64(p, v)=09do { *(uint64_t *)(p) =3D htonll(v); } while (0) + +#else + +static inline uint16_t get_be16(const void *ptr) +{ +=09const unsigned char *p =3D ptr; +=09return=09(uint16_t)p[0] << 8 | +=09=09(uint16_t)p[1] << 0; +} + +static inline uint32_t get_be32(const void *ptr) +{ +=09const unsigned char *p =3D ptr; +=09return=09(uint32_t)p[0] << 24 | +=09=09(uint32_t)p[1] << 16 | +=09=09(uint32_t)p[2] << 8 | +=09=09(uint32_t)p[3] << 0; +} + +static inline uint64_t get_be64(const void *ptr) +{ +=09const unsigned char *p =3D ptr; +=09return=09(uint64_t)get_be32(&p[0]) << 32 | +=09=09(uint64_t)get_be32(&p[4]) << 0; +} + +static inline void put_be32(void *ptr, uint32_t value) +{ +=09unsigned char *p =3D ptr; +=09p[0] =3D value >> 24; +=09p[1] =3D value >> 16; +=09p[2] =3D value >> 8; +=09p[3] =3D value >> 0; +} + +static inline void put_be64(void *ptr, uint64_t value) +{ +=09unsigned char *p =3D ptr; +=09p[0] =3D value >> 56; +=09p[1] =3D value >> 48; +=09p[2] =3D value >> 40; +=09p[3] =3D value >> 32; +=09p[4] =3D value >> 24; +=09p[5] =3D value >> 16; +=09p[6] =3D value >> 8; +=09p[7] =3D value >> 0; +} + +#endif + +#endif /* COMPAT_BSWAP_H */ diff --git a/block/sha256.c b/block/sha256.c new file mode 100644 index 0000000..b1f02be --- /dev/null +++ b/block/sha256.c @@ -0,0 +1,202 @@ +#include + +#include +#include +#include + +#include "./sha256.h" +#include "./bswap.h" + +#undef RND +#undef BLKSIZE + +#define BLKSIZE blk_SHA256_BLKSIZE + +void blk_SHA256_Init(blk_SHA256_CTX *ctx) +{ +=09ctx->offset =3D 0; +=09ctx->size =3D 0; +=09ctx->state[0] =3D 0x6a09e667ul; +=09ctx->state[1] =3D 0xbb67ae85ul; +=09ctx->state[2] =3D 0x3c6ef372ul; +=09ctx->state[3] =3D 0xa54ff53aul; +=09ctx->state[4] =3D 0x510e527ful; +=09ctx->state[5] =3D 0x9b05688cul; +=09ctx->state[6] =3D 0x1f83d9abul; +=09ctx->state[7] =3D 0x5be0cd19ul; +} + +static inline uint32_t ror(uint32_t x, unsigned n) +{ +=09return (x >> n) | (x << (32 - n)); +} + +static inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z) +{ +=09return z ^ (x & (y ^ z)); +} + +static inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z) +{ +=09return ((x | y) & z) | (x & y); +} + +static inline uint32_t sigma0(uint32_t x) +{ +=09return ror(x, 2) ^ ror(x, 13) ^ ror(x, 22); +} + +static inline uint32_t sigma1(uint32_t x) +{ +=09return ror(x, 6) ^ ror(x, 11) ^ ror(x, 25); +} + +static inline uint32_t gamma0(uint32_t x) +{ +=09return ror(x, 7) ^ ror(x, 18) ^ (x >> 3); +} + +static inline uint32_t gamma1(uint32_t x) +{ +=09return ror(x, 17) ^ ror(x, 19) ^ (x >> 10); +} + +static void blk_SHA256_Transform(blk_SHA256_CTX *ctx, const unsigned char = *buf) +{ + +=09uint32_t S[8], W[64], t0, t1; +=09int i; + +=09/* copy state into S */ +=09for (i =3D 0; i < 8; i++) +=09=09S[i] =3D ctx->state[i]; + +=09/* copy the state into 512-bits into W[0..15] */ +=09for (i =3D 0; i < 16; i++, buf +=3D sizeof(uint32_t)) +=09=09W[i] =3D get_be32(buf); + +=09/* fill W[16..63] */ +=09for (i =3D 16; i < 64; i++) +=09=09W[i] =3D gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]= ; + +#define RND(a,b,c,d,e,f,g,h,i,ki) \ +=09t0 =3D h + sigma1(e) + ch(e, f, g) + ki + W[i]; \ +=09t1 =3D sigma0(a) + maj(a, b, c); \ +=09d +=3D t0; \ +=09h =3D t0 + t1; + +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); +=09RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); +=09RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); +=09RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); +=09RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); +=09RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); +=09RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); +=09RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); +=09RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +=09for (i =3D 0; i < 8; i++) +=09=09ctx->state[i] +=3D S[i]; +} + +void blk_SHA256_Update(blk_SHA256_CTX *ctx, const void *data, size_t len) +{ +=09unsigned int len_buf =3D ctx->size & 63; + +=09ctx->size +=3D len; + +=09/* Read the data into buf and process blocks as they get full */ +=09if (len_buf) { +=09=09unsigned int left =3D 64 - len_buf; +=09=09if (len < left) +=09=09=09left =3D len; +=09=09memcpy(len_buf + ctx->buf, data, left); +=09=09len_buf =3D (len_buf + left) & 63; +=09=09len -=3D left; +=09=09data =3D ((const char *)data + left); +=09=09if (len_buf) +=09=09=09return; +=09=09blk_SHA256_Transform(ctx, ctx->buf); +=09} +=09while (len >=3D 64) { +=09=09blk_SHA256_Transform(ctx, data); +=09=09data =3D ((const char *)data + 64); +=09=09len -=3D 64; +=09} +=09if (len) +=09=09memcpy(ctx->buf, data, len); +} + +void blk_SHA256_Final(unsigned char *digest, blk_SHA256_CTX *ctx) +{ +=09static const unsigned char pad[64] =3D { 0x80 }; +=09unsigned int padlen[2]; +=09int i; + +=09/* Pad with a binary 1 (ie 0x80), then zeroes, then length */ +=09padlen[0] =3D htonl((uint32_t)(ctx->size >> 29)); +=09padlen[1] =3D htonl((uint32_t)(ctx->size << 3)); + +=09i =3D ctx->size & 63; +=09blk_SHA256_Update(ctx, pad, 1 + (63 & (55 - i))); +=09blk_SHA256_Update(ctx, padlen, 8); + +=09/* copy output */ +=09for (i =3D 0; i < 8; i++, digest +=3D sizeof(uint32_t)) +=09=09put_be32(digest, ctx->state[i]); +} diff --git a/block/sha256.h b/block/sha256.h new file mode 100644 index 0000000..5099d64 --- /dev/null +++ b/block/sha256.h @@ -0,0 +1,24 @@ +#ifndef SHA256_BLOCK_SHA256_H +#define SHA256_BLOCK_SHA256_H + +#define blk_SHA256_BLKSIZE 64 + +struct blk_SHA256_CTX { +=09uint32_t state[8]; +=09uint64_t size; +=09uint32_t offset; +=09uint8_t buf[blk_SHA256_BLKSIZE]; +}; + +typedef struct blk_SHA256_CTX blk_SHA256_CTX; + +void blk_SHA256_Init(blk_SHA256_CTX *ctx); +void blk_SHA256_Update(blk_SHA256_CTX *ctx, const void *data, size_t len); +void blk_SHA256_Final(unsigned char *digest, blk_SHA256_CTX *ctx); + +#define platform_SHA256_CTX blk_SHA256_CTX +#define platform_SHA256_Init blk_SHA256_Init +#define platform_SHA256_Update blk_SHA256_Update +#define platform_SHA256_Final blk_SHA256_Final + +#endif diff --git a/hash.h b/hash.h new file mode 100644 index 0000000..6fbed5c --- /dev/null +++ b/hash.h @@ -0,0 +1,66 @@ +#ifndef SYSLOGD_HASH_H_ +#define SYSLOGD_HASH_H_ + +#include "./block/sha256.h" + +/* A suitably aligned type for stack allocations of hash contexts. */ +union hash_ctx { +=09platform_SHA256_CTX sha256; +}; +typedef union hash_ctx hash_ctx_t; + +#ifdef USE_CHECKSUMS + +/* The length in bytes and in hex digits (SHA-256 value). */ +#define HASH_RAWSZ 32 +#define HASH_HEXSZ (2 * HASH_RAWSZ) + +#define HASH_NAME "sha256" +#define HASH_NAMESZ sizeof(HASH_NAME) - 1 + +#define EMPTY_HASH_LITERAL \ +=09HASH_NAME ":e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b785= 2b855" + +static inline void hash_init(hash_ctx_t *ctx) +{ + platform_SHA256_Init(&ctx->sha256); +} + +static inline void hash_update(hash_ctx_t *ctx, const void *data, size_t l= en) +{ + platform_SHA256_Update(&ctx->sha256, data, len); +} + +static inline void hash_final(unsigned char *hash, hash_ctx_t *ctx) +{ + platform_SHA256_Final(hash, &ctx->sha256); +} + +#else /* USE_CHECKSUMS */ + +#define HASH_RAWSZ 0 +#define HASH_HEXSZ 0 + +#define HASH_NAME "" +#define HASH_NAMESZ 0 + +#define EMPTY_HASH_LITERAL "" + + +static inline void hash_init(hash_ctx_t *ctx) +{ +=09return; +} + +static inline void hash_update(hash_ctx_t *ctx, const void *in, size_t len= ) +{ +=09return; +} + +static inline void hash_final(unsigned char *hash, hash_ctx_t *ctx) +{ +=09return; +} + +#endif /* USE_CHECKSUMS */ +#endif diff --git a/syslogd.c b/syslogd.c index 4c3c85f..dac7c37 100644 --- a/syslogd.c +++ b/syslogd.c @@ -61,6 +61,7 @@ #include "pidfile.h" #include "version.h" #include "attribute.h" +#include "hash.h" =20 #if defined(__linux__) #include @@ -186,6 +187,8 @@ struct filed { =09int=09f_prevcount;=09=09=09/* repetition cnt of prevline */ =09int=09f_repeatcount;=09=09=09/* number of "repeated" msgs */ =09int=09f_flags;=09=09=09/* store some additional flags */ +=09/* hash of last logged message */ +=09char f_prevhash[HASH_NAMESZ + 1 + HASH_HEXSZ + 1]; }; =20 /* @@ -292,6 +295,7 @@ struct sourceinfo { enum log_format_type { =09LOG_FORMAT_NONE =3D 0, =09LOG_FORMAT_BOL, +=09LOG_FORMAT_HASH, =09LOG_FORMAT_TIME, =09LOG_FORMAT_HOST, =09LOG_FORMAT_MSG, @@ -391,6 +395,7 @@ static void allocate_log(void); int set_log_format_field(struct log_format *log_fmt, size_t i, enum log_fo= rmat_type t, char *s, size_t n) =09SYSKLOGD_NONNULL((1)); int parse_log_format(struct log_format *log_fmt, char *s); +void calculate_digest(struct filed *f, struct log_format *log_fmt); void sighup_handler(int); =20 #ifdef SYSLOG_UNIXAF @@ -1528,6 +1533,36 @@ void clear_record_fields(struct log_format *log_fmt) =09} } =20 +void calculate_digest(struct filed *f, struct log_format *log_fmt) +{ +=09int i, n; +=09unsigned char digest[HASH_RAWSZ]; +=09hash_ctx_t hash_ctx; + +=09if (!(log_fmt->f_mask | (1 << LOG_FORMAT_HASH))) +=09=09return; + +=09digest[0] =3D 0; + +=09hash_init(&hash_ctx); +=09for (i =3D 0; i < LOG_FORMAT_IOVEC_MAX; i++) +=09=09hash_update(&hash_ctx, log_fmt->iov[i].iov_base, log_fmt->iov[i].iov= _len); +=09hash_final(digest, &hash_ctx); + +=09strncpy(f->f_prevhash, HASH_NAME, sizeof(f->f_prevhash)); +=09n =3D HASH_NAMESZ; + +=09strncpy(f->f_prevhash + n, ":", sizeof(f->f_prevhash) - n); +=09n +=3D 1; + +=09for (i =3D 0; i < HASH_RAWSZ; i++) { +=09=09snprintf(f->f_prevhash + n, sizeof(f->f_prevhash) - n, "%02x", diges= t[i]); +=09=09n +=3D 2; +=09} +=09f->f_prevhash[n] =3D 0; +=09return; +} + void fprintlog(struct filed *f, char *from, int flags, char *msg) { =09char repbuf[80]; @@ -1545,6 +1580,7 @@ void fprintlog(struct filed *f, char *from, int flags= , char *msg) =20 =09set_record_field(&log_fmt, LOG_FORMAT_TIME, f->f_lasttime, 15); =09set_record_field(&log_fmt, LOG_FORMAT_HOST, f->f_prevhost, -1); +=09set_record_field(&log_fmt, LOG_FORMAT_HASH, f->f_prevhash, -1); =09if (msg) { =09=09set_record_field(&log_fmt, LOG_FORMAT_MSG, msg, -1); =09} else if (f->f_prevcount > 1) { @@ -1690,6 +1726,8 @@ void fprintlog(struct filed *f, char *from, int flags= , char *msg) =09=09if (f->f_file =3D=3D -1) =09=09=09break; =20 +=09=09calculate_digest(f, &log_fmt); + =09=09if (writev(f->f_file, log_fmt.iov, LOG_FORMAT_IOVEC_MAX) < 0) { =09=09=09int e =3D errno; =20 @@ -1738,6 +1776,7 @@ void fprintlog(struct filed *f, char *from, int flags= , char *msg) =09=09f->f_time =3D now; =09=09verbosef("\n"); =09=09set_record_field(&log_fmt, LOG_FORMAT_EOL, "\r\n", 2); +=09=09calculate_digest(f, &log_fmt); =09=09wallmsg(f, &log_fmt); =09=09break; =09} /* switch */ @@ -2658,6 +2697,7 @@ static void allocate_log(void) =09 */ =09++nlogs; =09memset(&Files[nlogs], '\0', sizeof(struct filed)); +=09strncpy(Files[nlogs].f_prevhash, EMPTY_HASH_LITERAL, sizeof(Files[nlogs= ].f_prevhash)); =09return; } =20 @@ -2754,6 +2794,7 @@ int parse_log_format(struct log_format *log_fmt, char= *str) =09=09=09=09case 't': f_type =3D LOG_FORMAT_TIME; break; =09=09=09=09case 'h': f_type =3D LOG_FORMAT_HOST; break; =09=09=09=09case 'm': f_type =3D LOG_FORMAT_MSG; break; +=09=09=09=09case 'H': f_type =3D LOG_FORMAT_HASH; break; =09=09=09=09case '%': =09=09=09=09=09special =3D 0; =09=09=09=09=09goto create_special; diff --git a/tests/log-hashes/.gitignore b/tests/log-hashes/.gitignore new file mode 100644 index 0000000..5d86449 --- /dev/null +++ b/tests/log-hashes/.gitignore @@ -0,0 +1,5 @@ +output +log +pipe +syslog.conf +*.log diff --git a/tests/log-hashes/check b/tests/log-hashes/check new file mode 100755 index 0000000..c8cfcbb --- /dev/null +++ b/tests/log-hashes/check @@ -0,0 +1,28 @@ +#!/bin/sh -efu + +. "$TOPDIR/tests/common.sh" + +WORKDIR=3D"$1" + +prepare + +cat > "$WORKDIR/syslog.conf" <&2 'ERROR: hash chain broken at lineno=3D%d\n' "$lineno" +=09=09printf >&2 'expected hash: %s\n' "$hash" +=09=09printf >&2 ' logged hash: %s\n' "$loghash" +=09=09exit 1 +=09fi + +=09prevhash=3D"$loghash" +=09prevline=3D"$logline" + +=09lineno=3D$(($lineno + 1)) +done < "$logfile" --=20 2.25.4