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('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]
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_' + module,
@ -1731,7 +1732,7 @@ if conf.get('ENABLE_LOGIND') == 1
public_programs += exe
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',
pam_systemd_c,
@ -2847,9 +2848,7 @@ foreach tuple : sanitizers
test('@0@:@1@:@2@'.format(b, c, sanitizer),
env,
args : [exe.full_path(),
join_paths(meson.source_root(),
'test/fuzz-regressions',
p)])
join_paths(meson.source_root(), p)])
endif
endforeach
endif
@ -2861,7 +2860,7 @@ endforeach
if git.found()
all_files = run_command(
git,
['--git-dir=@0@/.git'.format(meson.current_source_dir()),
['--git-dir=@0@/.git'.format(meson.source_root()),
'ls-files',
':/*.[ch]'])
all_files = files(all_files.stdout().split())
@ -2869,10 +2868,10 @@ if git.found()
custom_target(
'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(
'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
if git.found()
@ -2885,17 +2884,17 @@ endif
if git.found()
git_head = run_command(
git,
['--git-dir=@0@/.git'.format(meson.current_source_dir()),
['--git-dir=@0@/.git'.format(meson.source_root()),
'rev-parse', 'HEAD']).stdout().strip()
git_head_short = run_command(
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()
run_target(
'git-snapshot',
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),
'--prefix', 'systemd-@0@/'.format(git_head),
'HEAD'])
@ -3053,10 +3052,10 @@ foreach tuple : [
['blkid'],
['dbus'],
['glib'],
['nss-myhostname', conf.get('ENABLE_NSS_MYHOSTNAME') == 1],
['nss-mymachines', conf.get('ENABLE_NSS_MYMACHINES') == 1],
['nss-resolve', conf.get('ENABLE_NSS_RESOLVE') == 1],
['nss-systemd', conf.get('ENABLE_NSS_SYSTEMD') == 1],
['nss-myhostname'],
['nss-mymachines'],
['nss-resolve'],
['nss-systemd'],
['hwdb'],
['tpm'],
['man pages', want_man],
@ -3072,6 +3071,7 @@ foreach tuple : [
['debug hashmap'],
['debug mmap cache'],
['valgrind', conf.get('VALGRIND') == 1],
['trace logging', conf.get('LOG_TRACE') == 1],
]
if tuple.length() >= 2

View File

@ -51,6 +51,8 @@ option('memory-accounting-default', type : 'boolean',
description : 'enable MemoryAccounting= by default')
option('valgrind', type : 'boolean', value : false,
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',
description : 'support for utmp/wtmp log handling')

View File

@ -1004,7 +1004,7 @@ int free_and_strdup(char **p, const char *s) {
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. */
if (streq_ptr(*p, s))
@ -1023,6 +1023,32 @@ int free_and_strdup(char **p, const char *s) {
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
/*
* 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 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 */
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+
fuzzers += [
[['src/fuzz/fuzz-bus-message.c'],
[libshared],
[]],
[['src/fuzz/fuzz-dns-packet.c',
dns_type_headers],
[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,
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_SIGNAL ? ansi_highlight() : "", special_glyph(TRIANGULAR_BULLET), ansi_normal(),
ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(),
m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "",
special_glyph(TRIANGULAR_BULLET),
ansi_normal(),
ansi_highlight(),
bus_message_type_to_string(m->header->type) ?: "(unknown)",
ansi_normal(),
m->header->endian,
m->header->flags,
m->header->version,

View File

@ -75,19 +75,38 @@ static void message_reset_parts(sd_bus_message *m) {
m->cached_rindex_part_begin = 0;
}
static void message_reset_containers(sd_bus_message *m) {
unsigned i;
static struct bus_container *message_get_last_container(sd_bus_message *m) {
assert(m);
for (i = 0; i < m->n_containers; i++) {
free(m->containers[i].signature);
free(m->containers[i].offsets);
}
if (m->n_containers == 0)
return &m->root_container;
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->n_containers = m->containers_allocated = 0;
m->containers_allocated = 0;
m->root_container.index = 0;
}
@ -110,10 +129,8 @@ static sd_bus_message* message_free(sd_bus_message *m) {
free(m->iovec);
message_reset_containers(m);
free(m->root_container.signature);
free(m->root_container.offsets);
free(m->root_container.peeked_signature);
assert(m->n_containers == 0);
message_free_last_container(m);
bus_creds_done(&m->creds);
return mfree(m);
@ -208,7 +225,7 @@ static int message_append_field_string(
/* dbus1 doesn't allow strings over 32bit, let's enforce this
* globally, to not risk convertability */
l = strlen(s);
if (l > (size_t) (uint32_t) -1)
if (l > UINT32_MAX)
return -EINVAL;
/* 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;
}
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 *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
* item in it, which will have the 0 offset, which we can
* ignore. */
c = message_get_container(m);
c = message_get_last_container(m);
if (!c->need_offsets)
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(!m->poisoned, -ESTALE);
c = message_get_container(m);
c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) {
/* 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->poisoned, -ESTALE);
c = message_get_container(m);
c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) {
/* Container signature is already set */
@ -1924,7 +1931,7 @@ _public_ int sd_bus_message_open_container(
char type,
const char *contents) {
struct bus_container *c, *w;
struct bus_container *c;
uint32_t *array_size = NULL;
_cleanup_free_ char *signature = NULL;
size_t before, begin = 0;
@ -1942,7 +1949,7 @@ _public_ int sd_bus_message_open_container(
return -ENOMEM;
}
c = message_get_container(m);
c = message_get_last_container(m);
signature = strdup(contents);
if (!signature) {
@ -1969,16 +1976,14 @@ _public_ int sd_bus_message_open_container(
return r;
/* OK, let's fill it in */
w = m->containers + m->n_containers++;
w->enclosing = type;
w->signature = TAKE_PTR(signature);
w->index = 0;
w->array_size = array_size;
w->before = before;
w->begin = begin;
w->n_offsets = w->offsets_allocated = 0;
w->offsets = NULL;
w->need_offsets = need_offsets;
m->containers[m->n_containers++] = (struct bus_container) {
.enclosing = type,
.signature = TAKE_PTR(signature),
.array_size = array_size,
.before = before,
.begin = begin,
.need_offsets = need_offsets,
};
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->poisoned, -ESTALE);
c = message_get_container(m);
c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY)
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;
int r;
assert_return(m, -EINVAL);
assert_return(types, -EINVAL);
assert_return(!m->sealed, -EPERM);
assert_return(!m->poisoned, -ESTALE);
va_start(ap, types);
r = sd_bus_message_appendv(m, types, ap);
va_end(ap);
@ -2673,7 +2673,7 @@ _public_ int sd_bus_message_append_string_memfd(
if (size > (uint64_t) (uint32_t) -1)
return -EINVAL;
c = message_get_container(m);
c = message_get_last_container(m);
if (c->signature && c->signature[c->index]) {
/* Container signature is already set */
@ -3006,7 +3006,7 @@ static bool message_end_of_signature(sd_bus_message *m) {
assert(m);
c = message_get_container(m);
c = message_get_last_container(m);
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);
c = message_get_container(m);
c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY)
return false;
@ -3110,6 +3110,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
assert(alignment > 0);
*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;
} else {
@ -3149,6 +3150,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
assert(alignment > 0);
*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->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))
return 0;
c = message_get_container(m);
c = message_get_last_container(m);
if (c->signature[c->index] != type)
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)) {
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);
if (r < 0)
return r;
@ -3381,6 +3389,10 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
return r;
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);
if (r < 0)
return r;
@ -3403,6 +3415,10 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
return r;
l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
@ -3494,7 +3510,7 @@ static int bus_message_enter_array(
size_t rindex;
void *q;
int r, alignment;
int r;
assert(m);
assert(c);
@ -3520,6 +3536,7 @@ static int bus_message_enter_array(
if (!BUS_MESSAGE_IS_GVARIANT(m)) {
/* dbus1 */
int alignment;
r = message_peek_body(m, &rindex, 4, 4, &q);
if (r < 0)
@ -3553,7 +3570,8 @@ static int bus_message_enter_array(
*n_offsets = 0;
} else {
size_t where, p = 0, framing, sz;
size_t where, previous = 0, framing, sz;
int alignment;
unsigned i;
/* gvariant: variable length array */
@ -3581,17 +3599,22 @@ static int bus_message_enter_array(
if (!*offsets)
return -ENOMEM;
alignment = bus_gvariant_get_alignment(c->signature);
assert(alignment > 0);
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);
if (x > c->item_size - sz)
return -EBADMSG;
if (x < p)
if (x < start)
return -EBADMSG;
(*offsets)[i] = rindex + x;
p = x;
previous = x;
}
*item_size = (*offsets)[0] - rindex;
@ -3661,6 +3684,10 @@ static int bus_message_enter_variant(
return r;
l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
@ -3689,7 +3716,7 @@ static int build_struct_offsets(
size_t *n_offsets) {
unsigned n_variable = 0, n_total = 0, v;
size_t previous = 0, where;
size_t previous, where;
const char *p;
size_t sz;
void *q;
@ -3768,6 +3795,7 @@ static int build_struct_offsets(
/* Second, loop again and build an offset table */
p = signature;
previous = m->rindex;
while (*p != 0) {
size_t n, offset;
int k;
@ -3781,37 +3809,37 @@ static int build_struct_offsets(
memcpy(t, p, n);
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);
if (k < 0) {
size_t x;
/* variable size */
/* Variable size */
if (v > 0) {
v--;
x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz);
if (x >= size)
return -EBADMSG;
if (m->rindex + x < previous)
return -EBADMSG;
} else
/* The last item's end
* is determined from
* the start of the
* offset array */
/* The last item's end is determined
* from the start of the offset array */
x = size - (n_variable * sz);
offset = m->rindex + x;
} else {
size_t align;
/* fixed size */
align = bus_gvariant_get_alignment(t);
assert(align > 0);
offset = (*n_offsets == 0 ? m->rindex : ALIGN_TO((*offsets)[*n_offsets-1], align)) + k;
}
if (offset < start) {
log_debug("For type %s with alignment %zu, message specifies offset %zu which is smaller than previous end %zu + alignment = %zu",
t, align, offset, previous, start);
return -EBADMSG;
}
} else
/* Fixed size */
offset = start + k;
}
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,
char type,
const char *contents) {
struct bus_container *c, *w;
struct bus_container *c;
uint32_t *array_size = NULL;
_cleanup_free_ char *signature = NULL;
size_t before;
size_t before, end;
_cleanup_free_ size_t *offsets = NULL;
size_t n_offsets = 0, item_size = 0;
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))
return 0;
c = message_get_container(m);
c = message_get_last_container(m);
signature = strdup(contents);
if (!signature)
@ -4023,28 +4051,26 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m,
return r;
/* 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) &&
type == SD_BUS_TYPE_STRUCT &&
isempty(signature))
w->end = m->rindex + 0;
end = m->rindex + 0;
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;
w->item_size = item_size;
w->offsets = TAKE_PTR(offsets);
w->n_offsets = n_offsets;
w->offset_index = 0;
.before = before,
.begin = m->rindex,
/* Unary type has fixed size of 1, but virtual size of 0 */
.end = end,
.array_size = array_size,
.item_size = item_size,
.offsets = TAKE_PTR(offsets),
.n_offsets = n_offsets,
};
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->n_containers > 0, -ENXIO);
c = message_get_container(m);
c = message_get_last_container(m);
if (c->enclosing != SD_BUS_TYPE_ARRAY) {
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;
}
free(c->signature);
free(c->peeked_signature);
free(c->offsets);
m->n_containers--;
c = message_get_container(m);
message_free_last_container(m);
c = message_get_last_container(m);
saved = c->index;
c->index = c->saved_index;
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->n_containers > 0);
c = message_get_container(m);
/* Undo seeks */
c = message_get_last_container(m);
assert(m->rindex >= c->before);
m->rindex = c->before;
/* Free container */
free(c->signature);
free(c->offsets);
m->n_containers--;
message_free_last_container(m);
/* Correct index of new top-level container */
c = message_get_container(m);
c = message_get_last_container(m);
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))
goto eof;
c = message_get_container(m);
c = message_get_last_container(m);
if (bus_type_is_basic(c->signature[c->index])) {
if (contents)
@ -4144,20 +4163,20 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
if (contents) {
size_t l;
char *sig;
r = signature_element_length(c->signature+c->index+1, &l);
if (r < 0)
return r;
assert(l >= 1);
/* signature_element_length does verification internally */
sig = strndup(c->signature + c->index + 1, l);
if (!sig)
/* The array element must not be empty */
assert(l >= 1);
if (free_and_strndup(&c->peeked_signature,
c->signature + c->index + 1, l) < 0)
return -ENOMEM;
free(c->peeked_signature);
*contents = c->peeked_signature = sig;
*contents = c->peeked_signature;
}
if (type)
@ -4170,19 +4189,17 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
if (contents) {
size_t l;
char *sig;
r = signature_element_length(c->signature+c->index, &l);
if (r < 0)
return r;
assert(l >= 2);
sig = strndup(c->signature + c->index + 1, l - 2);
if (!sig)
assert(l >= 3);
if (free_and_strndup(&c->peeked_signature,
c->signature + c->index + 1, l - 2) < 0)
return -ENOMEM;
free(c->peeked_signature);
*contents = c->peeked_signature = sig;
*contents = c->peeked_signature;
}
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)
return -EBADMSG;
free(c->peeked_signature);
c->peeked_signature = strndup((char*) q + 1, k - 1);
if (!c->peeked_signature)
if (free_and_strndup(&c->peeked_signature,
(char*) q + 1, k - 1) < 0)
return -ENOMEM;
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;
l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_body(m, &rindex, 1, l+1, &q);
if (r < 0)
return r;
@ -4277,11 +4297,10 @@ _public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
message_reset_containers(m);
m->rindex = 0;
c = message_get_container(m);
c = message_get_last_container(m);
} else {
c = message_get_container(m);
c = message_get_last_container(m);
c->offset_index = 0;
c->index = 0;
m->rindex = c->begin;
}
@ -4496,10 +4515,6 @@ _public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
va_list ap;
int r;
assert_return(m, -EINVAL);
assert_return(m->sealed, -EPERM);
assert_return(types, -EINVAL);
va_start(ap, types);
r = sd_bus_message_readv(m, types, 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))
return 0;
c = message_get_container(m);
c = message_get_last_container(m);
r = signature_element_length(c->signature + c->index, &l);
if (r < 0)
@ -4690,7 +4705,7 @@ _public_ int sd_bus_message_read_array(
if (r <= 0)
return r;
c = message_get_container(m);
c = message_get_last_container(m);
if (BUS_MESSAGE_IS_GVARIANT(m)) {
align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
@ -4827,6 +4842,10 @@ static int message_peek_field_string(
if (r < 0)
return r;
if (l == UINT32_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_fields(m, ri, 1, l+1, &q);
if (r < 0)
return r;
@ -4878,6 +4897,10 @@ static int message_peek_field_signature(
return r;
l = *(uint8_t*) q;
if (l == UINT8_MAX)
/* avoid overflow right below */
return -EBADMSG;
r = message_peek_fields(m, ri, 1, l+1, &q);
if (r < 0)
return r;
@ -4959,18 +4982,18 @@ static int message_skip_fields(
} else if (t == SD_BUS_TYPE_ARRAY) {
r = signature_element_length(*signature+1, &l);
r = signature_element_length(*signature + 1, &l);
if (r < 0)
return r;
assert(l >= 1);
{
char sig[l-1], *s;
char sig[l + 1], *s = sig;
uint32_t nas;
int alignment;
strncpy(sig, *signature + 1, l-1);
s = sig;
strncpy(sig, *signature + 1, l);
sig[l] = '\0';
alignment = bus_type_get_alignment(sig[0]);
if (alignment < 0)
@ -5014,9 +5037,9 @@ static int message_skip_fields(
assert(l >= 2);
{
char sig[l-1], *s;
strncpy(sig, *signature + 1, l-1);
s = sig;
char sig[l + 1], *s = sig;
strncpy(sig, *signature + 1, l);
sig[l] = '\0';
r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
if (r < 0)
@ -5025,7 +5048,7 @@ static int message_skip_fields(
*signature += l;
} else
return -EINVAL;
return -EBADMSG;
}
}
@ -5056,25 +5079,21 @@ int bus_message_parse_fields(sd_bus_message *m) {
if (*p == 0) {
size_t l;
char *c;
/* We found the beginning of the signature
* string, yay! We require the body to be a
* structure, so verify it and then strip the
* 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 ||
p[1] != SD_BUS_TYPE_STRUCT_BEGIN ||
p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
return -EBADMSG;
c = strndup(p + 1 + 1, l - 2);
if (!c)
if (free_and_strndup(&m->root_container.signature,
p + 1 + 1, l - 2) < 0)
return -ENOMEM;
free(m->root_container.signature);
m->root_container.signature = c;
break;
}
@ -5396,6 +5415,8 @@ int bus_message_parse_fields(sd_bus_message *m) {
&m->root_container.item_size,
&m->root_container.offsets,
&m->root_container.n_offsets);
if (r == -EINVAL)
return -EBADMSG;
if (r < 0)
return r;
}
@ -5591,7 +5612,7 @@ _public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complet
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);
}

View File

@ -56,6 +56,12 @@ static int signature_element_length_internal(
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;
return 0;
}

View File

@ -17,8 +17,10 @@
#include "util.h"
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("()") == -EINVAL);
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("b") > 0);
@ -42,8 +44,10 @@ static void test_bus_gvariant_is_fixed_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("()") == 1);
assert_se(bus_gvariant_get_size("()") == -EINVAL);
assert_se(bus_gvariant_get_size("y") == 1);
assert_se(bus_gvariant_get_size("u") == 4);
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) {
log_info("/* %s */", __func__);
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("b") == 1);
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 */
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);
@ -202,7 +211,7 @@ static int test_marshal(void) {
}
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_get_size();

View File

@ -18,8 +18,8 @@
#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
#include "escape.h"
#include "fd-util.h"
#include "hexdecoct.h"
#include "log.h"
#include "tests.h"
#include "util.h"
@ -111,7 +111,7 @@ int main(int argc, char *argv[]) {
uint8_t u, v;
void *buffer = NULL;
size_t sz;
char *h;
_cleanup_free_ char *h = NULL;
const int32_t integer_array[] = { -1, -2, 0, 1, 2 }, *return_array;
char *s;
_cleanup_free_ char *first = NULL, *second = NULL, *third = NULL;
@ -154,7 +154,7 @@ int main(int argc, char *argv[]) {
assert_se(r >= 0);
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");
assert_se(r >= 0);
@ -197,11 +197,9 @@ int main(int argc, char *argv[]) {
r = bus_message_get_blob(m, &buffer, &sz);
assert_se(r >= 0);
h = hexmem(buffer, sz);
h = cescape_length(buffer, sz);
assert_se(h);
log_info("message size = %zu, contents =\n%s", sz, h);
free(h);
#if HAVE_GLIB
#ifndef __SANITIZE_ADDRESS__
@ -298,7 +296,7 @@ int main(int argc, char *argv[]) {
assert_se(v == 10);
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);
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);
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(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("as", 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("{ss}", true));
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("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaau", false));
assert_se(signature_is_valid("(((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))", false));
assert_se(signature_is_valid("((((((((((((((((((((((((((((((((s))))))))))))))))))))))))))))))))", false));
assert_se(!signature_is_valid("((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))", false));
assert_se(namespace_complex_pattern("", ""));

View File

@ -5,6 +5,7 @@
#include "macro.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
#include "utf8.h"
static void test_string_erase(void) {
@ -30,6 +31,64 @@ static void test_string_erase(void) {
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) {
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[]) {
test_setup_logging(LOG_DEBUG);
test_string_erase();
test_free_and_strndup();
test_ascii_strcasecmp_n();
test_ascii_strcasecmp_nn();
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
subdir('fuzz-regressions')
subdir('fuzz')

View File

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