/*1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2022 Will Shand <[email protected]>4*5* Permission to use, copy, modify, and distribute this software for any6* purpose with or without fee is hereby granted, provided that the above7* copyright notice and this permission notice appear in all copies.8*9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16*/1718#include <config.h>1920#ifdef HAVE_APPARMOR2122# include <stdio.h>23# include <stdlib.h>24# include <sys/apparmor.h>2526# include <sudo.h>27# include <sudo_debug.h>2829/**30* @brief Check whether AppArmor is enabled.31*32* @return 1 if AppArmor is enabled, 0 otherwise.33*/34int35apparmor_is_enabled(void)36{37int ret;38FILE *fd;39debug_decl(apparmor_is_enabled, SUDO_DEBUG_APPARMOR);4041/*42* Check whether AppArmor is enabled by reading43* /sys/module/apparmor/parameters/enabled44*45* When this file exists and its contents are equal to "Y", AppArmor46* is enabled. This is a little more reliable than using47* aa_is_enabled(2), which performs an additional check on securityfs48* that will fail in settings where securityfs isn't available49* (e.g. inside a container).50*/5152fd = fopen("/sys/module/apparmor/parameters/enabled", "r");53if (fd == NULL)54debug_return_int(0);5556ret = (fgetc(fd) == 'Y');5758fclose(fd);59debug_return_int(ret);60}6162/**63* @brief Prepare to transition into a new AppArmor profile.64*65* @param new_profile The AppArmor profile to transition into on the66* next exec.67*68* @return 0 on success, and a nonzero value on failure.69*/70int71apparmor_prepare(const char *new_profile)72{73int ret;74char *mode, *old_profile;75debug_decl(apparmor_prepare, SUDO_DEBUG_APPARMOR);7677/* Determine the current AppArmor confinement status */78if ((ret = aa_getcon(&old_profile, &mode)) == -1) {79sudo_warn("%s", U_("failed to determine AppArmor confinement"));80old_profile = NULL;81goto done;82}8384/* Tell AppArmor to transition into the new profile on the85* next exec */86if ((ret = aa_change_onexec(new_profile)) != 0) {87sudo_warn(U_("unable to change AppArmor profile to %s"), new_profile);88goto done;89}9091if (mode == NULL) {92sudo_debug_printf(SUDO_DEBUG_INFO,93"%s: changing AppArmor profile: %s -> %s", __func__,94old_profile, new_profile ? new_profile : "?");95} else {96sudo_debug_printf(SUDO_DEBUG_INFO,97"%s: changing AppArmor profile: %s (%s) -> %s", __func__,98old_profile, mode, new_profile ? new_profile : "?");99}100101done:102/*103* The profile string returned by aa_getcon must be free'd, while the104* mode string must _not_ be free'd.105*/106if (old_profile != NULL)107free(old_profile);108109debug_return_int(ret);110}111112#endif /* HAVE_APPARMOR */113114115