Merge pull request #10246 from keszybz/fuzz-buss

Bus fuzzer
This commit is contained in:
Lennart Poettering 2018-10-02 15:45:21 +02:00 committed by GitHub
commit c3281539da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 401 additions and 228 deletions

View File

@ -781,6 +781,7 @@ conf.set10('ENABLE_DEBUG_HASHMAP', enable_debug_hashmap)
conf.set10('ENABLE_DEBUG_MMAP_CACHE', enable_debug_mmap_cache) conf.set10('ENABLE_DEBUG_MMAP_CACHE', enable_debug_mmap_cache)
conf.set10('VALGRIND', get_option('valgrind')) conf.set10('VALGRIND', get_option('valgrind'))
conf.set10('LOG_TRACE', get_option('log-trace'))
##################################################################### #####################################################################
@ -1476,7 +1477,7 @@ foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
module = tuple[0] module = tuple[0]
sym = 'src/nss-@0@/nss-@0@.sym'.format(module) sym = 'src/nss-@0@/nss-@0@.sym'.format(module)
version_script_arg = join_paths(meson.current_source_dir(), sym) version_script_arg = join_paths(meson.source_root(), sym)
nss = shared_library( nss = shared_library(
'nss_' + module, 'nss_' + module,
@ -1731,7 +1732,7 @@ if conf.get('ENABLE_LOGIND') == 1
public_programs += exe public_programs += exe
if conf.get('HAVE_PAM') == 1 if conf.get('HAVE_PAM') == 1
version_script_arg = join_paths(meson.current_source_dir(), pam_systemd_sym) version_script_arg = join_paths(meson.source_root(), pam_systemd_sym)
pam_systemd = shared_library( pam_systemd = shared_library(
'pam_systemd', 'pam_systemd',
pam_systemd_c, pam_systemd_c,
@ -2847,9 +2848,7 @@ foreach tuple : sanitizers
test('@0@:@1@:@2@'.format(b, c, sanitizer), test('@0@:@1@:@2@'.format(b, c, sanitizer),
env, env,
args : [exe.full_path(), args : [exe.full_path(),
join_paths(meson.source_root(), join_paths(meson.source_root(), p)])
'test/fuzz-regressions',
p)])
endif endif
endforeach endforeach
endif endif
@ -2861,7 +2860,7 @@ endforeach
if git.found() if git.found()
all_files = run_command( all_files = run_command(
git, git,
['--git-dir=@0@/.git'.format(meson.current_source_dir()), ['--git-dir=@0@/.git'.format(meson.source_root()),
'ls-files', 'ls-files',
':/*.[ch]']) ':/*.[ch]'])
all_files = files(all_files.stdout().split()) all_files = files(all_files.stdout().split())
@ -2869,10 +2868,10 @@ if git.found()
custom_target( custom_target(
'tags', 'tags',
output : 'tags', output : 'tags',
command : [env, 'etags', '-o', '@0@/TAGS'.format(meson.current_source_dir())] + all_files) command : [env, 'etags', '-o', '@0@/TAGS'.format(meson.source_root())] + all_files)
run_target( run_target(
'ctags', 'ctags',
command : [env, 'ctags', '-o', '@0@/tags'.format(meson.current_source_dir())] + all_files) command : [env, 'ctags', '-o', '@0@/tags'.format(meson.source_root())] + all_files)
endif endif
if git.found() if git.found()
@ -2885,17 +2884,17 @@ endif
if git.found() if git.found()
git_head = run_command( git_head = run_command(
git, git,
['--git-dir=@0@/.git'.format(meson.current_source_dir()), ['--git-dir=@0@/.git'.format(meson.source_root()),
'rev-parse', 'HEAD']).stdout().strip() 'rev-parse', 'HEAD']).stdout().strip()
git_head_short = run_command( git_head_short = run_command(
git, git,
['--git-dir=@0@/.git'.format(meson.current_source_dir()), ['--git-dir=@0@/.git'.format(meson.source_root()),
'rev-parse', '--short=7', 'HEAD']).stdout().strip() 'rev-parse', '--short=7', 'HEAD']).stdout().strip()
run_target( run_target(
'git-snapshot', 'git-snapshot',
command : ['git', 'archive', command : ['git', 'archive',
'-o', '@0@/systemd-@1@.tar.gz'.format(meson.current_source_dir(), '-o', '@0@/systemd-@1@.tar.gz'.format(meson.source_root(),
git_head_short), git_head_short),
'--prefix', 'systemd-@0@/'.format(git_head), '--prefix', 'systemd-@0@/'.format(git_head),
'HEAD']) 'HEAD'])
@ -3053,10 +3052,10 @@ foreach tuple : [
['blkid'], ['blkid'],
['dbus'], ['dbus'],
['glib'], ['glib'],
['nss-myhostname', conf.get('ENABLE_NSS_MYHOSTNAME') == 1], ['nss-myhostname'],
['nss-mymachines', conf.get('ENABLE_NSS_MYMACHINES') == 1], ['nss-mymachines'],
['nss-resolve', conf.get('ENABLE_NSS_RESOLVE') == 1], ['nss-resolve'],
['nss-systemd', conf.get('ENABLE_NSS_SYSTEMD') == 1], ['nss-systemd'],
['hwdb'], ['hwdb'],
['tpm'], ['tpm'],
['man pages', want_man], ['man pages', want_man],
@ -3072,6 +3071,7 @@ foreach tuple : [
['debug hashmap'], ['debug hashmap'],
['debug mmap cache'], ['debug mmap cache'],
['valgrind', conf.get('VALGRIND') == 1], ['valgrind', conf.get('VALGRIND') == 1],
['trace logging', conf.get('LOG_TRACE') == 1],
] ]
if tuple.length() >= 2 if tuple.length() >= 2

View File

@ -51,6 +51,8 @@ option('memory-accounting-default', type : 'boolean',
description : 'enable MemoryAccounting= by default') description : 'enable MemoryAccounting= by default')
option('valgrind', type : 'boolean', value : false, option('valgrind', type : 'boolean', value : false,
description : 'do extra operations to avoid valgrind warnings') description : 'do extra operations to avoid valgrind warnings')
option('log-trace', type : 'boolean', value : false,
description : 'enable low level debug logging')
option('utmp', type : 'boolean', option('utmp', type : 'boolean',
description : 'support for utmp/wtmp log handling') description : 'support for utmp/wtmp log handling')

View File

@ -1004,7 +1004,7 @@ int free_and_strdup(char **p, const char *s) {
assert(p); assert(p);
/* Replaces a string pointer with an strdup()ed new string, /* Replaces a string pointer with a strdup()ed new string,
* possibly freeing the old one. */ * possibly freeing the old one. */
if (streq_ptr(*p, s)) if (streq_ptr(*p, s))
@ -1023,6 +1023,32 @@ int free_and_strdup(char **p, const char *s) {
return 1; return 1;
} }
int free_and_strndup(char **p, const char *s, size_t l) {
char *t;
assert(p);
assert(s || l == 0);
/* Replaces a string pointer with a strndup()ed new string,
* freeing the old one. */
if (!*p && !s)
return 0;
if (*p && s && strneq(*p, s, l) && (l > strlen(*p) || (*p)[l] == '\0'))
return 0;
if (s) {
t = strndup(s, l);
if (!t)
return -ENOMEM;
} else
t = NULL;
free_and_replace(*p, t);
return 1;
}
#if !HAVE_EXPLICIT_BZERO #if !HAVE_EXPLICIT_BZERO
/* /*
* Pointer to memset is volatile so that compiler must de-reference * Pointer to memset is volatile so that compiler must de-reference

View File

@ -176,6 +176,7 @@ char *strrep(const char *s, unsigned n);
int split_pair(const char *s, const char *sep, char **l, char **r); int split_pair(const char *s, const char *sep, char **l, char **r);
int free_and_strdup(char **p, const char *s); int free_and_strdup(char **p, const char *s);
int free_and_strndup(char **p, const char *s, size_t l);
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ /* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include <stdio.h>
#include "alloc-util.h"
#include "bus-dump.h"
#include "bus-message.h"
#include "env-util.h"
#include "fd-util.h"
#include "fuzz.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_free_ char *out = NULL; /* out should be freed after g */
size_t out_size;
_cleanup_fclose_ FILE *g = NULL;
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_free_ void *buffer = NULL;
int r;
/* We don't want to fill the logs with messages about parse errors.
* Disable most logging if not running standalone */
if (!getenv("SYSTEMD_LOG_LEVEL"))
log_set_max_level(LOG_CRIT);
r = sd_bus_new(&bus);
assert_se(r >= 0);
assert_se(buffer = memdup(data, size));
r = bus_message_from_malloc(bus, buffer, size, NULL, 0, NULL, &m);
if (r == -EBADMSG)
return 0;
assert_se(r >= 0);
TAKE_PTR(buffer);
if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0)
assert_se(g = open_memstream(&out, &out_size));
bus_message_dump(m, g ?: stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
r = sd_bus_message_rewind(m, true);
assert_se(r >= 0);
return 0;
}

View File

@ -1,6 +1,10 @@
# SPDX-License-Identifier: LGPL-2.1+ # SPDX-License-Identifier: LGPL-2.1+
fuzzers += [ fuzzers += [
[['src/fuzz/fuzz-bus-message.c'],
[libshared],
[]],
[['src/fuzz/fuzz-dns-packet.c', [['src/fuzz/fuzz-dns-packet.c',
dns_type_headers], dns_type_headers],
[libsystemd_resolve_core, [libsystemd_resolve_core,

View File

@ -57,8 +57,14 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64, "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64,
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() : m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", special_glyph(TRIANGULAR_BULLET), ansi_normal(), m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "",
ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(), special_glyph(TRIANGULAR_BULLET),
ansi_normal(),
ansi_highlight(),
bus_message_type_to_string(m->header->type) ?: "(unknown)",
ansi_normal(),
m->header->endian, m->header->endian,
m->header->flags, m->header->flags,
m->header->version, m->header->version,

View File

@ -75,19 +75,38 @@ static void message_reset_parts(sd_bus_message *m) {
m->cached_rindex_part_begin = 0; m->cached_rindex_part_begin = 0;
} }
static void message_reset_containers(sd_bus_message *m) { static struct bus_container *message_get_last_container(sd_bus_message *m) {
unsigned i;
assert(m); assert(m);
for (i = 0; i < m->n_containers; i++) { if (m->n_containers == 0)
free(m->containers[i].signature); return &m->root_container;
free(m->containers[i].offsets);
} assert(m->containers);
return m->containers + m->n_containers - 1;
}
static void message_free_last_container(sd_bus_message *m) {
struct bus_container *c;
c = message_get_last_container(m);
free(c->signature);
free(c->peeked_signature);
free(c->offsets);
/* Move to previous container, but not if we are on root container */
if (m->n_containers > 0)
m->n_containers--;
}
static void message_reset_containers(sd_bus_message *m) {
assert(m);
while (m->n_containers > 0)
message_free_last_container(m);
m->containers = mfree(m->containers); m->containers = mfree(m->containers);
m->containers_allocated = 0;
m->n_containers = m->containers_allocated = 0;
m->root_container.index = 0; m->root_container.index = 0;
} }
@ -110,10 +129,8 @@ static sd_bus_message* message_free(sd_bus_message *m) {
free(m->iovec); free(m->iovec);
message_reset_containers(m); message_reset_containers(m);
free(m->root_container.signature); assert(m->n_containers == 0);
free(m->root_container.offsets); message_free_last_container(m);
free(m->root_container.peeked_signature);
bus_creds_done(&m->creds); bus_creds_done(&m->creds);
return mfree(m); return mfree(m);
@ -208,7 +225,7 @@ static int message_append_field_string(
/* dbus1 doesn't allow strings over 32bit, let's enforce this /* dbus1 doesn't allow strings over 32bit, let's enforce this
* globally, to not risk convertability */ * globally, to not risk convertability */
l = strlen(s); l = strlen(s);
if (l > (size_t) (uint32_t) -1) if (l > UINT32_MAX)
return -EINVAL; return -EINVAL;
/* Signature "(yv)" where the variant contains "s" */ /* Signature "(yv)" where the variant contains "s" */
@ -1088,16 +1105,6 @@ _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *
return 0; return 0;
} }
static struct bus_container *message_get_container(sd_bus_message *m) {
assert(m);
if (m->n_containers == 0)
return &m->root_container;
assert(m->containers);
return m->containers + m->n_containers - 1;
}
struct bus_body_part *message_append_part(sd_bus_message *m) { struct bus_body_part *message_append_part(sd_bus_message *m) {
struct bus_body_part *part; struct bus_body_part *part;
@ -1188,7 +1195,7 @@ static int message_add_offset(sd_bus_message *m, size_t offset) {
/* Add offset to current container, unless this is the first /* Add offset to current container, unless this is the first
* item in it, which will have the 0 offset, which we can * item in it, which will have the 0 offset, which we can
* ignore. */ * ignore. */
c = message_get_container(m); c = message_get_last_container(m);
if (!c->need_offsets) if (!c->need_offsets)
return 0; return 0;
@ -1360,7 +1367,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void
assert_return(bus_type_is_basic(type), -EINVAL); assert_return(bus_type_is_basic(type), -EINVAL);
assert_return(!m->poisoned, -ESTALE); assert_return(!m->poisoned, -ESTALE);
c = message_get_container(m); c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) { if (c->signature && c->signature[c->index]) {
/* Container signature is already set */ /* Container signature is already set */
@ -1553,7 +1560,7 @@ _public_ int sd_bus_message_append_string_space(
assert_return(!m->sealed, -EPERM); assert_return(!m->sealed, -EPERM);
assert_return(!m->poisoned, -ESTALE); assert_return(!m->poisoned, -ESTALE);
c = message_get_container(m); c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) { if (c->signature && c->signature[c->index]) {
/* Container signature is already set */ /* Container signature is already set */
@ -1924,7 +1931,7 @@ _public_ int sd_bus_message_open_container(
char type, char type,
const char *contents) { const char *contents) {
struct bus_container *c, *w; struct bus_container *c;
uint32_t *array_size = NULL; uint32_t *array_size = NULL;
_cleanup_free_ char *signature = NULL; _cleanup_free_ char *signature = NULL;
size_t before, begin = 0; size_t before, begin = 0;
@ -1942,7 +1949,7 @@ _public_ int sd_bus_message_open_container(
return -ENOMEM; return -ENOMEM;
} }
c = message_get_container(m); c = message_get_last_container(m);
signature = strdup(contents); signature = strdup(contents);
if (!signature) { if (!signature) {
@ -1969,16 +1976,14 @@ _public_ int sd_bus_message_open_container(
return r; return r;
/* OK, let's fill it in */ /* OK, let's fill it in */
w = m->containers + m->n_containers++; m->containers[m->n_containers++] = (struct bus_container) {
w->enclosing = type; .enclosing = type,
w->signature = TAKE_PTR(signature); .signature = TAKE_PTR(signature),
w->index = 0; .array_size = array_size,
w->array_size = array_size; .before = before,
w->before = before; .begin = begin,
w->begin = begin; .need_offsets = need_offsets,
w->n_offsets = w->offsets_allocated = 0; };
w->offsets = NULL;
w->need_offsets = need_offsets;
return 0; return 0;
} }
@ -2169,7 +2174,7 @@ _public_ int sd_bus_message_close_container(sd_bus_message *m) {
assert_return(m->n_containers > 0, -EINVAL); assert_return(m->n_containers > 0, -EINVAL);
assert_return(!m->poisoned, -ESTALE); assert_return(!m->poisoned, -ESTALE);
c = message_get_container(m); c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY) if (c->enclosing != SD_BUS_TYPE_ARRAY)
if (c->signature && c->signature[c->index] != 0) if (c->signature && c->signature[c->index] != 0)
@ -2439,11 +2444,6 @@ _public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
va_list ap; va_list ap;
int r; int r;
assert_return(m, -EINVAL);
assert_return(types, -EINVAL);
assert_return(!m->sealed, -EPERM);
assert_return(!m->poisoned, -ESTALE);
va_start(ap, types); va_start(ap, types);
r = sd_bus_message_appendv(m, types, ap); r = sd_bus_message_appendv(m, types, ap);
va_end(ap); va_end(ap);
@ -2673,7 +2673,7 @@ _public_ int sd_bus_message_append_string_memfd(
if (size > (uint64_t) (uint32_t) -1) if (size > (uint64_t) (uint32_t) -1)
return -EINVAL; return -EINVAL;
c = message_get_container(m); c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) { if (c->signature && c->signature[c->index]) {
/* Container signature is already set */ /* Container signature is already set */
@ -3006,7 +3006,7 @@ static bool message_end_of_signature(sd_bus_message *m) {
assert(m); assert(m);
c = message_get_container(m); c = message_get_last_container(m);
return !c->signature || c->signature[c->index] == 0; return !c->signature || c->signature[c->index] == 0;
} }
@ -3015,7 +3015,7 @@ static bool message_end_of_array(sd_bus_message *m, size_t index) {
assert(m); assert(m);
c = message_get_container(m); c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY) if (c->enclosing != SD_BUS_TYPE_ARRAY)
return false; return false;
@ -3110,6 +3110,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
assert(alignment > 0); assert(alignment > 0);
*rindex = ALIGN_TO(c->offsets[c->offset_index], alignment); *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
assert(c->offsets[c->offset_index+1] >= *rindex);
c->item_size = c->offsets[c->offset_index+1] - *rindex; c->item_size = c->offsets[c->offset_index+1] - *rindex;
} else { } else {
@ -3149,6 +3150,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
assert(alignment > 0); assert(alignment > 0);
*rindex = ALIGN_TO(c->offsets[c->offset_index], alignment); *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
assert(c->offsets[c->offset_index+1] >= *rindex);
c->item_size = c->offsets[c->offset_index+1] - *rindex; c->item_size = c->offsets[c->offset_index+1] - *rindex;
c->offset_index++; c->offset_index++;
@ -3276,7 +3278,7 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
if (message_end_of_array(m, m->rindex)) if (message_end_of_array(m, m->rindex))
return 0; return 0;
c = message_get_container(m); c = message_get_last_container(m);
if (c->signature[c->index] != type) if (c->signature[c->index] != type)
return -ENXIO; return -ENXIO;
@ -3287,6 +3289,12 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) { if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
bool ok; bool ok;
/* D-Bus spec: The marshalling formats for the string-like types all end
* with a single zero (NUL) byte, but that byte is not considered to be part
* of the text. */
if (c->item_size == 0)
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, c->item_size, &q); r = message_peek_body(m, &rindex, 1, c->item_size, &q);
if (r < 0) if (r < 0)
return r; return r;
@ -3381,6 +3389,10 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
return r; return r;
l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
if (l == UINT32_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, l+1, &q); r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0) if (r < 0)
return r; return r;
@ -3403,6 +3415,10 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
return r; return r;
l = *(uint8_t*) q; l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, l+1, &q); r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0) if (r < 0)
return r; return r;
@ -3494,7 +3510,7 @@ static int bus_message_enter_array(
size_t rindex; size_t rindex;
void *q; void *q;
int r, alignment; int r;
assert(m); assert(m);
assert(c); assert(c);
@ -3520,6 +3536,7 @@ static int bus_message_enter_array(
if (!BUS_MESSAGE_IS_GVARIANT(m)) { if (!BUS_MESSAGE_IS_GVARIANT(m)) {
/* dbus1 */ /* dbus1 */
int alignment;
r = message_peek_body(m, &rindex, 4, 4, &q); r = message_peek_body(m, &rindex, 4, 4, &q);
if (r < 0) if (r < 0)
@ -3553,7 +3570,8 @@ static int bus_message_enter_array(
*n_offsets = 0; *n_offsets = 0;
} else { } else {
size_t where, p = 0, framing, sz; size_t where, previous = 0, framing, sz;
int alignment;
unsigned i; unsigned i;
/* gvariant: variable length array */ /* gvariant: variable length array */
@ -3581,17 +3599,22 @@ static int bus_message_enter_array(
if (!*offsets) if (!*offsets)
return -ENOMEM; return -ENOMEM;
alignment = bus_gvariant_get_alignment(c->signature);
assert(alignment > 0);
for (i = 0; i < *n_offsets; i++) { for (i = 0; i < *n_offsets; i++) {
size_t x; size_t x, start;
start = ALIGN_TO(previous, alignment);
x = bus_gvariant_read_word_le((uint8_t*) q + i * sz, sz); x = bus_gvariant_read_word_le((uint8_t*) q + i * sz, sz);
if (x > c->item_size - sz) if (x > c->item_size - sz)
return -EBADMSG; return -EBADMSG;
if (x < p) if (x < start)
return -EBADMSG; return -EBADMSG;
(*offsets)[i] = rindex + x; (*offsets)[i] = rindex + x;
p = x; previous = x;
} }
*item_size = (*offsets)[0] - rindex; *item_size = (*offsets)[0] - rindex;
@ -3661,6 +3684,10 @@ static int bus_message_enter_variant(
return r; return r;
l = *(uint8_t*) q; l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, l+1, &q); r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0) if (r < 0)
return r; return r;
@ -3689,7 +3716,7 @@ static int build_struct_offsets(
size_t *n_offsets) { size_t *n_offsets) {
unsigned n_variable = 0, n_total = 0, v; unsigned n_variable = 0, n_total = 0, v;
size_t previous = 0, where; size_t previous, where;
const char *p; const char *p;
size_t sz; size_t sz;
void *q; void *q;
@ -3768,6 +3795,7 @@ static int build_struct_offsets(
/* Second, loop again and build an offset table */ /* Second, loop again and build an offset table */
p = signature; p = signature;
previous = m->rindex;
while (*p != 0) { while (*p != 0) {
size_t n, offset; size_t n, offset;
int k; int k;
@ -3781,37 +3809,37 @@ static int build_struct_offsets(
memcpy(t, p, n); memcpy(t, p, n);
t[n] = 0; t[n] = 0;
size_t align = bus_gvariant_get_alignment(t);
assert(align > 0);
/* The possible start of this member after including alignment */
size_t start = ALIGN_TO(previous, align);
k = bus_gvariant_get_size(t); k = bus_gvariant_get_size(t);
if (k < 0) { if (k < 0) {
size_t x; size_t x;
/* variable size */ /* Variable size */
if (v > 0) { if (v > 0) {
v--; v--;
x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz); x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz);
if (x >= size) if (x >= size)
return -EBADMSG; return -EBADMSG;
if (m->rindex + x < previous)
return -EBADMSG;
} else } else
/* The last item's end /* The last item's end is determined
* is determined from * from the start of the offset array */
* the start of the
* offset array */
x = size - (n_variable * sz); x = size - (n_variable * sz);
offset = m->rindex + x; offset = m->rindex + x;
if (offset < start) {
} else { log_debug("For type %s with alignment %zu, message specifies offset %zu which is smaller than previous end %zu + alignment = %zu",
size_t align; t, align, offset, previous, start);
return -EBADMSG;
/* fixed size */ }
align = bus_gvariant_get_alignment(t); } else
assert(align > 0); /* Fixed size */
offset = start + k;
offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
}
} }
previous = (*offsets)[(*n_offsets)++] = offset; previous = (*offsets)[(*n_offsets)++] = offset;
@ -3941,10 +3969,10 @@ static int bus_message_enter_dict_entry(
_public_ int sd_bus_message_enter_container(sd_bus_message *m, _public_ int sd_bus_message_enter_container(sd_bus_message *m,
char type, char type,
const char *contents) { const char *contents) {
struct bus_container *c, *w; struct bus_container *c;
uint32_t *array_size = NULL; uint32_t *array_size = NULL;
_cleanup_free_ char *signature = NULL; _cleanup_free_ char *signature = NULL;
size_t before; size_t before, end;
_cleanup_free_ size_t *offsets = NULL; _cleanup_free_ size_t *offsets = NULL;
size_t n_offsets = 0, item_size = 0; size_t n_offsets = 0, item_size = 0;
int r; int r;
@ -4000,7 +4028,7 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m,
if (message_end_of_array(m, m->rindex)) if (message_end_of_array(m, m->rindex))
return 0; return 0;
c = message_get_container(m); c = message_get_last_container(m);
signature = strdup(contents); signature = strdup(contents);
if (!signature) if (!signature)
@ -4023,28 +4051,26 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m,
return r; return r;
/* OK, let's fill it in */ /* OK, let's fill it in */
w = m->containers + m->n_containers++;
w->enclosing = type;
w->signature = TAKE_PTR(signature);
w->peeked_signature = NULL;
w->index = 0;
w->before = before;
w->begin = m->rindex;
/* Unary type has fixed size of 1, but virtual size of 0 */
if (BUS_MESSAGE_IS_GVARIANT(m) && if (BUS_MESSAGE_IS_GVARIANT(m) &&
type == SD_BUS_TYPE_STRUCT && type == SD_BUS_TYPE_STRUCT &&
isempty(signature)) isempty(signature))
w->end = m->rindex + 0; end = m->rindex + 0;
else else
w->end = m->rindex + c->item_size; end = m->rindex + c->item_size;
m->containers[m->n_containers++] = (struct bus_container) {
.enclosing = type,
.signature = TAKE_PTR(signature),
w->array_size = array_size; .before = before,
w->item_size = item_size; .begin = m->rindex,
w->offsets = TAKE_PTR(offsets); /* Unary type has fixed size of 1, but virtual size of 0 */
w->n_offsets = n_offsets; .end = end,
w->offset_index = 0; .array_size = array_size,
.item_size = item_size,
.offsets = TAKE_PTR(offsets),
.n_offsets = n_offsets,
};
return 1; return 1;
} }
@ -4058,7 +4084,7 @@ _public_ int sd_bus_message_exit_container(sd_bus_message *m) {
assert_return(m->sealed, -EPERM); assert_return(m->sealed, -EPERM);
assert_return(m->n_containers > 0, -ENXIO); assert_return(m->n_containers > 0, -ENXIO);
c = message_get_container(m); c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY) { if (c->enclosing != SD_BUS_TYPE_ARRAY) {
if (c->signature && c->signature[c->index] != 0) if (c->signature && c->signature[c->index] != 0)
@ -4077,13 +4103,9 @@ _public_ int sd_bus_message_exit_container(sd_bus_message *m) {
return -EBUSY; return -EBUSY;
} }
free(c->signature); message_free_last_container(m);
free(c->peeked_signature);
free(c->offsets);
m->n_containers--;
c = message_get_container(m);
c = message_get_last_container(m);
saved = c->index; saved = c->index;
c->index = c->saved_index; c->index = c->saved_index;
r = container_next_item(m, c, &m->rindex); r = container_next_item(m, c, &m->rindex);
@ -4101,19 +4123,16 @@ static void message_quit_container(sd_bus_message *m) {
assert(m->sealed); assert(m->sealed);
assert(m->n_containers > 0); assert(m->n_containers > 0);
c = message_get_container(m);
/* Undo seeks */ /* Undo seeks */
c = message_get_last_container(m);
assert(m->rindex >= c->before); assert(m->rindex >= c->before);
m->rindex = c->before; m->rindex = c->before;
/* Free container */ /* Free container */
free(c->signature); message_free_last_container(m);
free(c->offsets);
m->n_containers--;
/* Correct index of new top-level container */ /* Correct index of new top-level container */
c = message_get_container(m); c = message_get_last_container(m);
c->index = c->saved_index; c->index = c->saved_index;
} }
@ -4130,7 +4149,7 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
if (message_end_of_array(m, m->rindex)) if (message_end_of_array(m, m->rindex))
goto eof; goto eof;
c = message_get_container(m); c = message_get_last_container(m);
if (bus_type_is_basic(c->signature[c->index])) { if (bus_type_is_basic(c->signature[c->index])) {
if (contents) if (contents)
@ -4144,20 +4163,20 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
if (contents) { if (contents) {
size_t l; size_t l;
char *sig;
r = signature_element_length(c->signature+c->index+1, &l); r = signature_element_length(c->signature+c->index+1, &l);
if (r < 0) if (r < 0)
return r; return r;
assert(l >= 1); /* signature_element_length does verification internally */
sig = strndup(c->signature + c->index + 1, l); /* The array element must not be empty */
if (!sig) assert(l >= 1);
if (free_and_strndup(&c->peeked_signature,
c->signature + c->index + 1, l) < 0)
return -ENOMEM; return -ENOMEM;
free(c->peeked_signature); *contents = c->peeked_signature;
*contents = c->peeked_signature = sig;
} }
if (type) if (type)
@ -4170,19 +4189,17 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
if (contents) { if (contents) {
size_t l; size_t l;
char *sig;
r = signature_element_length(c->signature+c->index, &l); r = signature_element_length(c->signature+c->index, &l);
if (r < 0) if (r < 0)
return r; return r;
assert(l >= 2); assert(l >= 3);
sig = strndup(c->signature + c->index + 1, l - 2); if (free_and_strndup(&c->peeked_signature,
if (!sig) c->signature + c->index + 1, l - 2) < 0)
return -ENOMEM; return -ENOMEM;
free(c->peeked_signature); *contents = c->peeked_signature;
*contents = c->peeked_signature = sig;
} }
if (type) if (type)
@ -4222,9 +4239,8 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
if (k > c->item_size) if (k > c->item_size)
return -EBADMSG; return -EBADMSG;
free(c->peeked_signature); if (free_and_strndup(&c->peeked_signature,
c->peeked_signature = strndup((char*) q + 1, k - 1); (char*) q + 1, k - 1) < 0)
if (!c->peeked_signature)
return -ENOMEM; return -ENOMEM;
if (!signature_is_valid(c->peeked_signature, true)) if (!signature_is_valid(c->peeked_signature, true))
@ -4240,6 +4256,10 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
return r; return r;
l = *(uint8_t*) q; l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, l+1, &q); r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0) if (r < 0)
return r; return r;
@ -4277,11 +4297,10 @@ _public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
message_reset_containers(m); message_reset_containers(m);
m->rindex = 0; m->rindex = 0;
c = message_get_container(m); c = message_get_last_container(m);
} else { } else {
c = message_get_container(m); c = message_get_last_container(m);
c->offset_index = 0;
c->index = 0; c->index = 0;
m->rindex = c->begin; m->rindex = c->begin;
} }
@ -4496,10 +4515,6 @@ _public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
va_list ap; va_list ap;
int r; int r;
assert_return(m, -EINVAL);
assert_return(m->sealed, -EPERM);
assert_return(types, -EINVAL);
va_start(ap, types); va_start(ap, types);
r = sd_bus_message_readv(m, types, ap); r = sd_bus_message_readv(m, types, ap);
va_end(ap); va_end(ap);
@ -4524,7 +4539,7 @@ _public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
if (message_end_of_array(m, m->rindex)) if (message_end_of_array(m, m->rindex))
return 0; return 0;
c = message_get_container(m); c = message_get_last_container(m);
r = signature_element_length(c->signature + c->index, &l); r = signature_element_length(c->signature + c->index, &l);
if (r < 0) if (r < 0)
@ -4690,7 +4705,7 @@ _public_ int sd_bus_message_read_array(
if (r <= 0) if (r <= 0)
return r; return r;
c = message_get_container(m); c = message_get_last_container(m);
if (BUS_MESSAGE_IS_GVARIANT(m)) { if (BUS_MESSAGE_IS_GVARIANT(m)) {
align = bus_gvariant_get_alignment(CHAR_TO_STR(type)); align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
@ -4827,6 +4842,10 @@ static int message_peek_field_string(
if (r < 0) if (r < 0)
return r; return r;
if (l == UINT32_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_fields(m, ri, 1, l+1, &q); r = message_peek_fields(m, ri, 1, l+1, &q);
if (r < 0) if (r < 0)
return r; return r;
@ -4878,6 +4897,10 @@ static int message_peek_field_signature(
return r; return r;
l = *(uint8_t*) q; l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_fields(m, ri, 1, l+1, &q); r = message_peek_fields(m, ri, 1, l+1, &q);
if (r < 0) if (r < 0)
return r; return r;
@ -4959,18 +4982,18 @@ static int message_skip_fields(
} else if (t == SD_BUS_TYPE_ARRAY) { } else if (t == SD_BUS_TYPE_ARRAY) {
r = signature_element_length(*signature+1, &l); r = signature_element_length(*signature + 1, &l);
if (r < 0) if (r < 0)
return r; return r;
assert(l >= 1); assert(l >= 1);
{ {
char sig[l-1], *s; char sig[l + 1], *s = sig;
uint32_t nas; uint32_t nas;
int alignment; int alignment;
strncpy(sig, *signature + 1, l-1); strncpy(sig, *signature + 1, l);
s = sig; sig[l] = '\0';
alignment = bus_type_get_alignment(sig[0]); alignment = bus_type_get_alignment(sig[0]);
if (alignment < 0) if (alignment < 0)
@ -5014,9 +5037,9 @@ static int message_skip_fields(
assert(l >= 2); assert(l >= 2);
{ {
char sig[l-1], *s; char sig[l + 1], *s = sig;
strncpy(sig, *signature + 1, l-1); strncpy(sig, *signature + 1, l);
s = sig; sig[l] = '\0';
r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s); r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
if (r < 0) if (r < 0)
@ -5025,7 +5048,7 @@ static int message_skip_fields(
*signature += l; *signature += l;
} else } else
return -EINVAL; return -EBADMSG;
} }
} }
@ -5056,25 +5079,21 @@ int bus_message_parse_fields(sd_bus_message *m) {
if (*p == 0) { if (*p == 0) {
size_t l; size_t l;
char *c;
/* We found the beginning of the signature /* We found the beginning of the signature
* string, yay! We require the body to be a * string, yay! We require the body to be a
* structure, so verify it and then strip the * structure, so verify it and then strip the
* opening/closing brackets. */ * opening/closing brackets. */
l = ((char*) m->footer + m->footer_accessible) - p - (1 + sz); l = (char*) m->footer + m->footer_accessible - p - (1 + sz);
if (l < 2 || if (l < 2 ||
p[1] != SD_BUS_TYPE_STRUCT_BEGIN || p[1] != SD_BUS_TYPE_STRUCT_BEGIN ||
p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END) p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
return -EBADMSG; return -EBADMSG;
c = strndup(p + 1 + 1, l - 2); if (free_and_strndup(&m->root_container.signature,
if (!c) p + 1 + 1, l - 2) < 0)
return -ENOMEM; return -ENOMEM;
free(m->root_container.signature);
m->root_container.signature = c;
break; break;
} }
@ -5396,6 +5415,8 @@ int bus_message_parse_fields(sd_bus_message *m) {
&m->root_container.item_size, &m->root_container.item_size,
&m->root_container.offsets, &m->root_container.offsets,
&m->root_container.n_offsets); &m->root_container.n_offsets);
if (r == -EINVAL)
return -EBADMSG;
if (r < 0) if (r < 0)
return r; return r;
} }
@ -5591,7 +5612,7 @@ _public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complet
assert_return(m, NULL); assert_return(m, NULL);
c = complete ? &m->root_container : message_get_container(m); c = complete ? &m->root_container : message_get_last_container(m);
return strempty(c->signature); return strempty(c->signature);
} }

View File

@ -56,6 +56,12 @@ static int signature_element_length_internal(
p += t; p += t;
} }
if (p - s < 2)
/* D-Bus spec: Empty structures are not allowed; there
* must be at least one type code between the parentheses.
*/
return -EINVAL;
*l = p - s + 1; *l = p - s + 1;
return 0; return 0;
} }

View File

@ -17,8 +17,10 @@
#include "util.h" #include "util.h"
static void test_bus_gvariant_is_fixed_size(void) { static void test_bus_gvariant_is_fixed_size(void) {
log_info("/* %s */", __func__);
assert_se(bus_gvariant_is_fixed_size("") > 0); assert_se(bus_gvariant_is_fixed_size("") > 0);
assert_se(bus_gvariant_is_fixed_size("()") > 0); assert_se(bus_gvariant_is_fixed_size("()") == -EINVAL);
assert_se(bus_gvariant_is_fixed_size("y") > 0); assert_se(bus_gvariant_is_fixed_size("y") > 0);
assert_se(bus_gvariant_is_fixed_size("u") > 0); assert_se(bus_gvariant_is_fixed_size("u") > 0);
assert_se(bus_gvariant_is_fixed_size("b") > 0); assert_se(bus_gvariant_is_fixed_size("b") > 0);
@ -42,8 +44,10 @@ static void test_bus_gvariant_is_fixed_size(void) {
} }
static void test_bus_gvariant_get_size(void) { static void test_bus_gvariant_get_size(void) {
log_info("/* %s */", __func__);
assert_se(bus_gvariant_get_size("") == 0); assert_se(bus_gvariant_get_size("") == 0);
assert_se(bus_gvariant_get_size("()") == 1); assert_se(bus_gvariant_get_size("()") == -EINVAL);
assert_se(bus_gvariant_get_size("y") == 1); assert_se(bus_gvariant_get_size("y") == 1);
assert_se(bus_gvariant_get_size("u") == 4); assert_se(bus_gvariant_get_size("u") == 4);
assert_se(bus_gvariant_get_size("b") == 1); assert_se(bus_gvariant_get_size("b") == 1);
@ -74,8 +78,10 @@ static void test_bus_gvariant_get_size(void) {
} }
static void test_bus_gvariant_get_alignment(void) { static void test_bus_gvariant_get_alignment(void) {
log_info("/* %s */", __func__);
assert_se(bus_gvariant_get_alignment("") == 1); assert_se(bus_gvariant_get_alignment("") == 1);
assert_se(bus_gvariant_get_alignment("()") == 1); assert_se(bus_gvariant_get_alignment("()") == -EINVAL);
assert_se(bus_gvariant_get_alignment("y") == 1); assert_se(bus_gvariant_get_alignment("y") == 1);
assert_se(bus_gvariant_get_alignment("b") == 1); assert_se(bus_gvariant_get_alignment("b") == 1);
assert_se(bus_gvariant_get_alignment("u") == 4); assert_se(bus_gvariant_get_alignment("u") == 4);
@ -129,7 +135,10 @@ static int test_marshal(void) {
bus->message_version = 2; /* dirty hack to enable gvariant */ bus->message_version = 2; /* dirty hack to enable gvariant */
assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works", "an.interface.name", "AMethodName") >= 0); r = sd_bus_message_new_method_call(bus, &m, "a.service.name",
"/an/object/path/which/is/really/really/long/so/that/we/hit/the/eight/bit/boundary/by/quite/some/margin/to/test/this/stuff/that/it/really/works",
"an.interface.name", "AMethodName");
assert_se(r >= 0);
assert_cc(sizeof(struct bus_header) == 16); assert_cc(sizeof(struct bus_header) == 16);
@ -202,7 +211,7 @@ static int test_marshal(void) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
test_setup_logging(LOG_INFO); test_setup_logging(LOG_DEBUG);
test_bus_gvariant_is_fixed_size(); test_bus_gvariant_is_fixed_size();
test_bus_gvariant_get_size(); test_bus_gvariant_get_size();

View File

@ -18,8 +18,8 @@
#include "bus-label.h" #include "bus-label.h"
#include "bus-message.h" #include "bus-message.h"
#include "bus-util.h" #include "bus-util.h"
#include "escape.h"
#include "fd-util.h" #include "fd-util.h"
#include "hexdecoct.h"
#include "log.h" #include "log.h"
#include "tests.h" #include "tests.h"
#include "util.h" #include "util.h"
@ -111,7 +111,7 @@ int main(int argc, char *argv[]) {
uint8_t u, v; uint8_t u, v;
void *buffer = NULL; void *buffer = NULL;
size_t sz; size_t sz;
char *h; _cleanup_free_ char *h = NULL;
const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array; const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
char *s; char *s;
_cleanup_free_ char *first = NULL, *second = NULL, *third = NULL; _cleanup_free_ char *first = NULL, *second = NULL, *third = NULL;
@ -154,7 +154,7 @@ int main(int argc, char *argv[]) {
assert_se(r >= 0); assert_se(r >= 0);
r = sd_bus_message_append(m, "()"); r = sd_bus_message_append(m, "()");
assert_se(r >= 0); assert_se(r == -EINVAL);
r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3"); r = sd_bus_message_append(m, "ba(ss)", 255, 3, "aaa", "1", "bbb", "2", "ccc", "3");
assert_se(r >= 0); assert_se(r >= 0);
@ -197,11 +197,9 @@ int main(int argc, char *argv[]) {
r = bus_message_get_blob(m, &buffer, &sz); r = bus_message_get_blob(m, &buffer, &sz);
assert_se(r >= 0); assert_se(r >= 0);
h = hexmem(buffer, sz); h = cescape_length(buffer, sz);
assert_se(h); assert_se(h);
log_info("message size = %zu, contents =\n%s", sz, h); log_info("message size = %zu, contents =\n%s", sz, h);
free(h);
#if HAVE_GLIB #if HAVE_GLIB
#ifndef __SANITIZE_ADDRESS__ #ifndef __SANITIZE_ADDRESS__
@ -298,7 +296,7 @@ int main(int argc, char *argv[]) {
assert_se(v == 10); assert_se(v == 10);
r = sd_bus_message_read(m, "()"); r = sd_bus_message_read(m, "()");
assert_se(r > 0); assert_se(r < 0);
r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d); r = sd_bus_message_read(m, "ba(ss)", &boolean, 3, &x, &y, &a, &b, &c, &d);
assert_se(r > 0); assert_se(r > 0);
@ -379,7 +377,7 @@ int main(int argc, char *argv[]) {
assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0); assert_se(sd_bus_message_verify_type(m, 'a', "{yv}") > 0);
r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y()"); r = sd_bus_message_skip(m, "a{yv}y(ty)y(yt)y");
assert_se(r >= 0); assert_se(r >= 0);
assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0); assert_se(sd_bus_message_verify_type(m, 'b', NULL) > 0);

View File

@ -14,9 +14,9 @@ int main(int argc, char *argv[]) {
assert_se(signature_is_single("v", false)); assert_se(signature_is_single("v", false));
assert_se(signature_is_single("as", false)); assert_se(signature_is_single("as", false));
assert_se(signature_is_single("(ss)", false)); assert_se(signature_is_single("(ss)", false));
assert_se(signature_is_single("()", false)); assert_se(!signature_is_single("()", false));
assert_se(signature_is_single("(()()()()())", false)); assert_se(!signature_is_single("(()()()()())", false));
assert_se(signature_is_single("(((())))", false)); assert_se(!signature_is_single("(((())))", false));
assert_se(signature_is_single("((((s))))", false)); assert_se(signature_is_single("((((s))))", false));
assert_se(signature_is_single("{ss}", true)); assert_se(signature_is_single("{ss}", true));
assert_se(signature_is_single("a{ss}", false)); assert_se(signature_is_single("a{ss}", false));
@ -61,7 +61,7 @@ int main(int argc, char *argv[]) {
assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas", false)); assert_se(signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaas", false));
assert_se(!signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false)); assert_se(!signature_is_valid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false));
assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false)); assert_se(signature_is_valid("((((((((((((((((((((((((((((((((s))))))))))))))))))))))))))))))))", false));
assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false)); assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false));
assert_se(namespace_complex_pattern("", "")); assert_se(namespace_complex_pattern("", ""));

View File

@ -5,6 +5,7 @@
#include "macro.h" #include "macro.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "tests.h"
#include "utf8.h" #include "utf8.h"
static void test_string_erase(void) { static void test_string_erase(void) {
@ -30,6 +31,64 @@ static void test_string_erase(void) {
assert_se(x[9] == '\0'); assert_se(x[9] == '\0');
} }
static void test_free_and_strndup_one(char **t, const char *src, size_t l, const char *expected, bool change) {
int r;
log_debug("%s: \"%s\", \"%s\", %zd (expect \"%s\", %s)",
__func__, strnull(*t), strnull(src), l, strnull(expected), yes_no(change));
r = free_and_strndup(t, src, l);
assert_se(streq_ptr(*t, expected));
assert_se(r == change); /* check that change occurs only when necessary */
}
static void test_free_and_strndup(void) {
static const struct test_case {
const char *src;
size_t len;
const char *expected;
} cases[] = {
{"abc", 0, ""},
{"abc", 0, ""},
{"abc", 1, "a"},
{"abc", 2, "ab"},
{"abc", 3, "abc"},
{"abc", 4, "abc"},
{"abc", 5, "abc"},
{"abc", 5, "abc"},
{"abc", 4, "abc"},
{"abc", 3, "abc"},
{"abc", 2, "ab"},
{"abc", 1, "a"},
{"abc", 0, ""},
{"", 0, ""},
{"", 1, ""},
{"", 2, ""},
{"", 0, ""},
{"", 1, ""},
{"", 2, ""},
{"", 2, ""},
{"", 1, ""},
{"", 0, ""},
{NULL, 0, NULL},
{"foo", 3, "foo"},
{"foobar", 6, "foobar"},
};
_cleanup_free_ char *t = NULL;
const char *prev_expected = t;
for (unsigned i = 0; i < ELEMENTSOF(cases); i++) {
test_free_and_strndup_one(&t,
cases[i].src, cases[i].len, cases[i].expected,
!streq_ptr(cases[i].expected, prev_expected));
prev_expected = t;
}
}
static void test_ascii_strcasecmp_n(void) { static void test_ascii_strcasecmp_n(void) {
assert_se(ascii_strcasecmp_n("", "", 0) == 0); assert_se(ascii_strcasecmp_n("", "", 0) == 0);
@ -520,7 +579,10 @@ static void test_memory_startswith_no_case(void) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_string_erase(); test_string_erase();
test_free_and_strndup();
test_ascii_strcasecmp_n(); test_ascii_strcasecmp_n();
test_ascii_strcasecmp_nn(); test_ascii_strcasecmp_nn();
test_cellescape(); test_cellescape();

View File

@ -1 +0,0 @@
/*/* -whitespace

View File

@ -1,43 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1+
sanitize_address = custom_target(
'sanitize-address-fuzzers',
output : 'sanitize-address-fuzzers',
command : [meson_build_sh,
meson.source_root(),
'@OUTPUT@',
'fuzzers',
'-Db_lundef=false -Db_sanitize=address'])
sanitizers = [['address', sanitize_address]]
fuzz_regression_tests = '''
fuzz-dhcp6-client/crash-4003c06fce43a11fbd22f02584df2807ac333eae
fuzz-dhcp6-client/crash-6e88fcb6b85c9436bcbe05219aa8e550194645ef
fuzz-dns-packet/issue-7888
fuzz-dns-packet/oss-fuzz-5465
fuzz-journal-remote/crash-5a8f03d4c3a46fcded39527084f437e8e4b54b76
fuzz-journal-remote/crash-96dee870ea66d03e89ac321eee28ea63a9b9aa45
fuzz-journal-remote/oss-fuzz-8659
fuzz-journal-remote/oss-fuzz-8686
fuzz-journald-syslog/github-9795
fuzz-journald-syslog/github-9820
fuzz-journald-syslog/github-9827
fuzz-journald-syslog/github-9829
fuzz-ndisc-rs/timeout-2815b773c712fa33bea62f541dfa3017c64ea2f1
fuzz-ndisc-rs/timeout-61fff7fd1e5dcc07e1b656baab29065ce634ad5b
fuzz-unit-file/oss-fuzz-6884
fuzz-unit-file/oss-fuzz-6885
fuzz-unit-file/oss-fuzz-6886
fuzz-unit-file/oss-fuzz-6892
fuzz-unit-file/oss-fuzz-6897
fuzz-unit-file/oss-fuzz-6897-evverx
fuzz-unit-file/oss-fuzz-6908
fuzz-unit-file/oss-fuzz-6917
fuzz-unit-file/oss-fuzz-6977
fuzz-unit-file/oss-fuzz-6977-unminimized
fuzz-unit-file/oss-fuzz-7004
fuzz-unit-file/oss-fuzz-8064
fuzz-unit-file/oss-fuzz-8827
fuzz-unit-file/oss-fuzz-10007
'''.split()

Binary file not shown.

33
test/fuzz/meson.build Normal file
View File

@ -0,0 +1,33 @@
# SPDX-License-Identifier: LGPL-2.1+
sanitize_address = custom_target(
'sanitize-address-fuzzers',
output : 'sanitize-address-fuzzers',
command : [meson_build_sh,
meson.source_root(),
'@OUTPUT@',
'fuzzers',
'-Db_lundef=false -Db_sanitize=address'])
sanitizers = [['address', sanitize_address]]
if git.found()
out = run_command(
git,
'--git-dir=@0@/.git'.format(meson.source_root()),
'ls-files', ':/test/fuzz/*/*')
else
out = run_command(
'sh', '-c', 'ls @0@/*/*'.format(meson.current_source_dir()))
endif
fuzz_regression_tests = []
foreach p : out.stdout().split()
# Remove the last entry which is ''.
#
# Also, backslashes get mangled, so skip test. See
# https://github.com/mesonbuild/meson/issues/1564.
if not p.contains('\\')
fuzz_regression_tests += p
endif
endforeach

View File

@ -256,4 +256,4 @@ if conf.get('ENABLE_HWDB') == 1
endif endif
endif endif
subdir('fuzz-regressions') subdir('fuzz')

View File

@ -35,8 +35,10 @@ fi
meson $build -D$fuzzflag -Db_lundef=false meson $build -D$fuzzflag -Db_lundef=false
ninja -C $build fuzzers ninja -C $build fuzzers
for d in "$(dirname "$0")/../test/fuzz-corpus/"*; do # The seed corpus is a separate flat archive for each fuzzer,
zip -jqr $OUT/fuzz-$(basename "$d")_seed_corpus.zip "$d" # with a fixed name ${fuzzer}_seed_corpus.zip.
for d in "$(dirname "$0")/../test/fuzz/fuzz-"*; do
zip -jqr $OUT/$(basename "$d")_seed_corpus.zip "$d"
done done
# get fuzz-dns-packet corpus # get fuzz-dns-packet corpus