Hi,
We would like to change the AppArmor profile management we have in
https://github.com/Parrot-Developers/firmwared and switch to a whitelist
strategy, however we encounter some issues.
The attached C program (based on
https://github.com/Parrot-Developers/firmwared/blob/master/src/folders/instances.c)
shows one of those issues. This program can be compiled using the
attached Makefile by simply typing "make".
# Usage :
Suppose you have compiled busybox statically :
git://busybox.net/busybox.git
make menuconfig
LDFLAGS="--static" make
And you put it in the /tmp/aa-chroot/ folder like so :
/tmp/aa-chroot/bin/busybox
/tmp/aa-chroot/sbin/busybox
Now load the provided aa-chroot profile using the following command :
/sbin/apparmor_parser --replace < aa-chroot.profile
Then, as root, run the aa-chroot program :
./aa-chroot /tmp/aa-chroot /sbin/busybox sh
# Issue
What I don't understand is that the profile seems to have a default
allow policy although I thought deny was the default policy in AppArmor.
Indeed, the /bin/busybox sh call gets correctly denied because of the
explicit "audit deny /bin/* lrwxk" rule, however the "/sbin/busybox sh"
call is successful.
Could you explain to me why the default policy is allow instead of deny
and how can I change this ?
If that can be of any use, please note that I am on Ubuntu Xenial.
Any help would be greatly appreciated.
Thanks in advance,
Pierre Zurek
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif /* _XOPEN_SOURCE */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif /* _GNU_SOURCE */
#include <linux/limits.h>
#include <sched.h>
#include <errno.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <argz.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/signalfd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <sys/apparmor.h>
#define DISABLE_APPARMOR "DISABLE_APPARMOR"
#define PROFILE_NAME "aa-chroot"
static char *union_mount_point;
static char **command_args;
static char *disable_apparmor;
static bool is_apparmor_enabled(void)
{
if ((disable_apparmor != NULL)
&& (strncmp("y", disable_apparmor, 1) == 0)) {
return false;
}
return true;
}
static void load_apparmor_profile(void)
{
int ret;
if (is_apparmor_enabled()) {
ret = aa_change_onexec(PROFILE_NAME);
if (ret < 0) {
fprintf(stderr, "aa_change_onexec: %m\n");
_exit(EXIT_FAILURE);
}
}
}
static int setup_container(void)
{
int ret;
int flags;
/*
* use our own namespace for IPC, networking, mount points and uts
* (hostname and domain name), the pid namespace will be set up only
* after we have no more fork() (read: system()) calls to do for the
* setup
*/
flags = CLONE_FILES | CLONE_NEWIPC | CLONE_NEWNET |
CLONE_NEWNS | CLONE_NEWUTS | CLONE_SYSVSEM;
ret = unshare(flags);
if (ret < 0) {
ret = -errno;
fprintf(stderr, "unshare: %m\n");
return ret;
}
/*
* although we have a new mount points namespace, it is still necessary
* to make them private, recursively, so that changes aren't propagated
* to the parent namespace
*/
ret = mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL);
if (ret < 0) {
ret = -errno;
fprintf(stderr, "cannot make \"/\" private: %m\n");
return ret;
}
return 0;
}
static int setup_chroot(void)
{
int chroot_ret;
int chdir_ret;
/*
* coverity groans about chdir not being called before we read the errno
* value, which triggers implicitly a call to __errno_location()
* hence, we don't retrieve this value before calling chdir, but because
* of this, the corresponding errno is lost
*/
chroot_ret = chroot(union_mount_point);
chdir_ret = chdir("/");
if (chroot_ret == -1) {
/* dummy value, since errno is overwritten by chdir_ret */
chroot_ret = -ECANCELED;
fprintf(stderr, "chroot in %s failed, unknown error",
union_mount_point);
return chroot_ret;
}
if (chdir_ret < 0) {
chdir_ret = -errno;
fprintf(stderr, "chdir(/): %m\n");
return chdir_ret;
}
return 0;
}
static void launch_pid_1(void)
{
int ret;
ret = setup_chroot();
if (ret < 0) {
fprintf(stderr, "setup_chroot: %m\n");
_exit(EXIT_FAILURE);
}
fprintf(stderr, "%s\n", __func__);
ret = execv(command_args[0], command_args);
if (ret < 0)
fprintf(stderr, "execv \"%s\": %m\n", command_args[0]);
_exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int ret;
pid_t pid;
int status;
if (argc < 3)
fprintf(stderr, "wrong number of arguments : %d\n", argc);
union_mount_point = argv[1];
command_args = &argv[2];
disable_apparmor = getenv(DISABLE_APPARMOR);
ret = setup_container();
if (ret < 0) {
fprintf(stderr, "setup_container: %m\n");
_exit(EXIT_FAILURE);
}
/*
* at last, setup the pid namespace, no more fork allowed apart from
* pid 1
*/
ret = unshare(CLONE_NEWPID);
if (ret < 0) {
fprintf(stderr, "unshare: %m\n");
_exit(EXIT_FAILURE);
}
load_apparmor_profile();
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork: %m\n");
_exit(EXIT_FAILURE);
}
if (pid == 0)
launch_pid_1();
ret = waitpid(pid, &status, 0);
if (ret < 0) {
_exit(EXIT_FAILURE);
fprintf(stderr, "waitpid: %m\n");
}
if (WIFEXITED(status))
fprintf(stderr, "program exited with status %d\n", WEXITSTATUS(status));
fprintf(stderr, "instance terminated with status %d\n", status);
_exit(EXIT_SUCCESS);
}
profile aa-chroot flags=(attach_disconnected,chroot_relative) {
#{
# flags=(attach_disconnected,mediate_deleted) {
# firmwared will load it, with "=%S1%\nprofile %S2% %S3% " prepended,
# with :
# S1: the base workspace directory for the instance, containing the ro, rw,
# union and workdir directories / mountpoints
# S2: the instance unique name
# S3: the content of this very file
signal,
mount,
network,
#capability,
capability sys_chroot,
capability sys_admin,
capability chown,
capability dac_override,
capability dac_read_search,
capability fowner,
capability fsetid,
capability kill,
capability setgid,
capability setuid,
capability setpcap,
capability linux_immutable,
capability net_bind_service,
capability net_broadcast,
capability net_admin,
capability net_raw,
capability ipc_lock,
capability ipc_owner,
capability sys_module,
capability sys_rawio,
capability sys_chroot,
capability sys_ptrace,
capability sys_pacct,
capability sys_admin,
capability sys_boot,
capability sys_nice,
capability sys_resource,
capability sys_tty_config,
capability mknod,
capability lease,
capability audit_write,
capability audit_control,
capability setfcap,
capability mac_override,
capability mac_admin,
capability syslog,
file,
#umount,
audit deny /bin/* lrwxk,
}
all: aa-chroot
aa-chroot: aa-chroot.c
gcc -o aa-chroot aa-chroot.c -lapparmor
--
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at:
https://lists.ubuntu.com/mailman/listinfo/apparmor