From 83db3bbee4e19e7426a32ee89ad6c2d8e48260f2 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Tue, 18 Jun 2013 20:03:57 -0700 Subject: Also poison memcpy, memmove, and memset --- src/common/const_array.hpp | 2 + src/common/md5calc.cpp | 108 +++++++++++++++++++++++---------------------- src/common/mmo.hpp | 2 +- src/common/socket.cpp | 4 +- src/common/socket.hpp | 79 +++++++++++++++++++++++++++++++++ src/common/utils.hpp | 39 +++++++++++++++- 6 files changed, 178 insertions(+), 56 deletions(-) (limited to 'src/common') diff --git a/src/common/const_array.hpp b/src/common/const_array.hpp index 06045dc..a3a6d58 100644 --- a/src/common/const_array.hpp +++ b/src/common/const_array.hpp @@ -126,6 +126,8 @@ public: }; // subclass just provides a simpler name and some conversions +// Important note: it must be safe to dereference end, though +// the value is unspecified. class const_string : public const_array { public: diff --git a/src/common/md5calc.cpp b/src/common/md5calc.cpp index 36f220d..f773c9f 100644 --- a/src/common/md5calc.cpp +++ b/src/common/md5calc.cpp @@ -3,6 +3,7 @@ #include #include "random.hpp" +#include "utils.hpp" #include "../poison.hpp" @@ -43,7 +44,7 @@ const uint32_t T[64] = static uint32_t rotate_left(uint32_t val, unsigned shift) { - return val << shift | val >> (32-shift); + return val << shift | val >> (32 - shift); } static @@ -117,45 +118,45 @@ void MD5_init(MD5_state* state) void MD5_do_block(MD5_state* state, MD5_block block) { #define X block.data -#define a state->val[(16-i)%4] -#define b state->val[(17-i)%4] -#define c state->val[(18-i)%4] -#define d state->val[(19-i)%4] +#define a state->val[(16 - i) % 4] +#define b state->val[(17 - i) % 4] +#define c state->val[(18 - i) % 4] +#define d state->val[(19 - i) % 4] // save the values const MD5_state saved = *state; // round 1 - for (int i=0; i<16; i++) + for (int i = 0; i < 16; i++) { #define k MD5_round1[i].k #define s MD5_round1[i].s - a = b + rotate_left(a + F(b,c,d) + X[k] + T[i+0x0], s); + a = b + rotate_left(a + F(b, c, d) + X[k] + T[i + 0x0], s); #undef k #undef s } // round 2 - for (int i=0; i<16; i++) + for (int i = 0; i < 16; i++) { #define k MD5_round2[i].k #define s MD5_round2[i].s - a = b + rotate_left(a + G(b,c,d) + X[k] + T[i+0x10], s); + a = b + rotate_left(a + G(b, c, d) + X[k] + T[i + 0x10], s); #undef k #undef s } // round 3 - for (int i=0; i<16; i++) + for (int i = 0; i < 16; i++) { #define k MD5_round3[i].k #define s MD5_round3[i].s - a = b + rotate_left(a + H(b,c,d) + X[k] + T[i+0x20], s); + a = b + rotate_left(a + H(b, c, d) + X[k] + T[i + 0x20], s); #undef k #undef s } // round 4 - for (int i=0; i<16; i++) + for (int i = 0; i < 16; i++) { #define k MD5_round4[i].k #define s MD5_round4[i].s - a = b + rotate_left(a + I(b,c,d) + X[k] + T[i+0x30], s); + a = b + rotate_left(a + I(b, c, d) + X[k] + T[i + 0x30], s); #undef k #undef s } @@ -172,8 +173,8 @@ void MD5_do_block(MD5_state* state, MD5_block block) void MD5_to_bin(MD5_state state, uint8_t out[0x10]) { - for (int i=0; i<0x10; i++) - out[i] = state.val[i/4] >> 8*(i%4); + for (int i = 0; i < 0x10; i++) + out[i] = state.val[i / 4] >> 8 * (i % 4); } static @@ -183,9 +184,9 @@ void MD5_to_str(MD5_state state, char out[0x21]) { uint8_t bin[16]; MD5_to_bin(state, bin); - for (int i=0; i<0x10; i++) - out[2*i] = hex[bin[i] >> 4], - out[2*i+1] = hex[bin[i] & 0xf]; + for (int i = 0; i < 0x10; i++) + out[2 * i] = hex[bin[i] >> 4], + out[2 * i + 1] = hex[bin[i] & 0xf]; out[0x20] = '\0'; } @@ -197,31 +198,31 @@ MD5_state MD5_from_string(const char* msg, const size_t msglen) size_t rem = msglen; while (rem >= 64) { - for (int i=0; i<0x10; i++) - X[i] = msg[4*i+0] | msg[4*i+1]<<8 | msg[4*i+2]<<16 | msg[4*i+3]<<24; + for (int i = 0; i < 0x10; i++) + X[i] = msg[4 * i + 0] | msg[4 * i + 1] << 8 | msg[4 * i + 2] << 16 | msg[4 * i + 3] << 24; MD5_do_block(&state, block); msg += 64; rem -= 64; } // now pad 1-512 bits + the 64-bit length - may be two blocks uint8_t buf[0x40] = {}; - memcpy(buf, msg, rem); + really_memcpy(buf, reinterpret_cast(msg), rem); buf[rem] = 0x80; // a single one bit if (64 - rem > 8) { - for (int i=0; i<8; i++) - buf[0x38+i] = (static_cast(msglen)*8) >> (i*8); + for (int i = 0; i < 8; i++) + buf[0x38 + i] = (static_cast(msglen) * 8) >> (i * 8); } - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; MD5_do_block(&state, block); if (64 - rem <= 8) { - memset(buf,'\0', 0x38); - for (int i=0; i<8; i++) - buf[0x38+i] = (static_cast(msglen)*8) >> (i*8); - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + really_memset0(buf, 0x38); + for (int i = 0; i < 8; i++) + buf[0x38 + i] = (static_cast(msglen) * 8) >> (i * 8); + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; MD5_do_block(&state, block); } return state; @@ -233,7 +234,8 @@ MD5_state MD5_from_cstring(const char* msg) return MD5_from_string(msg, strlen(msg)); } -MD5_state MD5_from_FILE(FILE* in) { +MD5_state MD5_from_FILE(FILE* in) +{ uint64_t total_len = 0; uint8_t buf[0x40]; @@ -249,33 +251,33 @@ MD5_state MD5_from_FILE(FILE* in) { size_t rv = fread(buf + block_len, 1, 0x40 - block_len, in); if (!rv) break; - total_len += 8*rv; // in bits + total_len += 8 * rv; // in bits block_len += rv; if (block_len != 0x40) continue; - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; MD5_do_block(&state, block); block_len = 0; } // no more input, just pad and append the length buf[block_len] = 0x80; - memset(buf + block_len + 1, '\0', 0x40 - block_len - 1); + really_memset0(buf + block_len + 1, 0x40 - block_len - 1); if (block_len < 0x38) { - for (int i=0; i<8; i++) - buf[0x38+i] = total_len >> i*8; + for (int i = 0; i < 8; i++) + buf[0x38 + i] = total_len >> i * 8; } - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; MD5_do_block(&state, block); if (0x38 <= block_len) { - memset(buf, '\0', 0x38); - for (int i=0; i<8; i++) - buf[0x38+i] = total_len >> i*8; - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + really_memset0(buf, 0x38); + for (int i = 0; i < 8; i++) + buf[0x38 + i] = total_len >> i * 8; + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; MD5_do_block(&state, block); } return state; @@ -291,19 +293,20 @@ const char *MD5_saltcrypt(const char *key, const char *salt) // hash the key then the salt // buf ends up as a 64-char NUL-terminated string MD5_to_str(MD5_from_cstring(key), buf); - MD5_to_str(MD5_from_cstring(salt), buf+32); + MD5_to_str(MD5_from_cstring(salt), buf + 32); // Hash the buffer back into sbuf - this is stupid // (luckily, putting the result into itself is safe) - MD5_to_str(MD5_from_cstring(buf), buf+32); + MD5_to_str(MD5_from_cstring(buf), buf + 32); static char obuf[33]; // This truncates the string, but we have to keep it like that for compatibility - snprintf(obuf, 32, "!%s$%s", salt, buf+32); + snprintf(obuf, 32, "!%s$%s", salt, buf + 32); return obuf; } -const char *make_salt(void) { +const char *make_salt(void) +{ static char salt[6]; for (int i = 0; i < 5; i++) // 126 would probably actually be okay @@ -311,7 +314,8 @@ const char *make_salt(void) { return salt; } -bool pass_ok(const char *password, const char *crypted) { +bool pass_ok(const char *password, const char *crypted) +{ char buf[40]; strncpy(buf, crypted, 40); char *salt = buf + 1; @@ -324,15 +328,15 @@ bool pass_ok(const char *password, const char *crypted) { // to return a hopefully unique masked IP. struct in_addr MD5_ip(char *secret, struct in_addr ip) { - char ipbuf[32]; uint8_t obuf[16]; - union { + union + { uint8_t bytes[4]; struct in_addr ip; } conv; // MD5sum a secret + the IP address - memset(&ipbuf, 0, sizeof(ipbuf)); + char ipbuf[32] {}; snprintf(ipbuf, sizeof(ipbuf), "%u%s", ip.s_addr, secret); /// TODO stop it from being a cstring MD5_to_bin(MD5_from_cstring(ipbuf), obuf); diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp index a04fd34..14b8bac 100644 --- a/src/common/mmo.hpp +++ b/src/common/mmo.hpp @@ -78,7 +78,7 @@ struct item struct point { - char map[24]; + char map_[16]; short x, y; }; diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 0ee8712..c509825 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -38,7 +38,7 @@ std::array, FD_SETSIZE> session; inline void RFIFOFLUSH(int fd) { - memmove(&session[fd]->rdata[0], RFIFOP(fd, 0), RFIFOREST(fd)); + really_memmove(&session[fd]->rdata[0], static_cast(RFIFOP(fd, 0)), RFIFOREST(fd)); session[fd]->rdata_size = RFIFOREST(fd); session[fd]->rdata_pos = 0; } @@ -97,7 +97,7 @@ void send_from_fifo(int fd) session[fd]->wdata_size -= len; if (session[fd]->wdata_size) { - memmove(&session[fd]->wdata[0], &session[fd]->wdata[len], + really_memmove(&session[fd]->wdata[0], &session[fd]->wdata[len], session[fd]->wdata_size); } session[fd]->connected = 1; diff --git a/src/common/socket.hpp b/src/common/socket.hpp index d526379..ef7b193 100644 --- a/src/common/socket.hpp +++ b/src/common/socket.hpp @@ -102,6 +102,13 @@ FILE *fopen_(const char *path, const char *mode); bool free_fds(void); +template +uint8_t *pod_addressof(T& structure) +{ + static_assert(is_trivially_copyable::value, "Can only byte-copy POD-ish structs"); + return &reinterpret_cast(structure); +} + /// Check how much can be read @@ -131,6 +138,21 @@ uint32_t RFIFOL(int fd, size_t pos) { return *static_cast(RFIFOP(fd, pos)); } +template +void RFIFO_STRUCT(int fd, size_t pos, T& structure) +{ + really_memcpy(pod_addressof(structure), static_cast(RFIFOP(fd, pos)), sizeof(T)); +} +inline +void RFIFO_STRING(int fd, size_t pos, char *out, size_t len) +{ + strzcpy(out, static_cast(RFIFOP(fd, pos)), len); +} +inline +void RFIFO_BUF_CLONE(int fd, uint8_t *buf, size_t len) +{ + really_memcpy(buf, static_cast(RFIFOP(fd, 0)), len); +} /// Done reading void RFIFOSKIP(int fd, size_t len); @@ -156,6 +178,16 @@ uint32_t RBUFL(const uint8_t *p, size_t pos) { return *static_cast(RBUFP(p, pos)); } +template +void RBUF_STRUCT(const uint8_t *p, size_t pos, T& structure) +{ + really_memcpy(pod_addressof(structure), p + pos, sizeof(T)); +} +inline +void RBUF_STRING(const uint8_t *p, size_t pos, char *out, size_t len) +{ + strzcpy(out, static_cast(RBUFP(p, pos)), len); +} /// Unused - check how much data can be written @@ -185,6 +217,29 @@ uint32_t& WFIFOL(int fd, size_t pos) { return *static_cast(WFIFOP(fd, pos)); } +template +void WFIFO_STRUCT(int fd, size_t pos, T& structure) +{ + really_memcpy(static_cast(WFIFOP(fd, pos)), pod_addressof(structure), sizeof(T)); +} +inline +void WFIFO_STRING(int fd, size_t pos, const char *s, size_t len) +{ + strzcpy(static_cast(WFIFOP(fd, pos)), s, len); +} +inline +void WFIFO_ZERO(int fd, size_t pos, size_t len) +{ + uint8_t *b = static_cast(WFIFOP(fd, pos)); + uint8_t *e = b + len; + std::fill(b, e, '\0'); +} +inline +void WFIFO_BUF_CLONE(int fd, const uint8_t *buf, size_t len) +{ + really_memcpy(static_cast(WFIFOP(fd, 0)), buf, len); +} + /// Finish writing void WFIFOSET(int fd, size_t len); @@ -209,5 +264,29 @@ uint32_t& WBUFL(uint8_t *p, size_t pos) { return *static_cast(WBUFP(p, pos)); } +template +void WBUF_STRUCT(uint8_t *p, size_t pos, T& structure) +{ + really_memcpy(p + pos, pod_addressof(structure), sizeof(T)); +} +inline +void WBUF_STRING(uint8_t *p, size_t pos, const char *s, size_t len) +{ + strzcpy(static_cast(WBUFP(p, pos)), s, len); +} +inline +void WBUF_ZERO(uint8_t *p, size_t pos, size_t len) +{ + uint8_t *b = static_cast(WBUFP(p, pos)); + uint8_t *e = b + len; + std::fill(b, e, '\0'); +} + +inline +void RFIFO_WFIFO_CLONE(int rfd, int wfd, size_t len) +{ + really_memcpy(static_cast(WFIFOP(wfd, 0)), + static_cast(RFIFOP(rfd, 0)), len); +} #endif // SOCKET_HPP diff --git a/src/common/utils.hpp b/src/common/utils.hpp index caa39ed..cd45aa1 100644 --- a/src/common/utils.hpp +++ b/src/common/utils.hpp @@ -7,11 +7,21 @@ #include #include +#include #include "const_array.hpp" #include "operators.hpp" #include "utils2.hpp" +template +struct is_trivially_copyable +: std::integral_constant +{}; + int remove_control_chars(char *str); int e_mail_check(const char *email); int config_switch (const char *str); @@ -25,10 +35,37 @@ void strzcpy(char *dest, const char *src, size_t n) if (n) { strncpy(dest, src, n); - dest[n-1] = '\0'; + dest[n - 1] = '\0'; } } +inline +void really_memcpy(uint8_t *dest, const uint8_t *src, size_t n) +{ + memcpy(dest, src, n); +} + +inline +void really_memmove(uint8_t *dest, const uint8_t *src, size_t n) +{ + memmove(dest, src, n); +} + +inline +void really_memset0(uint8_t *dest, size_t n) +{ + memset(dest, '\0', n); +} +template +void really_memzero_this(T *v) +{ + static_assert(is_trivially_copyable::value, "only for mostly-pod types"); + static_assert(std::is_class::value || std::is_union::value, "Only for user-defined structures (for now)"); + memset(v, '\0', sizeof(*v)); +} +template +void really_memzero_this(T (&)[n]) = delete; + // Exists in place of time_t, to give it a predictable printf-format. // (on x86 and amd64, time_t == long, but not on x32) static_assert(sizeof(long long) >= sizeof(time_t), "long long >= time_t"); -- cgit v1.2.3-70-g09d2