forked from containers/toolbox
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support subordinate user and group IDs on enterprise set-ups
On enterprise FreeIPA set-ups, the subordinate user and group IDs are provided by SSSD's sss plugin for the GNU Name Service Switch (or NSS) functionality of the GNU C Library. They are not listed in /etc/subuid and /etc/subgid. The CGO interaction with libsubid.so is loosely based on 'readSubid' in github.com/containers/storage/pkg/idtools [1]. Unlike 'readSubid', this code considers the absence of any range (ie., nRanges == 0) to be an error as well. More importantly, this code uses dlopen(3) and friends to dynamically load the symbols from libsubid.so, instead of linking to libsubid.so at build-time and having the dependency noted in the /usr/bin/toolbox binary. This is done because libsubid.so itself depends on several other shared libraries, and indirect dependencies can't be influenced by the RUNPATH [2] embedded in the /usr/bin/toolbox binary [3]. Hence, when the binary is used inside Toolbx containers (eg., as the entry point), those indirect dependencies won't be picked from the host's runtime against which the binary was built. This can render the binary useless due to ABI compatibility issues. Using dlopen(3) avoids this problem, especially because libsubid.so is only used when running on the host. Care was taken to not load and link libsubid.so twice to separately validate the subordinate ranges for the user and the group. Sadly, there doesn't seem to be a way to close the file descriptor that's used by libsubid.so for logging. Hence, this one file descriptor (currently number 3, unless the parent process passes down others) pointing to /dev/null is leaked for the life cycle of the toolbox process. Version 4 of the libsubid.so API/ABI [4] was released in Shadow 4.10, which is newer than the versions shipped on RHEL 8 and Debian 10 [5], and even that newer version had some problems [6]. Therefore, support for older versions, with the relevant workarounds, is necessary. This code doesn't set the public variables Prog and shadow_logfd that older Shadow versions used to expect for logging, because from Shadow 4.9 onwards there's a separate function [4,7] to specify these. This can be changed if there are libsubid.so versions in the wild that really do need those public variables to be set. Finally, ISO C99 is required because of the use of <stdbool.h> in the libsubid.so API. Some changes by Debarshi Ray. [1] https://github.com/containers/storage/blob/main/pkg/idtools/idtools_supported.go [2] https://man7.org/linux/man-pages/man8/ld.so.8.html [3] Commit 6063eb2 containers#821 [4] Shadow commit 32f641b207f6ddff shadow-maint/shadow@32f641b207f6ddff shadow-maint/shadow#443 [5] https://packages.debian.org/source/buster/shadow [6] Shadow commit 79157cbad87f42cd shadow-maint/shadow@79157cbad87f42cd shadow-maint/shadow#465 [7] Shadow commit 2b22a6909dba60d shadow-maint/shadow@2b22a6909dba60d shadow-maint/shadow#325 containers#1074 Signed-off-by: Martin Jackson <[email protected]>
- Loading branch information
1 parent
e789c16
commit d3a9f3e
Showing
7 changed files
with
157 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* | ||
* Copyright © 2019 – 2022 Red Hat Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package utils | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os/user" | ||
"unsafe" | ||
) | ||
|
||
/* | ||
#cgo LDFLAGS: -ldl | ||
#include <stdbool.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <dlfcn.h> | ||
#include <shadow/subid.h> | ||
#if SUBID_ABI_MAJOR < 4 | ||
# define subid_get_gid_ranges get_subgid_ranges | ||
# define subid_get_uid_ranges get_subuid_ranges | ||
#endif | ||
#define TOOLBOX_STRINGIFY_HELPER(s) #s | ||
#define TOOLBOX_STRINGIFY(s) TOOLBOX_STRINGIFY_HELPER (s) | ||
typedef bool (*ToolboxSubidInitFunc) (const char *progname, FILE *logfd); | ||
typedef int (*ToolboxSubidGetRangesFunc) (const char *owner, struct subid_range **ranges); | ||
const char *TOOLBOX_LIBSUBID = "libsubid.so." TOOLBOX_STRINGIFY (SUBID_ABI_VERSION); | ||
const char *TOOLBOX_LIBSUBID_INIT = "libsubid_init"; | ||
const char *TOOLBOX_SUBID_INIT = "subid_init"; | ||
const char *TOOLBOX_SUBID_GET_GID_RANGES_SYMBOL = TOOLBOX_STRINGIFY (subid_get_gid_ranges); | ||
const char *TOOLBOX_SUBID_GET_UID_RANGES_SYMBOL = TOOLBOX_STRINGIFY (subid_get_uid_ranges); | ||
void | ||
toolbox_subid_init (void *subid_init_func) | ||
{ | ||
(* (ToolboxSubidInitFunc) subid_init_func) (NULL, NULL); | ||
} | ||
int | ||
toolbox_subid_get_id_ranges (void *subid_get_id_ranges_func, const char *owner, struct subid_range **ranges) | ||
{ | ||
int ret_val = 0; | ||
ret_val = (* (ToolboxSubidGetRangesFunc) subid_get_id_ranges_func) (owner, ranges); | ||
return ret_val; | ||
} | ||
*/ | ||
import "C" | ||
|
||
func validateSubIDRange(user *user.User, libsubid unsafe.Pointer, cSubidGetIDRangesSymbol *C.char) (bool, error) { | ||
subid_get_id_ranges := C.dlsym(libsubid, cSubidGetIDRangesSymbol) | ||
if subid_get_id_ranges == nil { | ||
subidGetIDRangesSymbol := C.GoString(cSubidGetIDRangesSymbol) | ||
return false, fmt.Errorf("cannot dlsym(3) %s", subidGetIDRangesSymbol) | ||
} | ||
|
||
cUsername := C.CString(user.Username) | ||
defer C.free(unsafe.Pointer(cUsername)) | ||
|
||
var cRanges *C.struct_subid_range | ||
defer C.free(unsafe.Pointer(cRanges)) | ||
|
||
nRanges := C.toolbox_subid_get_id_ranges(subid_get_id_ranges, cUsername, &cRanges) | ||
if nRanges <= 0 { | ||
cUid := C.CString(user.Uid) | ||
defer C.free(unsafe.Pointer(cUid)) | ||
|
||
nRanges = C.toolbox_subid_get_id_ranges(subid_get_id_ranges, cUid, &cRanges) | ||
} | ||
|
||
if nRanges <= 0 { | ||
return false, errors.New("cannot read subids") | ||
} | ||
|
||
return true, nil | ||
} | ||
|
||
func ValidateSubIDRanges(user *user.User) (bool, error) { | ||
if IsInsideContainer() { | ||
panic("cannot validate subordinate IDs inside container") | ||
} | ||
|
||
if user == nil { | ||
panic("cannot validate subordinate IDs when user is nil") | ||
} | ||
|
||
if user.Username == "ALL" { | ||
return false, errors.New("username ALL not supported") | ||
} | ||
|
||
libsubid := C.dlopen(C.TOOLBOX_LIBSUBID, C.RTLD_LAZY) | ||
if libsubid == nil { | ||
filename := C.GoString(C.TOOLBOX_LIBSUBID) | ||
return false, fmt.Errorf("cannot dlopen(3) %s", filename) | ||
} | ||
|
||
defer C.dlclose(libsubid) | ||
|
||
subid_init := C.dlsym(libsubid, C.TOOLBOX_SUBID_INIT) | ||
if subid_init == nil { | ||
subid_init = C.dlsym(libsubid, C.TOOLBOX_LIBSUBID_INIT) | ||
} | ||
|
||
if subid_init != nil { | ||
C.toolbox_subid_init(subid_init) | ||
} | ||
|
||
if _, err := validateSubIDRange(user, libsubid, C.TOOLBOX_SUBID_GET_GID_RANGES_SYMBOL); err != nil { | ||
return false, err | ||
} | ||
|
||
if _, err := validateSubIDRange(user, libsubid, C.TOOLBOX_SUBID_GET_UID_RANGES_SYMBOL); err != nil { | ||
return false, err | ||
} | ||
|
||
return true, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters