github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/interfaces/policy/basedeclaration.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 policy
    21  
    22  import (
    23  	"bytes"
    24  	"fmt"
    25  	"strings"
    26  
    27  	"github.com/snapcore/snapd/asserts"
    28  	"github.com/snapcore/snapd/interfaces"
    29  	"github.com/snapcore/snapd/interfaces/builtin"
    30  )
    31  
    32  // The headers of the builtin base-declaration describing the default
    33  // interface policies for all snaps. The base declaration focuses on the slot
    34  // side for almost all interfaces. Importantly, items are not merged between
    35  // the slots and plugs or between the base declaration and snap declaration
    36  // for a particular type of rule. This means that if you specify an
    37  // installation rule for both slots and plugs in the base declaration, only
    38  // the plugs side is used (plugs is preferred over slots).
    39  //
    40  // The interfaces listed in the base declaration can be broadly categorized
    41  // into:
    42  //
    43  // - manually connected implicit slots (eg, bluetooth-control)
    44  // - auto-connected implicit slots (eg, network)
    45  // - manually connected app-provided slots (eg, bluez)
    46  // - auto-connected app-provided slots (eg, mir)
    47  //
    48  // such that they will follow this pattern:
    49  //
    50  //   slots:
    51  //     manual-connected-implicit-slot:
    52  //       allow-installation:
    53  //         slot-snap-type:
    54  //           - core                     # implicit slot
    55  //       deny-auto-connection: true     # force manual connect
    56  //
    57  //     auto-connected-implicit-slot:
    58  //       allow-installation:
    59  //         slot-snap-type:
    60  //           - core                     # implicit slot
    61  //       allow-auto-connection: true    # allow auto-connect
    62  //
    63  //     manual-connected-provided-slot:
    64  //       allow-installation:
    65  //         slot-snap-type:
    66  //           - app                      # app provided slot
    67  //       deny-connection: true          # require allow-connection in snap decl
    68  //       deny-auto-connection: true     # force manual connect
    69  //
    70  //     auto-connected-provided-slot:
    71  //       allow-installation:
    72  //         slot-snap-type:
    73  //           - app                      # app provided slot
    74  //       deny-connection: true          # require allow-connection in snap decl
    75  //
    76  // App-provided slots use 'deny-connection: true' since slot implementations
    77  // require privileged access to the system and the snap must be trusted. In
    78  // this manner a snap declaration is required to override the base declaration
    79  // to allow connections with the app-provided slot.
    80  //
    81  // Slots dealing with hardware typically will specify 'gadget' and 'core' as
    82  // the slot-snap-type (eg, serial-port). Eg:
    83  //
    84  //   slots:
    85  //     manual-connected-hw-slot:
    86  //       allow-installation:
    87  //         slot-snap-type:
    88  //           - core
    89  //           - gadget
    90  //       deny-auto-connection: true
    91  //
    92  // So called super-privileged slot implementations should also be disallowed
    93  // installation on a system and a snap declaration is required to override the
    94  // base declaration to allow installation (eg, docker). Eg:
    95  //
    96  //   slots:
    97  //     manual-connected-super-privileged-slot:
    98  //       allow-installation: false
    99  //       deny-connection: true
   100  //       deny-auto-connection: true
   101  //
   102  // Like super-privileged slot implementation, super-privileged plugs should
   103  // also be disallowed installation on a system and a snap declaration is
   104  // required to override the base declaration to allow installation (eg,
   105  // kernel-module-control). Eg:
   106  //
   107  //   plugs:
   108  //     manual-connected-super-privileged-plug:
   109  //       allow-installation: false
   110  //       deny-auto-connection: true
   111  //   (remember this overrides slot side rules)
   112  //
   113  // Some interfaces have policy that is meant to be used with slot
   114  // implementations and on classic images. Since the slot implementation is
   115  // privileged, we require a snap declaration to be used for app-provided slot
   116  // implementations on non-classic systems (eg, network-manager). Eg:
   117  //
   118  //   slots:
   119  //     classic-or-not-slot:
   120  //       allow-installation:
   121  //         slot-snap-type:
   122  //           - app
   123  //           - core
   124  //       deny-auto-connection: true
   125  //       deny-connection:
   126  //         on-classic: false
   127  //
   128  // Some interfaces have policy that is only used with implicit slots on
   129  // classic and should be autoconnected only there (eg, home). Eg:
   130  //
   131  //   slots:
   132  //     implicit-classic-slot:
   133  //       allow-installation:
   134  //         slot-snap-type:
   135  //           - core
   136  //     deny-auto-connection:
   137  //       on-classic: false
   138  //
   139  
   140  const baseDeclarationHeader = `
   141  type: base-declaration
   142  authority-id: canonical
   143  series: 16
   144  revision: 0
   145  `
   146  
   147  const baseDeclarationPlugs = `
   148  plugs:
   149  `
   150  
   151  const baseDeclarationSlots = `
   152  slots:
   153  `
   154  
   155  func trimTrailingNewline(s string) string {
   156  	return strings.TrimRight(s, "\n")
   157  }
   158  
   159  func composeBaseDeclaration(ifaces []interfaces.Interface) ([]byte, error) {
   160  	var buf bytes.Buffer
   161  	// Trim newlines at the end of the string. All the elements may have
   162  	// spurious trailing newlines. All elements start with a leading newline.
   163  	// We don't want any blanks as that would no longer parse.
   164  	if _, err := buf.WriteString(trimTrailingNewline(baseDeclarationHeader)); err != nil {
   165  		return nil, err
   166  	}
   167  	if _, err := buf.WriteString(trimTrailingNewline(baseDeclarationPlugs)); err != nil {
   168  		return nil, err
   169  	}
   170  	for _, iface := range ifaces {
   171  		plugPolicy := interfaces.StaticInfoOf(iface).BaseDeclarationPlugs
   172  		if _, err := buf.WriteString(trimTrailingNewline(plugPolicy)); err != nil {
   173  			return nil, err
   174  		}
   175  	}
   176  	if _, err := buf.WriteString(trimTrailingNewline(baseDeclarationSlots)); err != nil {
   177  		return nil, err
   178  	}
   179  	for _, iface := range ifaces {
   180  		slotPolicy := interfaces.StaticInfoOf(iface).BaseDeclarationSlots
   181  		if _, err := buf.WriteString(trimTrailingNewline(slotPolicy)); err != nil {
   182  			return nil, err
   183  		}
   184  	}
   185  	if _, err := buf.WriteRune('\n'); err != nil {
   186  		return nil, err
   187  	}
   188  	return buf.Bytes(), nil
   189  }
   190  
   191  func init() {
   192  	decl, err := composeBaseDeclaration(builtin.Interfaces())
   193  	if err != nil {
   194  		panic(fmt.Sprintf("cannot compose base-declaration: %v", err))
   195  	}
   196  	if err := asserts.InitBuiltinBaseDeclaration(decl); err != nil {
   197  		panic(fmt.Sprintf("cannot initialize the builtin base-declaration: %v", err))
   198  	}
   199  }