https://github.com/cilium/cilium
Revision cc50936a67901f04b83210c821264e8769bd3551 authored by Joe Stringer on 07 August 2023, 20:25:21 UTC, committed by Joe Stringer on 10 August 2023, 16:13:05 UTC
[ upstream commit 74530b1880ec080959eb95aa71d6ce1d7101570b ] Commit c96b9d81a8a6 ("ipcache: Remove superfluous if condition") introduced a double-free for cases where the ipcache allocates a new (reference to a) security identity and there is already an identity corresponding to those labels which another subsystem injected directly into the ipcache via Upsert() and friends. This commit fixes the issue. IPCache has two sets of APIs: - Older APIs like Upsert() / UpsertGeneratedIdentities which require the caller to retain reference counts against each Identity and balance allocate/release calls. - Newer APIs like UpsertMetadata() / UpsertLabels() / UpsertPrefixes() which delegate the reference counting responsibility to the ipcache itself, which will hold one reference to the identity for all callers of the APIs. InjectLabels() is responsible for reference counting the identities associated with ipcache entries that it manages. In order to ensure balanced allocate and release, this function allocates and retains one reference to the identity for itself internally within this function. Under normal operation it will typically release this reference again once it has performed the ipcache update operations. It may be triggered multiple times for the same prefix, in which case it should only ever acquire one reference to the identity, otherwise the references could leak and the identity would not be freed. There is one exception to the "always allocate" + "always" release behaviour in InjectLabels(): Given that the ipcache needs to hold exactly one reference to the identity over time to ensure it remains live while in use by the ipcache, the very first time that InjectLabels() allocates the identity reference, it must hold onto the reference and not immediately release it. In particular, if another subsystem injected an ipcache entry via older APIs, then the first time that InjectLabels() runs, it also needs to acquire and hold a reference to the identity, even though the underlying ipcache already contains an CIDR -> Identity mapping that was injected via the older Upsert() API. In commit c96b9d81a8a6 ("ipcache: Remove superfluous if condition"), the check which was ensuring that ipcache entries that transition from being managed by older APIs towards newer APIs would not trigger allocation of a new identity reference to be held by the ipcache itself. The result would be that the resting number of references to the identity would be one less than what is necessary to keep the identity alive. If the other subsystem ever released its reference to the identity, then that would be the last reference and the identity would be freed, despite still being in use. This scenario leads to policy recalculation that removes any datapath allow rules for the corresponding CIDRs, ultimately resulting in packet loss for the impacted CIDRs. One such example involves CIDR identity restore startup logic in the daemon. That path allocates identities then injects them into the ipcache using older APIs. If any such CIDRs are used by network policies, then the network policies subsystem will insert the CIDR into the ipcache using newer ipcache APIs. Given this mix of API usage and the bug introduced in the identity reference counting internally in ipcache, this triggers the bug. This commit fixes it by checking whether InjectLabels() already assumed ownership over the underlying ipcache entry, which implies that the ipcache already holds a reference to the identity on behalf of all newer API users. During subsequent calls to InjectLabels(), the logic checks that the ipcache entry was installed by this function and accounts for the fact that a prior iteration had allocated an identity reference. It can then safely release references that were acquired during the current execution of the function. Fixes: c96b9d81a8a6 ("ipcache: Remove superfluous if condition") Reported-by: Boris Petrovic <carnerito.b@gmail.com> Reported-by: Kim-Eirik Karlsen <kim.eirik@gmail.com> Reported-by: Jason Witkowski <jason@witkow.ski> Signed-off-by: Joe Stringer <joe@cilium.io> Signed-off-by: Maciej Kwiek <maciej@isovalent.com>
1 parent 89c5f6a
Tip revision: cc50936a67901f04b83210c821264e8769bd3551 authored by Joe Stringer on 07 August 2023, 20:25:21 UTC
ipcache: Fix refcounting with mix of APIs
ipcache: Fix refcounting with mix of APIs
Tip revision: cc50936
File | Mode | Size |
---|---|---|
.devcontainer | ||
.github | ||
.nvim | ||
.travis | ||
.vscode | ||
Documentation | ||
api | ||
bpf | ||
bugtool | ||
cilium | ||
cilium-health | ||
clustermesh-apiserver | ||
contrib | ||
daemon | ||
envoy | ||
examples | ||
hack | ||
hubble-relay | ||
images | ||
install | ||
jenkinsfiles | ||
kvstoremesh | ||
operator | ||
pkg | ||
plugins | ||
test | ||
tools | ||
vendor | ||
.authors.aux | -rw-r--r-- | 416 bytes |
.clang-format | -rw-r--r-- | 3.9 KB |
.clomonitor.yml | -rw-r--r-- | 984 bytes |
.gitattributes | -rw-r--r-- | 887 bytes |
.gitignore | -rw-r--r-- | 1.8 KB |
.golangci.yaml | -rw-r--r-- | 3.6 KB |
.mailmap | -rw-r--r-- | 6.5 KB |
.travis.yml | -rw-r--r-- | 506 bytes |
AUTHORS | -rw-r--r-- | 41.5 KB |
CHANGELOG.md | -rw-r--r-- | 112.0 KB |
CODEOWNERS | -rw-r--r-- | 11.2 KB |
CODE_OF_CONDUCT.md | -rw-r--r-- | 2.2 KB |
CONTRIBUTING.md | -rw-r--r-- | 691 bytes |
FURTHER_READINGS.rst | -rw-r--r-- | 6.4 KB |
LICENSE | -rw-r--r-- | 11.1 KB |
MAINTAINERS.md | -rw-r--r-- | 4.3 KB |
Makefile | -rw-r--r-- | 34.9 KB |
Makefile.defs | -rw-r--r-- | 6.9 KB |
Makefile.docker | -rw-r--r-- | 7.3 KB |
Makefile.quiet | -rw-r--r-- | 818 bytes |
README.rst | -rw-r--r-- | 19.4 KB |
SECURITY.md | -rw-r--r-- | 1.0 KB |
USERS.md | -rw-r--r-- | 28.5 KB |
VERSION | -rw-r--r-- | 7 bytes |
Vagrantfile | -rw-r--r-- | 14.9 KB |
go.mod | -rw-r--r-- | 12.2 KB |
go.sum | -rw-r--r-- | 152.7 KB |
netlify.toml | -rw-r--r-- | 92 bytes |
vagrant_box_defaults.rb | -rw-r--r-- | 334 bytes |
Computing file changes ...