cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ssh.rst (14572B)


      1.. SPDX-License-Identifier: GPL-2.0+
      2
      3.. |u8| replace:: :c:type:`u8 <u8>`
      4.. |u16| replace:: :c:type:`u16 <u16>`
      5.. |TYPE| replace:: ``TYPE``
      6.. |LEN| replace:: ``LEN``
      7.. |SEQ| replace:: ``SEQ``
      8.. |SYN| replace:: ``SYN``
      9.. |NAK| replace:: ``NAK``
     10.. |ACK| replace:: ``ACK``
     11.. |DATA| replace:: ``DATA``
     12.. |DATA_SEQ| replace:: ``DATA_SEQ``
     13.. |DATA_NSQ| replace:: ``DATA_NSQ``
     14.. |TC| replace:: ``TC``
     15.. |TID| replace:: ``TID``
     16.. |IID| replace:: ``IID``
     17.. |RQID| replace:: ``RQID``
     18.. |CID| replace:: ``CID``
     19
     20===========================
     21Surface Serial Hub Protocol
     22===========================
     23
     24The Surface Serial Hub (SSH) is the central communication interface for the
     25embedded Surface Aggregator Module controller (SAM or EC), found on newer
     26Surface generations. We will refer to this protocol and interface as
     27SAM-over-SSH, as opposed to SAM-over-HID for the older generations.
     28
     29On Surface devices with SAM-over-SSH, SAM is connected to the host via UART
     30and defined in ACPI as device with ID ``MSHW0084``. On these devices,
     31significant functionality is provided via SAM, including access to battery
     32and power information and events, thermal read-outs and events, and many
     33more. For Surface Laptops, keyboard input is handled via HID directed
     34through SAM, on the Surface Laptop 3 and Surface Book 3 this also includes
     35touchpad input.
     36
     37Note that the standard disclaimer for this subsystem also applies to this
     38document: All of this has been reverse-engineered and may thus be erroneous
     39and/or incomplete.
     40
     41All CRCs used in the following are two-byte ``crc_ccitt_false(0xffff, ...)``.
     42All multi-byte values are little-endian, there is no implicit padding between
     43values.
     44
     45
     46SSH Packet Protocol: Definitions
     47================================
     48
     49The fundamental communication unit of the SSH protocol is a frame
     50(:c:type:`struct ssh_frame <ssh_frame>`). A frame consists of the following
     51fields, packed together and in order:
     52
     53.. flat-table:: SSH Frame
     54   :widths: 1 1 4
     55   :header-rows: 1
     56
     57   * - Field
     58     - Type
     59     - Description
     60
     61   * - |TYPE|
     62     - |u8|
     63     - Type identifier of the frame.
     64
     65   * - |LEN|
     66     - |u16|
     67     - Length of the payload associated with the frame.
     68
     69   * - |SEQ|
     70     - |u8|
     71     - Sequence ID (see explanation below).
     72
     73Each frame structure is followed by a CRC over this structure. The CRC over
     74the frame structure (|TYPE|, |LEN|, and |SEQ| fields) is placed directly
     75after the frame structure and before the payload. The payload is followed by
     76its own CRC (over all payload bytes). If the payload is not present (i.e.
     77the frame has ``LEN=0``), the CRC of the payload is still present and will
     78evaluate to ``0xffff``. The |LEN| field does not include any of the CRCs, it
     79equals the number of bytes inbetween the CRC of the frame and the CRC of the
     80payload.
     81
     82Additionally, the following fixed two-byte sequences are used:
     83
     84.. flat-table:: SSH Byte Sequences
     85   :widths: 1 1 4
     86   :header-rows: 1
     87
     88   * - Name
     89     - Value
     90     - Description
     91
     92   * - |SYN|
     93     - ``[0xAA, 0x55]``
     94     - Synchronization bytes.
     95
     96A message consists of |SYN|, followed by the frame (|TYPE|, |LEN|, |SEQ| and
     97CRC) and, if specified in the frame (i.e. ``LEN > 0``), payload bytes,
     98followed finally, regardless if the payload is present, the payload CRC. The
     99messages corresponding to an exchange are, in part, identified by having the
    100same sequence ID (|SEQ|), stored inside the frame (more on this in the next
    101section). The sequence ID is a wrapping counter.
    102
    103A frame can have the following types
    104(:c:type:`enum ssh_frame_type <ssh_frame_type>`):
    105
    106.. flat-table:: SSH Frame Types
    107   :widths: 1 1 4
    108   :header-rows: 1
    109
    110   * - Name
    111     - Value
    112     - Short Description
    113
    114   * - |NAK|
    115     - ``0x04``
    116     - Sent on error in previously received message.
    117
    118   * - |ACK|
    119     - ``0x40``
    120     - Sent to acknowledge receival of |DATA| frame.
    121
    122   * - |DATA_SEQ|
    123     - ``0x80``
    124     - Sent to transfer data. Sequenced.
    125
    126   * - |DATA_NSQ|
    127     - ``0x00``
    128     - Same as |DATA_SEQ|, but does not need to be ACKed.
    129
    130Both |NAK|- and |ACK|-type frames are used to control flow of messages and
    131thus do not carry a payload. |DATA_SEQ|- and |DATA_NSQ|-type frames on the
    132other hand must carry a payload. The flow sequence and interaction of
    133different frame types will be described in more depth in the next section.
    134
    135
    136SSH Packet Protocol: Flow Sequence
    137==================================
    138
    139Each exchange begins with |SYN|, followed by a |DATA_SEQ|- or
    140|DATA_NSQ|-type frame, followed by its CRC, payload, and payload CRC. In
    141case of a |DATA_NSQ|-type frame, the exchange is then finished. In case of a
    142|DATA_SEQ|-type frame, the receiving party has to acknowledge receival of
    143the frame by responding with a message containing an |ACK|-type frame with
    144the same sequence ID of the |DATA| frame. In other words, the sequence ID of
    145the |ACK| frame specifies the |DATA| frame to be acknowledged. In case of an
    146error, e.g. an invalid CRC, the receiving party responds with a message
    147containing an |NAK|-type frame. As the sequence ID of the previous data
    148frame, for which an error is indicated via the |NAK| frame, cannot be relied
    149upon, the sequence ID of the |NAK| frame should not be used and is set to
    150zero. After receival of an |NAK| frame, the sending party should re-send all
    151outstanding (non-ACKed) messages.
    152
    153Sequence IDs are not synchronized between the two parties, meaning that they
    154are managed independently for each party. Identifying the messages
    155corresponding to a single exchange thus relies on the sequence ID as well as
    156the type of the message, and the context. Specifically, the sequence ID is
    157used to associate an ``ACK`` with its ``DATA_SEQ``-type frame, but not
    158``DATA_SEQ``- or ``DATA_NSQ``-type frames with other ``DATA``- type frames.
    159
    160An example exchange might look like this:
    161
    162::
    163
    164    tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
    165    rx: ------------------------------------- SYN FRAME(A) CRC(F) CRC(P) --
    166
    167where both frames have the same sequence ID (``SEQ``). Here, ``FRAME(D)``
    168indicates a |DATA_SEQ|-type frame, ``FRAME(A)`` an ``ACK``-type frame,
    169``CRC(F)`` the CRC over the previous frame, ``CRC(P)`` the CRC over the
    170previous payload. In case of an error, the exchange would look like this:
    171
    172::
    173
    174    tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
    175    rx: ------------------------------------- SYN FRAME(N) CRC(F) CRC(P) --
    176
    177upon which the sender should re-send the message. ``FRAME(N)`` indicates an
    178|NAK|-type frame. Note that the sequence ID of the |NAK|-type frame is fixed
    179to zero. For |DATA_NSQ|-type frames, both exchanges are the same:
    180
    181::
    182
    183    tx: -- SYN FRAME(DATA_NSQ) CRC(F) PAYLOAD CRC(P) ----------------------
    184    rx: -------------------------------------------------------------------
    185
    186Here, an error can be detected, but not corrected or indicated to the
    187sending party. These exchanges are symmetric, i.e. switching ``rx`` and
    188``tx`` results again in a valid exchange. Currently, no longer exchanges are
    189known.
    190
    191
    192Commands: Requests, Responses, and Events
    193=========================================
    194
    195Commands are sent as payload inside a data frame. Currently, this is the
    196only known payload type of |DATA| frames, with a payload-type value of
    197``0x80`` (:c:type:`SSH_PLD_TYPE_CMD <ssh_payload_type>`).
    198
    199The command-type payload (:c:type:`struct ssh_command <ssh_command>`)
    200consists of an eight-byte command structure, followed by optional and
    201variable length command data. The length of this optional data is derived
    202from the frame payload length given in the corresponding frame, i.e. it is
    203``frame.len - sizeof(struct ssh_command)``. The command struct contains the
    204following fields, packed together and in order:
    205
    206.. flat-table:: SSH Command
    207   :widths: 1 1 4
    208   :header-rows: 1
    209
    210   * - Field
    211     - Type
    212     - Description
    213
    214   * - |TYPE|
    215     - |u8|
    216     - Type of the payload. For commands always ``0x80``.
    217
    218   * - |TC|
    219     - |u8|
    220     - Target category.
    221
    222   * - |TID| (out)
    223     - |u8|
    224     - Target ID for outgoing (host to EC) commands.
    225
    226   * - |TID| (in)
    227     - |u8|
    228     - Target ID for incoming (EC to host) commands.
    229
    230   * - |IID|
    231     - |u8|
    232     - Instance ID.
    233
    234   * - |RQID|
    235     - |u16|
    236     - Request ID.
    237
    238   * - |CID|
    239     - |u8|
    240     - Command ID.
    241
    242The command struct and data, in general, does not contain any failure
    243detection mechanism (e.g. CRCs), this is solely done on the frame level.
    244
    245Command-type payloads are used by the host to send commands and requests to
    246the EC as well as by the EC to send responses and events back to the host.
    247We differentiate between requests (sent by the host), responses (sent by the
    248EC in response to a request), and events (sent by the EC without a preceding
    249request).
    250
    251Commands and events are uniquely identified by their target category
    252(``TC``) and command ID (``CID``). The target category specifies a general
    253category for the command (e.g. system in general, vs. battery and AC, vs.
    254temperature, and so on), while the command ID specifies the command inside
    255that category. Only the combination of |TC| + |CID| is unique. Additionally,
    256commands have an instance ID (``IID``), which is used to differentiate
    257between different sub-devices. For example ``TC=3`` ``CID=1`` is a
    258request to get the temperature on a thermal sensor, where |IID| specifies
    259the respective sensor. If the instance ID is not used, it should be set to
    260zero. If instance IDs are used, they, in general, start with a value of one,
    261whereas zero may be used for instance independent queries, if applicable. A
    262response to a request should have the same target category, command ID, and
    263instance ID as the corresponding request.
    264
    265Responses are matched to their corresponding request via the request ID
    266(``RQID``) field. This is a 16 bit wrapping counter similar to the sequence
    267ID on the frames. Note that the sequence ID of the frames for a
    268request-response pair does not match. Only the request ID has to match.
    269Frame-protocol wise these are two separate exchanges, and may even be
    270separated, e.g. by an event being sent after the request but before the
    271response. Not all commands produce a response, and this is not detectable by
    272|TC| + |CID|. It is the responsibility of the issuing party to wait for a
    273response (or signal this to the communication framework, as is done in
    274SAN/ACPI via the ``SNC`` flag).
    275
    276Events are identified by unique and reserved request IDs. These IDs should
    277not be used by the host when sending a new request. They are used on the
    278host to, first, detect events and, second, match them with a registered
    279event handler. Request IDs for events are chosen by the host and directed to
    280the EC when setting up and enabling an event source (via the
    281enable-event-source request). The EC then uses the specified request ID for
    282events sent from the respective source. Note that an event should still be
    283identified by its target category, command ID, and, if applicable, instance
    284ID, as a single event source can send multiple different event types. In
    285general, however, a single target category should map to a single reserved
    286event request ID.
    287
    288Furthermore, requests, responses, and events have an associated target ID
    289(``TID``). This target ID is split into output (host to EC) and input (EC to
    290host) fields, with the respecting other field (e.g. output field on incoming
    291messages) set to zero. Two ``TID`` values are known: Primary (``0x01``) and
    292secondary (``0x02``). In general, the response to a request should have the
    293same ``TID`` value, however, the field (output vs. input) should be used in
    294accordance to the direction in which the response is sent (i.e. on the input
    295field, as responses are generally sent from the EC to the host).
    296
    297Note that, even though requests and events should be uniquely identifiable
    298by target category and command ID alone, the EC may require specific
    299target ID and instance ID values to accept a command. A command that is
    300accepted for ``TID=1``, for example, may not be accepted for ``TID=2``
    301and vice versa.
    302
    303
    304Limitations and Observations
    305============================
    306
    307The protocol can, in theory, handle up to ``U8_MAX`` frames in parallel,
    308with up to ``U16_MAX`` pending requests (neglecting request IDs reserved for
    309events). In practice, however, this is more limited. From our testing
    310(although via a python and thus a user-space program), it seems that the EC
    311can handle up to four requests (mostly) reliably in parallel at a certain
    312time. With five or more requests in parallel, consistent discarding of
    313commands (ACKed frame but no command response) has been observed. For five
    314simultaneous commands, this reproducibly resulted in one command being
    315dropped and four commands being handled.
    316
    317However, it has also been noted that, even with three requests in parallel,
    318occasional frame drops happen. Apart from this, with a limit of three
    319pending requests, no dropped commands (i.e. command being dropped but frame
    320carrying command being ACKed) have been observed. In any case, frames (and
    321possibly also commands) should be re-sent by the host if a certain timeout
    322is exceeded. This is done by the EC for frames with a timeout of one second,
    323up to two re-tries (i.e. three transmissions in total). The limit of
    324re-tries also applies to received NAKs, and, in a worst case scenario, can
    325lead to entire messages being dropped.
    326
    327While this also seems to work fine for pending data frames as long as no
    328transmission failures occur, implementation and handling of these seems to
    329depend on the assumption that there is only one non-acknowledged data frame.
    330In particular, the detection of repeated frames relies on the last sequence
    331number. This means that, if a frame that has been successfully received by
    332the EC is sent again, e.g. due to the host not receiving an |ACK|, the EC
    333will only detect this if it has the sequence ID of the last frame received
    334by the EC. As an example: Sending two frames with ``SEQ=0`` and ``SEQ=1``
    335followed by a repetition of ``SEQ=0`` will not detect the second ``SEQ=0``
    336frame as such, and thus execute the command in this frame each time it has
    337been received, i.e. twice in this example. Sending ``SEQ=0``, ``SEQ=1`` and
    338then repeating ``SEQ=1`` will detect the second ``SEQ=1`` as repetition of
    339the first one and ignore it, thus executing the contained command only once.
    340
    341In conclusion, this suggests a limit of at most one pending un-ACKed frame
    342(per party, effectively leading to synchronous communication regarding
    343frames) and at most three pending commands. The limit to synchronous frame
    344transfers seems to be consistent with behavior observed on Windows.