Quadlet: fix filters failure when the search paths are symlinks

Rootless units placed in `users` would be loaded for root when
`/etc/containers/systemd` is a symlink. In this case, since
`UnitDirAdmin` is hardcoded, `userLevelFilter` always returns `true`.
If `/etc/containers/systemd/users` is a symlink, any user would load
other users' units.
Fix the above two problems.

Fixes: #23483

Signed-off-by: Uzinn Kagurazaka <uzinn.kagurazaka@11555511.xyz>
This commit is contained in:
Uzinn Kagurazaka
2024-08-06 01:01:43 +08:00
parent 48e727f1b4
commit b0948a5cd0
2 changed files with 145 additions and 58 deletions

View File

@ -34,10 +34,6 @@ var (
versionFlag bool // True if -version is used
)
const (
SystemUserDirLevel = 5
)
var (
// data saved between logToKmsg calls
noKmsg = false
@ -59,6 +55,12 @@ var (
}
)
var (
unitDirAdminUser string
resolvedUnitDirAdminUser string
systemUserDirLevel int
)
// We log directly to /dev/kmsg, because that is the only way to get information out
// of the generator into the system logs.
func logToKmsg(s string) bool {
@ -115,6 +117,14 @@ func getUnitDirs(rootless bool) []string {
unitDirsEnv := os.Getenv("QUADLET_UNIT_DIRS")
dirs := make([]string, 0)
unitDirAdminUser = filepath.Join(quadlet.UnitDirAdmin, "users")
var err error
if resolvedUnitDirAdminUser, err = filepath.EvalSymlinks(unitDirAdminUser); err != nil {
Debugf("Error occurred resolving path %q: %s", unitDirAdminUser, err)
resolvedUnitDirAdminUser = unitDirAdminUser
}
systemUserDirLevel = len(strings.Split(resolvedUnitDirAdminUser, string(os.PathSeparator)))
if len(unitDirsEnv) > 0 {
for _, eachUnitDir := range strings.Split(unitDirsEnv, ":") {
if !filepath.IsAbs(eachUnitDir) {
@ -185,10 +195,10 @@ func appendSubPaths(dirs []string, path string, isUserFlag bool, filterPtr func(
func nonNumericFilter(_path string, isUserFlag bool) bool {
// when running in rootless, recursive walk directories that are non numeric
// ignore sub dirs under the `users` directory which correspond to a user id
if strings.Contains(_path, filepath.Join(quadlet.UnitDirAdmin, "users")) {
if strings.HasPrefix(_path, resolvedUnitDirAdminUser) {
listDirUserPathLevels := strings.Split(_path, string(os.PathSeparator))
if len(listDirUserPathLevels) > SystemUserDirLevel {
if !(regexp.MustCompile(`^[0-9]*$`).MatchString(listDirUserPathLevels[SystemUserDirLevel])) {
if len(listDirUserPathLevels) > systemUserDirLevel {
if !(regexp.MustCompile(`^[0-9]*$`).MatchString(listDirUserPathLevels[systemUserDirLevel])) {
return true
}
}
@ -201,7 +211,7 @@ func nonNumericFilter(_path string, isUserFlag bool) bool {
func userLevelFilter(_path string, isUserFlag bool) bool {
// if quadlet generator is run rootless, do not recurse other user sub dirs
// if quadlet generator is run as root, ignore users sub dirs
if strings.Contains(_path, filepath.Join(quadlet.UnitDirAdmin, "users")) {
if strings.HasPrefix(_path, resolvedUnitDirAdminUser) {
if isUserFlag {
return true
}