From: Arran Cudbard-Bell Date: Fri, 19 May 2017 04:22:35 +0000 (-0400) Subject: Add type checking functions for value box access X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ccb1e89686af9ad35fc41da4fe9dbd135c1d26af;p=thirdparty%2Ffreeradius-server.git Add type checking functions for value box access --- diff --git a/src/include/cbuff.h b/src/include/cbuff.h new file mode 100644 index 00000000000..bb59e18f17b --- /dev/null +++ b/src/include/cbuff.h @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef _FR_CBUFF_H +#define _FR_CBUFF_H +/* + * $Id$ + * + * @file include/cbuff.h + * @brief Simple circular buffer for debugging purposes. + * + * @copyright 2015-2017 Arran Cudbard-Bell + */ +#include +#include + +typedef struct fr_cbuff fr_cbuff_t; + +fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock); +void fr_cbuff_rp_insert(fr_cbuff_t *cbuff, void *obj); +void *fr_cbuff_rp_next(fr_cbuff_t *cbuff, TALLOC_CTX *ctx); +#endif /* _FR_CBUFF_H */ diff --git a/src/include/debug.h b/src/include/debug.h new file mode 100644 index 00000000000..373538d36c6 --- /dev/null +++ b/src/include/debug.h @@ -0,0 +1,95 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#ifndef _FR_DEBUG_H +#define _FR_DEBUG_H +/* + * $Id$ + * + * @file include/debug.h + * @brief Debugging function definitions and structures. + * + * @copyright 2015-2017 Arran Cudbard-Bell + */ +#include + +typedef enum { + DEBUGGER_STATE_UNKNOWN_NO_PTRACE = -3, //!< We don't have ptrace so can't check. + DEBUGGER_STATE_UNKNOWN_NO_PTRACE_CAP = -2, //!< CAP_SYS_PTRACE not set for the process. + DEBUGGER_STATE_UNKNOWN = -1, //!< Unknown, likely fr_get_debug_state() not called yet. + DEBUGGER_STATE_NOT_ATTACHED = 0, //!< We can attach, so a debugger must not be. + DEBUGGER_STATE_ATTACHED = 1 //!< We can't attach, it's likely a debugger is already tracing. +} fr_debug_state_t; + +extern fr_debug_state_t fr_debug_state; + +#define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__) +typedef void (*fr_fault_log_t)(char const *msg, ...) CC_HINT(format (printf, 1, 2)); + +/** Optional callback passed to fr_fault_setup + * + * Allows optional logic to be run before calling the main fault handler. + * + * If the callback returns < 0, the main fault handler will not be called. + * + * @param signum signal raised. + * @return + * - 0 on success. + * - < 0 on failure. + */ +typedef int (*fr_fault_cb_t)(int signum); +typedef struct fr_bt_marker fr_bt_marker_t; + +void fr_debug_state_store(void); +char const *fr_debug_state_to_msg(fr_debug_state_t state); +void fr_debug_break(bool always); +void backtrace_print(fr_cbuff_t *cbuff, void *obj); +int fr_backtrace_do(fr_bt_marker_t *marker); +fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj); + +void fr_panic_on_free(TALLOC_CTX *ctx); +int fr_set_dumpable_init(void); +int fr_set_dumpable(bool allow_core_dumps); +int fr_reset_dumpable(void); +int fr_log_talloc_report(TALLOC_CTX *ctx); +void fr_fault(int sig); +void fr_talloc_fault_setup(void); +int fr_fault_setup(char const *cmd, char const *program); +void fr_fault_set_cb(fr_fault_cb_t func); +void fr_fault_set_log_fd(int fd); +void fr_fault_log(char const *msg, ...) CC_HINT(format (printf, 1, 2)); +bool fr_cond_assert_fail(char const *file, int line, char const *expr); + +/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x + * + * Should be wrapped in a condition, and if false, should cause function to return + * an error code. This allows control to return to the caller if a precondition is + * not satisfied and we're not debugging. + * + * Example: + @verbatim + if (!fr_cond_assert(request)) return -1 + @endverbatim + * + * @param _x expression to test (should evaluate to true) + */ +#define fr_cond_assert(_x) (bool)((_x) ? true : (fr_cond_assert_fail(__FILE__, __LINE__, #_x) && false)) + +void NEVER_RETURNS _fr_exit(char const *file, int line, int status); +# define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x)) + +void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status); +# define fr_exit_now(_x) _fr_exit_now(__FILE__, __LINE__, (_x)) +#endif /* _FR_DEBUG_H */ diff --git a/src/include/libradius.h b/src/include/libradius.h index 239a64dc443..ec97fd32427 100644 --- a/src/include/libradius.h +++ b/src/include/libradius.h @@ -84,6 +84,7 @@ RCSIDH(libradius_h, "$Id$") #include #include #include +#include #ifdef SIZEOF_UNSIGNED_INT # if SIZEOF_UNSIGNED_INT != 4 @@ -232,88 +233,6 @@ void fr_rand_seed(void const *, size_t ); /* seed the random pool */ /* crypt wrapper from crypt.c */ int fr_crypt_check(char const *password, char const *reference_crypt); -/* cbuff.c */ - -typedef struct fr_cbuff fr_cbuff_t; - -fr_cbuff_t *fr_cbuff_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock); -void fr_cbuff_rp_insert(fr_cbuff_t *cbuff, void *obj); -void *fr_cbuff_rp_next(fr_cbuff_t *cbuff, TALLOC_CTX *ctx); - -/* debug.c */ -typedef enum { - DEBUGGER_STATE_UNKNOWN_NO_PTRACE = -3, //!< We don't have ptrace so can't check. - DEBUGGER_STATE_UNKNOWN_NO_PTRACE_CAP = -2, //!< CAP_SYS_PTRACE not set for the process. - DEBUGGER_STATE_UNKNOWN = -1, //!< Unknown, likely fr_get_debug_state() not called yet. - DEBUGGER_STATE_NOT_ATTACHED = 0, //!< We can attach, so a debugger must not be. - DEBUGGER_STATE_ATTACHED = 1 //!< We can't attach, it's likely a debugger is already tracing. -} fr_debug_state_t; - -#define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__) -typedef void (*fr_fault_log_t)(char const *msg, ...) CC_HINT(format (printf, 1, 2)); -extern fr_debug_state_t fr_debug_state; - -/** Optional callback passed to fr_fault_setup - * - * Allows optional logic to be run before calling the main fault handler. - * - * If the callback returns < 0, the main fault handler will not be called. - * - * @param signum signal raised. - * @return - * - 0 on success. - * - < 0 on failure. - */ -typedef int (*fr_fault_cb_t)(int signum); -typedef struct fr_bt_marker fr_bt_marker_t; - -void fr_debug_state_store(void); -char const *fr_debug_state_to_msg(fr_debug_state_t state); -void fr_debug_break(bool always); -void backtrace_print(fr_cbuff_t *cbuff, void *obj); -int fr_backtrace_do(fr_bt_marker_t *marker); -fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj); - -void fr_panic_on_free(TALLOC_CTX *ctx); -int fr_set_dumpable_init(void); -int fr_set_dumpable(bool allow_core_dumps); -int fr_reset_dumpable(void); -int fr_log_talloc_report(TALLOC_CTX *ctx); -void fr_fault(int sig); -void fr_talloc_fault_setup(void); -int fr_fault_setup(char const *cmd, char const *program); -void fr_fault_set_cb(fr_fault_cb_t func); -void fr_fault_set_log_fd(int fd); -void fr_fault_log(char const *msg, ...) CC_HINT(format (printf, 1, 2)); - -# ifdef WITH_VERIFY_PTR -void fr_pair_verify(char const *file, int line, VALUE_PAIR const *vp); -void fr_pair_list_verify(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps); -# endif - -bool fr_cond_assert_fail(char const *file, int line, char const *expr); - -/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x - * - * Should be wrapped in a condition, and if false, should cause function to return - * an error code. This allows control to return to the caller if a precondition is - * not satisfied and we're not debugging. - * - * Example: - @verbatim - if (!fr_cond_assert(request)) return -1 - @endverbatim - * - * @param _x expression to test (should evaluate to true) - */ -#define fr_cond_assert(_x) (bool)((_x) ? true : (fr_cond_assert_fail(__FILE__, __LINE__, #_x) && false)) - -void NEVER_RETURNS _fr_exit(char const *file, int line, int status); -# define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x)) - -void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status); -# define fr_exit_now(_x) _fr_exit_now(__FILE__, __LINE__, (_x)) - /* * FIFOs */ diff --git a/src/include/pair.h b/src/include/pair.h index 4892e5699c9..ac5b4ac6f70 100644 --- a/src/include/pair.h +++ b/src/include/pair.h @@ -182,6 +182,11 @@ typedef struct value_pair_raw { #define NUM_COUNT (INT_MIN + 2) #define NUM_LAST (INT_MIN + 3) +# ifdef WITH_VERIFY_PTR +void fr_pair_verify(char const *file, int line, VALUE_PAIR const *vp); +void fr_pair_list_verify(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps); +# endif + /* Allocation and management */ VALUE_PAIR *fr_pair_alloc(TALLOC_CTX *ctx); VALUE_PAIR *fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da); diff --git a/src/include/value.h b/src/include/value.h index e25b6e77575..89f063ebeab 100644 --- a/src/include/value.h +++ b/src/include/value.h @@ -17,6 +17,7 @@ #define _FR_VALUE_H #include #include +#include /* * Avoid circular type references. @@ -156,35 +157,171 @@ struct value_box { * These macros will in future do type checking in developer builds, * in addition to getting the box value. */ -#define fr_unbox_strvalue(_box) _box->datum.strvalue -#define fr_unbox_octets(_box) _box->datum.octets - -#define fr_unbox_ipv4addr(_box) _box->datum.ip -#define fr_unbox_ipv4prefix(_box) _box->datum.ip -#define fr_unbox_ipv6addr(_box) _box->datum.ip -#define fr_unbox_ipv6prefix(_box) _box->datum.ip - -#define fr_unbox_ifid(_box) _box->datum.ifid -#define fr_unbox_ether(_box) _box->datum.ether - -#define fr_unbox_uint8(_box) _box->datum.uint8 -#define fr_unbox_uint16(_box) _box->datum.uint16 -#define fr_unbox_uint32(_box) _box->datum.uint32 -#define fr_unbox_uint64(_box) _box->datum.uint64 -#define fr_unbox_uint128(_box) _box->datum.uint128 - -#define fr_unbox_int8(_box) _box->datum.int8 -#define fr_unbox_int16(_box) _box->datum.int16 -#define fr_unbox_int32(_box) _box->datum.int32 -#define fr_unbox_int64(_box) _box->datum.int64 - -#define fr_unbox_float32(_box) _box->datum.float32 -#define fr_unbox_float64(_box) _box->datum.float64 - -#define fr_unbox_date(_val) _box->datum.date -#define fr_unbox_date_milliseconds(_val) _box->datum.date_milliseconds -#define fr_unbox_date_microseconds(_val) _box->datum.date_microseconds -#define fr_unbox_date_nanoseconds(_val) _box->datum.date_nanoseconds +#ifndef NDEBUG +static inline char const *fr_unbox_strvalue(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_STRING)) return NULL; + return value->datum.strvalue; +} +static inline uint8_t const *fr_unbox_octets(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_OCTETS)) return NULL; + return value->datum.octets; +} + +static inline fr_ipaddr_t const *fr_unbox_ipv4addr(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_IPV4_ADDR)) return NULL; + if (!fr_cond_assert(value->datum.ip.af == AF_INET)) return NULL; + if (!fr_cond_assert(value->datum.ip.prefix == 32)) return NULL; + return &value->datum.ip; +} +static inline fr_ipaddr_t const *fr_unbox_ipv4prefix(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_IPV4_ADDR)) return NULL; + if (!fr_cond_assert(value->datum.ip.af == AF_INET)) return NULL; + if (!fr_cond_assert(value->datum.ip.prefix <= 32)) return NULL; + if (!fr_cond_assert(value->datum.ip.prefix >= 0)) return NULL; + return &value->datum.ip; +} +static inline fr_ipaddr_t const *fr_unbox_ipv6addr(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_IPV6_ADDR)) return NULL; + if (!fr_cond_assert(value->datum.ip.af == AF_INET6)) return NULL; + if (!fr_cond_assert(value->datum.ip.prefix == 128)) return NULL; + return &value->datum.ip; +} +static inline fr_ipaddr_t const *fr_unbox_ipv6prefix(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_IPV6_PREFIX)) return NULL; + if (!fr_cond_assert(value->datum.ip.af == AF_INET6)) return NULL; + if (!fr_cond_assert(value->datum.ip.prefix <= 128)) return NULL; + if (!fr_cond_assert(value->datum.ip.prefix >= 0)) return NULL; + return &value->datum.ip; +} + +static inline uint8_t const *fr_unbox_ifid(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_IFID)) return NULL; + return value->datum.ifid; +} +static inline uint8_t const *fr_unbox_ether(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_ETHERNET)) return NULL; + return value->datum.ether; +} + +static inline uint8_t fr_unbox_uint8(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT8)) return 0; + return value->datum.uint8; +} +static inline uint16_t fr_unbox_uint16(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT16)) return 0; + return value->datum.uint16; +} +static inline uint32_t fr_unbox_uint32(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT32)) return 0; + return value->datum.uint32; +} +static inline uint64_t fr_unbox_uint64(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT64)) return 0; + return value->datum.uint64; +} +/* +static inline uint128_t fr_unbox_uint128(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT128)) return 0; + return value->datum.uint128; +} +*/ + +static inline int8_t fr_unbox_int8(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT8)) return 0; + return value->datum.int8; +} +static inline int16_t fr_unbox_int16(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT16)) return 0; + return value->datum.int16; +} +static inline int32_t fr_unbox_int32(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT32)) return 0; + return value->datum.int32; +} +static inline int64_t fr_unbox_int64(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_UINT64)) return 0; + return value->datum.int64; +} + +static inline float fr_unbox_float32(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_FLOAT32)) return 0; + return value->datum.float32; +} +static inline float fr_unbox_float64(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_FLOAT64)) return 0; + return value->datum.float64; +} + +static inline uint32_t fr_unbox_date(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_DATE)) return 0; + return value->datum.date; +} +static inline uint64_t fr_unbox_date_milliseconds(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_DATE_MILLISECONDS)) return 0; + return value->datum.date_milliseconds; +} +static inline uint64_t fr_unbox_date_microseconds(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_DATE_MICROSECONDS)) return 0; + return value->datum.date_microseconds; +} +static inline uint64_t fr_unbox_date_nanoseconds(fr_value_box_t const *value) +{ + if (!fr_cond_assert(value->type == FR_TYPE_DATE_NANOSECONDS)) return 0; + return value->datum.date_nanoseconds; +} +#else +# define fr_unbox_strvalue(_box) _box->datum.strvalue +# define fr_unbox_octets(_box) _box->datum.octets + +# define fr_unbox_ipv4addr(_box) &(_box->datum.ip) +# define fr_unbox_ipv4prefix(_box) &(_box->datum.ip) +# define fr_unbox_ipv6addr(_box) &(_box->datum.ip) +# define fr_unbox_ipv6prefix(_box) &(_box->datum.ip) + +# define fr_unbox_ifid(_box) _box->datum.ifid +# define fr_unbox_ether(_box) _box->datum.ether + +# define fr_unbox_uint8(_box) _box->datum.uint8 +# define fr_unbox_uint16(_box) _box->datum.uint16 +# define fr_unbox_uint32(_box) _box->datum.uint32 +# define fr_unbox_uint64(_box) _box->datum.uint64 +# define fr_unbox_uint128(_box) _box->datum.uint128 + +# define fr_unbox_int8(_box) _box->datum.int8 +# define fr_unbox_int16(_box) _box->datum.int16 +# define fr_unbox_int32(_box) _box->datum.int32 +# define fr_unbox_int64(_box) _box->datum.int64 + +# define fr_unbox_float32(_box) _box->datum.float32 +# define fr_unbox_float64(_box) _box->datum.float64 + +# define fr_unbox_date(_val) _box->datum.date +# define fr_unbox_date_milliseconds(_val) _box->datum.date_milliseconds +# define fr_unbox_date_microseconds(_val) _box->datum.date_microseconds +# define fr_unbox_date_nanoseconds(_val) _box->datum.date_nanoseconds +#endif /* * Allocation