github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/sanity/squashfs.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2018 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package sanity 21 22 import ( 23 "bytes" 24 "fmt" 25 "io" 26 "io/ioutil" 27 "os" 28 "os/exec" 29 "path/filepath" 30 31 "compress/gzip" 32 "encoding/base64" 33 34 "github.com/snapcore/snapd/logger" 35 "github.com/snapcore/snapd/osutil" 36 "github.com/snapcore/snapd/osutil/squashfs" 37 "github.com/snapcore/snapd/sandbox/selinux" 38 ) 39 40 func init() { 41 checks = append(checks, checkSquashfsMount) 42 } 43 44 /* This image was created using: 45 46 #!/bin/sh 47 48 cd $(mktemp -d) 49 cat > canary.txt<<'EOF' 50 This file is used to check that snapd can read a squashfs image. 51 52 The squashfs was generated with: 53 EOF 54 cat $0 >> canary.txt 55 56 mksquashfs . /tmp/canary.squashfs -noappend -comp xz -no-xattrs -no-fragments >/dev/nul 57 cat /tmp/canary.squashfs | gzip - | base64 58 59 */ 60 var b64SquashfsImage = []byte(` 61 H4sIAGxdFVsAA8soLixmYmBgyIkVjWZgALEYGFgYBBkuMDECaQYGFQYI4INIMbBB6f9Q0MAI4R+D 62 0s+g9A8o/de8KiKKgYExU+meGfOB54wzmBUZuYDiVhPYbR4wTme4H8ugJcWpniK5waL4VLewwsUC 63 PgdVnS/pCycWn34g1rpj6bIywdLqaQdZFYQcYr7/vR1w9dTbDivRH3GahXc578hdW3Ri7mu9+KeF 64 PqYCrkk/5zepyFw0EjL+XxH/3ubc9E+/J0t0PxE+zv9J96pa0rt9CWyvX6aIvb3H65qo9mbikvjU 65 LZxrOupvcr32+2yYFzt1wTe2HdFfrOSmKXFFPf1i5ep7Wv+q+U+nBNWs/nu+UosO6PFvfl991nVG 66 R9XSJUxv/7/y2f2zid0+OnGi1+ey1/vatzDPvfbq+0LLwIu1Wx/u+m6/c8IN21vNCQwMX2dtWsHA 67 +BvodwaGpcmXftsZ8HaDg5ExMsqlgYlhCTisQDEAYiRAQxckNgMooADEjAwH4GqgEQCOK0UgBhrK 68 INcAFWRghMtyMiQn5iUWVeqVVJQIwOVh8QmLJ5aGF8wMsIgfBaNgFIyCUTAKRsEoGAWjYBSMglEw 69 bAEA+f+YuAAQAAA= 70 `) 71 72 var fuseBinary = "mount.fuse" 73 74 func firstCheckFuse() error { 75 if squashfs.NeedsFuse() { 76 if _, err := exec.LookPath(fuseBinary); err != nil { 77 return fmt.Errorf(`The "fuse" filesystem is required on this system but not available. Please try to install the fuse package.`) 78 } 79 } 80 return nil 81 } 82 83 func checkSquashfsMount() error { 84 if err := firstCheckFuse(); err != nil { 85 return err 86 } 87 88 tmpSquashfsFile, err := ioutil.TempFile("", "sanity-squashfs-") 89 if err != nil { 90 return err 91 } 92 defer os.Remove(tmpSquashfsFile.Name()) 93 94 tmpMountDir, err := ioutil.TempDir("", "sanity-mountpoint-") 95 if err != nil { 96 return err 97 } 98 defer os.RemoveAll(tmpMountDir) 99 100 // write the squashfs image 101 b64dec := base64.NewDecoder(base64.StdEncoding, bytes.NewBuffer(b64SquashfsImage)) 102 gzReader, err := gzip.NewReader(b64dec) 103 if err != nil { 104 return err 105 } 106 if _, err := io.Copy(tmpSquashfsFile, gzReader); err != nil { 107 return err 108 } 109 110 // the fstype can be squashfs or fuse.{snap,squash}fuse 111 fstype, _ := squashfs.FsType() 112 options := []string{"-t", fstype} 113 if selinux.ProbedLevel() != selinux.Unsupported { 114 if ctx := selinux.SnapMountContext(); ctx != "" { 115 options = append(options, "-o", "context="+ctx) 116 } 117 } 118 options = append(options, tmpSquashfsFile.Name(), tmpMountDir) 119 cmd := exec.Command("mount", options...) 120 output, err := cmd.CombinedOutput() 121 if err != nil { 122 return fmt.Errorf("cannot mount squashfs image using %q: %v", fstype, osutil.OutputErr(output, err)) 123 } 124 125 defer func() { 126 if output, err := exec.Command("umount", "-l", tmpMountDir).CombinedOutput(); err != nil { 127 // os.RemoveAll(tmpMountDir) will fail here if umount fails 128 logger.Noticef("cannot unmount sanity check squashfs image: %v", osutil.OutputErr(output, err)) 129 } 130 }() 131 132 // sanity check the 133 content, err := ioutil.ReadFile(filepath.Join(tmpMountDir, "canary.txt")) 134 if err != nil { 135 return fmt.Errorf("squashfs mount returned no err but canary file cannot be read") 136 } 137 if !bytes.HasPrefix(content, []byte("This file is used to check that snapd can read a squashfs image.")) { 138 return fmt.Errorf("unexpected squashfs canary content: %q", content) 139 } 140 141 return nil 142 }