all: add static assertion for maximumg alloca() allocated buffer

Add a compile time check that the buffer that we allocate on the stack
is reasonably small.
This commit is contained in:
Thomas Haller 2019-01-10 12:00:34 +01:00
parent 617bdbd8c2
commit 3263cab596
6 changed files with 58 additions and 39 deletions

View file

@ -1409,7 +1409,8 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro)
* If @str is longer then @trunc_at, the string is truncated and the closing
* quote is instead '^' to indicate truncation.
*
* Thus, the maximum stack allocated buffer will be @trunc_at+3. */
* Thus, the maximum stack allocated buffer will be @trunc_at+3. The maximum
* buffer size must be a constant and not larger than 300. */
#define nm_strquote_a(trunc_at, str) \
({ \
const char *const _str = (str); \
@ -1420,6 +1421,8 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro)
const gsize _strlen_trunc = NM_MIN (strlen (_str), _trunc_at); \
char *_buf; \
\
G_STATIC_ASSERT_EXPR ((trunc_at) <= 300); \
\
_buf = g_alloca (_strlen_trunc + 3); \
_buf[0] = '"'; \
memcpy (&_buf[1], _str, _strlen_trunc); \
@ -1444,19 +1447,30 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro)
_buf; \
})
#define nm_sprintf_bufa(n_elements, format, ...) \
/* it is "unsafe" because @bufsize must not be a constant expression and
* there is no check at compiletime. Regardless of that, the buffer size
* must not be larger than 300 bytes, as this gets stack allocated. */
#define nm_sprintf_buf_unsafe_a(bufsize, format, ...) \
({ \
char *_buf; \
int _buf_len; \
typeof (n_elements) _n_elements = (n_elements); \
typeof (bufsize) _bufsize = (bufsize); \
\
_buf = g_alloca (_n_elements); \
_buf_len = g_snprintf (_buf, _n_elements, \
nm_assert (_bufsize <= 300); \
\
_buf = g_alloca (_bufsize); \
_buf_len = g_snprintf (_buf, _bufsize, \
""format"", ##__VA_ARGS__); \
nm_assert (_buf_len < _n_elements); \
nm_assert (_buf_len >= 0 && _buf_len < _bufsize); \
_buf; \
})
#define nm_sprintf_bufa(bufsize, format, ...) \
({ \
G_STATIC_ASSERT_EXPR ((bufsize) <= 300); \
nm_sprintf_buf_unsafe_a ((bufsize), format, ##__VA_ARGS__); \
})
/* aims to alloca() a buffer and fill it with printf(format, name).
* Note that format must not contain any format specifier except
* "%s".
@ -1470,9 +1484,9 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro)
char *_buf2; \
\
nm_assert (_p_val_to_free && !*_p_val_to_free); \
if ( NM_STRLEN (format) < 200 \
&& _name_len < (gsize) (200 - NM_STRLEN (format))) \
_buf2 = nm_sprintf_bufa (NM_STRLEN (format) + _name_len, format, _name); \
if ( NM_STRLEN (format) <= 290 \
&& _name_len < (gsize) (290 - NM_STRLEN (format))) \
_buf2 = nm_sprintf_buf_unsafe_a (NM_STRLEN (format) + _name_len, format, _name); \
else { \
_buf2 = g_strdup_printf (format, _name); \
*_p_val_to_free = _buf2; \

View file

@ -278,6 +278,8 @@ _nm_strndup_a_step (char *s, const char *str, gsize len)
char **const _out_str_free = (out_str_free); \
char *_s; \
\
G_STATIC_ASSERT_EXPR ((alloca_maxlen) <= 300); \
\
if ( _out_str_free \
&& _len >= _alloca_maxlen) { \
_s = g_malloc (_len + 1); \

View file

@ -98,6 +98,8 @@ test_make_strv (void)
G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b" )) == 3);
G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b", )) == 3);
nm_strquote_a (300, "");
}
/*****************************************************************************/

View file

@ -42,17 +42,6 @@
#include "nm-utils/nm-time-utils.h"
#include "nm-errors.h"
/* often we have some static string where we need to know the maximum length.
* _MAX_LEN() returns @max but adds a debugging assertion that @str is indeed
* shorter then @mac. */
#define _MAX_LEN(max, str) \
({ \
const char *const _str = (str); \
\
nm_assert (_str && strlen (str) < (max)); \
(max); \
})
void (*_nm_logging_clear_platform_logging_cache) (void);
static void
@ -592,14 +581,25 @@ _iovec_set_format (struct iovec *iov, gpointer *iov_free, const char *format, ..
char *const _buf = g_alloca (_size); \
int _len; \
\
G_STATIC_ASSERT_EXPR ((reserve_extra) + (NM_STRLEN (format) + 3) <= 96); \
\
_len = g_snprintf (_buf, _size, ""format"", ##__VA_ARGS__);\
\
nm_assert (_len >= 0); \
nm_assert (_len <= _size); \
nm_assert (_len < _size); \
nm_assert (_len == strlen (_buf)); \
\
_iovec_set ((iov), _buf, _len); \
} G_STMT_END
#define _iovec_set_format_str_a(iov, max_str_len, format, str_arg) \
G_STMT_START { \
const char *_str_arg = (str_arg); \
\
nm_assert (_str_arg && strlen (_str_arg) < (max_str_len)); \
_iovec_set_format_a ((iov), (max_str_len), format, str_arg); \
} G_STMT_END
#endif
void
@ -699,7 +699,7 @@ _nm_log_impl (const char *file,
if (NM_FLAGS_ANY (dom, diter->num)) {
if (i_domain > 0) {
/* SYSLOG_FACILITY is specified multiple times for each domain that is actually enabled. */
_iovec_set_format_a (iov++, _MAX_LEN (30, diter->name), "SYSLOG_FACILITY=%s", diter->name);
_iovec_set_format_str_a (iov++, 30, "SYSLOG_FACILITY=%s", diter->name);
i_domain--;
}
dom &= ~diter->num;
@ -710,9 +710,9 @@ _nm_log_impl (const char *file,
if (s_domain_all)
_iovec_set (iov++, s_domain_all->str, s_domain_all->len);
else
_iovec_set_format_a (iov++, _MAX_LEN (30, s_domain_1), "NM_LOG_DOMAINS=%s", s_domain_1);
_iovec_set_format_str_a (iov++, 30, "NM_LOG_DOMAINS=%s", s_domain_1);
}
_iovec_set_format_a (iov++, _MAX_LEN (15, global.level_desc[level].name), "NM_LOG_LEVEL=%s", global.level_desc[level].name);
_iovec_set_format_str_a (iov++, 15, "NM_LOG_LEVEL=%s", global.level_desc[level].name);
if (func)
_iovec_set_format (iov++, iov_free++, "CODE_FUNC=%s", func);
_iovec_set_format (iov++, iov_free++, "CODE_FILE=%s", file ?: "");

View file

@ -2293,9 +2293,10 @@ link_set_option (NMPlatform *self, int ifindex, const char *category, const char
if (dirfd < 0)
return FALSE;
path = nm_sprintf_bufa (strlen (category) + strlen (option) + 2,
"%s/%s",
category, option);
path = nm_sprintf_buf_unsafe_a (strlen (category) + strlen (option) + 2,
"%s/%s",
category,
option);
return nm_platform_sysctl_set (self, NMP_SYSCTL_PATHID_NETDIR_unsafe (dirfd, ifname_verified, path), value);
}
@ -2313,9 +2314,9 @@ link_get_option (NMPlatform *self, int ifindex, const char *category, const char
if (dirfd < 0)
return NULL;
path = nm_sprintf_bufa (strlen (category) + strlen (option) + 2,
"%s/%s",
category, option);
path = nm_sprintf_buf_unsafe_a (strlen (category) + strlen (option) + 2,
"%s/%s",
category, option);
return nm_platform_sysctl_get (self, NMP_SYSCTL_PATHID_NETDIR_unsafe (dirfd, ifname_verified, path));
}

View file

@ -1087,15 +1087,15 @@ const char *nm_link_type_to_string (NMLinkType link_type);
((const char *) NULL), -1, (path)
#define NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname, path) \
nm_sprintf_bufa ( NM_STRLEN ("net:/sys/class/net//\0") \
+ NMP_IFNAMSIZ \
+ ({ \
const gsize _l = strlen (path); \
\
nm_assert (_l < 200); \
_l; \
}), \
"net:/sys/class/net/%s/%s", (ifname), (path)), \
nm_sprintf_buf_unsafe_a ( NM_STRLEN ("net:/sys/class/net//\0") \
+ NMP_IFNAMSIZ \
+ ({ \
const gsize _l = strlen (path); \
\
nm_assert (_l < 200); \
_l; \
}), \
"net:/sys/class/net/%s/%s", (ifname), (path)), \
(dirfd), (path)
#define NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, path) \