Skip to content

Possible unaligned access in TCP mode #28

@LGA1150

Description

@LGA1150

In UDP mode, a received OpenVPN data packet typically looks like:

IP header || UDP header || 4-byte opcode || 4-byte seq-no || 16-byte AEAD tag || ciphertext

The data area begins right after the UDP header, as long as the outer IP header is aligned, the 4-byte opcode and subsequent fields are also aligned.

In TCP mode, because TCP is a byte stream, an OpenVPN data packet may start at any offset within the TCP payload.

For example, a TCP segment may contain:

IP header || TCP header || 2-byte length || 4-byte opcode || 4-byte seq-no || 16-byte AEAD tag || ciphertext

or, if a packet spans multiple segments:

IP header || TCP header || (tail of previous ciphertext) || 2-byte length || 4-byte opcode || 4-byte seq-no || ...

ovpn uses strparser to process the TCP stream. strparser does not copy packet data - it only clones skbs and uses skb_shared_info::frag_list for continuation when one data packet spans multiple TCP segments.

As a result:

  • The 4-byte opcode and 4-byte sequence number are not guaranteed to be aligned.
  • After in-place decryption, the inner IP header may also become unaligned.

This is problematic on architectures without efficient unaligned access, such as MIPS. On MIPS, unaligned memory access triggers an exception and must be fixed in the exception handler (i.e., the cost is comparable to a syscall). Because the inner IP header is accessed multiple times during packet processing, this can severely impact performance.

The previous ovpn-dco module (and userspace implementation) did not suffer from this issue, because packet data were always copied into a newly allocated skb.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions