// OpenPackageFile opens a given snap file with the right backend func OpenPackageFile(path string) (PackageFile, error) { f, err := os.Open(path) if err != nil { return nil, err } defer f.Close() // look, libmagic! header := make([]byte, 20) if _, err := f.Read(header); err != nil { return nil, err } // note that we only support little endian squashfs for now if bytes.HasPrefix(header, []byte{'h', 's', 'q', 's'}) { return snapfs.New(path), nil } if strings.HasPrefix(string(header), "!<arch>\ndebian") { return clickdeb.Open(path) } return nil, fmt.Errorf("unknown header %v", header) }
// Open opens a given snap file with the right backend func Open(path string) (File, error) { f, err := os.Open(path) if err != nil { return nil, fmt.Errorf("cannot open snap: %v", err) } defer f.Close() // look, libmagic! header := make([]byte, 20) if _, err := f.ReadAt(header, 0); err != nil { return nil, fmt.Errorf("cannot read snap: %v", err) } // Note that we only support little endian squashfs. There // is nothing else with squashfs 4.0. if bytes.HasPrefix(header, []byte{'h', 's', 'q', 's'}) { return squashfs.New(path), nil } if strings.HasPrefix(string(header), "!<arch>\ndebian") { return clickdeb.Open(path) } return nil, fmt.Errorf("cannot open snap: unknown header: %q", header) }
func unpackAndDropPrivs(snapFile, targetDir, rootDir string) error { d, err := clickdeb.Open(snapFile) if err != nil { return err } defer d.Close() if helpers.ShouldDropPrivs() { var dropPrivsUser string // first find out what user to use passFile := passwdFile(rootDir, "passwd") for _, dropPrivsUser = range dropPrivsUsers { _, err := readUID(dropPrivsUser, passFile) if err == nil { break } } // then get uid/gid uid, err := readUID(dropPrivsUser, passFile) if err != nil { return err } groupFile := passwdFile(rootDir, "group") gid, err := readUID(dropPrivsUser, groupFile) if err != nil { return err } if err := os.MkdirAll(targetDir, 0755); err != nil { return err } if err := os.Chown(targetDir, uid, gid); err != nil { return err } // Setuid and Setgid only apply to the current Linux thread, so make // sure we don't get moved. runtime.LockOSThread() // run prctl(PR_SET_NO_NEW_PRIVS) rc := C.prctl_no_new_privs() if rc < 0 { return fmt.Errorf("prctl(PR_SET_NO_NEW_PRIVS) failed with %v", rc) } if err := syscall.Setgroups([]int{gid}); err != nil { return fmt.Errorf("Setgroups([]{%d}) call failed: %v", gid, err) } if err := setgid(gid); err != nil { return fmt.Errorf("Setgid(%d) call failed: %v", gid, err) } if err := setuid(uid); err != nil { return fmt.Errorf("Setuid(%d) call failed: %v", uid, err) } // extra paranoia if syscall.Getuid() != uid || syscall.Getgid() != gid { return fmt.Errorf("Dropping privileges failed, uid is %v, gid is %v", syscall.Getuid(), syscall.Getgid()) } } return d.UnpackAll(targetDir) }