Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] many: non-setuid snap-confine, caps v4 #15094

Draft
wants to merge 36 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
12f815c
cmd/snap-confine: update cgroup code to run under an ordinary user
mardy Nov 10, 2022
66ba243
snap-confine: create helper function to set capabilities
mardy Nov 9, 2022
d97d182
libsnap-confine-private: add more capability-related methods
mardy Nov 10, 2022
61b4cc8
cmd/snap-confine: drop setuid and use capabilities instead
mardy Nov 10, 2022
c379864
snap-confine: get the current working directory as a user
mardy Nov 10, 2022
c207b68
cmd/snap-confine: add a few debug checkpoints for capabilities
mardy Nov 10, 2022
af0a3a4
snap-confine: update apparmor profile for capability support
mardy Nov 10, 2022
eeaec37
cmd/snap-update-ns: explicitly specify ownership of mount profile
mardy Nov 10, 2022
9da1bc8
snap-confine: move AppArmor check earlier
mardy Nov 15, 2022
461ae9a
snap-confine: remove calls to sc_set_effective_identity()
mardy Nov 8, 2022
87cd9ae
packaging: set capabilities
Meulengracht Jan 2, 2024
4385c73
cmd/make: setcap capabilities when using 'hack' target
bboozzoo Feb 21, 2025
b4b97b8
cmd/make: install-exec-hook is no longer needed
bboozzoo Feb 21, 2025
b18f4a5
cmd/snap-confine: raise root privileges before creating the cgroup fr…
bboozzoo Jan 23, 2025
0e99a15
snapcraft: set snap-confine capabilities
bboozzoo Jan 24, 2025
51f4099
tests/main/snap-confine-caps: verify snap-confine file capabilities
bboozzoo Feb 18, 2025
382ce05
snapcraft: workaround snap pack xattr support HACK
bboozzoo Feb 18, 2025
34613bd
github: snap-builds: use fakeroot when extracting
bboozzoo Feb 18, 2025
26649d9
cmd/libsnap-confine-private: mkdir(at) & chmod helpers
bboozzoo Feb 19, 2025
e29ebbc
cmd/configure: check whether libcap supports cap_set_ambient
bboozzoo Feb 21, 2025
704b6d2
cmd: provide alternative cap_set_ambient, cap_reset_ambient
bboozzoo Feb 20, 2025
804bcc1
cmd/snap-confine/mount: TODOs
bboozzoo Feb 21, 2025
4d5fc9a
cmd/libsnap-confine-private: nonsetuid TODO
bboozzoo Feb 21, 2025
1e9564e
cmd/snap-confine: consolidate on using libcap and smart capability ha…
bboozzoo Feb 21, 2025
162e8b7
data/selinux: update SELinux policy
bboozzoo Feb 21, 2025
149f4fb
cmd/libsnap-confine-private/tool: do not change identity when switchi…
bboozzoo Feb 25, 2025
ee9ac50
cmd/snap-update-ns/bootstrap: verify capabilities, no uid switching
bboozzoo Feb 25, 2025
91e4949
cmd/snap-confine: drop unnecessary s-u-n caps
bboozzoo Feb 25, 2025
375e233
cmd/libsnap-confine-private/privs: simplify dropping privileges
bboozzoo Feb 25, 2025
6af630a
cmd/snap-discard-ns: asssert process capabilities
bboozzoo Feb 26, 2025
0159d2c
cmd/libsnap-confine-private/tool: no identity change when invokign sn…
bboozzoo Feb 26, 2025
db89a7f
tests/main/progress: collect verbose debug log from socat
bboozzoo Feb 26, 2025
bd9a522
fixup! tests/main/snap-confine-caps: verify snap-confine file capabil…
bboozzoo Feb 26, 2025
cf31fea
fixup! data/selinux: update SELinux policy
bboozzoo Feb 26, 2025
fb92de0
tests/main/snap-quota: explicitly remove all created groups during re…
bboozzoo Feb 26, 2025
c304154
tests/main/snap-confine-undesired-mode-group: fix wording and checks
bboozzoo Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
cmd/snap-update-ns: explicitly specify ownership of mount profile
We'll eventually run snap-update-ns as a normal user (when invoked from
snap-confine, at least), so make sure that the mount profile continues
to be owned by root.root
  • Loading branch information
mardy authored and bboozzoo committed Feb 26, 2025
commit eeaec37d9578733ed603f037cedb161e18282f02
8 changes: 0 additions & 8 deletions cmd/snap-update-ns/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,3 @@ func (upCtx *CommonProfileUpdateContext) LoadCurrentProfile() (*osutil.MountProf
}
return profile, nil
}

// SaveCurrentProfile saves the current mount profile.
func (upCtx *CommonProfileUpdateContext) SaveCurrentProfile(profile *osutil.MountProfile) error {
if err := profile.Save(upCtx.currentProfilePath); err != nil {
return fmt.Errorf("cannot save current mount profile of snap %q: %s", upCtx.instanceName, err)
}
return nil
}
18 changes: 0 additions & 18 deletions cmd/snap-update-ns/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/osutil"
"github.com/snapcore/snapd/sandbox/cgroup"
"github.com/snapcore/snapd/testutil"
)

type commonSuite struct {
Expand Down Expand Up @@ -157,20 +156,3 @@ func (s *commonSuite) TestLoadCurrentProfile(c *C) {
// The profile is returned unchanged.
c.Check(builder.String(), Equals, text)
}

func (s *commonSuite) TestSaveCurrentProfile(c *C) {
upCtx := s.upCtx
text := "tmpfs /tmp tmpfs defaults 0 0\n"

// Prepare a mount profile to be saved.
profile, err := osutil.LoadMountProfileText(text)
c.Assert(err, IsNil)

// Prepare the directory for saving the profile.
path := upCtx.CurrentProfilePath()
c.Assert(os.MkdirAll(filepath.Dir(path), 0755), IsNil)

// Ask the common profile update to write the current profile.
c.Assert(upCtx.SaveCurrentProfile(profile), IsNil)
c.Check(path, testutil.FileEquals, text)
}
6 changes: 6 additions & 0 deletions cmd/snap-update-ns/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,9 @@ func NewCommonProfileUpdateContext(instanceName string, fromSnapConfine bool, cu
desiredProfilePath: desiredProfilePath,
}
}

func MockSaveMountProfile(f func(p *osutil.MountProfile, fname string, uid sys.UserID, gid sys.GroupID) error) (restore func()) {
r := testutil.Backup(&osutilSaveMountProfile)
osutilSaveMountProfile = f
return r
}
45 changes: 41 additions & 4 deletions cmd/snap-update-ns/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/logger"
"github.com/snapcore/snapd/osutil"
"github.com/snapcore/snapd/osutil/sys"
"github.com/snapcore/snapd/sandbox/cgroup"
"github.com/snapcore/snapd/testutil"
)
Expand Down Expand Up @@ -86,10 +87,19 @@ func (s *mainSuite) TestExecuteMountProfileUpdate(c *C) {
c.Assert(err, IsNil)

upCtx := update.NewSystemProfileUpdateContext(snapName, false)
var profilePath string
var savedProfile string
restore = update.MockSaveMountProfile(func(p *osutil.MountProfile, fname string, uid sys.UserID, gid sys.GroupID) (err error) {
profilePath = fname
savedProfile, err = osutil.SaveMountProfileText(p)
return err
})
defer restore()
err = update.ExecuteMountProfileUpdate(upCtx)
c.Assert(err, IsNil)

c.Check(currentProfilePath, testutil.FileEquals, `/var/lib/snapd/hostfs/usr/local/share/fonts /usr/local/share/fonts none bind,ro 0 0
c.Check(profilePath, Equals, currentProfilePath)
c.Check(savedProfile, Equals, `/var/lib/snapd/hostfs/usr/local/share/fonts /usr/local/share/fonts none bind,ro 0 0
/var/lib/snapd/hostfs/usr/share/fonts /usr/share/fonts none bind,ro 0 0
`)
}
Expand Down Expand Up @@ -154,9 +164,18 @@ func (s *mainSuite) TestAddingSyntheticChanges(c *C) {
defer restore()

upCtx := update.NewSystemProfileUpdateContext(snapName, false)
var profilePath string
var savedProfile string
restore = update.MockSaveMountProfile(func(p *osutil.MountProfile, fname string, uid sys.UserID, gid sys.GroupID) (err error) {
profilePath = fname
savedProfile, err = osutil.SaveMountProfileText(p)
return err
})
defer restore()
c.Assert(update.ExecuteMountProfileUpdate(upCtx), IsNil)

c.Check(currentProfilePath, testutil.FileEquals,
c.Check(profilePath, Equals, currentProfilePath)
c.Check(savedProfile, Equals,
`tmpfs /usr/share tmpfs x-snapd.synthetic,x-snapd.needed-by=/usr/share/mysnap 0 0
/usr/share/adduser /usr/share/adduser none bind,ro,x-snapd.synthetic,x-snapd.needed-by=/usr/share/mysnap 0 0
/usr/share/awk /usr/share/awk none bind,ro,x-snapd.synthetic,x-snapd.needed-by=/usr/share/mysnap 0 0
Expand Down Expand Up @@ -232,9 +251,18 @@ func (s *mainSuite) TestRemovingSyntheticChanges(c *C) {
defer restore()

upCtx := update.NewSystemProfileUpdateContext(snapName, false)
var profilePath string
var savedProfile string
restore = update.MockSaveMountProfile(func(p *osutil.MountProfile, fname string, uid sys.UserID, gid sys.GroupID) (err error) {
profilePath = fname
savedProfile, err = osutil.SaveMountProfileText(p)
return err
})
defer restore()
c.Assert(update.ExecuteMountProfileUpdate(upCtx), IsNil)

c.Check(currentProfilePath, testutil.FileEquals, "")
c.Check(profilePath, Equals, currentProfilePath)
c.Check(savedProfile, Equals, "")
}

func (s *mainSuite) TestApplyingLayoutChanges(c *C) {
Expand Down Expand Up @@ -362,9 +390,18 @@ func (s *mainSuite) TestApplyIgnoredMissingMount(c *C) {

// The error was ignored, and no mount was recorded in the profile
upCtx := update.NewSystemProfileUpdateContext(snapName, false)
var profilePath string
var savedProfile string
restore = update.MockSaveMountProfile(func(p *osutil.MountProfile, fname string, uid sys.UserID, gid sys.GroupID) (err error) {
profilePath = fname
savedProfile, err = osutil.SaveMountProfileText(p)
return err
})
defer restore()
c.Assert(update.ExecuteMountProfileUpdate(upCtx), IsNil)
c.Check(s.log.String(), Equals, "")
c.Check(currentProfilePath, testutil.FileEquals, "")
c.Check(profilePath, Equals, currentProfilePath)
c.Check(savedProfile, Equals, "")
}

func (s *mainSuite) TestApplyUserFstabHomeRequiredAndValid(c *C) {
Expand Down
13 changes: 13 additions & 0 deletions cmd/snap-update-ns/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ import (
"os"

"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/osutil"
"github.com/snapcore/snapd/snap"
)

var (
osutilSaveMountProfile = osutil.SaveMountProfile
)

// SystemProfileUpdateContext contains information about update to system-wide mount namespace.
type SystemProfileUpdateContext struct {
CommonProfileUpdateContext
Expand Down Expand Up @@ -92,6 +97,14 @@ func (upCtx *SystemProfileUpdateContext) Assumptions() *Assumptions {
return as
}

// SaveCurrentProfile saves the current mount profile.
func (upCtx *SystemProfileUpdateContext) SaveCurrentProfile(profile *osutil.MountProfile) error {
if err := osutilSaveMountProfile(profile, upCtx.currentProfilePath, 0, 0); err != nil {
return fmt.Errorf("cannot save current mount profile of snap %q: %s", upCtx.instanceName, err)
}
return nil
}

// desiredSystemProfilePath returns the path of the fstab-like file with the desired, system-wide mount profile for a snap.
func desiredSystemProfilePath(snapName string) string {
return fmt.Sprintf("%s/snap.%s.fstab", dirs.SnapMountPolicyDir, snapName)
Expand Down
13 changes: 11 additions & 2 deletions cmd/snap-update-ns/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ import (
update "github.com/snapcore/snapd/cmd/snap-update-ns"
"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/osutil"
"github.com/snapcore/snapd/osutil/sys"
"github.com/snapcore/snapd/sandbox/cgroup"
"github.com/snapcore/snapd/testutil"
)

type systemSuite struct{}
Expand Down Expand Up @@ -149,8 +149,17 @@ func (s *systemSuite) TestSaveCurrentProfile(c *C) {
c.Assert(err, IsNil)

// Ask the system profile update to write the current profile.
var profilePath string
var savedProfile string
restore := update.MockSaveMountProfile(func(p *osutil.MountProfile, fname string, uid sys.UserID, gid sys.GroupID) (err error) {
profilePath = fname
savedProfile, err = osutil.SaveMountProfileText(p)
return err
})
defer restore()
c.Assert(upCtx.SaveCurrentProfile(profile), IsNil)
c.Check(update.CurrentSystemProfilePath(upCtx.InstanceName()), testutil.FileEquals, text)
c.Check(profilePath, Equals, update.CurrentSystemProfilePath(upCtx.InstanceName()))
c.Check(savedProfile, Equals, text)
}

func (s *systemSuite) TestDesiredSystemProfilePath(c *C) {
Expand Down
8 changes: 6 additions & 2 deletions osutil/mountprofile_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"io"
"os"
"strings"

"github.com/snapcore/snapd/osutil/sys"
)

// MountProfile represents an array of mount entries.
Expand Down Expand Up @@ -64,12 +66,14 @@ func SaveMountProfileText(p *MountProfile) (string, error) {

// Save saves a mount profile (fstab-like) to a given file.
// The profile is saved with an atomic write+rename+sync operation.
func (p *MountProfile) Save(fname string) error {
// If you don't want to alter the uid and gid of the created file, pass
// osutil.NoChown.
func SaveMountProfile(p *MountProfile, fname string, uid sys.UserID, gid sys.GroupID) error {
var buf bytes.Buffer
if _, err := p.WriteTo(&buf); err != nil {
return err
}
return AtomicWriteFile(fname, buf.Bytes(), 0644, AtomicWriteFlags(0))
return AtomicWriteFileChown(fname, buf.Bytes(), 0644, AtomicWriteFlags(0), uid, gid)
}

// ReadMountProfile reads and parses a mount profile.
Expand Down
2 changes: 1 addition & 1 deletion osutil/mountprofile_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (s *profileSuite) TestSaveMountProfile1(c *C) {
{Name: "name-1", Dir: "dir-1", Type: "type-1", Options: []string{"options-1"}, DumpFrequency: 1, CheckPassNumber: 1},
},
}
err := p.Save(fname)
err := osutil.SaveMountProfile(p, fname, osutil.NoChown, osutil.NoChown)
c.Assert(err, IsNil)

stat, err := os.Stat(fname)
Expand Down