Commit Graph

2325 Commits

Author SHA1 Message Date
Enrico Weigelt, metux IT consult b335a0fa20 dix: unexport CloseDownClient()
This function isn't used by drivers, so no need to export it.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1383>
2024-03-13 00:47:36 +00:00
Enrico Weigelt, metux IT consult d84fd3bf19 dix: drop now obsolete cursorScreenDevPriv
Since the two DDX'es which had used this key (xnest and xfree86) now using
their own ones, this global key is obsolete and can be removed.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1342>
2024-03-12 15:24:35 +00:00
Enrico Weigelt, metux IT consult 7f13fc7d2f dix: unexport callback manager init / teardown functions
Those are only needed inside DIX, thus no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1346>
2024-03-12 15:18:17 +00:00
Enrico Weigelt, metux IT consult 738edd3501 dix: unexport eventconvert.h functions
This header isn't installed, so no external modules could use the
functions declared there. Thus we can unexport it all.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1358>
2024-03-11 12:26:44 +01:00
Enrico Weigelt, metux IT consult 2a5e754275 dix: unexport SetAccelerationProfile()
Not used by any module, just locally within one source file, thus
unexport and make it static

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1347>
2024-03-09 18:01:52 +00:00
Enrico Weigelt, metux IT consult 1b983d7e82 dix: unexport FreeVelocityData()
Only used within one source, not used by external modules, thus unexport
and make it static.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1347>
2024-03-09 18:01:52 +00:00
Enrico Weigelt, metux IT consult 9d3766080b dix: unexport BasicComputeAcceleration()
only used locally within one source file, so unexport and make it static.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1347>
2024-03-09 18:01:52 +00:00
Enrico Weigelt, metux IT consult a09f2540d2 dix: unexport ProcessVelocityData2D()
Only used with on source file, so unexport and make it static.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1347>
2024-03-09 18:01:52 +00:00
Enrico Weigelt, metux IT consult b598727f1c dix: unexport InitTrackers()
Not used by any modules, thus no need to export it.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1347>
2024-03-09 18:01:52 +00:00
Enrico Weigelt, metux IT consult 4db1f3f760 dix: unexport InitVelocityData()
Not used by any modules, not even outside the source file, thus
no need to export it.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1347>
2024-03-09 18:01:52 +00:00
Enrico Weigelt, metux IT consult a3ebe4fa41 dix: move non-exported ptrveloc functions to separate header
unclutter ptrveloc.h by moving non-exported declarations into their own
private header file.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1347>
2024-03-09 18:01:52 +00:00
Enrico Weigelt, metux IT consult 040e41c7e9 dix: unexport global variables
Those aren't used by drivers, so no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1375>
2024-03-09 17:23:43 +00:00
Enrico Weigelt, metux IT consult b1ce5543f1 dix: unexport workqueue functions
These aren't used by drivers, so no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1376>
2024-03-07 22:57:53 +00:00
Enrico Weigelt, metux IT consult 53a0442b87 drop remains of DMX
DMX has long gone, but there's still some fallout from it's removal
yet to be cleaned up.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1362>
2024-03-05 16:57:52 +01:00
Enrico Weigelt, metux IT consult 6999bc49d3 dix: unexport AttachOffloadGPU() and DetachOffloadGPU()
These aren't externally used, thus no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1349>
2024-03-03 23:24:29 +00:00
Enrico Weigelt, metux IT consult 1277bb7143 dix: unexport AttachOutputGPU() and DetachOutputGPU()
These aren't externally used, thus no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1349>
2024-03-03 23:24:28 +00:00
Enrico Weigelt, metux IT consult 71b81a7473 dix: unexport AttachUnboundGPU() and DetachUnboundGPU()
These aren't externally used, thus no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1349>
2024-03-03 23:24:28 +00:00
Enrico Weigelt, metux IT consult 55dc4a8bdc dix: unexport RemoveGPUScreen()
This function isn't used by any modules/drivers, so no need to export it.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1349>
2024-03-03 23:24:28 +00:00
Enrico Weigelt, metux IT consult 27b83c4cd0 dix: unexport AddScreen() and AddGPUScreen()
These aren't used by any drivers/modules, just DDX'es, so no need to export.

Note: tigervnc does use it, but it has it's own DDX, therefore directly
linked in, just like the in-tree DDX'es which doesn't need exporting.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1349>
2024-03-03 23:24:28 +00:00
Enrico Weigelt, metux IT consult dc84331f5d include: drop obsolete registry.h
Now that there's no actual consumer of it left, it can be dropped.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1348>
2024-03-03 23:20:06 +00:00
Enrico Weigelt, metux IT consult 5f5d55be88 dix: unexport XREGISTRY_UNKNOWN define
It's not used by external modules, thus no need to have it in the
public API.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1348>
2024-03-03 23:20:06 +00:00
Enrico Weigelt, metux IT consult 4ebb02cdda dix: unexport extension registry functions
These aren't used by (known) external modules, thus no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1348>
2024-03-03 23:20:06 +00:00
Enrico Weigelt, metux IT consult 1f5ab6ec28 dix: unexport RegisterResourceName() and LookupResourceName()
These aren't used by external modules, thus no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1348>
2024-03-03 23:20:06 +00:00
Enrico Weigelt, metux IT consult 36e2cf64c8 dix: unexport registry setup/teardown functions
these aren't to be called by modules, thus no need to export them.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1348>
2024-03-03 23:20:06 +00:00
Enrico Weigelt, metux IT consult 489485ea7d dix: drop duplicate _X_EXPORT
These are already defined in privates.h

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1274>
2024-03-03 22:34:26 +00:00
Enrico Weigelt, metux IT consult fe1e2b7b3d dix: unexport and move maxBigRequestSize
* this symbol is a server configuration flag (can be passed via cmdline)
  for limiting the max size of big-requests. there shouldn't be any need
  to use it outside the core X server (in server modules like drivers
  or external extension) - therefore unexport it
* in order to reduce namespace pollution of public (server module API)
  headers, create a new internal header for those tings (more to come)

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1275>
2024-02-23 23:19:32 +00:00
Peter Hutterer eaa92ea422 Revert "include: move BUG_*() macros to separate header"
This breaks the xf86-input-synaptics driver:

  synaptics.c: In function 'clickpad_guess_clickfingers':
  synaptics.c:2638:5: error: implicit declaration of function 'BUG_RETURN_VAL' [-Werror=implicit-function-declaration]
   2638 |     BUG_RETURN_VAL(hw->num_mt_mask > sizeof(close_point) * 8, 0);

This reverts commit 442aec2219.

Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1316>
2024-02-23 23:11:01 +00:00
Enrico Weigelt, metux IT consult af9f70013a dix: dixutils: make workQueue pointer dix-private
The workQueue pointer is currently declared extern, so that WaitForSomething()
can check wether we've got something in the queue and call ProcessWorkQueue()
then.

But that's trivial to simplify: just let ProcessWorkQueue() return early if
workQueue == NULL. Gives us a better isolation of internal stuff as well as
ProcessWorkQueue() protecting itself from possible segfault.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1310>
2024-02-23 23:06:38 +00:00
Enrico Weigelt 442aec2219 include: move BUG_*() macros to separate header
Yet another step of uncluttering includes: move out the BUG_* macros
into a separate header, which then is included as-needed.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2024-02-15 23:33:46 +00:00
Enrico Weigelt, metux IT consult b3b86ae674 replace _X_INLINE by inline in internal static functions
Since xserver is compiled as C99, we just can use the `inline` keyword.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2024-02-05 19:26:14 +00:00
Wanli Niu e62246641b dix: Fix segfault if CreateGC() failed in XaceHook()
CreateGC() allocates a new GC and then checks the resource access rights
with XaceHook().

If the call to XaceHook() fails (i.e. GC creation is not granted to the
client), CreateGC() exits early and calls FreeGC() to avoid leaking the
newly allocated GC.

If that happens, the screen's own CreateGC() has not yet been invoked,
and as a result the GC functions (GCfuncs) have not been set yet.

FreeGC() will invoke the funcs->DestroyClip() and the funcs->DestroyGC()
functions, but since those haven't been set, the Xserver will segfault
trying to call a NULL function.

To prevent that issue, make sure the GC's functions are initialized
prior to call them in FreeGC().

Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1625
Reviewed-by: Olivier Fourdan <ofourdan@redhat.com>
2024-02-01 10:10:53 +01:00
Peter Hutterer 133e0d651c dix: fix valuator copy/paste error in the DeviceStateNotify event
Fixes 219c54b8a3
2024-01-22 21:24:58 +00:00
Peter Hutterer 26769aa71f dix: when disabling a master, float disabled slaved devices too
Disabling a master device floats all slave devices but we didn't do this
to already-disabled slave devices. As a result those devices kept their
reference to the master device resulting in access to already freed
memory if the master device was removed before the corresponding slave
device.

And to match this behavior, also forcibly reset that pointer during
CloseDownDevices().

Related to CVE-2024-21886, ZDI-CAN-22840
2024-01-16 09:24:31 +01:00
José Expósito bc1fdbe465 Xi: do not keep linked list pointer during recursion
The `DisableDevice()` function is called whenever an enabled device
is disabled and it moves the device from the `inputInfo.devices` linked
list to the `inputInfo.off_devices` linked list.

However, its link/unlink operation has an issue during the recursive
call to `DisableDevice()` due to the `prev` pointer pointing to a
removed device.

This issue leads to a length mismatch between the total number of
devices and the number of device in the list, leading to a heap
overflow and, possibly, to local privilege escalation.

Simplify the code that checked whether the device passed to
`DisableDevice()` was in `inputInfo.devices` or not and find the
previous device after the recursion.

CVE-2024-21886, ZDI-CAN-22840

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
2024-01-16 09:24:31 +01:00
Peter Hutterer 219c54b8a3 dix: fix DeviceStateNotify event calculation
The previous code only made sense if one considers buttons and keys to
be mutually exclusive on a device. That is not necessarily true, causing
a number of issues.

This function allocates and fills in the number of xEvents we need to
send the device state down the wire.  This is split across multiple
32-byte devices including one deviceStateNotify event and optional
deviceKeyStateNotify, deviceButtonStateNotify and (possibly multiple)
deviceValuator events.

The previous behavior would instead compose a sequence
of [state, buttonstate, state, keystate, valuator...]. This is not
protocol correct, and on top of that made the code extremely convoluted.

Fix this by streamlining: add both button and key into the deviceStateNotify
and then append the key state and button state, followed by the
valuators. Finally, the deviceValuator events contain up to 6 valuators
per event but we only ever sent through 3 at a time. Let's double that
troughput.

CVE-2024-0229, ZDI-CAN-22678

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
2024-01-16 09:24:01 +01:00
Peter Hutterer ece23be888 dix: Allocate sufficient xEvents for our DeviceStateNotify
If a device has both a button class and a key class and numButtons is
zero, we can get an OOB write due to event under-allocation.

This function seems to assume a device has either keys or buttons, not
both. It has two virtually identical code paths, both of which assume
they're applying to the first event in the sequence.

A device with both a key and button class triggered a logic bug - only
one xEvent was allocated but the deviceStateNotify pointer was pushed on
once per type. So effectively this logic code:

   int count = 1;
   if (button && nbuttons > 32) count++;
   if (key && nbuttons > 0) count++;
   if (key && nkeys > 32) count++; // this is basically always true
   // count is at 2 for our keys + zero button device

   ev = alloc(count * sizeof(xEvent));
   FixDeviceStateNotify(ev);
   if (button)
     FixDeviceStateNotify(ev++);
   if (key)
     FixDeviceStateNotify(ev++);   // santa drops into the wrong chimney here

If the device has more than 3 valuators, the OOB is pushed back - we're
off by one so it will happen when the last deviceValuator event is
written instead.

Fix this by allocating the maximum number of events we may allocate.
Note that the current behavior is not protocol-correct anyway, this
patch fixes only the allocation issue.

Note that this issue does not trigger if the device has at least one
button. While the server does not prevent a button class with zero
buttons, it is very unlikely.

CVE-2024-0229, ZDI-CAN-22678

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
2024-01-16 09:24:01 +01:00
Peter Hutterer 9e2ecb2af8 dix: allocate enough space for logical button maps
Both DeviceFocusEvent and the XIQueryPointer reply contain a bit for
each logical button currently down. Since buttons can be arbitrarily mapped
to anything up to 255 make sure we have enough bits for the maximum mapping.

CVE-2023-6816, ZDI-CAN-22664, ZDI-CAN-22665

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
2024-01-16 09:23:47 +01:00
Peter Hutterer de0031eefd dix: initialize the XTest sendEventsProc for all devices
XTest requests lets the client specify a device ID, only if none
is specified do we fall back to the XTEST special device.
As of commit
  aa4074251 input: Add new hook DeviceSendEventsProc for XTEST
regular devices are no longer able to send XTest events because they
have no sendEventsProc set.

This caused issue #1574 and the crash was fixed with commit
  e820030de xtest: Check whether there is a sendEventsProc to call
but we still cannot send XTest events through a specific device.

Fix this by defaulting every device to the XTest send function and
punting it to the DDX (i.e. Xwayland) to override the devices as
necessary.

Fixes e820030de2
Fixes aa4074251f
2024-01-09 00:45:31 +00:00
Peter Hutterer d0b0137a95 Two whitespace fixes 2024-01-09 09:49:54 +10:00
Peter Hutterer 0a9f223eec dix: factor out the duplicate the RemoveDevice code paths
This is the same loop twice, once over inputInfo.devices and once over
inputInfo.off_devices, let's make both the same.
2024-01-09 09:49:54 +10:00
Peter Hutterer 2cee5fb36c test: fix various leaks in the tests 2024-01-09 09:49:54 +10:00
Peter Hutterer 373cd80081 dix: use valuator_mask_free() to free the last touches vmask
No functional effect since that one is just a free() call anyway.
2024-01-09 09:49:54 +10:00
Peter Hutterer 7aba2514b2 dix: don't allow for devices with 0 axes
This just makes the existing behavior explicit, previously we relied on
a malloc(numAxes * ...) to return NULL to error out.
2024-01-09 09:49:54 +10:00
Peter Hutterer 0c1a93d319 Xi: allocate enough XkbActions for our buttons
button->xkb_acts is supposed to be an array sufficiently large for all
our buttons, not just a single XkbActions struct. Allocating
insufficient memory here means when we memcpy() later in
XkbSetDeviceInfo we write into memory that wasn't ours to begin with,
leading to the usual security ooopsiedaisies.

CVE-2023-6377, ZDI-CAN-22412, ZDI-CAN-22413

This vulnerability was discovered by:
Jan-Niklas Sohn working with Trend Micro Zero Day Initiative
2023-12-13 10:44:49 +10:00
Peter Hutterer 45009fb7f5 dix: clean up the GestureInfoRec on device close
Direct leak of 1080 byte(s) in 3 object(s) allocated from:
    #0 0x7f00a4ed8cc7 in calloc (/lib64/libasan.so.8+0xd8cc7) (BuildId: 6f17f87dc4c1aa9f9dde7c4856604c3a25ba4872)
    #1 0x59f740 in InitGestureClassDeviceStruct ../dix/devices.c:1692
    #2 0x418a0b in xwl_pointer_proc_pointer_gestures ../hw/xwayland/xwayland-input.c:325
    #3 0x598e5c in ActivateDevice ../dix/devices.c:578
    #4 0x420207 in init_pointer_gestures_device ../hw/xwayland/xwayland-input.c:1677
    #5 0x420bf1 in seat_handle_capabilities ../hw/xwayland/xwayland-input.c:1801
    #6 0x7f00a4145055 in ffi_call_unix64 (/lib64/libffi.so.8+0x9055) (BuildId: 308041eea4a8d89d9265d3c24b7261dfbe44a61e)

Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2023-12-05 14:21:28 +10:00
Peter Hutterer 564ccf2ce9 mi: reset the PointerWindows reference on screen switch
PointerWindows[] keeps a reference to the last window our sprite
entered - changes are usually handled by CheckMotion().

If we switch between screens via XWarpPointer our
dev->spriteInfo->sprite->win is set to the new screen's root window.
If there's another window at the cursor location CheckMotion() will
trigger the right enter/leave events later. If there is not, it skips
that process and we never trigger LeaveWindow() - PointerWindows[] for
the device still refers to the previous window.

If that window is destroyed we have a dangling reference that will
eventually cause a use-after-free bug when checking the window hierarchy
later.

To trigger this, we require:
- two protocol screens
- XWarpPointer to the other screen's root window
- XDestroyWindow before entering any other window

This is a niche bug so we hack around it by making sure we reset the
PointerWindows[] entry so we cannot have a dangling pointer. This
doesn't handle Enter/Leave events correctly but the previous code didn't
either.

CVE-2023-5380, ZDI-CAN-21608

This vulnerability was discovered by:
Sri working with Trend Micro Zero Day Initiative

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Adam Jackson <ajax@redhat.com>
2023-10-25 00:37:47 +00:00
Alan Coopersmith d6b20f5e36 Remove "All rights reserved" from Oracle copyright notices
Oracle no longer includes this term in our copyright & license notices.

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
2023-02-25 09:40:41 -08:00
Yao Wei 7ce57e179b dix: Force update LEDs after device state update in EnableDevice
This is to make sure the hardware gets the device states regardless
whether the internal state has changed or not, to overcome situations
that device LEDs are out of sync e.g. switching between VTs.

Signed-off-by: Yao Wei (魏銘廷) <yao.wei@canonical.com>
2023-02-21 03:43:05 +00:00
Peter Hutterer d2158d4063 dix: fix wheel emulation lockup when a negative increment is set
The increment sign wasn't taking into account when checking if the next
value is past our current value. The result was that for negative
increments, we kept looping indefinitely, locking up the server.

Easiest to reproduce with the evdev driver which has a negative
increment on the y axis.

Fixes 0a22502c34
  dix: switch scroll button emulation to multiples of increment

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2023-02-20 15:11:23 +10:00
Peter Hutterer 0a22502c34 dix: switch scroll button emulation to multiples of increment
The current algorithm triggers a bug in Xwayland when two devices have
different granularity of scrolling. In Xwayland, the scroll increment is
1 and all physical devices scroll through the same (x)wayland pointer
device.

This may cause events to get lost when changing devices:
- mouse scrolls by full increment, current value is 1.0
  last scroll button was sent for valuator value 0.0,
  delta is 1.0 and we emulate a button event.
- touchpad scrolls by partial increment, current value is 1.3
  last scroll button was sent for valuator value 1.0, delta is 0.3
  and no button event is emulated
- mouse scrolls by full increment, current value is -0.7,
  last scroll button was sent for valuator value 1.0, delta is -0.7
  and no button event is emulated

Thus the wheel event appears to get lost. Xwayland cannot reliably
detect this case because we don't see the physical devices.

We can work around this by instead emulating buttons whenever we cross
a multiple of increment. However, this has a drawback:
high-resolution scroll devices can now trigger a button event storm by
jittering across the multiple of increment. e.g. in the example above
the touchpad moving from 1.3 to 1.0 would cause a click, despite this
being a third of an increment.

Fixes #1339

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Acked-by: Olivier Fourdan <ofourdan@redhat.com>
2023-02-16 10:25:16 +00:00