-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: initial commit for erofs support
Signed-off-by: Ramkumar Chinchani <[email protected]>
- Loading branch information
Showing
30 changed files
with
1,507 additions
and
358 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package atomfs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package common | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
type uidmapTestcase struct { | ||
uidmap string | ||
expected bool | ||
} | ||
|
||
var uidmapTests = []uidmapTestcase{ | ||
{ | ||
uidmap: ` 0 0 4294967295`, | ||
expected: true, | ||
}, | ||
{ | ||
uidmap: ` 0 0 1000 | ||
2000 2000 1`, | ||
expected: false, | ||
}, | ||
{ | ||
uidmap: ` 0 0 1000`, | ||
expected: false, | ||
}, | ||
{ | ||
uidmap: ` 10 0 4294967295`, | ||
expected: false, | ||
}, | ||
{ | ||
uidmap: ` 0 10 4294967295`, | ||
expected: false, | ||
}, | ||
{ | ||
uidmap: ` 0 0 1`, | ||
expected: false, | ||
}, | ||
} | ||
|
||
func TestAmHostRoot(t *testing.T) { | ||
t.Parallel() | ||
assert := assert.New(t) | ||
for _, testcase := range uidmapTests { | ||
v := uidmapIsHost(testcase.uidmap) | ||
assert.Equal(v, testcase.expected) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package common | ||
|
||
import ( | ||
"bytes" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
// ExcludePaths represents a list of paths to exclude in a squashfs listing. | ||
// Users should do something like filepath.Walk() over the whole filesystem, | ||
// calling AddExclude() or AddInclude() based on whether they want to include | ||
// or exclude a particular file. Note that if e.g. /usr is excluded, then | ||
// everyting underneath is also implicitly excluded. The | ||
// AddExclude()/AddInclude() methods do the math to figure out what is the | ||
// correct set of things to exclude or include based on what paths have been | ||
// previously included or excluded. | ||
type ExcludePaths struct { | ||
exclude map[string]bool | ||
include []string | ||
} | ||
|
||
func NewExcludePaths() *ExcludePaths { | ||
return &ExcludePaths{ | ||
exclude: map[string]bool{}, | ||
include: []string{}, | ||
} | ||
} | ||
|
||
func (eps *ExcludePaths) AddExclude(p string) { | ||
for _, inc := range eps.include { | ||
// If /usr/bin/ls has changed but /usr hasn't, we don't want to list | ||
// /usr in the include paths any more, so let's be sure to only | ||
// add things which aren't prefixes. | ||
if strings.HasPrefix(inc, p) { | ||
return | ||
} | ||
} | ||
eps.exclude[p] = true | ||
} | ||
|
||
func (eps *ExcludePaths) AddInclude(orig string, isDir bool) { | ||
// First, remove this thing and all its parents from exclude. | ||
p := orig | ||
|
||
// normalize to the first dir | ||
if !isDir { | ||
p = path.Dir(p) | ||
} | ||
for { | ||
// our paths are all absolute, so this is a base case | ||
if p == "/" { | ||
break | ||
} | ||
|
||
delete(eps.exclude, p) | ||
p = filepath.Dir(p) | ||
} | ||
|
||
// now add it to the list of includes, so we don't accidentally re-add | ||
// anything above. | ||
eps.include = append(eps.include, orig) | ||
} | ||
|
||
func (eps *ExcludePaths) String() (string, error) { | ||
var buf bytes.Buffer | ||
for p := range eps.exclude { | ||
_, err := buf.WriteString(p) | ||
if err != nil { | ||
return "", err | ||
} | ||
_, err = buf.WriteString("\n") | ||
if err != nil { | ||
return "", err | ||
} | ||
} | ||
|
||
_, err := buf.WriteString("\n") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return buf.String(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package common | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
) | ||
|
||
func FileChanged(a os.FileInfo, path string) bool { | ||
b, err := os.Lstat(path) | ||
if err != nil { | ||
return true | ||
} | ||
return !os.SameFile(a, b) | ||
} | ||
|
||
// Takes /proc/self/uid_map contents as one string | ||
// Returns true if this is a uidmap representing the whole host | ||
// uid range. | ||
func uidmapIsHost(oneline string) bool { | ||
oneline = strings.TrimSuffix(oneline, "\n") | ||
if len(oneline) == 0 { | ||
return false | ||
} | ||
lines := strings.Split(oneline, "\n") | ||
if len(lines) != 1 { | ||
return false | ||
} | ||
words := strings.Fields(lines[0]) | ||
if len(words) != 3 || words[0] != "0" || words[1] != "0" || words[2] != "4294967295" { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
func AmHostRoot() bool { | ||
// if not uid 0, not host root | ||
if os.Geteuid() != 0 { | ||
return false | ||
} | ||
// if uid_map doesn't map 0 to 0, not host root | ||
bytes, err := os.ReadFile("/proc/self/uid_map") | ||
if err != nil { | ||
return false | ||
} | ||
return uidmapIsHost(string(bytes)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package common | ||
|
||
import ( | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
|
||
"github.com/pkg/errors" | ||
"golang.org/x/sys/unix" | ||
"machinerun.io/atomfs/pkg/mount" | ||
"machinerun.io/atomfs/pkg/verity" | ||
) | ||
|
||
func HostMount(squashfs string, mountpoint string, rootHash string, veritySize int64, verityOffset uint64) error { | ||
return verity.VerityHostMount(squashfs, mountpoint, rootHash, veritySize, verityOffset) | ||
} | ||
|
||
// Mount a filesystem as container root, without host root | ||
// privileges. We do this using squashfuse. | ||
func GuestMount(squashFile string, mountpoint string, cmd *exec.Cmd) error { | ||
if isMountpoint(mountpoint) { | ||
return errors.Errorf("%s is already mounted", mountpoint) | ||
} | ||
|
||
abs, err := filepath.Abs(squashFile) | ||
if err != nil { | ||
return errors.Errorf("Failed to get absolute path for %s: %v", squashFile, err) | ||
} | ||
squashFile = abs | ||
|
||
abs, err = filepath.Abs(mountpoint) | ||
if err != nil { | ||
return errors.Errorf("Failed to get absolute path for %s: %v", mountpoint, err) | ||
} | ||
mountpoint = abs | ||
|
||
if err := cmd.Process.Release(); err != nil { | ||
return errors.Errorf("Failed to release process after guestmount %s: %v", squashFile, err) | ||
} | ||
return nil | ||
} | ||
|
||
func Umount(mountpoint string) error { | ||
mounts, err := mount.ParseMounts("/proc/self/mountinfo") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// first, find the verity device that backs the mount | ||
theMount, found := mounts.FindMount(mountpoint) | ||
if !found { | ||
return errors.Errorf("%s is not a mountpoint", mountpoint) | ||
} | ||
|
||
err = unix.Unmount(mountpoint, 0) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed unmounting %v", mountpoint) | ||
} | ||
|
||
if _, err := os.Stat(theMount.Source); err != nil { | ||
if os.IsNotExist(err) { | ||
return nil | ||
} | ||
return errors.WithStack(err) | ||
} | ||
|
||
return verity.VerityUnmount(theMount.Source) | ||
} | ||
|
||
func isMountpoint(dest string) bool { | ||
mounted, err := mount.IsMountpoint(dest) | ||
return err == nil && mounted | ||
} | ||
|
||
func IsMountedAtDir(_, dest string) (bool, error) { | ||
dstat, err := os.Stat(dest) | ||
if os.IsNotExist(err) { | ||
return false, nil | ||
} | ||
if !dstat.IsDir() { | ||
return false, nil | ||
} | ||
mounts, err := mount.ParseMounts("/proc/self/mountinfo") | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
fdest, err := filepath.Abs(dest) | ||
if err != nil { | ||
return false, err | ||
} | ||
for _, m := range mounts { | ||
if m.Target == fdest { | ||
return true, nil | ||
} | ||
} | ||
|
||
return false, nil | ||
} |
Oops, something went wrong.