gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/website/blog/2020-04-02-networking-security.md (about)

     1  # gVisor Networking Security
     2  
     3  In our
     4  [first blog post](https://gvisor.dev/blog/2019/11/18/gvisor-security-basics-part-1/),
     5  we covered some secure design principles and how they guided the architecture of
     6  gVisor as a whole. In this post, we will cover how these principles guided the
     7  networking architecture of gVisor, and the tradeoffs involved. In particular, we
     8  will cover how these principles culminated in two networking modes, how they
     9  work, and the properties of each.
    10  
    11  ## gVisor's security architecture in the context of networking
    12  
    13  Linux networking is complicated. The TCP protocol is over 40 years old, and has
    14  been repeatedly extended over the years to keep up with the rapid pace of
    15  network infrastructure improvements, all while maintaining compatibility. On top
    16  of that, Linux networking has a fairly large API surface. Linux supports
    17  [over 150 options](https://github.com/google/gvisor/blob/960f6a975b7e44c0efe8fd38c66b02017c4fe137/pkg/sentry/strace/socket.go#L476-L644)
    18  for the most common socket types alone. In fact, the net subsystem is one of the
    19  largest and fastest growing in Linux at approximately 1.1 million lines of code.
    20  For comparison, that is several times the size of the entire gVisor codebase.
    21  
    22  At the same time, networking is increasingly important. The cloud era is
    23  arguably about making everything a network service, and in order to make that
    24  work, the interconnect performance is critical. Adding networking support to
    25  gVisor was difficult, not just due to the inherent complexity, but also because
    26  it has the potential to significantly weaken gVisor's security model.
    27  
    28  As outlined in the previous blog post, gVisor's
    29  [secure design principles](https://gvisor.dev/blog/2019/11/18/gvisor-security-basics-part-1/#design-principles)
    30  are:
    31  
    32  1.  Defense in Depth: each component of the software stack trusts each other
    33      component as little as possible.
    34  1.  Least Privilege: each software component has only the permissions it needs
    35      to function, and no more.
    36  1.  Attack Surface Reduction: limit the surface area of the host exposed to the
    37      sandbox.
    38  1.  Secure by Default: the default choice for a user should be safe.
    39  
    40  gVisor manifests these principles as a multi-layered system. An application
    41  running in the sandbox interacts with the Sentry, a userspace kernel, which
    42  mediates all interactions with the Host OS and beyond. The Sentry is written in
    43  pure Go with minimal unsafe code, making it less vulnerable to buffer overflows
    44  and related memory bugs that can lead to a variety of compromises including code
    45  injection. It emulates Linux using only a minimal and audited set of Host OS
    46  syscalls that limit the Host OS's attack surface exposed to the Sentry itself.
    47  The syscall restrictions are enforced by running the Sentry with seccomp
    48  filters, which enforce that the Sentry can only use the expected set of
    49  syscalls. The Sentry runs as an unprivileged user and in namespaces, which,
    50  along with the seccomp filters, ensure that the Sentry is run with the Least
    51  Privilege required.
    52  
    53  gVisor's multi-layered design provides Defense in Depth. The Sentry, which does
    54  not trust the application because it may attack the Sentry and try to bypass it,
    55  is the first layer. The sandbox that the Sentry runs in is the second layer. If
    56  the Sentry were compromised, the attacker would still be in a highly restrictive
    57  sandbox which they must also break out of in order to compromise the Host OS.
    58  
    59  To enable networking functionality while preserving gVisor's security
    60  properties, we implemented a
    61  [userspace network stack](https://github.com/google/gvisor/tree/master/pkg/tcpip)
    62  in the Sentry, which we creatively named Netstack. Netstack is also written in
    63  Go, not only to avoid unsafe code in the network stack itself, but also to avoid
    64  a complicated and unsafe Foreign Function Interface. Having its own integrated
    65  network stack allows the Sentry to implement networking operations using up to
    66  three Host OS syscalls to read and write packets. These syscalls allow a very
    67  minimal set of operations which are already allowed (either through the same or
    68  a similar syscall). Moreover, because packets typically come from off-host (e.g.
    69  the internet), the Host OS's packet processing code has received a lot of
    70  scrutiny, hopefully resulting in a high degree of hardening.
    71  
    72  ![Figure 1](/assets/images/2020-04-02-networking-security-figure1.png "Network and gVisor.")
    73  
    74  ## Writing a network stack
    75  
    76  Netstack was written from scratch specifically for gVisor. Because Netstack was
    77  designed and implemented to be modular, flexible and self-contained, there are
    78  now several more projects using Netstack in creative and exciting ways. As we
    79  discussed, a custom network stack has enabled a variety of security-related
    80  goals which would not have been possible any other way. This came at a cost
    81  though. Network stacks are complex and writing a new one comes with many
    82  challenges, mostly related to application compatibility and performance.
    83  
    84  Compatibility issues typically come in two forms: missing features, and features
    85  with behavior that differs from Linux (usually due to bugs). Both of these are
    86  inevitable in an implementation of a complex system spanning many quickly
    87  evolving and ambiguous standards. However, we have invested heavily in this
    88  area, and the vast majority of applications have no issues using Netstack. For
    89  example,
    90  [we now support setting 34 different socket options](https://github.com/google/gvisor/blob/815df2959a76e4a19f5882e40402b9bbca9e70be/pkg/sentry/socket/netstack/netstack.go#L830-L1764)
    91  versus
    92  [only 7 in our initial git commit](https://github.com/google/gvisor/blob/d02b74a5dcfed4bfc8f2f8e545bca4d2afabb296/pkg/sentry/socket/epsocket/epsocket.go#L445-L702).
    93  We are continuing to make good progress in this area.
    94  
    95  Performance issues typically come from TCP behavior and packet processing speed.
    96  To improve our TCP behavior, we are working on implementing the full set of TCP
    97  RFCs. There are many RFCs which are significant to performance (e.g.
    98  [RACK](https://tools.ietf.org/id/draft-ietf-tcpm-rack-03.html) and
    99  [BBR](https://tools.ietf.org/html/draft-cardwell-iccrg-bbr-congestion-control-00))
   100  that we have yet to implement. This mostly affects TCP performance with
   101  non-ideal network conditions (e.g. cross continent connections). Faster packet
   102  processing mostly improves TCP performance when network conditions are very good
   103  (e.g. within a datacenter). Our primary strategy here is to reduce interactions
   104  with the Go runtime, specifically the garbage collector (GC) and scheduler. We
   105  are currently optimizing buffer management to reduce the amount of garbage,
   106  which will lower the GC cost. To reduce scheduler interactions, we are
   107  re-architecting the TCP implementation to use fewer goroutines. Performance
   108  today is good enough for most applications and we are making steady
   109  improvements. For example, since May of 2019, we have improved the Netstack
   110  runsc
   111  [iperf3 download benchmark](https://github.com/google/gvisor/tree/master/test/benchmarks/network)
   112  score by roughly 15% and upload score by around 10,000X. Current numbers are
   113  about 17 Gbps download and about 8 Gbps upload versus about 42 Gbps and 43 Gbps
   114  for native (Linux) respectively.
   115  
   116  ## An alternative
   117  
   118  We also offer an alternative network mode: passthrough. This name can be
   119  misleading as syscalls are never passed through from the app to the Host OS.
   120  Instead, the passthrough mode implements networking in gVisor using the Host
   121  OS's network stack. (This mode is called
   122  [hostinet](https://github.com/google/gvisor/tree/master/pkg/sentry/socket/hostinet)
   123  in the codebase.) Passthrough mode can improve performance for some use cases as
   124  the Host OS's network stack has had an enormous number of person-years poured
   125  into making it highly performant. However, there is a rather large downside to
   126  using passthrough mode: it weakens gVisor's security model by increasing the
   127  Host OS's Attack Surface. This is because using the Host OS's network stack
   128  requires the Sentry to use the Host OS's
   129  [Berkeley socket interface](https://en.wikipedia.org/wiki/Berkeley_sockets). The
   130  Berkeley socket interface is a much larger API surface than the packet interface
   131  that our network stack uses. When passthrough mode is in use, the Sentry is
   132  allowed to use
   133  [15 additional syscalls](https://github.com/google/gvisor/blob/b1576e533223e98ebe4bd1b82b04e3dcda8c4bf1/runsc/boot/filter/config.go#L312-L517).
   134  Further, this set of syscalls includes some that allow the Sentry to create file
   135  descriptors, something that
   136  [we don't normally allow](https://gvisor.dev/blog/2019/11/18/gvisor-security-basics-part-1/#sentry-host-os-interface)
   137  as it opens up classes of file-based attacks.
   138  
   139  There are some networking features that we can't implement on top of syscalls
   140  that we feel are safe (most notably those behind
   141  [ioctl](http://man7.org/linux/man-pages/man2/ioctl.2.html)) and therefore are
   142  not supported. Because of this, we actually support fewer networking features in
   143  passthrough mode than we do in Netstack, reducing application compatibility.
   144  That's right: using our networking stack provides better overall application
   145  compatibility than using our passthrough mode.
   146  
   147  That said, gVisor with passthrough networking still provides a high level of
   148  isolation. Applications cannot specify host syscall arguments directly, and the
   149  sentry's seccomp policy restricts its syscall use significantly more than a
   150  general purpose seccomp policy.
   151  
   152  ## Secure by Default
   153  
   154  The goal of the Secure by Default principle is to make it easy to securely
   155  sandbox containers. Of course, disabling network access entirely is the most
   156  secure option, but that is not practical for most applications. To make gVisor
   157  Secure by Default, we have made Netstack the default networking mode in gVisor
   158  as we believe that it provides significantly better isolation. For this reason
   159  we strongly caution users from changing the default unless Netstack flat out
   160  won't work for them. The passthrough mode option is still provided, but we want
   161  users to make an informed decision when selecting it.
   162  
   163  Another way in which gVisor makes it easy to securely sandbox containers is by
   164  allowing applications to run unmodified, with no special configuration needed.
   165  In order to do this, gVisor needs to support all of the features and syscalls
   166  that applications use. Neither seccomp nor gVisor's passthrough mode can do this
   167  as applications commonly use syscalls which are too dangerous to be included in
   168  a secure policy. Even if this dream isn't fully realized today, gVisor's
   169  architecture with Netstack makes this possible.
   170  
   171  ## Give Netstack a Try
   172  
   173  If you haven't already, try running a workload in gVisor with Netstack. You can
   174  find instructions on how to get started in our
   175  [Quick Start](/docs/user_guide/quick_start/docker/). We want to hear about both
   176  your successes and any issues you encounter. We welcome your contributions,
   177  whether that be verbal feedback or code contributions, via our
   178  [Gitter channel](https://gitter.im/gvisor/community),
   179  [email list](https://groups.google.com/forum/#!forum/gvisor-users),
   180  [issue tracker](https://gvisor.dev/issue/new), and
   181  [Github repository](https://github.com/google/gvisor). Feel free to express
   182  interest in an [open issue](https://gvisor.dev/issue/), or reach out if you
   183  aren't sure where to start.