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