github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/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 "compress/gzip" 25 "encoding/base64" 26 "fmt" 27 "io" 28 "io/ioutil" 29 "os" 30 "os/exec" 31 "path/filepath" 32 33 "github.com/snapcore/snapd/logger" 34 "github.com/snapcore/snapd/osutil" 35 "github.com/snapcore/snapd/osutil/squashfs" 36 "github.com/snapcore/snapd/sandbox/selinux" 37 ) 38 39 func init() { 40 checks = append(checks, checkSquashfsMount) 41 } 42 43 /* This image was created using: 44 45 #!/bin/sh 46 47 cd $(mktemp -d) 48 cat > canary.txt<<'EOF' 49 This file is used to check that snapd can read a squashfs image. 50 51 The squashfs was generated with: 52 EOF 53 cat $0 >> canary.txt 54 55 mksquashfs . /tmp/canary.squashfs -noappend -comp xz -no-xattrs -no-fragments >/dev/nul 56 cat /tmp/canary.squashfs | gzip - | base64 57 58 */ 59 var b64SquashfsImage = []byte(` 60 H4sIAGxdFVsAA8soLixmYmBgyIkVjWZgALEYGFgYBBkuMDECaQYGFQYI4INIMbBB6f9Q0MAI4R+D 61 0s+g9A8o/de8KiKKgYExU+meGfOB54wzmBUZuYDiVhPYbR4wTme4H8ugJcWpniK5waL4VLewwsUC 62 PgdVnS/pCycWn34g1rpj6bIywdLqaQdZFYQcYr7/vR1w9dTbDivRH3GahXc578hdW3Ri7mu9+KeF 63 PqYCrkk/5zepyFw0EjL+XxH/3ubc9E+/J0t0PxE+zv9J96pa0rt9CWyvX6aIvb3H65qo9mbikvjU 64 LZxrOupvcr32+2yYFzt1wTe2HdFfrOSmKXFFPf1i5ep7Wv+q+U+nBNWs/nu+UosO6PFvfl991nVG 65 R9XSJUxv/7/y2f2zid0+OnGi1+ey1/vatzDPvfbq+0LLwIu1Wx/u+m6/c8IN21vNCQwMX2dtWsHA 66 +BvodwaGpcmXftsZ8HaDg5ExMsqlgYlhCTisQDEAYiRAQxckNgMooADEjAwH4GqgEQCOK0UgBhrK 67 INcAFWRghMtyMiQn5iUWVeqVVJQIwOVh8QmLJ5aGF8wMsIgfBaNgFIyCUTAKRsEoGAWjYBSMglEw 68 bAEA+f+YuAAQAAA= 69 `) 70 71 var fuseBinary = "mount.fuse" 72 73 func firstCheckFuse() error { 74 if squashfs.NeedsFuse() { 75 if _, err := exec.LookPath(fuseBinary); err != nil { 76 return fmt.Errorf(`The "fuse" filesystem is required on this system but not available. Please try to install the fuse package.`) 77 } 78 } 79 return nil 80 } 81 82 func checkSquashfsMount() error { 83 if err := firstCheckFuse(); err != nil { 84 return err 85 } 86 87 tmpSquashfsFile, err := ioutil.TempFile("", "sanity-squashfs-") 88 if err != nil { 89 return err 90 } 91 defer os.Remove(tmpSquashfsFile.Name()) 92 93 tmpMountDir, err := ioutil.TempDir("", "sanity-mountpoint-") 94 if err != nil { 95 return err 96 } 97 defer os.RemoveAll(tmpMountDir) 98 99 // write the squashfs image 100 b64dec := base64.NewDecoder(base64.StdEncoding, bytes.NewBuffer(b64SquashfsImage)) 101 gzReader, err := gzip.NewReader(b64dec) 102 if err != nil { 103 return err 104 } 105 if _, err := io.Copy(tmpSquashfsFile, gzReader); err != nil { 106 return err 107 } 108 109 // the fstype can be squashfs or fuse.{snap,squash}fuse 110 fstype, _ := squashfs.FsType() 111 options := []string{"-t", fstype} 112 if selinux.ProbedLevel() != selinux.Unsupported { 113 if ctx := selinux.SnapMountContext(); ctx != "" { 114 options = append(options, "-o", "context="+ctx) 115 } 116 } 117 options = append(options, tmpSquashfsFile.Name(), tmpMountDir) 118 cmd := exec.Command("mount", options...) 119 output, err := cmd.CombinedOutput() 120 if err != nil { 121 return fmt.Errorf("cannot mount squashfs image using %q: %v", fstype, osutil.OutputErr(output, err)) 122 } 123 124 defer func() { 125 if output, err := exec.Command("umount", "-l", tmpMountDir).CombinedOutput(); err != nil { 126 // os.RemoveAll(tmpMountDir) will fail here if umount fails 127 logger.Noticef("cannot unmount sanity check squashfs image: %v", osutil.OutputErr(output, err)) 128 } 129 }() 130 131 // sanity check the 132 content, err := ioutil.ReadFile(filepath.Join(tmpMountDir, "canary.txt")) 133 if err != nil { 134 return fmt.Errorf("squashfs mount returned no err but canary file cannot be read") 135 } 136 if !bytes.HasPrefix(content, []byte("This file is used to check that snapd can read a squashfs image.")) { 137 return fmt.Errorf("unexpected squashfs canary content: %q", content) 138 } 139 140 return nil 141 }