UPSTREAM: bpf: Fix overrunning reservations in ringbuf

[ Upstream commit cfa1a2329a691ffd991fcf7248a57d752e712881 ]

The BPF ring buffer internally is implemented as a power-of-2 sized circular
buffer, with two logical and ever-increasing counters: consumer_pos is the
consumer counter to show which logical position the consumer consumed the
data, and producer_pos which is the producer counter denoting the amount of
data reserved by all producers.

Each time a record is reserved, the producer that "owns" the record will
successfully advance producer counter. In user space each time a record is
read, the consumer of the data advanced the consumer counter once it finished
processing. Both counters are stored in separate pages so that from user
space, the producer counter is read-only and the consumer counter is read-write.

One aspect that simplifies and thus speeds up the implementation of both
producers and consumers is how the data area is mapped twice contiguously
back-to-back in the virtual memory, allowing to not take any special measures
for samples that have to wrap around at the end of the circular buffer data
area, because the next page after the last data page would be first data page
again, and thus the sample will still appear completely contiguous in virtual
memory.

Each record has a struct bpf_ringbuf_hdr { u32 len; u32 pg_off; } header for
book-keeping the length and offset, and is inaccessible to the BPF program.
Helpers like bpf_ringbuf_reserve() return `(void *)hdr + BPF_RINGBUF_HDR_SZ`
for the BPF program to use. Bing-Jhong and Muhammad reported that it is however
possible to make a second allocated memory chunk overlapping with the first
chunk and as a result, the BPF program is now able to edit first chunk's
header.

For example, consider the creation of a BPF_MAP_TYPE_RINGBUF map with size
of 0x4000. Next, the consumer_pos is modified to 0x3000 /before/ a call to
bpf_ringbuf_reserve() is made. This will allocate a chunk A, which is in
[0x0,0x3008], and the BPF program is able to edit [0x8,0x3008]. Now, lets
allocate a chunk B with size 0x3000. This will succeed because consumer_pos
was edited ahead of time to pass the `new_prod_pos - cons_pos > rb->mask`
check. Chunk B will be in range [0x3008,0x6010], and the BPF program is able
to edit [0x3010,0x6010]. Due to the ring buffer memory layout mentioned
earlier, the ranges [0x0,0x4000] and [0x4000,0x8000] point to the same data
pages. This means that chunk B at [0x4000,0x4008] is chunk A's header.
bpf_ringbuf_submit() / bpf_ringbuf_discard() use the header's pg_off to then
locate the bpf_ringbuf itself via bpf_ringbuf_restore_from_rec(). Once chunk
B modified chunk A's header, then bpf_ringbuf_commit() refers to the wrong
page and could cause a crash.

Fix it by calculating the oldest pending_pos and check whether the range
from the oldest outstanding record to the newest would span beyond the ring
buffer size. If that is the case, then reject the request. We've tested with
the ring buffer benchmark in BPF selftests (./benchs/run_bench_ringbufs.sh)
before/after the fix and while it seems a bit slower on some benchmarks, it
is still not significantly enough to matter.

Bug: 349976340
Fixes: 457f44363a88 ("bpf: Implement BPF ring buffer and verifier support for it")
Reported-by: Bing-Jhong Billy Jheng <[email protected]>
Reported-by: Muhammad Ramdhan <[email protected]>
Co-developed-by: Bing-Jhong Billy Jheng <[email protected]>
Co-developed-by: Andrii Nakryiko <[email protected]>
Signed-off-by: Bing-Jhong Billy Jheng <[email protected]>
Signed-off-by: Andrii Nakryiko <[email protected]>
Signed-off-by: Daniel Borkmann <[email protected]>
Signed-off-by: Andrii Nakryiko <[email protected]>
Link: https://lore.kernel.org/bpf/[email protected]
Signed-off-by: Sasha Levin <[email protected]>
(cherry picked from commit d1b9df0435bc61e0b44f578846516df8ef476686)
Signed-off-by: Lee Jones <[email protected]>
Change-Id: I57847858a13e15118ef18a00257e45f96597e938
1 file changed
tree: ba75031f9a9a648381fa1dceb6c633ba83b39e27
  1. android/
  2. arch/
  3. block/
  4. certs/
  5. crypto/
  6. Documentation/
  7. drivers/
  8. fs/
  9. include/
  10. init/
  11. io_uring/
  12. ipc/
  13. kernel/
  14. lib/
  15. LICENSES/
  16. mm/
  17. net/
  18. rust/
  19. samples/
  20. scripts/
  21. security/
  22. sound/
  23. tools/
  24. usr/
  25. virt/
  26. .clang-format
  27. .cocciconfig
  28. .get_maintainer.ignore
  29. .gitattributes
  30. .gitignore
  31. .mailmap
  32. .rustfmt.toml
  33. BUILD.bazel
  34. build.config.aarch64
  35. build.config.allmodconfig
  36. build.config.allmodconfig.aarch64
  37. build.config.allmodconfig.arm
  38. build.config.allmodconfig.x86_64
  39. build.config.amlogic
  40. build.config.arm
  41. build.config.common
  42. build.config.constants
  43. build.config.crashdump
  44. build.config.crashdump.aarch64
  45. build.config.crashdump.x86_64
  46. build.config.db845c
  47. build.config.gki
  48. build.config.gki-debug.aarch64
  49. build.config.gki-debug.x86_64
  50. build.config.gki.aarch64
  51. build.config.gki.aarch64.fips140
  52. build.config.gki.riscv64
  53. build.config.gki.x86_64
  54. build.config.gki_kasan
  55. build.config.gki_kasan.aarch64
  56. build.config.gki_kasan.x86_64
  57. build.config.gki_kprobes
  58. build.config.gki_kprobes.aarch64
  59. build.config.gki_kprobes.x86_64
  60. build.config.khwasan
  61. build.config.microdroid
  62. build.config.microdroid.aarch64
  63. build.config.microdroid.x86_64
  64. build.config.riscv64
  65. build.config.rockchip
  66. build.config.rockpi4
  67. build.config.x86_64
  68. COPYING
  69. CREDITS
  70. Kbuild
  71. Kconfig
  72. Kconfig.ext
  73. MAINTAINERS
  74. Makefile
  75. modules.bzl
  76. OWNERS
  77. README
  78. README.md
README.md

How do I submit patches to Android Common Kernels

  1. BEST: Make all of your changes to upstream Linux. If appropriate, backport to the stable releases. These patches will be merged automatically in the corresponding common kernels. If the patch is already in upstream Linux, post a backport of the patch that conforms to the patch requirements below.

    • Do not send patches upstream that contain only symbol exports. To be considered for upstream Linux, additions of EXPORT_SYMBOL_GPL() require an in-tree modular driver that uses the symbol -- so include the new driver or changes to an existing driver in the same patchset as the export.
    • When sending patches upstream, the commit message must contain a clear case for why the patch is needed and beneficial to the community. Enabling out-of-tree drivers or functionality is not not a persuasive case.
  2. LESS GOOD: Develop your patches out-of-tree (from an upstream Linux point-of-view). Unless these are fixing an Android-specific bug, these are very unlikely to be accepted unless they have been coordinated with [email protected]. If you want to proceed, post a patch that conforms to the patch requirements below.

Common Kernel patch requirements

  • All patches must conform to the Linux kernel coding standards and pass scripts/checkpatch.pl
  • Patches shall not break gki_defconfig or allmodconfig builds for arm, arm64, x86, x86_64 architectures (see https://source.android.com/setup/build/building-kernels)
  • If the patch is not merged from an upstream branch, the subject must be tagged with the type of patch: UPSTREAM:, BACKPORT:, FROMGIT:, FROMLIST:, or ANDROID:.
  • All patches must have a Change-Id: tag (see https://gerrit-review.googlesource.com/Documentation/user-changeid.html)
  • If an Android bug has been assigned, there must be a Bug: tag.
  • All patches must have a Signed-off-by: tag by the author and the submitter

Additional requirements are listed below based on patch type

Requirements for backports from mainline Linux: UPSTREAM:, BACKPORT:

  • If the patch is a cherry-pick from Linux mainline with no changes at all
    • tag the patch subject with UPSTREAM:.
    • add upstream commit information with a (cherry picked from commit ...) line
    • Example:
      • if the upstream commit message is
        important patch from upstream

        This is the detailed description of the important patch

        Signed-off-by: Fred Jones <[email protected]>
  • then Joe Smith would upload the patch for the common kernel as
        UPSTREAM: important patch from upstream

        This is the detailed description of the important patch

        Signed-off-by: Fred Jones <[email protected]>

        Bug: 135791357
        Change-Id: I4caaaa566ea080fa148c5e768bb1a0b6f7201c01
        (cherry picked from commit c31e73121f4c1ec41143423ac6ce3ce6dafdcec1)
        Signed-off-by: Joe Smith <[email protected]>
  • If the patch requires any changes from the upstream version, tag the patch with BACKPORT: instead of UPSTREAM:.
    • use the same tags as UPSTREAM:
    • add comments about the changes under the (cherry picked from commit ...) line
    • Example:
        BACKPORT: important patch from upstream

        This is the detailed description of the important patch

        Signed-off-by: Fred Jones <[email protected]>

        Bug: 135791357
        Change-Id: I4caaaa566ea080fa148c5e768bb1a0b6f7201c01
        (cherry picked from commit c31e73121f4c1ec41143423ac6ce3ce6dafdcec1)
        [joe: Resolved minor conflict in drivers/foo/bar.c ]
        Signed-off-by: Joe Smith <[email protected]>

Requirements for other backports: FROMGIT:, FROMLIST:,

  • If the patch has been merged into an upstream maintainer tree, but has not yet been merged into Linux mainline
    • tag the patch subject with FROMGIT:
    • add info on where the patch came from as (cherry picked from commit <sha1> <repo> <branch>). This must be a stable maintainer branch (not rebased, so don't use linux-next for example).
    • if changes were required, use BACKPORT: FROMGIT:
    • Example:
      • if the commit message in the maintainer tree is
        important patch from upstream

        This is the detailed description of the important patch

        Signed-off-by: Fred Jones <[email protected]>
  • then Joe Smith would upload the patch for the common kernel as
        FROMGIT: important patch from upstream

        This is the detailed description of the important patch

        Signed-off-by: Fred Jones <[email protected]>

        Bug: 135791357
        (cherry picked from commit 878a2fd9de10b03d11d2f622250285c7e63deace
         https://git.kernel.org/pub/scm/linux/kernel/git/foo/bar.git test-branch)
        Change-Id: I4caaaa566ea080fa148c5e768bb1a0b6f7201c01
        Signed-off-by: Joe Smith <[email protected]>
  • If the patch has been submitted to LKML, but not accepted into any maintainer tree
    • tag the patch subject with FROMLIST:
    • add a Link: tag with a link to the submittal on lore.kernel.org
    • add a Bug: tag with the Android bug (required for patches not accepted into a maintainer tree)
    • if changes were required, use BACKPORT: FROMLIST:
    • Example:
        FROMLIST: important patch from upstream

        This is the detailed description of the important patch

        Signed-off-by: Fred Jones <[email protected]>

        Bug: 135791357
        Link: https://lore.kernel.org/lkml/[email protected]/
        Change-Id: I4caaaa566ea080fa148c5e768bb1a0b6f7201c01
        Signed-off-by: Joe Smith <[email protected]>

Requirements for Android-specific patches: ANDROID:

  • If the patch is fixing a bug to Android-specific code
    • tag the patch subject with ANDROID:
    • add a Fixes: tag that cites the patch with the bug
    • Example:
        ANDROID: fix android-specific bug in foobar.c

        This is the detailed description of the important fix

        Fixes: 1234abcd2468 ("foobar: add cool feature")
        Change-Id: I4caaaa566ea080fa148c5e768bb1a0b6f7201c01
        Signed-off-by: Joe Smith <[email protected]>
  • If the patch is a new feature
    • tag the patch subject with ANDROID:
    • add a Bug: tag with the Android bug (required for android-specific features)