Commit graph

3973 commits

Author SHA1 Message Date
Wim Taymans
a6155387da security: fix unchecked alloca in pulse-server property list handling
Memory Safety: Medium

Two alloca() calls in the PulseAudio protocol server were missed by the
previous alloca bounds-checking fix (commit 0d2877c0d):

1. fill_node_info_proplist() adds n_items counts from node properties
   and client properties without checking the total before alloca().
   A client with a very large number of properties can exhaust the stack.

2. fill_card_info() uses pi->n_props from port info for an alloca()
   without bounds checking. A card object with many port properties can
   similarly exhaust the stack.

Add MAX_ALLOCA_SIZE checks consistent with the existing pattern to
prevent stack overflow from large property counts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
95ef466b9b security: add O_NOFOLLOW to native protocol lock file creation
File and Resource Handling: Medium

The lock_socket() function opens the lock file without O_NOFOLLOW. If an
attacker places a symlink at the lock file path, open() follows it and
creates or truncates a file at the symlink target with the caller's
privileges. While the lock path is typically in a user-owned runtime
directory, adding O_NOFOLLOW is a low-cost defense-in-depth measure that
prevents symlink attacks in case the directory permissions are
misconfigured or the path is influenced by untrusted input.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
613b35eedf security: fix TOCTOU race and symlink following in native protocol socket
File and Resource Handling: Medium

The socket initialization code uses stat() followed by unlink() to clean
up stale socket files. This creates two issues:

1. stat() follows symlinks, so an attacker who places a symlink at the
   socket path can trick the daemon into unlinking an arbitrary file.

2. The gap between stat() and unlink() creates a TOCTOU race window
   where the file could be replaced between the check and the removal.

Fix by using lstat() to detect symlinks without following them, refusing
to proceed if the path is a symlink, and only unlinking files that are
actually sockets (S_ISSOCK). This narrows the race window and prevents
symlink-based file deletion attacks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
4c9ec363a3 security: fix inverted overflow check in RTP MIDI message size parsing
Memory Safety: High

In get_midi_size(), the overflow check for SysEx and meta-event message
sizes has the comparison operator inverted. The check
  (unsigned int)(INT_MAX - size - 1) > value
rejects small (safe) payload sizes and accepts large sizes that cause
signed integer overflow in the subsequent size += (int)value + 1.

This means all SysEx messages (0xF0, 0xF7) and system reset/meta events
(0xFF) with valid payloads are incorrectly rejected, while crafted
packets with very large variable-length values bypass the check. Although
the caller has a secondary bounds check that mitigates most exploitation,
the inverted check is both a functional bug (breaks SysEx over RTP) and
a defense-in-depth failure.

Fix by swapping the operands so that the check correctly rejects values
that would overflow: value > (unsigned int)(INT_MAX - size - 1).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
7a969654f6 security: fix out-of-bounds read from non-null-terminated netjack2 strings
Memory Safety: High

The nj2_dump_session_params() function logs char array fields (type,
name, driver_name, follower_name) from network-received
nj2_session_params structs using %s format. These fields are fixed-size
char arrays filled by recvfrom() and are not guaranteed to contain a null
terminator. A malicious peer can send a packet with no null bytes in
these fields, causing pw_log_info to read past the struct boundary,
potentially crashing the process or leaking adjacent heap memory.

Use %.*s format specifier with explicit maximum lengths in the dump
function to bound the string reads. Also force null-terminate the
string fields in nj2_session_params_ntoh() so that all downstream
consumers after byte-order conversion are safe.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
e01ca8919e security: fix integer underflow in AVB stream packet handling
Memory Safety: Critical

In handle_iec61883_packet(), the data_len field from an incoming network
packet is converted via ntohs() and then unconditionally has 8 subtracted
from it. If an attacker sends a malformed AVB packet with data_len < 8,
the subtraction wraps the uint32_t n_bytes to a very large value
(~4 billion). This corrupted size is then passed to
spa_ringbuffer_write_data(), which can overwrite the ring buffer and
adjacent heap memory with attacker-controlled network data.

Add a bounds check to verify data_len >= 8 before the subtraction,
returning early on malformed packets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
00413a3263 security: fix stack exhaustion via unbounded alloca in pulse-server
Memory Safety: Medium

Several functions in the PulseAudio protocol implementation use alloca()
to allocate arrays of port_info, profile_info, or dict_item structs
based on counts derived from card parameters or client property lists.
These counts have no upper bounds, so a card object with a very large
number of parameters or a client sending many properties can cause
alloca() to exhaust the stack, resulting in a stack overflow crash.

Add a MAX_ALLOCA_SIZE (64KB) limit and check element counts before each
alloca() call. If the requested allocation exceeds the limit, the
function returns -ENOMEM instead of crashing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
b2bdd65338 security: fix TOCTOU and symlink vulnerabilities in pipe-tunnel FIFO
File and Resource Handling: High

The pipe-tunnel module creates FIFOs and then adjusts their
permissions using chmod() on the path. Between mkfifo() and
chmod(), an attacker with write access to the directory (e.g.,
/tmp with the default hardcoded paths) can delete the FIFO and
replace it with a symlink to a target file. The chmod(0666) then
changes permissions on the symlink target, allowing the attacker
to make arbitrary files world-readable/writable.

Fix by:
1. Adding O_NOFOLLOW to the open() call so symlinks are rejected
   at open time rather than followed.
2. Moving the permission change from chmod() (path-based, follows
   symlinks) to fchmod() (fd-based, operates on the already-opened
   and validated file descriptor), and doing it after the fstat
   S_ISFIFO check confirms we opened an actual FIFO.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
56c5eaf317 security: fix integer overflow in netjack2 socket buffer size calculation
Memory Safety: Medium

In both module-netjack2-driver.c and module-netjack2-manager.c, the
socket buffer size is computed as:
  NETWORK_MAX_LATENCY * (mtu + period_size * sizeof(float) * n_ports)

This arithmetic is performed in int (signed 32-bit) but the
intermediate values can exceed INT_MAX with large but valid network
parameters. Signed integer overflow is undefined behavior in C,
and the resulting negative value passed to setsockopt would set an
incorrect socket buffer size.

Fix by widening the intermediate computation to size_t and clamping
the result to INT_MAX before storing in the int variable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
835ba5efd6 security: fix integer truncation in combine-stream delay calculation
Memory Safety: Medium

In update_delay(), the delay compensation size is computed as
delay * sizeof(float) where delay is int64_t but size is uint32_t.
When the delay value is very large, the multiplication result
truncates to a small uint32_t value. This causes an undersized
buffer allocation in resize_delay(), while compensate_samples
retains the original large value. Subsequent use of
compensate_samples could then write past the end of the buffer.

A negative delay (possible if delay_samples overflows) would also
produce a large unsigned size due to implicit conversion.

Fix by clamping the delay to be non-negative and within the maximum
delay buffer size before the multiplication, ensuring the size
cannot truncate or wrap.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
1d68d7f2e9 security: fix integer overflow in loopback delay buffer allocation
Memory Safety: Medium

In recalculate_buffer(), the buffer size computation
(delay + (1u<<15)) * 4 can overflow uint32_t when delay is large.
Additionally, the subsequent multiplication buffer_size * channels
for the realloc size can also overflow uint32_t, wrapping to a
small value and causing an undersized allocation. Later writes to
the buffer using the logical buffer_size would then overflow the
heap.

The delay value derives from rate * target_delay where both values
come from stream negotiation properties.

Fix by adding an overflow check on the delay computation and
widening the allocation size to size_t to prevent the second
overflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
4305d7e82d security: fix integer overflows in netjack2 peer buffer allocations
Memory Safety: High

In netjack2_init(), several buffer sizes are computed by multiplying
network-provided session parameters (period_size, channel counts,
kbps) without overflow checks. A malicious network peer can send
crafted session parameters that cause these multiplications to
overflow, resulting in undersized buffer allocations. Subsequent
writes to these buffers then overflow the heap.

Specific issues fixed:
1. midi_size = period_size * sizeof(float) * max_midi_channels can
   overflow, causing calloc to allocate a small buffer.
2. encoded_size = max_encoded_size * max_audio_channels can overflow
   for both INT and OPUS encoders.
3. OPUS kbps * period_size * 1024 numerator can overflow uint32_t;
   widen to uint64_t for the intermediate calculation.
4. Division by zero if sample_rate is 0 in OPUS encoder path.
5. Missing NULL checks on calloc for empty and midi_data buffers.
6. Channel counts not capped to MAX_CHANNELS before use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
d4ec630b2f security: fix missing packet length validation in VBAN MIDI receive
Memory Safety: High

In vban_midi_receive(), the received buffer is cast to struct
vban_header and its n_frames field is accessed before validating
that the packet is large enough to contain the header. A truncated
packet shorter than VBAN_HEADER_SIZE would cause an out-of-bounds
read.

Fix by checking that len >= VBAN_HEADER_SIZE before accessing the
header, matching the fix applied to vban_audio_receive().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
3709cac938 security: fix missing packet length validation in VBAN audio receive
Memory Safety: High

In vban_audio_receive(), the received buffer is cast to struct
vban_header and its fields are accessed before validating that the
packet is large enough to contain the header. If a truncated packet
shorter than VBAN_HEADER_SIZE is received, this reads past the end
of the buffer.

Additionally, when len < hlen, the plen calculation (len - hlen)
produces a negative ssize_t value which, when used in the unsigned
division plen / stride, gets implicitly converted to a very large
value, potentially causing further out-of-bounds reads.

Fix by checking that len >= VBAN_HEADER_SIZE before accessing the
header.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
hackerman-kl
0ac8b1c5fa module-avb: fix GET_NAME to validate length before field reads and reply with fixed size 2026-04-24 11:50:23 +02:00
hackerman-kl
01dd7e607c module-avb: bound packet copy length in reply_status helper 2026-04-24 11:50:20 +02:00
hackerman-kl
f091b85b03 module-avb: enforce minimum AECP packet length and replace VLA on dispatch 2026-04-23 17:25:26 +02:00
hackerman-kl
6ca2f509e3 module-avb: bound descriptor size in READ_DESCRIPTOR reply to prevent stack overflow 2026-04-22 19:19:10 +02:00
hackerman-kl
a8832c74d0 module-avb: bound packet copy length in get-set-name handlers 2026-04-20 18:29:56 +02:00
hackerman-kl
e6b4de6442 milan-avb: guard against size_t underflow on short packets in unsol reply prepare 2026-04-19 18:58:01 +02:00
hackerman-kl
09f9100ce7 milan-avb: validate packet length before dereferencing SET_CONTROL value byte 2026-04-19 07:39:03 +02:00
hackerman-kl
0291895498 milan-avb: zero-pad oversized SET_CONTROL reply buffer to avoid stack info leak 2026-04-18 17:13:05 +02:00
hackerman-kl
b831fd857f milan-avb: bound packet copy length in get-set-control handlers 2026-04-16 19:50:33 +02:00
hackerman-kl
f06234fda8 milan-avb: bound packet copy length in clock-source handlers 2026-04-16 19:07:59 +02:00
hackerman-kl
d1deabe5ac milan-avb: fix descriptor field and endianness in GET_CLOCK_SOURCE lookup 2026-04-14 19:00:02 +02:00
hackerman-kl
8fbeb23bbf milan-avb: implement deregister unsolicited notifications to actually clear registration 2026-04-13 18:52:30 +02:00
Wim Taymans
cd00ea2462 security: clear sensitive auth data from stack buffers in RAOP
Information Disclosure: Medium

The MD5_hash() function formats password material into a 1024-byte
stack buffer for hashing but never clears it afterward. Similarly,
the Basic auth path in rtsp_add_raop_auth_header() formats
username:password into a stack buffer without clearing it.

These buffers remain on the stack after the functions return, and
could be exposed through memory disclosure vulnerabilities, core
dumps, or memory inspection.

Clear the buffers with explicit_bzero() immediately after they are
no longer needed, consistent with the existing practice of clearing
the password before freeing in impl_destroy().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 17:49:43 +02:00
Wim Taymans
2c78c1e1fb security: fix integer overflows in netjack2 float packet handling
Memory Safety: High

In netjack2_recv_float(), several values from untrusted network packet
headers are used in arithmetic without overflow protection:

1. active_ports from the network header had no upper bound check. A
   very large value causes `active_ports * sub_period_bytes` to
   overflow uint32_t, producing a small value that passes the length
   check, then the loop iterates out of bounds on the receive buffer.

2. The sub_cycle bounds check `sub_cycle * sub_period_size >
   quantum_limit` can overflow, allowing a large sub_cycle to pass
   the check and cause an out-of-bounds write when computing the
   destination offset.

Fix by capping active_ports to MAX_CHANNELS, casting to size_t for the
length check to prevent overflow, and rewriting the sub_cycle check as
a division to avoid overflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 17:48:15 +02:00
Wim Taymans
e277a91842 security: fix integer overflows in netjack2 MIDI packet handling
Memory Safety: High

In netjack2_recv_midi(), the offset calculation `max_size * sub_cycle`
uses sub_cycle from an untrusted network packet header. A large
sub_cycle value could cause integer overflow, producing a small offset
that passes the subsequent bounds check and leads to an out-of-bounds
write into the MIDI data buffer.

Similarly, the bounds check `offset + len < midi_size` could itself
overflow, and the `used` size calculation from network-controlled
event_count and write_pos fields could overflow to bypass the size
check.

Fix by adding an explicit overflow check before the multiplication,
rewriting the bounds check to use subtraction (which cannot overflow
after the prior check), and adding an underflow check on the `used`
calculation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 17:47:27 +02:00
Wim Taymans
8d352fe52e security: fix integer overflow in PulseAudio message buffer allocation
Memory Safety: High

In ensure_size(), the check `m->length + size <= m->allocated` could
overflow when both m->length and size are large uint32_t values,
wrapping around to a small number and incorrectly passing the bounds
check. This could allow writing past the end of the allocated buffer.

Rewrite the check as `size <= m->allocated - m->length` which cannot
overflow since we already verified m->length <= m->allocated. Also add
an explicit overflow check for the new allocation size calculation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 17:46:47 +02:00
Wim Taymans
6798f591bd security: clear RAOP password from memory before freeing
Information Disclosure: Medium

The RAOP authentication password was freed without first clearing the
memory contents. This leaves the plaintext password in freed heap
memory where it could be recovered by an attacker with access to
process memory (e.g. via /proc/pid/mem, core dumps, or a separate
memory safety vulnerability).

Use explicit_bzero() to securely clear the password before freeing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 16:59:20 +02:00
Wim Taymans
440f24f35f security: fix missing strdup NULL checks in RAOP authentication
Memory Safety: High

In rtsp_do_options_auth(), the return values of strdup() for
auth_method, realm, and nonce were not checked for NULL. If strdup()
fails due to memory exhaustion, spa_streq() on auth_method will
dereference NULL, and the realm/nonce pointers will be used later in
MD5_hash() causing NULL pointer dereferences.

Add NULL checks after each strdup() call, returning -ENOMEM on failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 16:59:10 +02:00
Wim Taymans
135620ab64 security: fix missing malloc NULL checks in echo-cancel
Memory Safety: High

Three malloc calls for ring buffers (rec_buffer, play_buffer,
out_buffer) had no NULL checks. If any allocation fails, the
NULL pointers would be passed to memset and ringbuffer
operations in reset_buffers(), causing a NULL pointer
dereference crash.

Additionally, the ring size calculations used uint32_t
arithmetic which could overflow with large user-configurable
buffer.max_size values. Cast to size_t to perform the
multiplication in 64-bit, preventing intermediate overflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 16:25:19 +02:00
Wim Taymans
46e732c28b security: fix unbounded sprintf in RAOP MD5 hash formatting
Memory Safety: Low

sprintf was used to format MD5 hex digest bytes into a fixed-size
buffer without explicit bounds. While the output is bounded by the
fixed MD5 digest length (16 bytes = 32 hex chars), using snprintf
with an explicit size of 3 (2 hex chars + null) ensures correctness
even if the surrounding code changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 16:25:01 +02:00
Wim Taymans
6353eb526d security: fix unbounded sprintf in check_flatpak
Memory Safety: Medium

sprintf was used to format a /proc path without bounds checking.
While pid_t values are practically bounded, using snprintf with
sizeof(root_path) ensures the buffer cannot overflow regardless
of the input value, following defense-in-depth principles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 16:24:46 +02:00
Wim Taymans
c6ae30593c filter-graph: use convolver2 for sofa
We don't need 2 convolvers anymore, we can use the same convolver with
2 outputs with the left and right ir.

Add latency option to the sofa plugin. I believe the latency of the
SOFA filters is by default 0, so use that.
2026-04-21 16:52:49 +02:00
Wim Taymans
9cae4ce7e7 filter-chain: add convolver2
Add support for multiple convolver outputs. This makes things more
efficient because we only need to do the input FFT once to produce the N
outputs.

Add convolver2 that can have multiple outputs.
2026-04-21 16:24:38 +02:00
hackerman-kl
f0a33cddbd module-avb: es_builder: use the descriptor rather than a pointer to avoid overwriting it 2026-04-20 10:10:58 +02:00
hackerman-kl
e66a24dc5b modules-avb: legacy-avb: entity warnings 2026-04-19 08:15:55 +02:00
Wim Taymans
7df106bc25 filter-chain: deactivate when Format is unset
We need to deactivate the graph when the format was cleared on both the
input and output. This means we got suspended and we need to clear. We
can safely do this now because we take the right locks.
2026-04-17 13:05:28 +02:00
hackerman-kl
c551acf4d1 milan-avb: lock: make it lockable:
1. The period calls were added to handle timeouts.
2. Handle the case where lock must be unlocked after 60s if the
   controller owning the locked does not release it.
2026-04-16 12:42:23 +02:00
zuozhiwei
b4457b871f core: use %u format specifier for uint32_t IDs
The object, node, client, factory, module, and link IDs are all uint32_t values but were being formatted with %d.
This would produce incorrect negative values if an ID ever exceeded INT_MAX
2026-04-16 08:54:15 +00:00
Wim Taymans
e490c503fd pulse-server: update initial stream is_paused state
When the stream starts corked, we set the INACTIVE flag and we also need
to set the stream state as PAUSED or else uncork will not unpause
anything.
2026-04-15 18:25:28 +02:00
Wim Taymans
823dcd8843 scheduler: make nodes move to IDLE when inactive
When a node is inactive but linked to a driver, the only reason it is
not being scheduled is because it is inactive.

We already set up the links and negotiate the format and buffers to
prepare going to RUNNING. This patch now also make the node go to IDLE,
which makes the adapter negotiate a forma and buffers with the internal
node.

This makes things more symetrical, when linking a node, it becomes IDLE,
when activating it becomes RUNNABLE, when inactive it goes back to IDLE.
The switch to RUNNING will also be faster when things are already set up
in the IDLE state.

The main advantage is that it allows us to implement the startup of
corked streams in pulseaudio better. Before this patch we had to set the
stream to active to make it go through the Format and buffer negotiation
and then quickly set it back to inactive, hopefully without skipping a
cycle. After this patch, the corked stream goes all the way to IDLE,
where it then waits to become active.

See #4991
2026-04-14 14:28:29 +02:00
Wim Taymans
0cc3644e55 dlopen: support search path ending in /
When the search path is /usr/lib/, /usr/lib/foo.so fails to load because
there is no / after the search path. Fix this by requiring that either
the search path end with / or the following char is a /.
2026-04-13 10:26:33 +02:00
zuozhiwei
11d28c661b Fix spelling errors in comments and log messages
- Fix durring → during in es-builder.c error message
- Fix capabilty → capability in impl-port.c debug log
- Fix supress → suppress in rate-control.h comment

Improve code readability
2026-04-13 07:20:11 +00:00
Wim Taymans
c2f85ffc51 filter-chain: improve docs
Add the default values to the docs for some of the convolver config
variables.
2026-04-09 16:35:17 +02:00
Christian F.K. Schaller
14310e66fe module-avb: extend transport abstraction to stream data path
Add stream_setup_socket and stream_send ops to avb_transport_ops so the
stream data plane can use the same pluggable transport backend as the
control plane. Move the raw AF_PACKET socket setup from stream.c into
avdecc.c as raw_stream_setup_socket(), and add a raw_stream_send()
wrapper around sendmsg().

Add a stream list (spa_list) to struct server so streams can be iterated
after creation, and add stream_activate_virtual() for lightweight
activation without MRP/MAAP network operations.

Implement loopback stream ops: eventfd-based dummy sockets and no-op
send that discards audio data. This enables virtual AVB nodes that work
without network hardware or privileges.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
ef4ff8cfd0 test: add AVB protocol test suite with loopback transport
Add a test suite for the AVB (Audio Video Bridging) protocol stack that
runs entirely in software, requiring no hardware, root privileges, or
running PipeWire daemon.

The loopback transport (avb-transport-loopback.h) replaces raw AF_PACKET
sockets with in-memory packet capture, using a synthetic MAC address and
eventfd for protocol handlers that need a valid fd.

Test utilities (test-avb-utils.h) provide helpers for creating test
servers, injecting packets, advancing time, and building ADP packets.

Tests cover:
- ADP entity available/departing/discover/timeout
- MRP attribute lifecycle (create, begin, join)
- Milan v1.2 mode server creation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00
Christian F.K. Schaller
a73988d38d module-avb: add transport abstraction for pluggable network backends
Introduce struct avb_transport_ops vtable with setup/send_packet/
make_socket/destroy callbacks. The existing raw AF_PACKET socket code
becomes the default "raw" transport. avdecc_server_new() defaults to
avb_transport_raw if no transport is set, and avdecc_server_free()
delegates cleanup through the transport ops.

This enables alternative transports (e.g. loopback for testing) without
modifying protocol handler code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 07:43:19 +00:00