cmd/snap-update-ns: detect and report read-only filesystems #4166

Merged
merged 2 commits into from Nov 13, 2017
Jump to file or symbol
Failed to load files and symbols.
+32 −0
Split
Viewing a subset of changes. View all
Prev

cmd/snap-update-ns: detect and report read-only filesystems

This small patch adds detection of read-only filesystems to
secure-mkdir-all. This will be soon picked up by the hole-poking code.

Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
  • Loading branch information...
commit c21a85a15c923a5935d5374fe76c29463030c588 @zyga zyga committed Nov 7, 2017
@@ -47,6 +47,15 @@ var (
sysFchown = syscall.Fchown
)
+// ReadOnlyFsError is an error encapsulating encountered EROFS.
+type ReadOnlyFsError struct {
+ Path string
+}
+
+func (e *ReadOnlyFsError) Error() string {
+ return fmt.Sprintf("cannot operate on read-only filesystem at %s", e.Path)
+}
+
// Create directories for all but the last segments and return the file
// descriptor to the leaf directory. This function is a base for secure
// variants of mkdir, touch and symlink.
@@ -102,6 +111,12 @@ func secureMkDir(fd int, segments []string, i int, perm os.FileMode, uid, gid in
switch err {
case syscall.EEXIST:
made = false
+ case syscall.EROFS:
+ // Treat EROFS specially: this is a hint that we have to poke a
+ // hole using tmpfs. The path below is the location where we
+ // need to poke the hole.
+ p := "/" + strings.Join(segments[:i], "/")
+ return -1, &ReadOnlyFsError{Path: p}
default:
return -1, fmt.Errorf("cannot mkdir path segment %q: %v", segment, err)
}
@@ -115,6 +115,23 @@ func (s *utilsSuite) TestSecureMkdirAllLevel3(c *C) {
})
}
+// Ensure that we can detect read only filesystems.
+func (s *utilsSuite) TestSecureMkdirAllROFS(c *C) {
+ s.sys.InsertFault(`mkdirat 3 "rofs" 0755`, syscall.EEXIST) // just realistic
+ s.sys.InsertFault(`mkdirat 4 "path" 0755`, syscall.EROFS)
+ err := update.SecureMkdirAll("/rofs/path", 0755, 123, 456)
+ c.Assert(err, ErrorMatches, `cannot operate on read-only filesystem at /rofs`)
+ c.Assert(err.(*update.ReadOnlyFsError).Path, Equals, "/rofs")
+ c.Assert(s.sys.Calls(), DeepEquals, []string{
+ `open "/" O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY 0`, // -> 3
+ `mkdirat 3 "rofs" 0755`, // -> EEXIST
+ `openat 3 "rofs" O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY 0`, // -> 4
+ `close 3`,
+ `mkdirat 4 "path" 0755`, // -> EROFS
+ `close 4`,
+ })
+}
+
// Ensure that we don't chown existing directories.
func (s *utilsSuite) TestSecureMkdirAllExistingDirsDontChown(c *C) {
s.sys.InsertFault(`mkdirat 3 "abs" 0755`, syscall.EEXIST)