github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/cmd/libsnap-confine-private/apparmor-support.c (about)

     1  /*
     2   * Copyright (C) 2016 Canonical Ltd
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License version 3 as
     6   * published by the Free Software Foundation.
     7   *
     8   * This program is distributed in the hope that it will be useful,
     9   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11   * GNU General Public License for more details.
    12   *
    13   * You should have received a copy of the GNU General Public License
    14   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15   *
    16   */
    17  
    18  #ifdef HAVE_CONFIG_H
    19  #include "config.h"
    20  #endif
    21  
    22  #include "apparmor-support.h"
    23  
    24  #include <string.h>
    25  #include <errno.h>
    26  #ifdef HAVE_APPARMOR
    27  #include <sys/apparmor.h>
    28  #endif				// ifdef HAVE_APPARMOR
    29  
    30  #include "../libsnap-confine-private/cleanup-funcs.h"
    31  #include "../libsnap-confine-private/utils.h"
    32  
    33  // NOTE: Those constants map exactly what apparmor is returning and cannot be
    34  // changed without breaking apparmor functionality.
    35  #define SC_AA_ENFORCE_STR "enforce"
    36  #define SC_AA_COMPLAIN_STR "complain"
    37  #define SC_AA_MIXED_STR "mixed"
    38  #define SC_AA_UNCONFINED_STR "unconfined"
    39  
    40  void sc_init_apparmor_support(struct sc_apparmor *apparmor)
    41  {
    42  #ifdef HAVE_APPARMOR
    43  	// Use aa_is_enabled() to see if apparmor is available in the kernel and
    44  	// enabled at boot time. If it isn't log a diagnostic message and assume
    45  	// we're not confined.
    46  	if (aa_is_enabled() != true) {
    47  		switch (errno) {
    48  		case ENOSYS:
    49  			debug
    50  			    ("apparmor extensions to the system are not available");
    51  			break;
    52  		case ECANCELED:
    53  			debug
    54  			    ("apparmor is available on the system but has been disabled at boot");
    55  			break;
    56  		case ENOENT:
    57  			debug
    58  			    ("apparmor is available but the interface but the interface is not available");
    59  			break;
    60  		case EPERM:
    61  			// NOTE: fall-through
    62  		case EACCES:
    63  			debug
    64  			    ("insufficient permissions to determine if apparmor is enabled");
    65  			break;
    66  		default:
    67  			debug("apparmor is not enabled: %s", strerror(errno));
    68  			break;
    69  		}
    70  		apparmor->is_confined = false;
    71  		apparmor->mode = SC_AA_NOT_APPLICABLE;
    72  		return;
    73  	}
    74  	// Use aa_getcon() to check the label of the current process and
    75  	// confinement type. Note that the returned label must be released with
    76  	// free() but the mode is a constant string that must not be freed.
    77  	char *label SC_CLEANUP(sc_cleanup_string) = NULL;
    78  	char *mode = NULL;
    79  	if (aa_getcon(&label, &mode) < 0) {
    80  		die("cannot query current apparmor profile");
    81  	}
    82  	debug("apparmor label on snap-confine is: %s", label);
    83  	debug("apparmor mode is: %s", mode);
    84  	// The label has a special value "unconfined" that is applied to all
    85  	// processes without a dedicated profile. If that label is used then the
    86  	// current process is not confined. All other labels imply confinement.
    87  	if (label != NULL && strcmp(label, SC_AA_UNCONFINED_STR) == 0) {
    88  		apparmor->is_confined = false;
    89  	} else {
    90  		apparmor->is_confined = true;
    91  	}
    92  	// There are several possible results for the confinement type (mode) that
    93  	// are checked for below.
    94  	if (mode != NULL && strcmp(mode, SC_AA_COMPLAIN_STR) == 0) {
    95  		apparmor->mode = SC_AA_COMPLAIN;
    96  	} else if (mode != NULL && strcmp(mode, SC_AA_ENFORCE_STR) == 0) {
    97  		apparmor->mode = SC_AA_ENFORCE;
    98  	} else if (mode != NULL && strcmp(mode, SC_AA_MIXED_STR) == 0) {
    99  		apparmor->mode = SC_AA_MIXED;
   100  	} else {
   101  		apparmor->mode = SC_AA_INVALID;
   102  	}
   103  #else
   104  	apparmor->mode = SC_AA_NOT_APPLICABLE;
   105  	apparmor->is_confined = false;
   106  #endif				// ifdef HAVE_APPARMOR
   107  }
   108  
   109  void
   110  sc_maybe_aa_change_onexec(struct sc_apparmor *apparmor, const char *profile)
   111  {
   112  #ifdef HAVE_APPARMOR
   113  	if (apparmor->mode == SC_AA_NOT_APPLICABLE) {
   114  		return;
   115  	}
   116  	debug("requesting changing of apparmor profile on next exec to %s",
   117  	      profile);
   118  	if (aa_change_onexec(profile) < 0) {
   119  		if (secure_getenv("SNAPPY_LAUNCHER_INSIDE_TESTS") == NULL) {
   120  			die("cannot change profile for the next exec call");
   121  		}
   122  	}
   123  #endif				// ifdef HAVE_APPARMOR
   124  }
   125  
   126  void
   127  sc_maybe_aa_change_hat(struct sc_apparmor *apparmor,
   128  		       const char *subprofile, unsigned long magic_token)
   129  {
   130  #ifdef HAVE_APPARMOR
   131  	if (apparmor->mode == SC_AA_NOT_APPLICABLE) {
   132  		return;
   133  	}
   134  	if (apparmor->is_confined) {
   135  		debug("changing apparmor hat to %s", subprofile);
   136  		if (aa_change_hat(subprofile, magic_token) < 0) {
   137  			die("cannot change apparmor hat");
   138  		}
   139  	}
   140  #endif				// ifdef HAVE_APPARMOR
   141  }