8000 caps: bounds-check accesses to the capability sets by b84330808 · Pull Request #386 · google/nsjail · GitHub
[go: up one dir, main page]

caps: bounds-check accesses to the capability sets - #386

Open
b84330808 wants to merge 1 commit into
google:masterfrom
b84330808:hardening-caps-bounds
Open

b84330808 wants to merge 1 commit into
google:masterfrom
b84330808:hardening-caps-bounds

Conversation

@b84330808
Copy link
Copy Markdown

getCaps() returned a raw pointer to a thread-local array, and the
get/set helpers indexed it with CAP_TO_INDEX(cap) without checking the
index against the two elements that capget()/capset() exchange.

This keeps the capability sets in a caller-owned std::array and looks
up a capability's element through a helper that rejects out-of-range
capabilities. An out-of-range capability reads as not set, and
requesting one makes initNs() fail, as an unpermitted capability
already does.

No capability in capNames is out of range today (the highest is
CAP_CHECKPOINT_RESTORE, 40), so behavior doesn't change. A capability

= 64 added to the table later would fail closed instead of reading
and writing past the array. caps.cc now builds without clang
-Wunsafe-buffer-usage warnings (5 before).

Testing: make test gives the same results as master. CapInh, CapPrm,
CapEff, CapBnd and CapAmb inside the jail are identical before and
after for: the default; --cap CAP_NET_RAW --cap CAP_SYS_ADMIN;
--keep_caps; --cap CAP_BPF --cap CAP_CHECKPOINT_RESTORE (second array
element); --disable_clone_newuser --cap CAP_NET_ADMIN; and
--user 99999 --cap CAP_KILL.

getCaps() returned a raw pointer to a thread-local array, and the
get/set helpers indexed it with CAP_TO_INDEX(cap) without checking the
result against the _LINUX_CAPABILITY_U32S_3 elements that capget() and
capset() exchange.

Keep the capability sets in a caller-owned std::array instead, and look
up the element for a capability through capEntry(), which rejects
capabilities outside of the array. A capability which is out of range
reads as not set, and requesting one fails initNs(), as an unpermitted
capability already does.

The highest capability in capNames is CAP_CHECKPOINT_RESTORE (40), so
no current capability is out of range and behavior doesn't change: the
jailed process gets the same capability sets as before for --cap
(including CAP_BPF and CAP_CHECKPOINT_RESTORE, which live in the second
element) and for --keep_caps. A future capability >= 64 added to the
table now fails closed instead of reading and writing past the array.

caps.cc now builds without clang -Wunsafe-buffer-usage warnings (5
before).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0