github.com/rigado/snapd@v2.42.5-go-mod+incompatible/selinux/label_linux.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  package selinux
    20  
    21  import (
    22  	"os"
    23  	"os/exec"
    24  	"regexp"
    25  
    26  	"github.com/snapcore/snapd/osutil"
    27  )
    28  
    29  var (
    30  	// actual matchpathcon -V output:
    31  	// /home/guest/snap has context unconfined_u:object_r:user_home_t:s0, should be unconfined_u:object_r:snappy_home_t:s0
    32  	matchIncorrectLabel = regexp.MustCompile("^.* has context .* should be .*\n$")
    33  )
    34  
    35  // VerifyPathContext checks whether a given path is labeled according to its default
    36  // SELinux context
    37  func VerifyPathContext(aPath string) (bool, error) {
    38  	if _, err := os.Stat(aPath); err != nil {
    39  		// path that cannot be accessed cannot be verified
    40  		return false, err
    41  	}
    42  	// matchpathcon -V verifies whether the context of a path matches the
    43  	// default
    44  	cmd := exec.Command("matchpathcon", "-V", aPath)
    45  	cmd.Env = append(os.Environ(), "LC_ALL=C")
    46  	out, err := cmd.Output()
    47  	if err == nil {
    48  		// the path was verified
    49  		return true, nil
    50  	}
    51  	exit, _ := osutil.ExitCode(err)
    52  	// exits with 1 when the verification failed or other error occurred,
    53  	// when verification failed a message like this will be printed to
    54  	// stdout:
    55  	//   <the-path> has context <some-context>, should be <some-other-context>
    56  	// match the message so that we can distinguish a failed verification
    57  	// case from other errors
    58  	if exit == 1 && matchIncorrectLabel.Match(out) {
    59  		return false, nil
    60  	}
    61  	return false, err
    62  }
    63  
    64  // RestoreContext restores the default SELinux context of given path
    65  func RestoreContext(aPath string, mode RestoreMode) error {
    66  	if _, err := os.Stat(aPath); err != nil {
    67  		// path that cannot be accessed cannot be restored
    68  		return err
    69  	}
    70  
    71  	args := make([]string, 0, 2)
    72  	if mode.Recursive {
    73  		// -R: recursive
    74  		args = append(args, "-R")
    75  	}
    76  	args = append(args, aPath)
    77  
    78  	return exec.Command("restorecon", args...).Run()
    79  }
    80  
    81  // SnapMountContext finds out the right context for mounting snaps
    82  func SnapMountContext() string {
    83  	// TODO: consider reading this from an external configuration file, such
    84  	// as per app contexts, from
    85  	// /etc/selinux/targeted/contexts/snapd_contexts like go-selinux and
    86  	// podman do for container volumes.
    87  	return "system_u:object_r:snappy_snap_t:s0"
    88  }