/*
* AppArmor security module
*
* This file contains AppArmor LSM hooks.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/lsm_hooks.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/ptrace.h>
#include <linux/ctype.h>
#include <linux/sysctl.h>
#include <linux/audit.h>
#include <linux/user_namespace.h>
#include <linux/kmemleak.h>
#include <net/sock.h>
#include "include/apparmor.h"
#include "include/apparmorfs.h"
#include "include/audit.h"
#include "include/capability.h"
#include "include/context.h"
#include "include/file.h"
#include "include/ipc.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/policy_ns.h"
#include "include/procattr.h"
/* Flag indicating whether initialization completed */
int apparmor_initialized;
DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
/*
* LSM hook functions
*/
/*
* free the associated aa_task_ctx and put its profiles
*/
static void apparmor_cred_free(struct cred *cred)
{
aa_free_task_context(cred_ctx(cred));
cred_ctx(cred) = NULL;
}
/*
* allocate the apparmor part of blank credentials
*/
static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
/* freed by apparmor_cred_free */
struct aa_task_ctx *ctx = aa_alloc_task_context(gfp);
if (!ctx)
return -ENOMEM;
cred_ctx(cred) = ctx;
return 0;
}
/*
* prepare new aa_task_ctx for modification by prepare_cred block
*/
static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
/* freed by apparmor_cred_free */
struct aa_task_ctx *ctx = aa_alloc_task_context(gfp);
if (!ctx)
return -ENOMEM;
aa_dup_task_context(ctx, cred_ctx(old));
cred_ctx(new) = ctx;
return 0;
}
/*
* transfer the apparmor data to a blank set of creds
*/
static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
{
const struct aa_task_ctx *old_ctx = cred_ctx(old);
struct aa_task_ctx *new_ctx = cred_ctx(new);
aa_dup_task_context(new_ctx, old_ctx);
}
static int apparmor_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
return aa_ptrace(current, child, mode);
}
static int apparmor_ptrace_traceme(struct task_struct *parent)
{
return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
}
/* Derived from security/commoncap.c:cap_capget */
static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
struct aa_profile *profile;
const struct cred *cred;
rcu_read_lock();
cred = __task_cred(target);
profile = aa_cred_profile(cred);
/*
* cap_capget is stacked ahead of this and will
* initialize effective and permitted.
*/
if (!unconfined(profile) && !COMPLAIN_MODE(profile)) {
*effective = cap_intersect(*effective, profile->caps.allow);
*permitted = cap_intersect(*permitted, profile->caps.allow);
}
rcu_read_unlock();
return 0;
}
static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit)
{
struct aa_profile *profile;
int error = 0;
profile = aa_cred_profile(cred);
if (!unconfined(profile))
error = aa_capable(profile, cap, audit);
return error;
}
/**
* common_perm - basic common permission check wrapper fn for paths
* @op: operation being checked
* @path: path to check permission of (NOT NULL)
* @mask: requested permissions mask
* @cond: conditional info for the permission request (NOT NULL)
*
* Returns: %0 else error code if error or permission denied
*/
static int common_perm(const char *op, const struct path *path, u32 mask,
struct path_cond *cond)
{
struct aa_profile *profile;
int error = 0;
profile = __aa_current_profile();
if (!unconfined(profile))
error = aa_path_perm(op, profile, path, 0, mask, cond);
return error;
}
/**
* common_perm_cond - common permission wrapper around inode cond
* @op: operation being checked
* @path: location to check (NOT NULL)
* @mask: requested permi