Skip to content

Conversation

capnspacehook
Copy link

@capnspacehook capnspacehook commented May 20, 2025

Ported getseuserbyname (https://github.com/SELinuxProject/selinux/blob/main/libselinux/src/seusers.c#L188) to Go, and added failsafe_context parsing to GetDefaultContextWithLevel as that's what libselinux's get_default_context_with_level does (https://github.com/SELinuxProject/selinux/blob/main/libselinux/src/get_context_list.c#L488).

getseuserbyname reads theseusers file (https://www.man7.org/linux/man-pages/man5/seusers.5.html) to find the SELinux user and the MLS level for a given Linux user.

get_default_context_with_level takes a SELinux user, MLS level, and an SELinux context (combination of SELinux user, role, domain, and MLS level, in many cases this context is the context of the caller) and returns the SELinux context that should be used when creating processes as a certain Linux user.

get_default_context_with_level attempts to find a suitable context for the specific SELinux user that was passed first, then searches in the list of global context mappings if no match was found, and finally just returns the failsafe context if no match was found anywhere else. GetDefaultContextWithLevel previously returned an error if no context could be found for the SELinux user or globally.

Man page for failsafe_context: https://www.man7.org/linux//man-pages/man5/failsafe_context.5.html

@rhatdan
Copy link
Collaborator

rhatdan commented Sep 4, 2025

Missed this, could you sign your commit?

@rhatdan
Copy link
Collaborator

rhatdan commented Sep 4, 2025

LGTM
@kolyshkin @thaJeztah PTAL

@capnspacehook
Copy link
Author

@rhatdan no prob, signed commit

@kolyshkin
Copy link
Collaborator

@capnspacehook can you split this into two commits, by functionality. Same PR is fine.

@capnspacehook
Copy link
Author

@kolyshkin split into two commits

Comment on lines +1277 to +1284
usr, err := user.Lookup(username)
if err != nil {
return "", "", fmt.Errorf("failed to lookup user %q", username)
}
gids, err := usr.GroupIds()
if err != nil {
return "", "", fmt.Errorf("failed to find user %q's groups", username)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like both user.Lookup and (*user.User).GroupIds already return adequate errors, such as:

user: unknown user xxx
user: lookup username xxx: <os-error>
user: list groups for xxx: invalid gid yyy
user: xxx is a member of more than <maxGroups> groups
user: list groups for xxx failed

Why are you choosing to not pass it onto the caller? I would just do return err here.

Comment on lines +1269 to +1271
func getSeUserByName(username string) (seUser string, level string, err error) {
seUsersConf := filepath.Join(policyRoot(), "seusers")
confFile, err := os.Open(seUsersConf)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we have two err variables here: first comes from a named return value, and the second you instantiate here. Not a bug per se but makes the code slightly more complicated.

var groupSeUser, groupLevel string

lineNum := -1
scanner := bufio.NewScanner(r)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use bufio.NewReader and ReadBytes('\n') here.

Comment on lines +1210 to +1211
// remove any trailing comments, then extra whitespace
parts := strings.SplitN(line, "#", 2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are trailing comments allowed? In C code they ignore empty lines, or lines consisting entirely of whitespace, or lines that start with (optional) whitespace and then #. I don't see any trailing comments handling.

continue
}

parts = strings.SplitN(line, ":", 3)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use strings.Cut here as otherwise you're allocating slices for the garbage collector to free.

Copy link
Collaborator

@kolyshkin kolyshkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the second patch -- I see we're opening two files in getDefaultContextWithLevel, while we might not even read the second one. Your patch adds a third file to open.

Maybe we can rework the code first to open the file only when needed (the most changes will be in the tests I guess), then add the failsafe context?

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.

3 participants