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
idmap improvements #1509
idmap improvements #1509
Conversation
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
e78ea55
to
208a0da
Compare
src/lxc/conf.c
Outdated
if (!has_sufficient_privilege && | ||
lxc_file_cap_is_set(newuidmap_path, CAP_SETUID, CAP_EFFECTIVE) && | ||
lxc_file_cap_is_set(newuidmap_path, CAP_SETUID, CAP_PERMITTED) && | ||
sb.st_uid == 0) |
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.
File does not need to be owned by root for filecaps to take effect. The sb.st_uid check can be removed afaics.
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.
You would still be able to write to new_{g,u}idmap
even if euid > 0
?
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.
Write to it? Aren't you going to execute it?
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 mean will new{g,u}idmap
be able to write to /proc/<pid>/uid_map
when it is not uid 0
?
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.
Unless of course, uid_map
is owned by another the unpriv user.
src/lxc/conf.c
Outdated
free(cmdpath); | ||
newuidmap_path = on_path("newuidmap", NULL); | ||
if (newuidmap_path) { | ||
bool has_sufficient_privilege = false; |
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.
This block sure seems like a good candidate for a helper function :) Not requisite for this patch, just a comment.
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.
Yeah, thought about it as well. Might just write it 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.
So if you turn that block into a helper then it goes away? :)
In either case, the check here to break out of the loop needs to be for fret right? or not?
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.
Oops, that last comment was supposed to go with the block below.
src/lxc/conf.c
Outdated
} else { | ||
left = LXC_IDMAPLEN - (pos - buf); | ||
fill = snprintf(pos, left, "\n"); | ||
if (fill <= 0 || fill >= left) | ||
SYSERROR("Too many {g,u}id mappings defined."); | ||
pos += fill; | ||
ret = system(buf); | ||
fret = system(buf); | ||
} | ||
if (ret) |
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.
Should this check still be on ret, or on fret? What was the reason for switching from ret to fret?
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.
ret
is used in the new{g,u}idmap
block before and might get initialized to a non-zero value but the for
-loop, as unlikely as this is, might not be run and then you'd exit with error.
208a0da
to
238ab1f
Compare
src/lxc/conf.c
Outdated
return -1; | ||
} | ||
|
||
if (has_privileged_newuidmap && !has_privileged_newgidmap) { |
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 think it makes sense to error out when we find only one of the two binaries.
src/lxc/utils.c
Outdated
/* Check if it has file capabilities. */ | ||
if (lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) && | ||
lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED) && | ||
st.st_uid == uid) { |
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 left this in for now. But if we're sure I'll remove it before the merge.
src/lxc/conf.c
Outdated
if (cmdpath) { | ||
use_shadow = 1; | ||
free(cmdpath); | ||
newuidmap_path = on_path("newuidmap", NULL); |
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 didn't move the on_path()
part into the setuid checks. But I probably could. Should we do that, what do you think?
Quoting Christian Brauner (notifications@github.com):
brauner commented on this pull request.
> + newgidmap_path = on_path("newgidmap", NULL);
+ if (newgidmap_path) {
+ has_privileged_newgidmap = is_setuid_binary(newgidmap_path, 0);
+ if (!has_privileged_newgidmap) {
+ ERROR("The newgidmap binary lacks sufficient privilege.");
+ free(newgidmap_path);
+ return -1;
+ }
+ free(newgidmap_path);
+ use_shadow++;
+ } else if (euid > 0) {
+ ERROR("The newgidmap binary is missing and euid is %d.", euid);
+ return -1;
+ }
+
+ if (has_privileged_newuidmap && !has_privileged_newgidmap) {
I think it makes sense to error out when we find only one of the two binaries.
Yes. I'm only suggesting using a helper to check if the binary is there and
sufficiently privileged, since you have around 30 lines of code duplicated.
|
Quoting Christian Brauner (notifications@github.com):
brauner commented on this pull request.
> + if (ret < 0) {
+ SYSERROR("Failed to stat \"%s\".", newuidmap_path);
+ free(newuidmap_path);
+ return -1;
+ }
+
+ /* Check if the newuidmap binary is setuid. */
+ if ((sb.st_mode & S_ISUID) && sb.st_uid == 0)
+ has_sufficient_privilege = true;
+
+ #if HAVE_LIBCAP
+ /* Check if it has file capabilities. */
+ if (!has_sufficient_privilege &&
+ lxc_file_cap_is_set(newuidmap_path, CAP_SETUID, CAP_EFFECTIVE) &&
+ lxc_file_cap_is_set(newuidmap_path, CAP_SETUID, CAP_PERMITTED) &&
+ sb.st_uid == 0)
I mean will `new{g,u}idmap` be able to write to `/proc/<pid>/uid_map` when it is not uid `0`?
Yes, you only need CAP_SETUID for uid_map and CAP_SETGID for gid_map.
|
Quoting Christian Brauner (notifications@github.com):
brauner commented on this pull request.
> * will protected it by preventing another user from being handed the
* range by shadow.
*/
- cmdpath = on_path("newuidmap", NULL);
- if (cmdpath) {
- use_shadow = 1;
- free(cmdpath);
+ newuidmap_path = on_path("newuidmap", NULL);
I didn't move the `on_path()` part into the setuid checks. But I probably could. Should we do that, what do you think?
I don't know, depends on whether the privilege-only check is more reusable.
I suspect just a on_path_and_privileged("newuidmap", CAP_SETUID) and
on_path_privileged("newgidmap", CAP_SETGID | CAP_SETUID) works out nicely.
|
f5f350c
to
608d9d0
Compare
608d9d0
to
ac5f143
Compare
ac5f143
to
22f5365
Compare
Add two new helpers that allow to determine whether a given proc or file has a capability in the given set and move lxc_cap_is_set() to static function that both call internally. Closes lxc#296. Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
22f5365
to
032768a
Compare
@hallyn, updated. |
032768a
to
2c45c2c
Compare
Hi, looks good. Just two more comments for now:
|
The new{g,u}idmap binaries where a source of trouble for users when they lacked sufficient privileges. This commit adds code to check for sufficient privilege. It checks whether new{g,u}idmap is root owned and has the setuid bit set and if it doesn't it checks whether new{g,u}idmap is root owned and has CAP_SETUID in its CAP_PERMITTED and CAP_EFFECTIVE set. Closes lxc#296. Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
2c45c2c
to
91c3e28
Compare
As discussed on IRC
|
@hallyn, should be ready to merge. |
Awesome, thanks. |
Signed-off-by: Evgeni Golov <evgeni@debian.org>
Signed-off-by: Evgeni Golov <evgeni@debian.org>
Signed-off-by: Christian Brauner christian.brauner@ubuntu.com