1
0
mirror of https://github.com/systemd/systemd synced 2025-11-07 19:04:46 +01:00

Compare commits

...

19 Commits

Author SHA1 Message Date
Anita Zhang
b10ceb4783
Merge pull request #15557 from poettering/journal-zero-fix
journal: deal better with reading from zeroed out journal mmaps
2020-05-20 18:14:51 -07:00
Evgeny Vereshchagin
a88dce2bdd
Merge pull request #15865 from evverx/ubsan-to-the-rescue
build-system: build the fuzz targets with both ASan and UBSan
2020-05-21 03:17:20 +03:00
Anita Zhang
acf70f8dd1
Merge pull request #15854 from poettering/call-method-ret-error
explain async bus method callback ret_error parameter
2020-05-20 15:12:37 -07:00
Anita Zhang
30ed6e2250
Merge pull request #15864 from poettering/pam-sudo-fixes-part3
two more pam_systemd fixes, split out of #15742
2020-05-20 15:01:52 -07:00
Evgeny Vereshchagin
157dcb8de3 fuzzit: turn on the pointer-overflow check
Now that https://github.com/systemd/systemd/issues/15583 is gone, it
should be safe to turn it on.
2020-05-20 16:07:26 +02:00
Evgeny Vereshchagin
8976715804 build-system: build the fuzz targets with both ASan and UBSan
Just a follow-up to https://github.com/systemd/systemd/pull/15860
2020-05-20 16:07:13 +02:00
Lennart Poettering
2efa512a1a man: let's document explicitly that method reply handlers won't get ret_error set to method error
Fixes: #8108
2020-05-20 15:56:48 +02:00
Lennart Poettering
af955f917f man: include sd_bus_message_handler_t prototype in synopsys of all man pages that reference the type
The type is not trivial, and kinda important to understand things, hence
import it everywhere where appropriate.
2020-05-20 15:56:09 +02:00
Lennart Poettering
e945dd9eed pam_systemd: clean up success path
Let's make sure we always apply the process properties from the user
record, in all our three successful paths:

1. when we register a regular session
2. when we run for the systemd --user session
3. when we have no logind (but might still have complex user records
   from elsewhere) and thus exit early
2020-05-20 00:47:37 +02:00
Lennart Poettering
764ae4dd51 man_systemd_home: intrdouce SYSTEMD_HOME_SUSPEND env var
This variable is read by the module and can be used instead of the
suspend= PAM module parameter.

It is also set for the session itself to make debugging easy.
2020-05-20 00:47:37 +02:00
Lennart Poettering
bfbd5be02a journal: no need to check offset twice, journal_file_move_to_object() does it again 2020-04-23 12:13:21 +02:00
Lennart Poettering
893e0f8fb6 journal: make sure to explicitly copy out values of mmap before doing arithmetics on them
Our journal code is generally supposed to be written in a fashion that
the underlying file can be deallocated any time, i.e. our mmap of it
suddenly becomes all zeroes. The idea is that we catch that when parsing
everything. For that to work safely we need to make sure that when doing
arithmetics or comparisons on values read from the map we don't run into
TTOCTTOU issues when determining validity. Hence we need to copy out the
values before use and operate on the copies. This requires some special
care since the C compiler could suppress our copies as optimization.
Hence use the new READ_NOW() macro to force a copy by using memcpy(),
and use it whenever we start doing an arithmetic operation on it, or
validity checking of multiple steps.

Fixes: #14943
2020-04-23 12:13:10 +02:00
Lennart Poettering
711398986e journal: several minor coding style fixes/clean-ups 2020-04-23 12:12:58 +02:00
Lennart Poettering
0600ff0e66 journal: don't assert on mmap'ed object type
Mappings canbe replaced by all zeroes under our feet if vacuuming
decides to unallocate some file. Hence let's not check for this kind of
stuff in an assert.

(Typically, we should genreate runtime errors in this case, in
particular EBADMSG, which the callers generally look for. But in this
case this is just an extra precaution check anyway, so let's just remove
it.)
2020-04-23 12:12:55 +02:00
Lennart Poettering
13933c6b6f memory-util: add missing () in macro evaulation 2020-04-23 12:12:45 +02:00
Lennart Poettering
bba6e4aeec journal: use structured initialization for Location structure 2020-04-23 12:12:33 +02:00
Lennart Poettering
e6fea3063b journal: use a bitfield where appropriate 2020-04-23 12:12:20 +02:00
Lennart Poettering
20ee282bb7 journal-file: avoid risky subtraction when validity checking object
The value might change beneath what we do, and hence let's avoid any
chance of underflow.
2020-04-23 12:12:17 +02:00
Lennart Poettering
ed50f18c4d macro: add READ_NOW() macro for force reading of memory, making a copy
When accessing journal files we generally are fine when values change
beneath our feet, while we are looking at them, as long as they change
from something valid to zero. This is required since we nowadays
forcibly unallocate journal files on vacuuming, to ensure they are
actually released.

However, we need to make sure that the validity checks we enforce are
done on suitable copies of the fields in the file. Thus provide a macro
that forces a copy, and disallows the compiler from merging our copy
with the actually memory where it is from.
2020-04-23 12:11:24 +02:00
18 changed files with 303 additions and 146 deletions

View File

@ -73,7 +73,12 @@
the re-authentication must take place from a component running outside of the user's context, so that
it does not require access to the user's home directory for operation. Traditionally, most desktop
environments do not implement screen locking this way, and need to be updated
accordingly.</para></listitem>
accordingly.</para>
<para>This setting may also be controlled via the <varname>$SYSTEMD_HOME_SUSPEND</varname>
environment variable (see below), which <command>pam_systemd_home</command> reads during initialization and sets
for sessions. If both the environment variable is set and the module parameter specified the latter
takes precedence.</para></listitem>
</varlistentry>
<varlistentry>
@ -105,6 +110,15 @@
<listitem><para>Indicates that the user's home directory is managed by <filename>systemd-homed.service</filename>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>$SYSTEMD_HOME_SUSPEND=</varname></term>
<listitem><para>Indicates whether the session has been registered with the suspend mechanism enabled
or disabled (see above). The variable's value is either <literal>0</literal> or
<literal>1</literal>. Note that the module both reads the variable when initializing, and sets it for
sessions.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -33,7 +33,7 @@
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcprototype id="sd_bus_message_handler_t">
<funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>

View File

@ -41,12 +41,7 @@
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus-vtable.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
<paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
<paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
</funcprototype>
<xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
<funcprototype>
<funcdef>typedef int (*<function>sd_bus_property_get_t</function>)</funcdef>

View File

@ -27,6 +27,8 @@
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
<funcprototype>
<funcdef>int <function>sd_bus_call</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>
@ -59,32 +61,33 @@
received a D-Bus error reply), <parameter>ret_error</parameter> is initialized to an instance of
<structname>sd_bus_error</structname> describing the error.</para>
<para><function>sd_bus_call_async()</function> is like <function>sd_bus_call()</function> but
works asynchronously. The <parameter>callback</parameter> indicates the function to call when
the response arrives. The <parameter>userdata</parameter> pointer will be passed to the callback
function, and may be chosen freely by the caller. If <parameter>slot</parameter> is not
<constant>NULL</constant> and <function>sd_bus_call_async()</function> succeeds,
<parameter>slot</parameter> is set to a slot object which can be used to cancel the method call
at a later time using
<para><function>sd_bus_call_async()</function> is like <function>sd_bus_call()</function> but works
asynchronously. The <parameter>callback</parameter> indicates the function to call when the response
arrives. The <parameter>userdata</parameter> pointer will be passed to the callback function, and may be
chosen freely by the caller. If <parameter>slot</parameter> is not <constant>NULL</constant> and
<function>sd_bus_call_async()</function> succeeds, <parameter>slot</parameter> is set to a slot object
which can be used to cancel the method call at a later time using
<citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
If <parameter>slot</parameter> is <constant>NULL</constant>, the lifetime of the method call is
bound to the lifetime of the bus object itself, and it cannot be cancelled independently. See
If <parameter>slot</parameter> is <constant>NULL</constant>, the lifetime of the method call is bound to
the lifetime of the bus object itself, and it cannot be cancelled independently. See
<citerefentry><refentrytitle>sd_bus_slot_set_floating</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details. <parameter>callback</parameter> is called when a reply arrives with the reply,
<parameter>userdata</parameter> and an <structname>sd_bus_error</structname> output
parameter as its arguments. Unlike <function>sd_bus_call()</function>, the
<structname>sd_bus_error</structname> output parameter passed to the callback will be empty. To
determine whether the method call succeeded, use
<parameter>userdata</parameter> and an <structname>sd_bus_error</structname> output parameter as its
arguments. Unlike <function>sd_bus_call()</function>, the <structname>sd_bus_error</structname> output
parameter passed to the callback will be empty. To determine whether the method call succeeded, use
<citerefentry><refentrytitle>sd_bus_message_is_method_error</refentrytitle><manvolnum>3</manvolnum></citerefentry>
on the reply message passed to the callback instead. If the callback returns zero and the
<structname>sd_bus_error</structname> output parameter is still empty when the callback
inishes, other handlers registered with functions such as
<structname>sd_bus_error</structname> output parameter is still empty when the callback finishes, other
handlers registered with functions such as
<citerefentry><refentrytitle>sd_bus_add_filter</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
<citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>
are given a chance to process the message. If the callback returns a non-zero value or the
<structname>sd_bus_error</structname> output parameter is not empty when the callback finishes,
no further processing of the message is done. Generally, you want to return zero from the
callback to give other registered handlers a chance to process the reply as well.</para>
<citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry> are
given a chance to process the message. If the callback returns a non-zero value or the
<structname>sd_bus_error</structname> output parameter is not empty when the callback finishes, no
further processing of the message is done. Generally, you want to return zero from the callback to give
other registered handlers a chance to process the reply as well. (Note that the
<structname>sd_bus_error</structname> parameter is an output parameter of the callback function, not an
input parameter; it can be used to propagate errors from the callback handler, it will not receive any
error that was received as method reply.)</para>
<para>If <parameter>usec</parameter> is zero, the default D-Bus method call timeout is used. See
<citerefentry><refentrytitle>sd_bus_get_method_call_timeout</refentrytitle><manvolnum>3</manvolnum></citerefentry>.

View File

@ -30,6 +30,8 @@
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
<funcprototype>
<funcdef>int <function>sd_bus_call_method</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>

View File

@ -28,6 +28,8 @@
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
<funcprototype>
<funcdef>sd_bus_message_handler_t <function>sd_bus_get_current_handler</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>

View File

@ -28,6 +28,8 @@
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
<funcprototype>
<funcdef>int <function>sd_bus_request_name</function></funcdef>
<paramdef>sd_bus *<parameter>bus</parameter></paramdef>

View File

@ -27,6 +27,8 @@
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<xi:include href="sd_bus_add_match.xml" xpointer="sd_bus_message_handler_t"/>
<funcprototype>
<funcdef>sd_bus *<function>sd_bus_slot_get_bus</function></funcdef>
<paramdef>sd_bus_slot *<parameter>slot</parameter></paramdef>

View File

@ -3368,6 +3368,8 @@ foreach tuple : sanitizers
if want_tests != 'false' and slow_tests
test('@0@:@1@:@2@'.format(b, c, sanitizer),
env,
env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
timeout : 60,
args : [exe.full_path(),
join_paths(project_source_root, p)])
endif

View File

@ -585,4 +585,17 @@ static inline int __coverity_check_and_return__(int condition) {
DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \
DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func);
/* A macro to force copying of a variable from memory. This is useful whenever we want to read something from
* memory and want to make sure the compiler won't optimize away the destination variable for us. It's not
* supposed to be a full CPU memory barrier, i.e. CPU is still allowed to reorder the reads, but it is not
* allowed to remove our local copies of the variables. We want this to work for unaligned memory, hence
* memcpy() is great for our purposes. */
#define READ_NOW(x) \
({ \
typeof(x) _copy; \
memcpy(&_copy, &(x), sizeof(_copy)); \
asm volatile ("" : : : "memory"); \
_copy; \
})
#include "log.h"

View File

@ -12,7 +12,7 @@
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
#define PAGE_ALIGN_DOWN(l) (l & ~(page_size() - 1))
#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
static inline void memcpy_safe(void *dst, const void *src, size_t n) {

View File

@ -60,6 +60,35 @@ static int parse_argv(
return 0;
}
static int parse_env(
pam_handle_t *handle,
bool *please_suspend) {
const char *v;
int r;
/* Let's read the suspend setting from an env var in addition to the PAM command line. That makes it
* easy to declare the features of a display manager in code rather than configuration, and this is
* really a feature of code */
v = pam_getenv(handle, "SYSTEMD_HOME_SUSPEND");
if (!v) {
/* Also check the process env block, so that people can control this via an env var from the
* outside of our process. */
v = secure_getenv("SYSTEMD_HOME_SUSPEND");
if (!v)
return 0;
}
r = parse_boolean(v);
if (r < 0)
pam_syslog(handle, LOG_WARNING, "Failed to parse $SYSTEMD_HOME_SUSPEND argument, ignoring: %s", v);
else if (please_suspend)
*please_suspend = r;
return 0;
}
static int acquire_user_record(
pam_handle_t *handle,
const char *username,
@ -636,6 +665,9 @@ _public_ PAM_EXTERN int pam_sm_authenticate(
bool debug = false, suspend_please = false;
if (parse_env(handle, &suspend_please) < 0)
return PAM_AUTH_ERR;
if (parse_argv(handle,
argc, argv,
&suspend_please,
@ -660,6 +692,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
bool debug = false, suspend_please = false;
int r;
if (parse_env(handle, &suspend_please) < 0)
return PAM_SESSION_ERR;
if (parse_argv(handle,
argc, argv,
&suspend_please,
@ -681,6 +716,12 @@ _public_ PAM_EXTERN int pam_sm_open_session(
return r;
}
r = pam_putenv(handle, suspend_please ? "SYSTEMD_HOME_SUSPEND=1" : "SYSTEMD_HOME_SUSPEND=0");
if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to set PAM environment variable $SYSTEMD_HOME_SUSPEND: %s", pam_strerror(handle, r));
return r;
}
/* Let's release the D-Bus connection, after all the session might live quite a long time, and we are
* not going to process the bus connection in that time, so let's better close before the daemon
* kicks us off because we are not processing anything. */
@ -764,6 +805,9 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt(
usec_t t;
int r;
if (parse_env(handle, &please_suspend) < 0)
return PAM_AUTH_ERR;
if (parse_argv(handle,
argc, argv,
&please_suspend,

View File

@ -533,7 +533,7 @@ static int journal_file_verify_header(JournalFile *f) {
if (f->header->state >= _STATE_MAX)
return -EBADMSG;
header_size = le64toh(f->header->header_size);
header_size = le64toh(READ_NOW(f->header->header_size));
/* The first addition was n_data, so check that we are at least this large */
if (header_size < HEADER_SIZE_MIN)
@ -542,7 +542,7 @@ static int journal_file_verify_header(JournalFile *f) {
if (JOURNAL_HEADER_SEALED(f->header) && !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
return -EBADMSG;
arena_size = le64toh(f->header->arena_size);
arena_size = le64toh(READ_NOW(f->header->arena_size));
if (UINT64_MAX - header_size < arena_size || header_size + arena_size > (uint64_t) f->last_stat.st_size)
return -ENODATA;
@ -625,26 +625,29 @@ int journal_file_fstat(JournalFile *f) {
}
static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) {
uint64_t old_size, new_size;
uint64_t old_size, new_size, old_header_size, old_arena_size;
int r;
assert(f);
assert(f->header);
/* We assume that this file is not sparse, and we know that
* for sure, since we always call posix_fallocate()
* ourselves */
/* We assume that this file is not sparse, and we know that for sure, since we always call
* posix_fallocate() ourselves */
if (size > PAGE_ALIGN_DOWN(UINT64_MAX) - offset)
return -EINVAL;
if (mmap_cache_got_sigbus(f->mmap, f->cache_fd))
return -EIO;
old_size =
le64toh(f->header->header_size) +
le64toh(f->header->arena_size);
old_header_size = le64toh(READ_NOW(f->header->header_size));
old_arena_size = le64toh(READ_NOW(f->header->arena_size));
if (old_arena_size > PAGE_ALIGN_DOWN(UINT64_MAX) - old_header_size)
return -EBADMSG;
new_size = PAGE_ALIGN(offset + size);
if (new_size < le64toh(f->header->header_size))
new_size = le64toh(f->header->header_size);
old_size = old_header_size + old_arena_size;
new_size = MAX(PAGE_ALIGN(offset + size), old_header_size);
if (new_size <= old_size) {
@ -690,7 +693,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
if (r != 0)
return -r;
f->header->arena_size = htole64(new_size - le64toh(f->header->header_size));
f->header->arena_size = htole64(new_size - old_header_size);
return journal_file_fstat(f);
}
@ -702,7 +705,15 @@ static unsigned type_to_context(ObjectType type) {
return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
}
static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret, size_t *ret_size) {
static int journal_file_move_to(
JournalFile *f,
ObjectType type,
bool keep_always,
uint64_t offset,
uint64_t size,
void **ret,
size_t *ret_size) {
int r;
assert(f);
@ -711,6 +722,9 @@ static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_alway
if (size <= 0)
return -EINVAL;
if (size > UINT64_MAX - offset)
return -EBADMSG;
/* Avoid SIGBUS on invalid accesses */
if (offset + size > (uint64_t) f->last_stat.st_size) {
/* Hmm, out of range? Let's refresh the fstat() data
@ -760,7 +774,7 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
le64toh(o->data.n_entries),
offset);
if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
if (le64toh(o->object.size) <= offsetof(DataObject, payload))
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Bad object size (<= %zu): %" PRIu64 ": %" PRIu64,
offsetof(DataObject, payload),
@ -782,7 +796,7 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
break;
case OBJECT_FIELD:
if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
if (le64toh(o->object.size) <= offsetof(FieldObject, payload))
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Bad field size (<= %zu): %" PRIu64 ": %" PRIu64,
offsetof(FieldObject, payload),
@ -798,18 +812,22 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
offset);
break;
case OBJECT_ENTRY:
if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
case OBJECT_ENTRY: {
uint64_t sz;
sz = le64toh(READ_NOW(o->object.size));
if (sz < offsetof(EntryObject, items) ||
(sz - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Bad entry size (<= %zu): %" PRIu64 ": %" PRIu64,
offsetof(EntryObject, items),
le64toh(o->object.size),
sz,
offset);
if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
if ((sz - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Invalid number items in entry: %" PRIu64 ": %" PRIu64,
(le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem),
(sz - offsetof(EntryObject, items)) / sizeof(EntryItem),
offset);
if (le64toh(o->entry.seqnum) <= 0)
@ -831,25 +849,35 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
offset);
break;
}
case OBJECT_DATA_HASH_TABLE:
case OBJECT_FIELD_HASH_TABLE:
if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
(le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
case OBJECT_FIELD_HASH_TABLE: {
uint64_t sz;
sz = le64toh(READ_NOW(o->object.size));
if (sz < offsetof(HashTableObject, items) ||
(sz - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
(sz - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Invalid %s hash table size: %" PRIu64 ": %" PRIu64,
o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
le64toh(o->object.size),
sz,
offset);
break;
}
case OBJECT_ENTRY_ARRAY:
if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
(le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
case OBJECT_ENTRY_ARRAY: {
uint64_t sz;
sz = le64toh(READ_NOW(o->object.size));
if (sz < offsetof(EntryArrayObject, items) ||
(sz - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
(sz - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"Invalid object entry array size: %" PRIu64 ": %" PRIu64,
le64toh(o->object.size),
sz,
offset);
if (!VALID64(le64toh(o->entry_array.next_entry_array_offset)))
@ -859,6 +887,7 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o)
offset);
break;
}
case OBJECT_TAG:
if (le64toh(o->object.size) != sizeof(TagObject))
@ -905,7 +934,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
return r;
o = (Object*) t;
s = le64toh(o->object.size);
s = le64toh(READ_NOW(o->object.size));
if (s == 0)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
@ -995,11 +1024,21 @@ int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, O
if (p == 0)
p = le64toh(f->header->header_size);
else {
uint64_t sz;
r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &tail);
if (r < 0)
return r;
p += ALIGN64(le64toh(tail->object.size));
sz = le64toh(READ_NOW(tail->object.size));
if (sz > UINT64_MAX - sizeof(uint64_t) + 1)
return -EBADMSG;
sz = ALIGN64(sz);
if (p > UINT64_MAX - sz)
return -EBADMSG;
p += sz;
}
r = journal_file_allocate(f, p, size);
@ -1011,10 +1050,10 @@ int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, O
return r;
o = (Object*) t;
zero(o->object);
o->object.type = type;
o->object.size = htole64(size);
o->object = (ObjectHeader) {
.type = type,
.size = htole64(size),
};
f->header->tail_object_offset = htole64(p);
f->header->n_objects = htole64(le64toh(f->header->n_objects) + 1);
@ -1156,7 +1195,7 @@ static int journal_file_link_field(
if (o->object.type != OBJECT_FIELD)
return -EINVAL;
m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
m = le64toh(READ_NOW(f->header->field_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@ -1201,7 +1240,7 @@ static int journal_file_link_data(
if (o->object.type != OBJECT_DATA)
return -EINVAL;
m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
m = le64toh(READ_NOW(f->header->data_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@ -1257,7 +1296,7 @@ int journal_file_find_field_object_with_hash(
osize = offsetof(Object, field.payload) + size;
m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem);
m = le64toh(READ_NOW(f->header->field_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@ -1329,7 +1368,7 @@ int journal_file_find_data_object_with_hash(
osize = offsetof(Object, data.payload) + size;
m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
m = le64toh(READ_NOW(f->header->data_hash_table_size)) / sizeof(HashItem);
if (m <= 0)
return -EBADMSG;
@ -1351,7 +1390,7 @@ int journal_file_find_data_object_with_hash(
uint64_t l;
size_t rsize = 0;
l = le64toh(o->object.size);
l = le64toh(READ_NOW(o->object.size));
if (l <= offsetof(Object, data.payload))
return -EBADMSG;
@ -1576,30 +1615,47 @@ static int journal_file_append_data(
}
uint64_t journal_file_entry_n_items(Object *o) {
uint64_t sz;
assert(o);
if (o->object.type != OBJECT_ENTRY)
return 0;
return (le64toh(o->object.size) - offsetof(Object, entry.items)) / sizeof(EntryItem);
sz = le64toh(READ_NOW(o->object.size));
if (sz < offsetof(Object, entry.items))
return 0;
return (sz - offsetof(Object, entry.items)) / sizeof(EntryItem);
}
uint64_t journal_file_entry_array_n_items(Object *o) {
uint64_t sz;
assert(o);
if (o->object.type != OBJECT_ENTRY_ARRAY)
return 0;
return (le64toh(o->object.size) - offsetof(Object, entry_array.items)) / sizeof(uint64_t);
sz = le64toh(READ_NOW(o->object.size));
if (sz < offsetof(Object, entry_array.items))
return 0;
return (sz - offsetof(Object, entry_array.items)) / sizeof(uint64_t);
}
uint64_t journal_file_hash_table_n_items(Object *o) {
uint64_t sz;
assert(o);
if (!IN_SET(o->object.type, OBJECT_DATA_HASH_TABLE, OBJECT_FIELD_HASH_TABLE))
return 0;
return (le64toh(o->object.size) - offsetof(Object, hash_table.items)) / sizeof(HashItem);
sz = le64toh(READ_NOW(o->object.size));
if (sz < offsetof(Object, hash_table.items))
return 0;
return (sz - offsetof(Object, hash_table.items)) / sizeof(HashItem);
}
static int link_entry_into_array(JournalFile *f,
@ -1617,7 +1673,7 @@ static int link_entry_into_array(JournalFile *f,
assert(p > 0);
a = le64toh(*first);
i = hidx = le64toh(*idx);
i = hidx = le64toh(READ_NOW(*idx));
while (a > 0) {
r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
@ -1682,6 +1738,7 @@ static int link_entry_into_array_plus_one(JournalFile *f,
le64_t *idx,
uint64_t p) {
uint64_t hidx;
int r;
assert(f);
@ -1690,32 +1747,33 @@ static int link_entry_into_array_plus_one(JournalFile *f,
assert(idx);
assert(p > 0);
if (*idx == 0)
hidx = le64toh(READ_NOW(*idx));
if (hidx == UINT64_MAX)
return -EBADMSG;
if (hidx == 0)
*extra = htole64(p);
else {
le64_t i;
i = htole64(le64toh(*idx) - 1);
i = htole64(hidx - 1);
r = link_entry_into_array(f, first, &i, p);
if (r < 0)
return r;
}
*idx = htole64(le64toh(*idx) + 1);
*idx = htole64(hidx + 1);
return 0;
}
static int journal_file_link_entry_item(JournalFile *f, Object *o, uint64_t offset, uint64_t i) {
uint64_t p;
int r;
assert(f);
assert(o);
assert(offset > 0);
p = le64toh(o->entry.items[i].object_offset);
if (p == 0)
return -EINVAL;
r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
if (r < 0)
return r;
@ -2435,6 +2493,7 @@ _pure_ static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle
}
static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
uint64_t sq;
Object *o;
int r;
@ -2445,9 +2504,10 @@ static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) {
if (r < 0)
return r;
if (le64toh(o->entry.seqnum) == needle)
sq = le64toh(READ_NOW(o->entry.seqnum));
if (sq == needle)
return TEST_FOUND;
else if (le64toh(o->entry.seqnum) < needle)
else if (sq < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
@ -2473,6 +2533,7 @@ int journal_file_move_to_entry_by_seqnum(
static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
uint64_t rt;
int r;
assert(f);
@ -2482,9 +2543,10 @@ static int test_object_realtime(JournalFile *f, uint64_t p, uint64_t needle) {
if (r < 0)
return r;
if (le64toh(o->entry.realtime) == needle)
rt = le64toh(READ_NOW(o->entry.realtime));
if (rt == needle)
return TEST_FOUND;
else if (le64toh(o->entry.realtime) < needle)
else if (rt < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
@ -2510,6 +2572,7 @@ int journal_file_move_to_entry_by_realtime(
static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
Object *o;
uint64_t m;
int r;
assert(f);
@ -2519,9 +2582,10 @@ static int test_object_monotonic(JournalFile *f, uint64_t p, uint64_t needle) {
if (r < 0)
return r;
if (le64toh(o->entry.monotonic) == needle)
m = le64toh(READ_NOW(o->entry.monotonic));
if (m == needle)
return TEST_FOUND;
else if (le64toh(o->entry.monotonic) < needle)
else if (m < needle)
return TEST_LEFT;
else
return TEST_RIGHT;
@ -2679,7 +2743,7 @@ int journal_file_next_entry(
assert(f);
assert(f->header);
n = le64toh(f->header->n_entries);
n = le64toh(READ_NOW(f->header->n_entries));
if (n <= 0)
return 0;
@ -2752,7 +2816,7 @@ int journal_file_next_entry_for_data(
if (r < 0)
return r;
n = le64toh(d->data.n_entries);
n = le64toh(READ_NOW(d->data.n_entries));
if (n <= 0)
return n;
@ -2981,7 +3045,7 @@ void journal_file_dump(JournalFile *f) {
journal_file_print_header(f);
p = le64toh(f->header->header_size);
p = le64toh(READ_NOW(f->header->header_size));
while (p != 0) {
r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o);
if (r < 0)
@ -3038,7 +3102,7 @@ void journal_file_dump(JournalFile *f) {
if (p == le64toh(f->header->tail_object_offset))
p = 0;
else
p = p + ALIGN64(le64toh(o->object.size));
p += ALIGN64(le64toh(o->object.size));
}
return;
@ -3659,7 +3723,11 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
if (le_hash != o->data.hash)
return -EBADMSG;
l = le64toh(o->object.size) - offsetof(Object, data.payload);
l = le64toh(READ_NOW(o->object.size));
if (l < offsetof(Object, data.payload))
return -EBADMSG;
l -= offsetof(Object, data.payload);
t = (size_t) l;
/* We hit the limit on 32bit machines */

View File

@ -41,10 +41,10 @@ struct Match {
struct Location {
LocationType type;
bool seqnum_set;
bool realtime_set;
bool monotonic_set;
bool xor_hash_set;
bool seqnum_set:1;
bool realtime_set:1;
bool monotonic_set:1;
bool xor_hash_set:1;
uint64_t seqnum;
sd_id128_t seqnum_id;

View File

@ -115,28 +115,24 @@ static void detach_location(sd_journal *j) {
journal_file_reset_location(f);
}
static void reset_location(sd_journal *j) {
assert(j);
detach_location(j);
zero(j->current_location);
}
static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
assert(l);
assert(IN_SET(type, LOCATION_DISCRETE, LOCATION_SEEK));
assert(f);
assert(o->object.type == OBJECT_ENTRY);
l->type = type;
l->seqnum = le64toh(o->entry.seqnum);
l->seqnum_id = f->header->seqnum_id;
l->realtime = le64toh(o->entry.realtime);
l->monotonic = le64toh(o->entry.monotonic);
l->boot_id = o->entry.boot_id;
l->xor_hash = le64toh(o->entry.xor_hash);
l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true;
*l = (Location) {
.type = type,
.seqnum = le64toh(o->entry.seqnum),
.seqnum_id = f->header->seqnum_id,
.realtime = le64toh(o->entry.realtime),
.monotonic = le64toh(o->entry.monotonic),
.boot_id = o->entry.boot_id,
.xor_hash = le64toh(o->entry.xor_hash),
.seqnum_set = true,
.realtime_set = true,
.monotonic_set = true,
.xor_hash_set = true,
};
}
static void set_location(sd_journal *j, JournalFile *f, Object *o) {
@ -1014,9 +1010,10 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
!realtime_set)
return -EINVAL;
reset_location(j);
j->current_location.type = LOCATION_SEEK;
detach_location(j);
j->current_location = (Location) {
.type = LOCATION_SEEK,
};
if (realtime_set) {
j->current_location.realtime = (uint64_t) realtime;
@ -1129,11 +1126,14 @@ _public_ int sd_journal_seek_monotonic_usec(sd_journal *j, sd_id128_t boot_id, u
assert_return(j, -EINVAL);
assert_return(!journal_pid_changed(j), -ECHILD);
reset_location(j);
j->current_location.type = LOCATION_SEEK;
j->current_location.boot_id = boot_id;
j->current_location.monotonic = usec;
j->current_location.monotonic_set = true;
detach_location(j);
j->current_location = (Location) {
.type = LOCATION_SEEK,
.boot_id = boot_id,
.monotonic = usec,
.monotonic_set = true,
};
return 0;
}
@ -1142,10 +1142,13 @@ _public_ int sd_journal_seek_realtime_usec(sd_journal *j, uint64_t usec) {
assert_return(j, -EINVAL);
assert_return(!journal_pid_changed(j), -ECHILD);
reset_location(j);
j->current_location.type = LOCATION_SEEK;
j->current_location.realtime = usec;
j->current_location.realtime_set = true;
detach_location(j);
j->current_location = (Location) {
.type = LOCATION_SEEK,
.realtime = usec,
.realtime_set = true,
};
return 0;
}
@ -1154,8 +1157,11 @@ _public_ int sd_journal_seek_head(sd_journal *j) {
assert_return(j, -EINVAL);
assert_return(!journal_pid_changed(j), -ECHILD);
reset_location(j);
j->current_location.type = LOCATION_HEAD;
detach_location(j);
j->current_location = (Location) {
.type = LOCATION_HEAD,
};
return 0;
}
@ -1164,8 +1170,11 @@ _public_ int sd_journal_seek_tail(sd_journal *j) {
assert_return(j, -EINVAL);
assert_return(!journal_pid_changed(j), -ECHILD);
reset_location(j);
j->current_location.type = LOCATION_TAIL;
detach_location(j);
j->current_location = (Location) {
.type = LOCATION_TAIL,
};
return 0;
}
@ -2357,7 +2366,10 @@ static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **da
uint64_t l;
int compression;
l = le64toh(o->object.size) - offsetof(Object, data.payload);
l = le64toh(READ_NOW(o->object.size));
if (l < offsetof(Object, data.payload))
return -EBADMSG;
l -= offsetof(Object, data.payload);
t = (size_t) l;
/* We can't read objects larger than 4G on a 32bit machine */

View File

@ -647,10 +647,6 @@ _public_ PAM_EXTERN int pam_sm_open_session(
assert(handle);
/* Make this a NOP on non-logind systems */
if (!logind_running())
return PAM_SUCCESS;
if (parse_argv(handle,
argc, argv,
&class_pam,
@ -666,6 +662,10 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (r != PAM_SUCCESS)
return r;
/* Make most of this a NOP on non-logind systems */
if (!logind_running())
goto success;
/* Make sure we don't enter a loop by talking to
* systemd-logind when it is actually waiting for the
* background to finish start-up. If the service is
@ -689,11 +689,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (r != PAM_SUCCESS)
return r;
r = apply_user_record_settings(handle, ur, debug);
if (r != PAM_SUCCESS)
return r;
return PAM_SUCCESS;
goto success;
}
/* Otherwise, we ask logind to create a session for us */
@ -847,7 +843,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
if (debug)
pam_syslog(handle, LOG_DEBUG, "Not creating session: %s", bus_error_message(&error, r));
return PAM_SUCCESS;
/* We are already in a session, don't do anything */
goto success;
} else {
pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r));
return PAM_SESSION_ERR;
@ -944,6 +942,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
}
}
success:
r = apply_user_record_settings(handle, ur, debug);
if (r != PAM_SUCCESS)
return r;

View File

@ -1,17 +1,17 @@
# SPDX-License-Identifier: LGPL-2.1+
sanitize_address = custom_target(
'sanitize-address-fuzzers',
output : 'sanitize-address-fuzzers',
sanitize_address_undefined = custom_target(
'sanitize-address-undefined-fuzzers',
output : 'sanitize-address-undefined-fuzzers',
command : [meson_build_sh,
project_source_root,
'@OUTPUT@',
'fuzzers',
'-Db_lundef=false -Db_sanitize=address',
'-Db_lundef=false -Db_sanitize=address,undefined',
' '.join(cc.cmd_array()),
cxx_cmd])
sanitizers = [['address', sanitize_address]]
sanitizers = [['address,undefined', sanitize_address_undefined]]
if git.found()
out = run_command(

View File

@ -22,11 +22,10 @@ cd $REPO_ROOT
export PATH="$HOME/.local/bin/:$PATH"
# We use a subset of https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks instead of "undefined"
# because our fuzzers crash with "pointer-overflow" and "float-cast-overflow":
# https://github.com/systemd/systemd/pull/12771#issuecomment-502139157
# because our fuzzers crash with "float-cast-overflow":
# https://github.com/systemd/systemd/pull/12812#issuecomment-502780455
# TODO: figure out what to do about unsigned-integer-overflow: https://github.com/google/oss-fuzz/issues/910
export SANITIZER="address -fsanitize=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,unsigned-integer-overflow,vla-bound,vptr -fno-sanitize-recover=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr"
export SANITIZER="address -fsanitize=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,pointer-overflow,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,unsigned-integer-overflow,vla-bound,vptr -fno-sanitize-recover=alignment,array-bounds,bool,bounds,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,object-size,pointer-overflow,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr"
tools/oss-fuzz.sh
FUZZING_TYPE=${1:-regression}