mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2024-12-25 14:36:33 +01:00
build: add initial build structure for sub packages.
This commit is contained in:
parent
467b24ccee
commit
a1c8260305
5 changed files with 391 additions and 37 deletions
|
@ -37,8 +37,6 @@ func init() {
|
|||
|
||||
// Compatibility with AppArmor 3
|
||||
switch prebuild.Distribution {
|
||||
case "arch":
|
||||
|
||||
case "ubuntu":
|
||||
if !slices.Contains([]string{"noble"}, prebuild.Release["VERSION_CODENAME"]) {
|
||||
prebuild.ABI = 3
|
||||
|
|
|
@ -6,6 +6,8 @@ package builder
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/roddhjav/apparmor.d/pkg/paths"
|
||||
"github.com/roddhjav/apparmor.d/pkg/prebuild"
|
||||
|
@ -33,7 +35,7 @@ type Option struct {
|
|||
|
||||
func NewOption(file *paths.Path) *Option {
|
||||
return &Option{
|
||||
Name: file.Base(),
|
||||
Name: strings.TrimSuffix(file.Base(), ".apparmor.d"),
|
||||
File: file,
|
||||
}
|
||||
}
|
||||
|
@ -41,13 +43,26 @@ func NewOption(file *paths.Path) *Option {
|
|||
func Register(names ...string) {
|
||||
for _, name := range names {
|
||||
if b, present := Builders[name]; present {
|
||||
Builds = append(Builds, b)
|
||||
if !slices.Contains(Builds, b) {
|
||||
Builds = append(Builds, b)
|
||||
}
|
||||
} else {
|
||||
panic(fmt.Sprintf("Unknown builder: %s", name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Unregister(names ...string) {
|
||||
for _, name := range names {
|
||||
for i, b := range Builds {
|
||||
if b.Name() == name {
|
||||
Builds = slices.Delete(Builds, i, i+1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterBuilder(d Builder) {
|
||||
Builders[d.Name()] = d
|
||||
}
|
||||
|
|
|
@ -19,17 +19,19 @@ import (
|
|||
|
||||
const (
|
||||
nilABI uint = 0
|
||||
usage = `aa-prebuild [-h] [--complain | --enforce] [--full] [--abi 3|4]
|
||||
usage = `aa-prebuild [-h] [-s] [--complain|--enforce] [--packages] [--full] [--abi 3|4]
|
||||
|
||||
Prebuild apparmor.d profiles for a given distribution and apply
|
||||
internal built-in directives.
|
||||
Prebuild apparmor.d profiles for a given distribution, apply
|
||||
internal built-in directives and build sub-packages structure.
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message and exit.
|
||||
-c, --complain Set complain flag on all profiles.
|
||||
-e, --enforce Set enforce flag on all profiles.
|
||||
-e, --enforce Set enforce flag on ALL profiles.
|
||||
-a, --abi ABI Target apparmor ABI.
|
||||
-f, --full Set AppArmor for full system policy.
|
||||
-p, --packages Build all split packages.
|
||||
-s, --status Show build configuration.
|
||||
-F, --file Only prebuild a given file.
|
||||
`
|
||||
)
|
||||
|
@ -39,6 +41,7 @@ var (
|
|||
complain bool
|
||||
enforce bool
|
||||
full bool
|
||||
packages bool
|
||||
abi uint
|
||||
file string
|
||||
)
|
||||
|
@ -54,6 +57,8 @@ func init() {
|
|||
flag.BoolVar(&enforce, "enforce", false, "Set enforce flag on all profiles.")
|
||||
flag.UintVar(&abi, "a", nilABI, "Target apparmor ABI.")
|
||||
flag.UintVar(&abi, "abi", nilABI, "Target apparmor ABI.")
|
||||
flag.BoolVar(&packages, "p", false, "Build all split packages.")
|
||||
flag.BoolVar(&packages, "packages", false, "Build all split packages.")
|
||||
flag.StringVar(&file, "F", "", "Only prebuild a given file.")
|
||||
flag.StringVar(&file, "file", "", "Only prebuild a given file.")
|
||||
}
|
||||
|
@ -79,12 +84,6 @@ func Prebuild() {
|
|||
prepare.Register("systemd-early")
|
||||
}
|
||||
|
||||
if complain {
|
||||
builder.Register("complain")
|
||||
} else if enforce {
|
||||
builder.Register("enforce")
|
||||
}
|
||||
|
||||
if abi != nilABI {
|
||||
prebuild.ABI = abi
|
||||
}
|
||||
|
@ -104,13 +103,32 @@ func Prebuild() {
|
|||
overwrite.OneFile = true
|
||||
}
|
||||
|
||||
logging.Step("Building apparmor.d profiles for %s on ABI%d.", prebuild.Distribution, prebuild.ABI)
|
||||
// Prepare the build directories
|
||||
logging.Step("Building apparmor.d profiles for %s (abi%d).", prebuild.Distribution, prebuild.ABI)
|
||||
prebuild.RootApparmord = prebuild.Root.Join(prebuild.Src)
|
||||
if err := Prepare(); err != nil {
|
||||
logging.Fatal("%s", err.Error())
|
||||
}
|
||||
|
||||
// Generate the packages
|
||||
if packages {
|
||||
if err := Packages(); err != nil {
|
||||
logging.Fatal("%s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Build the apparmor.d profiles
|
||||
if err := Build(); err != nil {
|
||||
logging.Fatal("%s", err.Error())
|
||||
}
|
||||
|
||||
if packages {
|
||||
// Move all other profiles to apparmor.d.other
|
||||
prebuild.RootApparmord = prebuild.Root.Join(prebuild.Src)
|
||||
if err := prebuild.RootApparmord.Rename(prebuild.Root.Join("other")); err != nil {
|
||||
logging.Fatal("%s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Prepare() error {
|
||||
|
@ -136,26 +154,64 @@ func Prepare() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func Packages() error {
|
||||
logging.Success("Building apparmor.d.* packages structure:")
|
||||
|
||||
for _, name := range prebuild.Packages {
|
||||
pkg := prebuild.NewPackage(name)
|
||||
msg, err := pkg.Generate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = pkg.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
logging.Indent = " "
|
||||
logging.Bullet("apparmor.d.%s", name)
|
||||
logging.Indent += " "
|
||||
for _, line := range util.RemoveDuplicate(msg) {
|
||||
logging.Warning("%s", line)
|
||||
}
|
||||
logging.Indent = ""
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Build() error {
|
||||
files, _ := prebuild.RootApparmord.ReadDirRecursiveFiltered(nil, paths.FilterOutDirectories())
|
||||
for _, file := range files {
|
||||
if !file.Exist() {
|
||||
continue
|
||||
sources := []string{prebuild.Src}
|
||||
if packages {
|
||||
sources = append(sources, prebuild.Packages...)
|
||||
}
|
||||
|
||||
for _, src := range sources {
|
||||
prebuild.RootApparmord = prebuild.Root.Join(src)
|
||||
if src == prebuild.Src {
|
||||
setMode("")
|
||||
} else {
|
||||
pkg := prebuild.NewPackage(src)
|
||||
setMode(pkg.Mode)
|
||||
}
|
||||
profile, err := file.ReadFileAsString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profile, err = builder.Run(file, profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profile, err = directive.Run(file, profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.WriteFile([]byte(profile)); err != nil {
|
||||
return err
|
||||
|
||||
files, _ := prebuild.RootApparmord.ReadDirRecursiveFiltered(nil, paths.FilterOutDirectories())
|
||||
for _, file := range files {
|
||||
if !file.Exist() {
|
||||
continue
|
||||
}
|
||||
profile, err := file.ReadFileAsString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profile, err = builder.Run(file, profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
profile, err = directive.Run(file, profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := file.WriteFile([]byte(profile)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,3 +229,20 @@ func Build() error {
|
|||
logging.Indent = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func setMode(mode string) {
|
||||
if mode == "" {
|
||||
if complain {
|
||||
mode = "complain"
|
||||
} else if enforce {
|
||||
mode = "enforce"
|
||||
}
|
||||
}
|
||||
switch mode {
|
||||
case "complain":
|
||||
builder.Register("complain")
|
||||
builder.Unregister("enforce")
|
||||
case "enforce":
|
||||
builder.Unregister("complain")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,17 +4,28 @@
|
|||
|
||||
package prebuild
|
||||
|
||||
import "github.com/roddhjav/apparmor.d/pkg/paths"
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/roddhjav/apparmor.d/pkg/paths"
|
||||
)
|
||||
|
||||
var (
|
||||
// AppArmor ABI version
|
||||
ABI uint = 0
|
||||
|
||||
// Root is the root directory for the build (default: .build)
|
||||
Root *paths.Path = paths.New(".build")
|
||||
// Root is the root directory for the build (default: ./.build)
|
||||
Root *paths.Path = getRootBuild()
|
||||
|
||||
// RootApparmord is the final built apparmor.d directory (default: .build/apparmor.d)
|
||||
RootApparmord *paths.Path = Root.Join("apparmor.d")
|
||||
RootApparmord *paths.Path = Root.Join(Src)
|
||||
|
||||
// src is the basename of the source directory (default: apparmor.d)
|
||||
Src = "apparmor.d"
|
||||
|
||||
// SrcApparmord is the source apparmor.d directory (default: ./apparmor.d)
|
||||
SrcApparmord *paths.Path = paths.New(Src)
|
||||
|
||||
// DistDir is the directory where the distribution specific files are stored
|
||||
DistDir *paths.Path = paths.New("dists")
|
||||
|
@ -25,6 +36,9 @@ var (
|
|||
// IgnoreDir is the directory where the ignore files are stored
|
||||
IgnoreDir *paths.Path = DistDir.Join("ignore")
|
||||
|
||||
// PkgDir is the directory where the packages files are stored
|
||||
PkgDir *paths.Path = DistDir.Join("packages")
|
||||
|
||||
// SystemdDir is the directory where the systemd drop-in files are stored
|
||||
SystemdDir *paths.Path = paths.New("systemd")
|
||||
|
||||
|
@ -34,6 +48,29 @@ var (
|
|||
// DebianHide is the path to the debian/apparmor.d.hide file
|
||||
DebianHide = DebianHider{path: DebianDir.Join("apparmor.d.hide")}
|
||||
|
||||
// Packages are the packages to build
|
||||
Packages = getPackages()
|
||||
|
||||
Ignore = Ignorer{}
|
||||
Flags = Flagger{}
|
||||
)
|
||||
|
||||
func getRootBuild() *paths.Path {
|
||||
root, present := os.LookupEnv("BUILD")
|
||||
if !present {
|
||||
root = ".build"
|
||||
}
|
||||
return paths.New(root)
|
||||
}
|
||||
|
||||
func getPackages() []string {
|
||||
files, err := PkgDir.ReadDirRecursiveFiltered(nil, paths.FilterOutDirectories())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
packages := make([]string, 0, len(files))
|
||||
for _, file := range files {
|
||||
packages = append(packages, strings.TrimSuffix(file.Base(), ".conf"))
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
|
231
pkg/prebuild/packages.go
Normal file
231
pkg/prebuild/packages.go
Normal file
|
@ -0,0 +1,231 @@
|
|||
// apparmor.d - Full set of apparmor profiles
|
||||
// Copyright (C) 2021-2024 Alexandre Pujol <alexandre@pujol.io>
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
package prebuild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/roddhjav/apparmor.d/pkg/paths"
|
||||
)
|
||||
|
||||
type Package struct {
|
||||
Name string
|
||||
Mode string
|
||||
Required []string
|
||||
Profiles []string
|
||||
Ignores []string
|
||||
Ignored []string
|
||||
builddir *paths.Path
|
||||
}
|
||||
|
||||
func NewPackage(name string) *Package {
|
||||
path := PkgDir.Join(name + ".conf")
|
||||
if !path.Exist() {
|
||||
panic(fmt.Sprintf("Unknown package: %s", name))
|
||||
}
|
||||
lines := path.MustReadFilteredFileAsLines()
|
||||
mode := ""
|
||||
profiles := make([]string, 0, len(lines))
|
||||
ignores := []string{}
|
||||
dependencies := []string{}
|
||||
ignored := getFilesIgnoredByDistribution()
|
||||
for _, line := range lines {
|
||||
switch {
|
||||
case strings.HasPrefix(line, "mode="):
|
||||
mode = strings.TrimPrefix(line, "mode=")
|
||||
case strings.HasPrefix(line, "require="):
|
||||
dependencies = strings.Split(strings.TrimPrefix(line, "require="), ",")
|
||||
case strings.HasPrefix(line, "!"):
|
||||
ignores = append(ignores, strings.TrimPrefix(line, "!"))
|
||||
default:
|
||||
profiles = append(profiles, line)
|
||||
}
|
||||
}
|
||||
return &Package{
|
||||
Name: name,
|
||||
Mode: mode,
|
||||
Required: dependencies,
|
||||
Profiles: profiles,
|
||||
Ignores: ignores,
|
||||
Ignored: ignored,
|
||||
builddir: Root.Join(name),
|
||||
}
|
||||
}
|
||||
|
||||
func getFilesIgnoredByDistribution() []string {
|
||||
res := []string{}
|
||||
for _, iname := range []string{"main", Distribution} {
|
||||
for _, ignore := range Ignore.Read(iname) {
|
||||
if !strings.HasPrefix(ignore, Src) {
|
||||
continue
|
||||
}
|
||||
profile := strings.TrimPrefix(ignore, Src+"/")
|
||||
path := SrcApparmord.Join(profile)
|
||||
if path.IsDir() {
|
||||
files, err := path.ReadDirRecursiveFiltered(nil, paths.FilterOutDirectories())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
res = append(res, file.Base())
|
||||
}
|
||||
} else if path.Exist() {
|
||||
res = append(res, path.Base())
|
||||
} else {
|
||||
panic(fmt.Errorf("%s.ignore: no files found for '%s'", iname, profile))
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *Package) Generate() ([]string, error) {
|
||||
var res []string
|
||||
|
||||
if err := p.builddir.RemoveAll(); err != nil {
|
||||
return res, err
|
||||
}
|
||||
if err := p.builddir.MkdirAll(); err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
explode := paths.PathList{
|
||||
paths.New("groups"), paths.New("profiles-a-f"),
|
||||
paths.New("profiles-m-r"), paths.New("profiles-s-z"),
|
||||
}
|
||||
for _, name := range p.Profiles {
|
||||
originalPath := SrcApparmord.Join(name)
|
||||
|
||||
if originalPath.IsDir() {
|
||||
originFiles, err := originalPath.ReadDirRecursiveFiltered(nil, paths.FilterOutDirectories())
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
for _, originFile := range originFiles {
|
||||
file, err := originFile.RelFrom(SrcApparmord)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if slices.Contains(p.Ignores, file.String()) {
|
||||
continue
|
||||
}
|
||||
|
||||
done := false
|
||||
for _, e := range explode {
|
||||
if ok, _ := file.IsInsideDir(e); ok {
|
||||
base := file.Base()
|
||||
msg, err := p.move(base)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = append(res, msg)
|
||||
done = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !done {
|
||||
msg, err := p.move(file)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = append(res, msg)
|
||||
}
|
||||
}
|
||||
|
||||
} else if originalPath.Exist() {
|
||||
base := originalPath.Base()
|
||||
if slices.Contains(p.Ignores, base) {
|
||||
continue
|
||||
}
|
||||
msg, err := p.move(base)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = append(res, msg)
|
||||
|
||||
} else {
|
||||
return res, fmt.Errorf("No %s", originalPath)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (p *Package) move(origin any) (string, error) {
|
||||
var src *paths.Path
|
||||
var dst *paths.Path
|
||||
var srcOverridden *paths.Path
|
||||
var dstOverridden *paths.Path
|
||||
var srcSymlink *paths.Path
|
||||
var dstSymlink *paths.Path
|
||||
const ext = ".apparmor.d"
|
||||
|
||||
switch value := any(origin).(type) {
|
||||
case string:
|
||||
src = RootApparmord.Join(value)
|
||||
dst = p.builddir.Join(value)
|
||||
srcOverridden = RootApparmord.Join(value + ext)
|
||||
dstOverridden = p.builddir.Join(value + ext)
|
||||
srcSymlink = RootApparmord.Join("disable", value)
|
||||
dstSymlink = p.builddir.Join("disable", value)
|
||||
|
||||
case *paths.Path:
|
||||
src = RootApparmord.JoinPath(value)
|
||||
dst = p.builddir.JoinPath(value)
|
||||
srcOverridden = RootApparmord.JoinPath(value.Parent()).Join(value.Base() + ext)
|
||||
dstOverridden = p.builddir.JoinPath(value.Parent()).Join(value.Base() + ext)
|
||||
srcSymlink = RootApparmord.Join("disable").JoinPath(value)
|
||||
dstSymlink = p.builddir.Join("disable").JoinPath(value)
|
||||
|
||||
default:
|
||||
panic("Package.move: unsupported type")
|
||||
}
|
||||
|
||||
if src.Exist() {
|
||||
if err := dst.Parent().MkdirAll(); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if err := src.Rename(dst); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
// fmt.Printf("%s -> %s\n", src, dst)
|
||||
|
||||
} else if srcOverridden.Exist() {
|
||||
if err := dstOverridden.Parent().MkdirAll(); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if err := dstSymlink.Parent().MkdirAll(); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if err := srcOverridden.Rename(dstOverridden); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if err := srcSymlink.Rename(dstSymlink); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
// fmt.Printf("%s -> %s\n", srcOverridden, dstOverridden)
|
||||
|
||||
} else {
|
||||
srcRltv, err := src.RelFrom(RootApparmord)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
if !slices.Contains(p.Ignored, srcRltv.String()) {
|
||||
fmt.Printf("Warning: No %s\n", src)
|
||||
// return "", fmt.Errorf("No %s", src)
|
||||
}
|
||||
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Validate ensures a package has its required dependencies
|
||||
func (p *Package) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in a new issue