github.com/rigado/snapd@v2.42.5-go-mod+incompatible/interfaces/dbus/backend.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 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 dbus implements interaction between snappy and dbus. 21 // 22 // Snappy creates dbus configuration files that describe how various 23 // services on the system bus can communicate with other peers. 24 // 25 // Each configuration is an XML file containing <busconfig>...</busconfig>. 26 // Particular security snippets define whole <policy>...</policy> entires. 27 // This is explained in detail in https://dbus.freedesktop.org/doc/dbus-daemon.1.html 28 package dbus 29 30 import ( 31 "bytes" 32 "fmt" 33 "os" 34 "path/filepath" 35 36 "github.com/snapcore/snapd/dirs" 37 "github.com/snapcore/snapd/interfaces" 38 "github.com/snapcore/snapd/logger" 39 "github.com/snapcore/snapd/osutil" 40 "github.com/snapcore/snapd/release" 41 "github.com/snapcore/snapd/snap" 42 "github.com/snapcore/snapd/timings" 43 ) 44 45 // Backend is responsible for maintaining DBus policy files. 46 type Backend struct{} 47 48 // Initialize does nothing. 49 func (b *Backend) Initialize() error { 50 return nil 51 } 52 53 // Name returns the name of the backend. 54 func (b *Backend) Name() interfaces.SecuritySystem { 55 return "dbus" 56 } 57 58 // setupDbusServiceForUserd will setup the service file for the new 59 // `snap userd` instance on re-exec 60 func setupDbusServiceForUserd(snapInfo *snap.Info) error { 61 coreOrSnapdRoot := snapInfo.MountDir() 62 63 // fugly - but we need to make sure that the content of the 64 // "snapd" snap wins 65 // 66 // TODO: this is also racy but the content of the files in core and 67 // snapd is identical cleanup after link-snap and 68 // setup-profiles are unified 69 if snapInfo.InstanceName() == "core" && osutil.FileExists(filepath.Join(coreOrSnapdRoot, "../..", "snapd/current")) { 70 return nil 71 } 72 73 for _, srv := range []string{ 74 "io.snapcraft.Launcher.service", 75 "io.snapcraft.Settings.service", 76 } { 77 dst := filepath.Join("/usr/share/dbus-1/services/", srv) 78 src := filepath.Join(coreOrSnapdRoot, dst) 79 80 // we only need the GlobalRootDir for testing 81 dst = filepath.Join(dirs.GlobalRootDir, dst) 82 if !osutil.FilesAreEqual(src, dst) { 83 if err := osutil.CopyFile(src, dst, osutil.CopyFlagPreserveAll); err != nil { 84 return err 85 } 86 } 87 } 88 return nil 89 } 90 91 // Setup creates dbus configuration files specific to a given snap. 92 // 93 // DBus has no concept of a complain mode so confinment type is ignored. 94 func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, repo *interfaces.Repository, tm timings.Measurer) error { 95 snapName := snapInfo.InstanceName() 96 // Get the snippets that apply to this snap 97 spec, err := repo.SnapSpecification(b.Name(), snapName) 98 if err != nil { 99 return fmt.Errorf("cannot obtain dbus specification for snap %q: %s", snapName, err) 100 } 101 102 // core/snapd on classic are special 103 if (snapInfo.GetType() == snap.TypeOS || snapInfo.GetType() == snap.TypeSnapd) && release.OnClassic { 104 if err := setupDbusServiceForUserd(snapInfo); err != nil { 105 logger.Noticef("cannot create host `snap userd` dbus service file: %s", err) 106 } 107 } 108 109 // Get the files that this snap should have 110 content, err := b.deriveContent(spec.(*Specification), snapInfo) 111 if err != nil { 112 return fmt.Errorf("cannot obtain expected DBus configuration files for snap %q: %s", snapName, err) 113 } 114 glob := fmt.Sprintf("%s.conf", interfaces.SecurityTagGlob(snapName)) 115 dir := dirs.SnapBusPolicyDir 116 if err := os.MkdirAll(dir, 0755); err != nil { 117 return fmt.Errorf("cannot create directory for DBus configuration files %q: %s", dir, err) 118 } 119 _, _, err = osutil.EnsureDirState(dir, glob, content) 120 if err != nil { 121 return fmt.Errorf("cannot synchronize DBus configuration files for snap %q: %s", snapName, err) 122 } 123 return nil 124 } 125 126 // Remove removes dbus configuration files of a given snap. 127 // 128 // This method should be called after removing a snap. 129 func (b *Backend) Remove(snapName string) error { 130 glob := fmt.Sprintf("%s.conf", interfaces.SecurityTagGlob(snapName)) 131 _, _, err := osutil.EnsureDirState(dirs.SnapBusPolicyDir, glob, nil) 132 if err != nil { 133 return fmt.Errorf("cannot synchronize DBus configuration files for snap %q: %s", snapName, err) 134 } 135 return nil 136 } 137 138 // deriveContent combines security snippets collected from all the interfaces 139 // affecting a given snap into a content map applicable to EnsureDirState. 140 func (b *Backend) deriveContent(spec *Specification, snapInfo *snap.Info) (content map[string]*osutil.FileState, err error) { 141 for _, appInfo := range snapInfo.Apps { 142 securityTag := appInfo.SecurityTag() 143 appSnippets := spec.SnippetForTag(securityTag) 144 if appSnippets == "" { 145 continue 146 } 147 if content == nil { 148 content = make(map[string]*osutil.FileState) 149 } 150 151 addContent(securityTag, appSnippets, content) 152 } 153 154 for _, hookInfo := range snapInfo.Hooks { 155 securityTag := hookInfo.SecurityTag() 156 hookSnippets := spec.SnippetForTag(securityTag) 157 if hookSnippets == "" { 158 continue 159 } 160 if content == nil { 161 content = make(map[string]*osutil.FileState) 162 } 163 164 addContent(securityTag, hookSnippets, content) 165 } 166 167 return content, nil 168 } 169 170 func addContent(securityTag string, snippet string, content map[string]*osutil.FileState) { 171 var buffer bytes.Buffer 172 buffer.Write(xmlHeader) 173 buffer.WriteString(snippet) 174 buffer.Write(xmlFooter) 175 176 content[fmt.Sprintf("%s.conf", securityTag)] = &osutil.FileState{ 177 Content: buffer.Bytes(), 178 Mode: 0644, 179 } 180 } 181 182 func (b *Backend) NewSpecification() interfaces.Specification { 183 return &Specification{} 184 } 185 186 // SandboxFeatures returns list of features supported by snapd for dbus communication. 187 func (b *Backend) SandboxFeatures() []string { 188 return []string{"mediated-bus-access"} 189 }