diff options
Diffstat (limited to 'security/apparmor/resource.c')
| -rw-r--r-- | security/apparmor/resource.c | 134 | 
1 files changed, 134 insertions, 0 deletions
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c new file mode 100644 index 000000000000..4a368f1fd36d --- /dev/null +++ b/security/apparmor/resource.c @@ -0,0 +1,134 @@ +/* + * AppArmor security module + * + * This file contains AppArmor resource mediation and attachment + * + * 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/audit.h> + +#include "include/audit.h" +#include "include/resource.h" +#include "include/policy.h" + +/* + * Table of rlimit names: we generate it from resource.h. + */ +#include "rlim_names.h" + +/* audit callback for resource specific fields */ +static void audit_cb(struct audit_buffer *ab, void *va) +{ +	struct common_audit_data *sa = va; + +	audit_log_format(ab, " rlimit=%s value=%lu", +			 rlim_names[sa->aad.rlim.rlim], sa->aad.rlim.max); +} + +/** + * audit_resource - audit setting resource limit + * @profile: profile being enforced  (NOT NULL) + * @resoure: rlimit being auditing + * @value: value being set + * @error: error value + * + * Returns: 0 or sa->error else other error code on failure + */ +static int audit_resource(struct aa_profile *profile, unsigned int resource, +			  unsigned long value, int error) +{ +	struct common_audit_data sa; + +	COMMON_AUDIT_DATA_INIT(&sa, NONE); +	sa.aad.op = OP_SETRLIMIT, +	sa.aad.rlim.rlim = resource; +	sa.aad.rlim.max = value; +	sa.aad.error = error; +	return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_KERNEL, &sa, +			audit_cb); +} + +/** + * aa_map_resouce - map compiled policy resource to internal # + * @resource: flattened policy resource number + * + * Returns: resource # for the current architecture. + * + * rlimit resource can vary based on architecture, map the compiled policy + * resource # to the internal representation for the architecture. + */ +int aa_map_resource(int resource) +{ +	return rlim_map[resource]; +} + +/** + * aa_task_setrlimit - test permission to set an rlimit + * @profile - profile confining the task  (NOT NULL) + * @resource - the resource being set + * @new_rlim - the new resource limit  (NOT NULL) + * + * Control raising the processes hard limit. + * + * Returns: 0 or error code if setting resource failed + */ +int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource, +		      struct rlimit *new_rlim) +{ +	int error = 0; + +	if (profile->rlimits.mask & (1 << resource) && +	    new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max) + +		error = audit_resource(profile, resource, new_rlim->rlim_max, +			-EACCES); + +	return error; +} + +/** + * __aa_transition_rlimits - apply new profile rlimits + * @old: old profile on task  (NOT NULL) + * @new: new profile with rlimits to apply  (NOT NULL) + */ +void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new) +{ +	unsigned int mask = 0; +	struct rlimit *rlim, *initrlim; +	int i; + +	/* for any rlimits the profile controlled reset the soft limit +	 * to the less of the tasks hard limit and the init tasks soft limit +	 */ +	if (old->rlimits.mask) { +		for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) { +			if (old->rlimits.mask & mask) { +				rlim = current->signal->rlim + i; +				initrlim = init_task.signal->rlim + i; +				rlim->rlim_cur = min(rlim->rlim_max, +						     initrlim->rlim_cur); +			} +		} +	} + +	/* set any new hard limits as dictated by the new profile */ +	if (!new->rlimits.mask) +		return; +	for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) { +		if (!(new->rlimits.mask & mask)) +			continue; + +		rlim = current->signal->rlim + i; +		rlim->rlim_max = min(rlim->rlim_max, +				     new->rlimits.limits[i].rlim_max); +		/* soft limit should not exceed hard limit */ +		rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max); +	} +}  | 
