Merge FSP: rewrite the systemd profiles #753

* dev: (49 commits)
  fix: use mappings/sudo in su.
  build: justfile: add group.
  tests: update sbin.list
  fix: linter check.
  fix: add gpartedbin back to sbin.list.
  tests: show error line in sbin check.
  feat(profile): update sbin list and ensure the profiles use the good variable (sbin or bin).
  tests: remove symbolic link from sbin.
  test: add some security checks.
  tests: add more check for sbin path
  tests: rewrite and expand the profile check to more files.
  feat(tunable): add the archive_path variable.
  feat(profile): update gnome profiles.
  feat(fsp): small fsp improvement.
  feat(abs): minor improvement & cosmetic.
  feat(profile): add profiles for whoopsie.
  feat(profile): add initial profile for systemd-initctl.
  feat(profile): minor fsp related improvment.
  feat(fsp): setup RBAC mapping in auth enabled profiles.
  build: ignore all rule in abi3.
  ...
This commit is contained in:
Alexandre Pujol 2025-06-16 21:41:08 +02:00
commit 5e14271f76
No known key found for this signature in database
GPG key ID: C5469996F0DF68EC
326 changed files with 2692 additions and 1532 deletions

View file

@ -29,7 +29,7 @@ func init() {
"ro", "rw", "acl", "async", "atime", "bind", "dev", "diratime",
"dirsync", "exec", "iversion", "loud", "mand", "move", "noacl",
"noatime", "nodev", "nodiratime", "noexec", "noiversion", "nomand",
"norelatime", "nosuid", "nouser", "private", "rbind", "relatime",
"norelatime", "nosuid", "nosymfollow", "nouser", "private", "rbind", "relatime",
"remount", "rprivate", "rshared", "rslave", "runbindable", "shared",
"silent", "slave", "strictatime", "suid", "sync", "unbindable",
"user", "verbose",

View file

@ -182,7 +182,7 @@ func toValues(kind Kind, key string, input string) ([]string, error) {
continue
}
if !slices.Contains(req, res[idx]) {
return nil, fmt.Errorf("unrecognized %s: %s", key, res[idx])
return nil, fmt.Errorf("unrecognized %s for rule %s: %s", key, kind, res[idx])
}
}
slices.SortFunc(res, func(i, j string) int {

View file

@ -14,6 +14,7 @@ var (
`abi/4.0`, `abi/3.0`,
` userns,`, ` # userns,`,
` mqueue`, ` # mqueue`,
` all`, ` # all`,
` deny mqueue`, ` # deny mqueue`,
})
)

View file

@ -80,6 +80,7 @@ func Configure() {
if full && paths.New("apparmor.d/groups/_full").Exist() {
prepare.Register("fsp")
builder.Register("fsp")
prebuild.RBAC = true
} else if prebuild.SystemdDir.Exist() {
prepare.Register("systemd-early")
}

View file

@ -39,6 +39,10 @@ func init() {
}
func filterRuleForUs(opt *Option) bool {
if prebuild.RBAC && slices.Contains(opt.ArgList, "RBAC") {
return true
}
abiStr := fmt.Sprintf("abi%d", prebuild.ABI)
if slices.Contains(opt.ArgList, abiStr) {
return true

View file

@ -55,7 +55,10 @@ func (s Stack) Apply(opt *Option, profile string) (string, error) {
res := ""
for name := range opt.ArgMap {
stackedProfile := prebuild.RootApparmord.Join(name).MustReadFileAsString()
stackedProfile, err := prebuild.RootApparmord.Join(name).ReadFileAsString()
if err != nil {
return "", fmt.Errorf("%s need to stack: %w", name, err)
}
m := regRules.FindStringSubmatch(stackedProfile)
if len(m) < 2 {
return "", fmt.Errorf("no profile found in %s", name)

View file

@ -13,6 +13,9 @@ var (
// AppArmor version
Version = 4.0
// Either or not RBAC is enabled
RBAC = false
// Pkgname is the name of the package
Pkgname = "apparmor.d"

View file

@ -5,11 +5,60 @@
package prepare
import (
"strings"
"regexp"
"github.com/roddhjav/apparmor.d/pkg/paths"
"github.com/roddhjav/apparmor.d/pkg/prebuild"
"github.com/roddhjav/apparmor.d/pkg/util"
)
var (
tunables = map[string]string{
// Set systemd profiles name
"sd": "sd",
"sdu": "sdu",
"systemd_user": "systemd-user",
"systemd": "systemd",
// With FSP on apparmor 4.1+, the dbus profiles don't get stacked as they
"dbus_system": "dbus-system",
"dbus_session": "dbus-session",
// Update name of stacked profiles
"apt_news": "",
"colord": "",
"e2scrub_all": "",
"e2scrub": "",
"fprintd": "",
"fwupd": "",
"fwupdmgr": "",
"geoclue": "",
"irqbalance": "",
"logrotate": "",
"ModemManager": "",
"nm_priv_helper": "",
"pcscd": "",
"polkitd": "",
"power_profiles_daemon": "",
"rsyslogd": "",
"systemd_coredump": "",
"systemd_homed": "",
"systemd_hostnamed": "",
"systemd_importd": "",
"systemd_initctl": "",
"systemd_journal_remote": "",
"systemd_journald": "",
"systemd_localed": "",
"systemd_logind": "",
"systemd_machined": "",
"systemd_networkd": "",
"systemd_oomd": "",
"systemd_resolved": "",
"systemd_rfkill": "",
"systemd_timedated": "",
"systemd_timesyncd": "",
"systemd_userdbd": "",
"upowerd": "",
}
)
type FullSystemPolicy struct {
@ -33,28 +82,20 @@ func (p FullSystemPolicy) Apply() ([]string, error) {
return res, err
}
// Set systemd profile name
// Set profile name for FSP
path := prebuild.RootApparmord.Join("tunables/multiarch.d/profiles")
out, err := path.ReadFileAsString()
if err != nil {
return res, err
}
out = strings.ReplaceAll(out, "@{p_systemd}=unconfined", "@{p_systemd}=systemd")
out = strings.ReplaceAll(out, "@{p_systemd_executor}=unconfined", "@{p_systemd_executor}=systemd-executor")
out = strings.ReplaceAll(out, "@{p_systemd_user}=unconfined", "@{p_systemd_user}=systemd-user")
out = strings.ReplaceAll(out, "@{p_systemd_user_executor}=unconfined", "@{p_systemd_user_executor}=systemd-user-executor")
if err := path.WriteFile([]byte(out)); err != nil {
return res, err
for varname, profile := range tunables {
pattern := regexp.MustCompile(`(@\{p_` + varname + `}=)([^\s]+)`)
if profile == "" {
out = pattern.ReplaceAllString(out, `@{p_`+varname+`}={$2,sd//&$2,$2//&sd}`)
} else {
out = pattern.ReplaceAllString(out, `@{p_`+varname+`}=`+profile)
}
}
// Fix conflicting x modifiers in abstractions - FIXME: Temporary solution
path = prebuild.RootApparmord.Join("abstractions/gstreamer")
out, err = path.ReadFileAsString()
if err != nil {
return res, err
}
regFixConflictX := util.ToRegexRepl([]string{`.*gst-plugin-scanner.*`, ``})
out = regFixConflictX.Replace(out)
if err := path.WriteFile([]byte(out)); err != nil {
return res, err
}