-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
capability: add separate API for ambient capabilities #165
Conversation
Once #164 merged, I'll rebase this PR. |
a336f24
to
e502b72
Compare
I think we should just make "greedy" mode a default. Out of curiosity, have you checked what other implementations do? libcap C and Go versions, for example? |
It seems like there is no function provided in For go version, it provides such type function, there are two difference comparing with us:
The go version implementation code is: //go:uintptrescapes
func (sc *syscaller) setAmbient(enable bool, val ...Value) error {
dir := uintptr(prCapAmbientLower)
if enable {
dir = prCapAmbientRaise
}
for _, v := range val {
_, err := sc.prctlwcall6(prCapAmbient, dir, uintptr(v), 0, 0, 0)
if err != nil {
return err
}
}
return nil
} So I think we can have some choices:
|
In fact I’m prefer to the first solution, this is our own distinguishing feature, and I think it’s more convenient for the callers. |
I'd like to follow the KISS principle here. In other words, a separate function that changes a way errors are handled is a bit too much. |
In fact, if we provide a function to apply capabilities one by one, a user can control what do to about errors. |
e502b72
to
3b5d22e
Compare
Quite agree, I add 3 APIs for ambient cap, maybe runc can use these APIs to support ambient cap set. |
capability/capability_linux.go
Outdated
@@ -117,6 +117,11 @@ func newPid(pid int) (c Capabilities, retErr error) { | |||
return | |||
} | |||
|
|||
func ignorableError(err error) bool { | |||
// Ignore EINVAL as not supported on kernels before 4.3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See, the original code has two different comments about why we're ignoring EINVAL:
- For
PR_CAPBSET_DROP
, it says "Ignore EINVAL since the capability may not be supported in this system." - For
PR_CAPSET_AMBIENT
, it says "Ignore EINVAL as not supported on kernels before 4.3."
With this change, you remove the first comment, moved the second one into this function, and thus it is now applicable to both cases, which is incorrect.
capability/capability_linux.go
Outdated
continue | ||
} | ||
return | ||
if err != nil && !ignorableError(err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, with this change, in case kind
only has BOUNDS
and the kernel returns EINVAL
for the last PR_CAPBSET_DROP, it will be returned, while the code before your changes returns nil
in the same case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. ignorableError
is not the main reason of this refactor, removing the named return param is the main refactor, err
is now a local val, not the return name. It will help to avoid causing other issues like the original issue of ambient
implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the first commit -- the implementation in this PR is incorrect for a few reasons (see comments above). See #166 for a more correct implementation of what you're trying to achieve.
3b5d22e
to
27a611c
Compare
Fixed the comment. |
This comment was marked as outdated.
This comment was marked as outdated.
Yes, I think, we should set ambient capabilities separately and one by one, so we have a chance to ignore or warn errors. I'd rename functions to |
6886234
to
6153b26
Compare
Changed like yours. |
Changed all function names. |
capability/capability_linux.go
Outdated
@@ -117,6 +117,14 @@ func newPid(pid int) (c Capabilities, retErr error) { | |||
return | |||
} | |||
|
|||
func ignoreEINVAL(err error) error { | |||
// Ignore EINVAL since the op or the capability may not be supported in this system. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please remove this comment? Instead, explain why we're ignoring EINVAL when we call this function.
I just realized this package API is flawed. You start with c, err := capability.NewPid(somePid)
...
c.Set(capability.AMBIENT, capability.CAP_CHOWN)
c.Apply(capability.AMBIENT) The ambient capability will be applied to the current process, rather than the process identified by 😓 Will open a new issue. This PR is related, since it adds new methods to the above API. Since we can only raise/lower/clear own capabilities, Those should probably just be functions. I'm also thinking we should only accept only one single capability as the argument, since otherwise we have the same problem with the errors (whether to continue or return an error if we caught one). func AmbientRaise(Cap) error
func AmbientLower(Cap) error
func AmbientClearAll() error |
👍 This is really a long time bug.
Yes, for other users, to have a compatibility, we may also need to add a pid check in
It's not very important, we can keep support a cap array, someone who want to ignore the error, he can pass a single cap one by one. |
c5a04f3
to
3ce9f85
Compare
Needs a rebase (#164 is merged). |
OK, I'll split this PR to two. |
306ccc1
to
92ccf70
Compare
Signed-off-by: lifubang <[email protected]>
Signed-off-by: lifubang <[email protected]>
Signed-off-by: lifubang <[email protected]>
92ccf70
to
11c8cd1
Compare
Looks like this actually works now!
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
@lifubang thanks, only one nit: the last commit subject should be prefixed with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am looking into C library (cap
) and maybe we should design API here in the same way.
They have:
int cap_set_ambient(cap_value_t cap, cap_flag_value_t value);
int cap_reset_ambient(void);
Maybe we should do something similar?
// AmbientSet raises or lowers specified ambient capabilities for the calling process.
func AmbientSet(raise bool, cap ...Cap) error
or
// AmbientSet raises or lowers the specified ambient capability for the calling process.
func AmbientSet(cap Cap, raise bool) error
I'm thinking about the last form because I'm still not very convinced we should provide a function which sets multiple capabilities. It adds some complexity but on the caller's side it's just a simple for
loop.
Also because we can provide |
In runtime-spec said[1]:
Runtimes SHOULD NOT fail if the container configuration requests capabilities that cannot be granted, for example, if the runtime operates in a restricted environment with a limited set of capabilities.
So this is the default mode when requesting capabilities. As a package used by
runc
, I think most of code about capabilities should be in this project, not in runc.For the first edition of ambient implementation, though it masked the err because of a bug, but there was no
return
when got an error, it is different from the error handling in other place, so I think it was the author's original ideal to raise as many ambient cap sets as possible when got some errors.There is no return in ambient caps apply:
sys/capability/capability/capability_linux.go
Lines 477 to 482 in 7b553f5
There is a return in other place:
sys/capability/capability/capability_linux.go
Lines 451 to 459 in 7b553f5
So, I think we should provide a choice to let users make the decision, for ambient cap sets apply, we should provide at least two modes:1. Greedy mode: it should be the default mode to be compatible with the past, it means raise ambient caps as many as possible and return the last error;2. Stop on error mode: it means that we should stop to raise other ambient caps when got an error.So, I think we should provide the abilities to let users can make a decision to ignore the ambient cap raise/lower error or not.
[1] https://github.com/opencontainers/runtime-spec/blob/8f3fbc881602d85699e5c448634ec1288860d966/config.md?plain=1#L286-L292