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 }