2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 10:07:12 +00:00
Steve Beattie 1a008da295 mod_apparmor: fix AADefaultHatName storage
When defining an AADefaultHatName entry, it was being stored in the
passed mconfig location, which is not the module specific server
config, but instead the top level (i.e. no path defined) default
directory/location config. This would be superceded by a more specific
directory config if it applied to the request. Thus, if an AAHatName was
defined that applied, but the named hat was not defined in the apparmor
policy, mod_apparmor would not attempt to fall back to the defined
AADefaultHatName, but instead jump directly to trying the DEFAULT_URI
hat.

This patch fixes it by storing the defined AADefaultHatName correctly in
the module specific storage in the related server data structure. It
also adds a bit of developer debugging statements.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>


Bug: https://launchpad.net/bugs/1207424
2014-01-23 13:46:17 -08:00

372 lines
11 KiB
C

/*
* Copyright (c) 2004, 2005, 2006 NOVELL (All rights reserved)
*
* The mod_apparmor module is licensed under the terms of the GNU
* Lesser General Public License, version 2.1. Please see the file
* COPYING.LGPL.
*
* mod_apparmor - (apache 2.0.x)
* Author: Steve Beattie <sbeattie@suse.de>
*
* This currently only implements change_hat functionality, but could be
* extended for other stuff we decide to do.
*/
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_request.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "util_filter.h"
#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include <sys/apparmor.h>
#include <unistd.h>
/* #define DEBUG */
#ifndef __unused
#define __unused __attribute__((unused))
#endif
/* should the following be configurable? */
#define DEFAULT_HAT "HANDLING_UNTRUSTED_INPUT"
#define DEFAULT_URI_HAT "DEFAULT_URI"
/* Compatibility with apache 2.2 */
#if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER < 3
#define APLOG_TRACE1 APLOG_DEBUG
server_rec *ap_server_conf = NULL;
#endif
#ifdef APLOG_USE_MODULE
APLOG_USE_MODULE(apparmor);
#endif
module AP_MODULE_DECLARE_DATA apparmor_module;
static unsigned long magic_token = 0;
static int inside_default_hat = 0;
typedef struct {
const char * hat_name;
char * path;
} immunix_dir_cfg;
typedef struct {
const char * hat_name;
int is_initialized;
} immunix_srv_cfg;
/* immunix_init() gets invoked in the post_config stage of apache.
* Unfortunately, apache reads its config once when it starts up, then
* it re-reads it when goes into its restart loop, where it starts it's
* children. This means we cannot call change_hat here, as the modules
* memory will be wiped out, and the magic_token will be lost, so apache
* wouldn't be able to change_hat back out. */
static int
immunix_init (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
apr_file_t * file;
apr_size_t size = sizeof (magic_token);
int ret;
ret = apr_file_open (&file, "/dev/urandom", APR_READ, APR_OS_DEFAULT, p);
if (!ret) {
apr_file_read (file, (void *) &magic_token, &size);
apr_file_close (file);
} else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "Failed to open /dev/urandom");
}
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "Opened /dev/urandom successfully");
return OK;
}
/* As each child starts up, we'll change_hat into a default hat, mostly
* to protect ourselves from bugs in parsing network input, but before
* we change_hat to the uri specific hat. */
static void
immunix_child_init (apr_pool_t *p, server_rec *s)
{
int ret;
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
"init: calling change_hat with '%s'", DEFAULT_HAT);
ret = aa_change_hat(DEFAULT_HAT, magic_token);
if (ret < 0) {
aa_change_hat(NULL, magic_token);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "Failed to change_hat to '%s'",
DEFAULT_HAT);
} else {
inside_default_hat = 1;
}
}
static void
debug_dump_uri(request_rec *r)
{
apr_uri_t *uri = &r->parsed_uri;
if (uri)
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Dumping uri info "
"scheme='%s' host='%s' path='%s' query='%s' fragment='%s'",
uri->scheme, uri->hostname, uri->path, uri->query,
uri->fragment);
else
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Asked to dump NULL uri");
}
/*
immunix_enter_hat will attempt to change_hat in the following order:
(1) to a hatname in a location directive
(2) to the uri
(3) to a per-server default
(4) to DEFAULT_URI
(5) back to the parent profile
*/
static int
immunix_enter_hat (request_rec *r)
{
int sd_ret = -1;
immunix_dir_cfg * dcfg = (immunix_dir_cfg *)
ap_get_module_config (r->per_dir_config, &apparmor_module);
immunix_srv_cfg * scfg = (immunix_srv_cfg *)
ap_get_module_config (r->server->module_config, &apparmor_module);
debug_dump_uri(r);
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "in immunix_enter_hat (%s) n:0x%lx p:0x%lx main:0x%lx",
dcfg->path, (unsigned long) r->next, (unsigned long) r->prev,
(unsigned long) r->main);
/* We only call change_hat for the main request, not subrequests */
if (r->main)
return OK;
if (inside_default_hat) {
aa_change_hat(NULL, magic_token);
inside_default_hat = 0;
}
if (dcfg != NULL && dcfg->hat_name != NULL) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat [dcfg] %s", dcfg->hat_name);
sd_ret = aa_change_hat(dcfg->hat_name, magic_token);
if (sd_ret < 0) {
aa_change_hat(NULL, magic_token);
} else {
return OK;
}
}
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat [uri] %s", r->uri);
sd_ret = aa_change_hat(r->uri, magic_token);
if (sd_ret < 0) {
aa_change_hat(NULL, magic_token);
} else {
return OK;
}
if (scfg) {
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Dumping scfg info: "
"scfg='0x%lx' scfg->hat_name='%s'",
(unsigned long) scfg, scfg->hat_name);
} else {
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "scfg is null");
}
if (scfg != NULL && scfg->hat_name != NULL) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat [scfg] %s", scfg->hat_name);
sd_ret = aa_change_hat(scfg->hat_name, magic_token);
if (sd_ret < 0) {
aa_change_hat(NULL, magic_token);
} else {
return OK;
}
}
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat DEFAULT_URI");
sd_ret = aa_change_hat(DEFAULT_URI_HAT, magic_token);
if (sd_ret < 0) aa_change_hat(NULL, magic_token);
return OK;
}
static int
immunix_exit_hat (request_rec *r)
{
int sd_ret;
immunix_dir_cfg * dcfg = (immunix_dir_cfg *)
ap_get_module_config (r->per_dir_config, &apparmor_module);
/* immunix_srv_cfg * scfg = (immunix_srv_cfg *)
ap_get_module_config (r->server->module_config, &apparmor_module); */
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "exiting change_hat: dir hat %s dir path %s",
dcfg->hat_name, dcfg->path);
aa_change_hat(NULL, magic_token);
sd_ret = aa_change_hat(DEFAULT_HAT, magic_token);
if (sd_ret < 0) {
aa_change_hat(NULL, magic_token);
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Failed to change_hat to '%s'",
DEFAULT_HAT);
} else {
inside_default_hat = 1;
}
return OK;
}
static const char *
aa_cmd_ch_path (cmd_parms * cmd, void * mconfig, const char * parm1)
{
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "directory config change hat %s",
parm1 ? parm1 : "DEFAULT");
immunix_dir_cfg * dcfg = mconfig;
if (parm1 != NULL) {
dcfg->hat_name = parm1;
} else {
dcfg->hat_name = "DEFAULT";
}
return NULL;
}
static int path_warn_once;
static const char *
immunix_cmd_ch_path (cmd_parms * cmd, void * mconfig, const char * parm1)
{
if (path_warn_once == 0) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "ImmHatName is "
"deprecated, please use AAHatName instead");
path_warn_once = 1;
}
return aa_cmd_ch_path(cmd, mconfig, parm1);
}
static const char *
aa_cmd_ch_srv (cmd_parms * cmd, void * mconfig, const char * parm1)
{
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "server config change hat %s",
parm1 ? parm1 : "DEFAULT");
immunix_srv_cfg * scfg = (immunix_srv_cfg *)
ap_get_module_config(cmd->server->module_config, &apparmor_module);
if (parm1 != NULL) {
scfg->hat_name = parm1;
} else {
scfg->hat_name = "DEFAULT";
}
return NULL;
}
static int srv_warn_once;
static const char *
immunix_cmd_ch_srv (cmd_parms * cmd, void * mconfig, const char * parm1)
{
if (srv_warn_once == 0) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "ImmDefaultHatName is "
"deprecated, please use AADefaultHatName instead");
srv_warn_once = 1;
}
return aa_cmd_ch_srv(cmd, mconfig, parm1);
}
static void *
immunix_create_dir_config (apr_pool_t * p, char * path)
{
immunix_dir_cfg * newcfg = (immunix_dir_cfg *) apr_pcalloc(p, sizeof(* newcfg));
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_create_dir (%s)", path ? path : ":no path:");
if (newcfg == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "immunix_create_dir: couldn't alloc dir config");
return NULL;
}
newcfg->path = apr_pstrdup (p, path ? path : ":no path:");
return newcfg;
}
/* XXX: Should figure out an appropriate action to take here, if any
static void *
immunix_merge_dir_config (apr_pool_t * p, void * parent, void * child)
{
immunix_dir_cfg * newcfg = (immunix_dir_cfg *) apr_pcalloc(p, sizeof(* newcfg));
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_merge_dir ()");
if (newcfg == NULL)
return NULL;
return newcfg;
}
*/
static void *
immunix_create_srv_config (apr_pool_t * p, server_rec * srv)
{
immunix_srv_cfg * newcfg = (immunix_srv_cfg *) apr_pcalloc(p, sizeof(* newcfg));
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_create_srv");
if (newcfg == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "immunix_create_srv: couldn't alloc srv config");
return NULL;
}
return newcfg;
}
static const command_rec immunix_cmds[] = {
AP_INIT_TAKE1 (
"ImmHatName",
immunix_cmd_ch_path,
NULL,
ACCESS_CONF,
""
),
AP_INIT_TAKE1 (
"ImmDefaultHatName",
immunix_cmd_ch_srv,
NULL,
RSRC_CONF,
""
),
AP_INIT_TAKE1 (
"AAHatName",
aa_cmd_ch_path,
NULL,
ACCESS_CONF,
""
),
AP_INIT_TAKE1 (
"AADefaultHatName",
aa_cmd_ch_srv,
NULL,
RSRC_CONF,
""
),
{ NULL }
};
static void
register_hooks (apr_pool_t *p)
{
ap_hook_post_config (immunix_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init (immunix_child_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_access_checker(immunix_enter_hat, NULL, NULL, APR_HOOK_FIRST);
/* ap_hook_post_read_request(immunix_enter_hat, NULL, NULL, APR_HOOK_FIRST); */
ap_hook_log_transaction(immunix_exit_hat, NULL, NULL, APR_HOOK_LAST);
}
module AP_MODULE_DECLARE_DATA apparmor_module = {
STANDARD20_MODULE_STUFF,
immunix_create_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
/* immunix_merge_dir_config, */ /* dir merger --- default is to override */
immunix_create_srv_config, /* server config */
NULL, /* merge server config */
immunix_cmds, /* command table */
register_hooks /* register hooks */
};