Skip to content

Commit d05c3e7

Browse files
authored
Fix shadow-utils detection in imager as well as validator (#11914)
1 parent cf0f291 commit d05c3e7

3 files changed

Lines changed: 99 additions & 22 deletions

File tree

toolkit/tools/imageconfigvalidator/imageconfigvalidator.go

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"github.com/microsoft/azurelinux/toolkit/tools/imagegen/installutils"
1616
"github.com/microsoft/azurelinux/toolkit/tools/internal/exe"
1717
"github.com/microsoft/azurelinux/toolkit/tools/internal/logger"
18-
"github.com/microsoft/azurelinux/toolkit/tools/internal/pkgjson"
1918
"github.com/microsoft/azurelinux/toolkit/tools/internal/timestamp"
2019
"github.com/microsoft/azurelinux/toolkit/tools/pkg/profile"
2120

@@ -135,28 +134,30 @@ func validatePackages(config configuration.Config) (err error) {
135134
selinuxPkgName = configuration.SELinuxPolicyDefault
136135
}
137136

138-
for _, pkg := range packageList {
139-
// The installer tools have an undocumented feature which can support both "pkg-name" and "pkg-name=version" formats.
140-
// This is in use, so we need to handle pinned versions in this check. Technically, 'tdnf' also supports "pkg-name-version" format,
141-
// but it is not easily distinguishable from "long-package-name" format so it will not be supported here.
142-
pkgVer, err := pkgjson.PackageStringToPackageVer(pkg)
143-
if err != nil {
144-
return fmt.Errorf("%s: %w", validateError, err)
145-
}
137+
foundKernelPackage, err := installutils.PackagelistContainsPackage(packageList, kernelPkgName)
138+
if err != nil {
139+
return fmt.Errorf("%s: %w", validateError, err)
140+
}
146141

147-
if pkgVer.Name == kernelPkgName {
148-
return fmt.Errorf("%s: kernel should not be included in a package list, add via config file's [KernelOptions] entry", validateError)
149-
}
150-
if pkgVer.Name == dracutFipsPkgName {
151-
foundDracutFipsPackage = true
152-
}
153-
if pkgVer.Name == selinuxPkgName {
154-
foundSELinuxPackage = true
155-
}
156-
if pkgVer.Name == userAddPkgName {
157-
foundUserAddPackage = true
158-
}
142+
foundDracutFipsPackage, err = installutils.PackagelistContainsPackage(packageList, dracutFipsPkgName)
143+
if err != nil {
144+
return fmt.Errorf("%s: %w", validateError, err)
159145
}
146+
147+
foundSELinuxPackage, err = installutils.PackagelistContainsPackage(packageList, selinuxPkgName)
148+
if err != nil {
149+
return fmt.Errorf("%s: %w", validateError, err)
150+
}
151+
152+
foundUserAddPackage, err = installutils.PackagelistContainsPackage(packageList, userAddPkgName)
153+
if err != nil {
154+
return fmt.Errorf("%s: %w", validateError, err)
155+
}
156+
157+
if foundKernelPackage {
158+
return fmt.Errorf("%s: kernel should not be included in a package list, add via config file's [KernelOptions] entry", validateError)
159+
}
160+
160161
if strings.Contains(kernelCmdLineString, fipsKernelCmdLine) || systemConfig.KernelCommandLine.EnableFIPS {
161162
if !foundDracutFipsPackage {
162163
return fmt.Errorf("%s: 'fips=1' provided on kernel cmdline, but '%s' package is not included in the package lists", validateError, dracutFipsPkgName)

toolkit/tools/imagegen/installutils/installutils.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,29 @@ func orderPackageInstallList(packageList []string) []string {
453453
return orderedPackageList
454454
}
455455

456+
// PackagelistContainsPackage checks if the given package is in the list of packages to install. It will do
457+
// a fuzzy search for the package name and try to ignore version info.
458+
//
459+
// The installer tools have an undocumented feature which can support both "pkg-name" and "pkg-name=version" formats.
460+
// This is in use, so we need to handle pinned versions in this check. Technically, 'tdnf' also supports "pkg-name-version" format,
461+
// but it is not easily distinguishable from "long-package-name" format so it will not be supported here.
462+
func PackagelistContainsPackage(packageList []string, packageName string) (found bool, err error) {
463+
if packageName == "" {
464+
return false, fmt.Errorf("can't search for an empty package name")
465+
}
466+
467+
for _, pkg := range packageList {
468+
pkgVer, err := pkgjson.PackageStringToPackageVer(pkg)
469+
if err != nil {
470+
return false, err
471+
}
472+
if pkgVer.Name == packageName {
473+
return true, nil
474+
}
475+
}
476+
return false, nil
477+
}
478+
456479
// PopulateInstallRoot fills the installroot with packages and configures the image for boot
457480
// - installChroot is a pointer to the install Chroot object
458481
// - packagesToInstall is a slice of packages to install
@@ -532,7 +555,13 @@ func PopulateInstallRoot(installChroot *safechroot.Chroot, packagesToInstall []s
532555

533556
// imageconfigvalidator should have ensured that we intend to install shadow-utils, so we can go ahead and do that here.
534557
if len(config.Users) > 0 || len(config.Groups) > 0 {
535-
if !sliceutils.ContainsValue(packagesToInstall, "shadow-utils") {
558+
var hasShadowUtils bool
559+
hasShadowUtils, err = PackagelistContainsPackage(packagesToInstall, "shadow-utils")
560+
if err != nil {
561+
err = fmt.Errorf("failed to check for shadow-utils package in package list:\n%w", err)
562+
return
563+
}
564+
if !hasShadowUtils {
536565
err = fmt.Errorf("shadow-utils package must be added to the image's package lists when setting users or groups")
537566
return
538567
}

toolkit/tools/imagegen/installutils/installutils_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,50 @@ func TestAddImageIDFileGuardClause(t *testing.T) {
197197
err = AddImageIDFile(chroot.RootDir(), "")
198198
assert.Error(t, err)
199199
}
200+
201+
func TestPackagelistContainsPackage(t *testing.T) {
202+
packageList := []string{
203+
"package1",
204+
"package2",
205+
"package3",
206+
}
207+
208+
found, err := PackagelistContainsPackage(packageList, "package2")
209+
assert.NoError(t, err)
210+
assert.True(t, found)
211+
212+
found, err = PackagelistContainsPackage(packageList, "package4")
213+
assert.NoError(t, err)
214+
assert.False(t, found)
215+
216+
found, err = PackagelistContainsPackage(nil, "package4")
217+
assert.NoError(t, err)
218+
assert.False(t, found)
219+
220+
found, err = PackagelistContainsPackage(packageList, "")
221+
assert.Error(t, err)
222+
assert.False(t, found)
223+
}
224+
225+
func TestPackagelistContainsPackageBadVersion(t *testing.T) {
226+
packageList := []string{
227+
"bad package = bad < version",
228+
}
229+
230+
found, err := PackagelistContainsPackage(packageList, "package2")
231+
assert.Error(t, err)
232+
assert.False(t, found)
233+
}
234+
235+
func TestPackagelistContainsPackageVersions(t *testing.T) {
236+
packageList := []string{
237+
"package1",
238+
"package2",
239+
"package3",
240+
"package4 = 1.2.3",
241+
}
242+
243+
found, err := PackagelistContainsPackage(packageList, "package4")
244+
assert.NoError(t, err)
245+
assert.True(t, found)
246+
}

0 commit comments

Comments
 (0)