apparmor: add per policy ns .load, .replace, .remove interface files
Having per policy ns interface files helps with containers restoring policy. Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
@@ -117,7 +117,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(int op,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t policy_update(int binop, const char __user *buf, size_t size,
|
static ssize_t policy_update(int binop, const char __user *buf, size_t size,
|
||||||
loff_t *pos)
|
loff_t *pos, struct aa_ns *ns)
|
||||||
{
|
{
|
||||||
ssize_t error;
|
ssize_t error;
|
||||||
struct aa_loaddata *data;
|
struct aa_loaddata *data;
|
||||||
@@ -126,24 +126,29 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size,
|
|||||||
/* high level check about policy management - fine grained in
|
/* high level check about policy management - fine grained in
|
||||||
* below after unpack
|
* below after unpack
|
||||||
*/
|
*/
|
||||||
error = aa_may_manage_policy(profile, profile->ns, op);
|
error = aa_may_manage_policy(profile, ns, op);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
data = aa_simple_write_to_buffer(op, buf, size, size, pos);
|
data = aa_simple_write_to_buffer(op, buf, size, size, pos);
|
||||||
error = PTR_ERR(data);
|
error = PTR_ERR(data);
|
||||||
if (!IS_ERR(data)) {
|
if (!IS_ERR(data)) {
|
||||||
error = aa_replace_profiles(profile->ns, profile, binop, data);
|
error = aa_replace_profiles(ns ? ns : profile->ns, profile,
|
||||||
|
binop, data);
|
||||||
aa_put_loaddata(data);
|
aa_put_loaddata(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .load file hook fn to load policy */
|
||||||
static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
|
static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
|
||||||
loff_t *pos)
|
loff_t *pos)
|
||||||
{
|
{
|
||||||
int error = policy_update(PROF_ADD, buf, size, pos);
|
struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
|
||||||
|
int error = policy_update(PROF_ADD, buf, size, pos, ns);
|
||||||
|
|
||||||
|
aa_put_ns(ns);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -157,7 +162,10 @@ static const struct file_operations aa_fs_profile_load = {
|
|||||||
static ssize_t profile_replace(struct file *f, const char __user *buf,
|
static ssize_t profile_replace(struct file *f, const char __user *buf,
|
||||||
size_t size, loff_t *pos)
|
size_t size, loff_t *pos)
|
||||||
{
|
{
|
||||||
int error = policy_update(PROF_REPLACE, buf, size, pos);
|
struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
|
||||||
|
int error = policy_update(PROF_REPLACE, buf, size, pos, ns);
|
||||||
|
|
||||||
|
aa_put_ns(ns);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -167,18 +175,20 @@ static const struct file_operations aa_fs_profile_replace = {
|
|||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* .remove file hook fn to remove loaded policy */
|
||||||
static ssize_t profile_remove(struct file *f, const char __user *buf,
|
static ssize_t profile_remove(struct file *f, const char __user *buf,
|
||||||
size_t size, loff_t *pos)
|
size_t size, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct aa_loaddata *data;
|
struct aa_loaddata *data;
|
||||||
struct aa_profile *profile;
|
struct aa_profile *profile;
|
||||||
ssize_t error;
|
ssize_t error;
|
||||||
|
struct aa_ns *ns = aa_get_ns(f->f_inode->i_private);
|
||||||
|
|
||||||
profile = aa_current_profile();
|
profile = aa_current_profile();
|
||||||
/* high level check about policy management - fine grained in
|
/* high level check about policy management - fine grained in
|
||||||
* below after unpack
|
* below after unpack
|
||||||
*/
|
*/
|
||||||
error = aa_may_manage_policy(profile, profile->ns, OP_PROF_RM);
|
error = aa_may_manage_policy(profile, ns, OP_PROF_RM);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -192,11 +202,12 @@ static ssize_t profile_remove(struct file *f, const char __user *buf,
|
|||||||
error = PTR_ERR(data);
|
error = PTR_ERR(data);
|
||||||
if (!IS_ERR(data)) {
|
if (!IS_ERR(data)) {
|
||||||
data->data[size] = 0;
|
data->data[size] = 0;
|
||||||
error = aa_remove_profiles(profile->ns, profile, data->data,
|
error = aa_remove_profiles(ns ? ns : profile->ns, profile,
|
||||||
size);
|
data->data, size);
|
||||||
aa_put_loaddata(data);
|
aa_put_loaddata(data);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
aa_put_ns(ns);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,12 +687,77 @@ void __aa_fs_ns_rmdir(struct aa_ns *ns)
|
|||||||
mutex_unlock(&sub->lock);
|
mutex_unlock(&sub->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ns_subns_dir(ns)) {
|
||||||
|
sub = d_inode(ns_subns_dir(ns))->i_private;
|
||||||
|
aa_put_ns(sub);
|
||||||
|
}
|
||||||
|
if (ns_subload(ns)) {
|
||||||
|
sub = d_inode(ns_subload(ns))->i_private;
|
||||||
|
aa_put_ns(sub);
|
||||||
|
}
|
||||||
|
if (ns_subreplace(ns)) {
|
||||||
|
sub = d_inode(ns_subreplace(ns))->i_private;
|
||||||
|
aa_put_ns(sub);
|
||||||
|
}
|
||||||
|
if (ns_subremove(ns)) {
|
||||||
|
sub = d_inode(ns_subremove(ns))->i_private;
|
||||||
|
aa_put_ns(sub);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
|
for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
|
||||||
securityfs_remove(ns->dents[i]);
|
securityfs_remove(ns->dents[i]);
|
||||||
ns->dents[i] = NULL;
|
ns->dents[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* assumes cleanup in caller */
|
||||||
|
static int __aa_fs_ns_mkdir_entries(struct aa_ns *ns, struct dentry *dir)
|
||||||
|
{
|
||||||
|
struct dentry *dent;
|
||||||
|
|
||||||
|
AA_BUG(!ns);
|
||||||
|
AA_BUG(!dir);
|
||||||
|
|
||||||
|
dent = securityfs_create_dir("profiles", dir);
|
||||||
|
if (IS_ERR(dent))
|
||||||
|
return PTR_ERR(dent);
|
||||||
|
ns_subprofs_dir(ns) = dent;
|
||||||
|
|
||||||
|
dent = securityfs_create_dir("raw_data", dir);
|
||||||
|
if (IS_ERR(dent))
|
||||||
|
return PTR_ERR(dent);
|
||||||
|
ns_subdata_dir(ns) = dent;
|
||||||
|
|
||||||
|
dent = securityfs_create_file(".load", 0640, dir, ns,
|
||||||
|
&aa_fs_profile_load);
|
||||||
|
if (IS_ERR(dent))
|
||||||
|
return PTR_ERR(dent);
|
||||||
|
aa_get_ns(ns);
|
||||||
|
ns_subload(ns) = dent;
|
||||||
|
|
||||||
|
dent = securityfs_create_file(".replace", 0640, dir, ns,
|
||||||
|
&aa_fs_profile_replace);
|
||||||
|
if (IS_ERR(dent))
|
||||||
|
return PTR_ERR(dent);
|
||||||
|
aa_get_ns(ns);
|
||||||
|
ns_subreplace(ns) = dent;
|
||||||
|
|
||||||
|
dent = securityfs_create_file(".remove", 0640, dir, ns,
|
||||||
|
&aa_fs_profile_remove);
|
||||||
|
if (IS_ERR(dent))
|
||||||
|
return PTR_ERR(dent);
|
||||||
|
aa_get_ns(ns);
|
||||||
|
ns_subremove(ns) = dent;
|
||||||
|
|
||||||
|
dent = securityfs_create_dir("namespaces", dir);
|
||||||
|
if (IS_ERR(dent))
|
||||||
|
return PTR_ERR(dent);
|
||||||
|
aa_get_ns(ns);
|
||||||
|
ns_subns_dir(ns) = dent;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name)
|
int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name)
|
||||||
{
|
{
|
||||||
struct aa_ns *sub;
|
struct aa_ns *sub;
|
||||||
@@ -689,30 +765,31 @@ int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name)
|
|||||||
struct dentry *dent, *dir;
|
struct dentry *dent, *dir;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
AA_BUG(!ns);
|
||||||
|
AA_BUG(!parent);
|
||||||
|
AA_BUG(!mutex_is_locked(&ns->lock));
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
name = ns->base.name;
|
name = ns->base.name;
|
||||||
|
|
||||||
|
/* create ns dir if it doesn't already exist */
|
||||||
dent = securityfs_create_dir(name, parent);
|
dent = securityfs_create_dir(name, parent);
|
||||||
if (IS_ERR(dent))
|
if (IS_ERR(dent))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ns_dir(ns) = dir = dent;
|
ns_dir(ns) = dir = dent;
|
||||||
|
error = __aa_fs_ns_mkdir_entries(ns, dir);
|
||||||
|
if (error)
|
||||||
|
goto fail2;
|
||||||
|
|
||||||
dent = securityfs_create_dir("profiles", dir);
|
/* profiles */
|
||||||
if (IS_ERR(dent))
|
|
||||||
goto fail;
|
|
||||||
ns_subprofs_dir(ns) = dent;
|
|
||||||
|
|
||||||
dent = securityfs_create_dir("namespaces", dir);
|
|
||||||
if (IS_ERR(dent))
|
|
||||||
goto fail;
|
|
||||||
ns_subns_dir(ns) = dent;
|
|
||||||
|
|
||||||
list_for_each_entry(child, &ns->base.profiles, base.list) {
|
list_for_each_entry(child, &ns->base.profiles, base.list) {
|
||||||
error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
|
error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
|
||||||
if (error)
|
if (error)
|
||||||
goto fail2;
|
goto fail2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* subnamespaces */
|
||||||
list_for_each_entry(sub, &ns->sub_ns, base.list) {
|
list_for_each_entry(sub, &ns->sub_ns, base.list) {
|
||||||
mutex_lock(&sub->lock);
|
mutex_lock(&sub->lock);
|
||||||
error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL);
|
error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL);
|
||||||
@@ -1003,12 +1080,9 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct aa_fs_entry aa_fs_entry_apparmor[] = {
|
static struct aa_fs_entry aa_fs_entry_apparmor[] = {
|
||||||
AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
|
|
||||||
AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
|
|
||||||
AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
|
|
||||||
AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level),
|
AA_FS_FILE_FOPS(".ns_level", 0666, &aa_fs_ns_level),
|
||||||
AA_FS_FILE_FOPS(".ns_name", 0640, &aa_fs_ns_name),
|
AA_FS_FILE_FOPS(".ns_name", 0640, &aa_fs_ns_name),
|
||||||
AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
|
AA_FS_FILE_FOPS("profiles", 0440, &aa_fs_profiles_fops),
|
||||||
AA_FS_DIR("features", aa_fs_entry_features),
|
AA_FS_DIR("features", aa_fs_entry_features),
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
@@ -1172,6 +1246,7 @@ out:
|
|||||||
*/
|
*/
|
||||||
static int __init aa_create_aafs(void)
|
static int __init aa_create_aafs(void)
|
||||||
{
|
{
|
||||||
|
struct dentry *dent;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (!apparmor_initialized)
|
if (!apparmor_initialized)
|
||||||
@@ -1187,7 +1262,34 @@ static int __init aa_create_aafs(void)
|
|||||||
if (error)
|
if (error)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
dent = securityfs_create_file(".load", 0666, aa_fs_entry.dentry,
|
||||||
|
NULL, &aa_fs_profile_load);
|
||||||
|
if (IS_ERR(dent)) {
|
||||||
|
error = PTR_ERR(dent);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ns_subload(root_ns) = dent;
|
||||||
|
|
||||||
|
dent = securityfs_create_file(".replace", 0666, aa_fs_entry.dentry,
|
||||||
|
NULL, &aa_fs_profile_replace);
|
||||||
|
if (IS_ERR(dent)) {
|
||||||
|
error = PTR_ERR(dent);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ns_subreplace(root_ns) = dent;
|
||||||
|
|
||||||
|
dent = securityfs_create_file(".remove", 0666, aa_fs_entry.dentry,
|
||||||
|
NULL, &aa_fs_profile_remove);
|
||||||
|
if (IS_ERR(dent)) {
|
||||||
|
error = PTR_ERR(dent);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ns_subremove(root_ns) = dent;
|
||||||
|
|
||||||
|
mutex_lock(&root_ns->lock);
|
||||||
error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy");
|
error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy");
|
||||||
|
mutex_unlock(&root_ns->lock);
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@@ -71,6 +71,9 @@ enum aafs_ns_type {
|
|||||||
AAFS_NS_PROFS,
|
AAFS_NS_PROFS,
|
||||||
AAFS_NS_NS,
|
AAFS_NS_NS,
|
||||||
AAFS_NS_RAW_DATA,
|
AAFS_NS_RAW_DATA,
|
||||||
|
AAFS_NS_LOAD,
|
||||||
|
AAFS_NS_REPLACE,
|
||||||
|
AAFS_NS_REMOVE,
|
||||||
AAFS_NS_COUNT,
|
AAFS_NS_COUNT,
|
||||||
AAFS_NS_MAX_COUNT,
|
AAFS_NS_MAX_COUNT,
|
||||||
AAFS_NS_SIZE,
|
AAFS_NS_SIZE,
|
||||||
@@ -96,6 +99,9 @@ enum aafs_prof_type {
|
|||||||
#define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS])
|
#define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS])
|
||||||
#define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS])
|
#define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS])
|
||||||
#define ns_subdata_dir(X) ((X)->dents[AAFS_NS_RAW_DATA])
|
#define ns_subdata_dir(X) ((X)->dents[AAFS_NS_RAW_DATA])
|
||||||
|
#define ns_subload(X) ((X)->dents[AAFS_NS_LOAD])
|
||||||
|
#define ns_subreplace(X) ((X)->dents[AAFS_NS_REPLACE])
|
||||||
|
#define ns_subremove(X) ((X)->dents[AAFS_NS_REMOVE])
|
||||||
|
|
||||||
#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
|
#define prof_dir(X) ((X)->dents[AAFS_PROF_DIR])
|
||||||
#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
|
#define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS])
|
||||||
|
Reference in New Issue
Block a user