From d4c35ebcf6aec999b55e755fc9b43cf02ebde5a2 Mon Sep 17 00:00:00 2001 From: Mathew Gordon Date: Sat, 13 Aug 2022 03:41:47 +0000 Subject: [PATCH] Improve API and security Switch `[]string` to `string...` in ai.AddFiles... etc, now copy over AppImage's profile to the system to prevent an AppImage from modifying its own permissions, add Open-typer and Cro-Mag Rally to supported profiles and add FreeCAD Weekly as an an alias --- appimage.go | 68 +++++++++++++++++++++++++++++--------- cmd/aisap/main.go | 12 +++---- helpers/offset.go | 6 ++-- permissions/getperms.go | 6 ++-- permissions/modifyperms.go | 18 +++++----- profiles/profiles.go | 19 ++++++++--- 6 files changed, 89 insertions(+), 40 deletions(-) diff --git a/appimage.go b/appimage.go index c65ea4e..7b3c921 100644 --- a/appimage.go +++ b/appimage.go @@ -5,6 +5,7 @@ package aisap import ( + "bufio" "crypto/md5" "debug/elf" "fmt" @@ -20,6 +21,7 @@ import ( profiles "github.com/mgord9518/aisap/profiles" permissions "github.com/mgord9518/aisap/permissions" squashfs "github.com/CalebQ42/squashfs" + xdg "github.com/adrg/xdg" ) type AppImage struct { @@ -44,7 +46,7 @@ type AppImage struct { // Current version of aisap const ( - Version = "0.7.3-alpha" + Version = "0.7.5-alpha" ) // Create a new AppImage object from a path @@ -63,7 +65,6 @@ func NewAppImage(src string) (*AppImage, error) { if err != nil { return nil, err } ai.rootDir = "/" - ai.Offset, err = helpers.GetOffset(src) if err != nil { return nil, err } @@ -80,7 +81,12 @@ func NewAppImage(src string) (*AppImage, error) { } // Prefer local entry if it exists (located at $XDG_DATA_HOME/aisap/[ai.Name]) - ai.Desktop, err = ai.getEntry() + desktopReader, err := ai.getEntry() + if err != nil { return ai, err } + + ai.Desktop, err = ini.LoadSources(ini.LoadOptions{ + IgnoreInlineComment: true, + }, desktopReader) if err != nil { return ai, err } ai.Name = ai.Desktop.Section("Desktop Entry").Key("Name").Value() @@ -92,6 +98,7 @@ func NewAppImage(src string) (*AppImage, error) { ai.Version = "1.0" } + // If PREFER_AISAP_PROFILE is set, attempt to use it over the AppImage's // suggested permissions. If no profile exists in aisap, fall back on saved // permissions in aisap, and then finally the AppImage's internal desktop @@ -110,8 +117,25 @@ func NewAppImage(src string) (*AppImage, error) { } } + // Fall back to permissions inside AppImage if all else fails if err != nil { ai.Perms, _ = permissions.FromIni(ai.Desktop) + + // Copy AppImage permissions to system to prevent an AppImage from + // modifying its own permissions through an update. This also gives + // users a good template to customize their permissions on a per-app + // basis. + aisapConfig := filepath.Join(xdg.DataHome, "aisap", "profiles") + if !helpers.DirExists(aisapConfig) { + os.MkdirAll(aisapConfig, 0744) + } + + filePath := filepath.Join(aisapConfig, ai.Name) + if !helpers.FileExists(filePath) { + desktopReader, _ = ai.getEntry() + permFile, _ := os.Create(filePath) + io.Copy(permFile, desktopReader) + } } return ai, nil @@ -265,9 +289,9 @@ func (ai *AppImage) Icon() (io.ReadCloser, string, error) { } // Extract the desktop file from the AppImage -func (ai *AppImage) getEntry() (*ini.File, error) { +func (ai *AppImage) getEntry() (io.Reader, error) { + var r io.Reader var err error - var r io.ReadCloser if ai.imageType == -2 { r, err = helpers.ExtractResourceReader(ai.Path, "desktop_entry") @@ -283,14 +307,10 @@ func (ai *AppImage) getEntry() (*ini.File, error) { return nil, NoDesktopFile } - r, err = ai.reader.Open(fp[0]) - defer r.Close() - if err != nil { return nil, err } + return ai.reader.Open(fp[0]) } - return ini.LoadSources(ini.LoadOptions{ - IgnoreInlineComment: true, - }, r) + return r, err } // Determine what architectures a bundle supports @@ -320,10 +340,28 @@ func (ai *AppImage) getArchitectures() ([]string, error) { } // Assume arch via shImg runtime - // TODO: implement - //if ai.Type() < -1 { - - //} + if ai.Type() < -1 { + scanner := bufio.NewScanner(ai.file) + arches := []string{} + + counter := 0 + for scanner.Scan() { + counter++ + if strings.HasPrefix(scanner.Text(), "arch='") { + str := scanner.Text() + str = strings.ReplaceAll(str, "arch='", "") + str = strings.ReplaceAll(str, "'", "") + arches = helpers.SplitKey(str) + return arches, nil + } + + // All shImg info should be at the top of the file, 50 is more than + // enough + if counter >= 50 { + break + } + } + } return s, errors.New("failed to determine arch") } diff --git a/cmd/aisap/main.go b/cmd/aisap/main.go index 20dbd66..9ce1173 100644 --- a/cmd/aisap/main.go +++ b/cmd/aisap/main.go @@ -141,12 +141,12 @@ func main() { // Add (and remove) permissions as passed from flags. eg: `--add-file` // Note: If *not* using XDG standard names (eg: `xdg-desktop`) you MUST // Provide the full filepath when using `AddFiles` - ai.Perms.RemoveFiles(rmFile) - ai.Perms.RemoveDevices(rmDevice) - ai.Perms.RemoveSockets(rmSocket) - ai.Perms.AddFiles(addFile) - ai.Perms.AddDevices(addDevice) - ai.Perms.AddSockets(addSocket) + ai.Perms.RemoveFiles(rmFile...) + ai.Perms.RemoveDevices(rmDevice...) + ai.Perms.RemoveSockets(rmSocket...) + ai.Perms.AddFiles(addFile...) + ai.Perms.AddDevices(addDevice...) + ai.Perms.AddSockets(addSocket...) // If the `--level` flag is used, set the AppImage to that level if *level > -1 && *level <= 3 { diff --git a/helpers/offset.go b/helpers/offset.go index 938ebe7..55030f8 100644 --- a/helpers/offset.go +++ b/helpers/offset.go @@ -69,8 +69,8 @@ func getElfSize(src string) (int, error) { sr := io.NewSectionReader(f, 0, 1<<63-1) var shoff, shentsize, shnum int - switch e.Class.String() { - case "ELFCLASS64": + switch e.Class { + case elf.ELFCLASS64: hdr := new(elf.Header64) _, err = sr.Seek(0, 0) @@ -81,7 +81,7 @@ func getElfSize(src string) (int, error) { shoff = int(hdr.Shoff) shnum = int(hdr.Shnum) shentsize = int(hdr.Shentsize) - case "ELFCLASS32": + case elf.ELFCLASS32: hdr := new(elf.Header32) _, err = sr.Seek(0, 0) diff --git a/permissions/getperms.go b/permissions/getperms.go index 7c56bad..0a70eb4 100644 --- a/permissions/getperms.go +++ b/permissions/getperms.go @@ -41,9 +41,9 @@ func FromIni(e *ini.File) (*AppImagePerms, error) { } // Split string into slices and clean up the names - p.AddFiles(helpers.SplitKey(filePerms)) - p.AddDevices(helpers.SplitKey(devicePerms)) - p.AddSockets(helpers.SplitKey(socketPerms)) + p.AddFiles(helpers.SplitKey(filePerms)...) + p.AddDevices(helpers.SplitKey(devicePerms)...) + p.AddSockets(helpers.SplitKey(socketPerms)...) return p, nil } diff --git a/permissions/modifyperms.go b/permissions/modifyperms.go index dca628c..f901720 100644 --- a/permissions/modifyperms.go +++ b/permissions/modifyperms.go @@ -14,9 +14,9 @@ func (p *AppImagePerms) AddFile(str string) { p.Files = append(p.Files, helpers.CleanFile(str)) } -func (p *AppImagePerms) AddFiles(s []string) { +func (p *AppImagePerms) AddFiles(s ...string) { // Remove previous files of the same name if they exist - p.RemoveFiles(s) + p.RemoveFiles(s...) p.Files = append(p.Files, helpers.CleanFiles(s)...) } @@ -27,8 +27,8 @@ func (p *AppImagePerms) AddDevice(str string) { p.Devices = append(p.Devices, helpers.CleanDevice(str)) } -func (p *AppImagePerms) AddDevices(s []string) { - p.RemoveDevices(s) +func (p *AppImagePerms) AddDevices(s ...string) { + p.RemoveDevices(s...) p.Devices = append(p.Devices, helpers.CleanDevices(s)...) } @@ -39,8 +39,8 @@ func (p *AppImagePerms) AddSocket(str string) { p.Sockets = append(p.Sockets, str) } -func (p *AppImagePerms) AddSockets(s []string) { - p.RemoveSockets(s) +func (p *AppImagePerms) AddSockets(s ...string) { + p.RemoveSockets(s...) p.Sockets = append(p.Sockets, s...) } @@ -58,7 +58,7 @@ func (p *AppImagePerms) RemoveFile(str string) { } } -func (p *AppImagePerms) RemoveFiles(s []string) { +func (p *AppImagePerms) RemoveFiles(s ...string) { for i := range(s) { p.RemoveFile(s[i]) } @@ -70,7 +70,7 @@ func (p *AppImagePerms) RemoveDevice(str string) { } } -func (p *AppImagePerms) RemoveDevices(s []string) { +func (p *AppImagePerms) RemoveDevices(s ...string) { for i := range(s) { p.RemoveDevice(s[i]) } @@ -82,7 +82,7 @@ func (p *AppImagePerms) RemoveSocket(str string) { } } -func (p *AppImagePerms) RemoveSockets(s []string) { +func (p *AppImagePerms) RemoveSockets(s ...string) { for i := range(s) { p.RemoveSocket(s[i]) } diff --git a/profiles/profiles.go b/profiles/profiles.go index c0cde0c..3f6c117 100644 --- a/profiles/profiles.go +++ b/profiles/profiles.go @@ -14,7 +14,7 @@ import ( // issue and any error messages you encounter so that I can try to fix them // NOTE: Some app permissions are `aliases` of others, so care must be taken // that modifying the parent permission will also affect apps based on it -// 90 unique apps currently supported +// 92 unique apps currently supported var profiles = map[string]permissions.AppImagePerms{ "0 a.d.": { Level: 3, @@ -113,6 +113,11 @@ var profiles = map[string]permissions.AppImagePerms{ Devices: []string{ "dri" }, Sockets: []string{ "x11", "pid" }, }, + "cro-mag rally": { + Level: 3, + Devices: []string{ "dri" }, + Sockets: []string{ "x11", "alsa" }, + }, "deemix-gui": { Level: 2, Devices: []string{ "dri" }, @@ -153,7 +158,7 @@ var profiles = map[string]permissions.AppImagePerms{ Files: []string{ "xdg-documents:rw", "xdg-publicshare:rw", "xdg-templates:rw", "xdg-desktop:rw", "xdg-documents:rw", "xdg-download:rw", - "xdg-music:rw", "xdg-videos:rw"}, + "xdg-music:rw", "xdg-videos:rw" }, Sockets: []string{ "x11", "audio" }, }, "edex-ui": { @@ -161,8 +166,8 @@ var profiles = map[string]permissions.AppImagePerms{ Devices: []string{ "dri" }, Files: []string{ "~/.config/nvim:ro", "~/.profile:ro", "~/.bashrc:ro", "~/.zshrc:ro", - "~/.viminfo:ro"}, - Sockets: []string{ "x11", "network" }, + "~/.viminfo:ro" }, + Sockets: []string{ "x11", "network", "alsa" }, }, "element": { Level: 2, @@ -374,6 +379,11 @@ var profiles = map[string]permissions.AppImagePerms{ Devices: []string{ "dri" }, Sockets: []string{ "x11", "alsa" }, }, + "open-typer": { + Level: 2, + Devices: []string{ "dri" }, + Sockets: []string{ "x11" }, + }, "passy": { Level: 2, Devices: []string{ "dri" }, @@ -565,6 +575,7 @@ func FromName(name string) (*permissions.AppImagePerms, error) { "aranym mmu": "aranym jit", "firefox beta": "firefox", "firefox nightly": "firefox", + "freecad weekly": "freecad conda", "python2.7.18": "python", "python3": "python", "python3.5.10": "python",