2019-01-16 23:46:06 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* SafeSetID Linux Security Module
|
|
|
|
*
|
|
|
|
* Author: Micah Morton <mortonm@chromium.org>
|
|
|
|
*
|
|
|
|
* Copyright (C) 2018 The Chromium OS Authors.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2, as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
*/
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
|
|
|
|
#define pr_fmt(fmt) "SafeSetID: " fmt
|
|
|
|
|
2019-01-16 23:46:06 +08:00
|
|
|
#include <linux/security.h>
|
|
|
|
#include <linux/cred.h>
|
|
|
|
|
|
|
|
#include "lsm.h"
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
static DEFINE_MUTEX(uid_policy_update_lock);
|
|
|
|
static DEFINE_MUTEX(gid_policy_update_lock);
|
2019-01-16 23:46:06 +08:00
|
|
|
|
|
|
|
/*
|
2020-07-17 03:52:01 +08:00
|
|
|
* In the case the input buffer contains one or more invalid IDs, the kid_t
|
2019-04-11 00:55:48 +08:00
|
|
|
* variables pointed to by @parent and @child will get updated but this
|
2019-01-16 23:46:06 +08:00
|
|
|
* function will return an error.
|
2019-04-11 00:55:48 +08:00
|
|
|
* Contents of @buf may be modified.
|
2019-01-16 23:46:06 +08:00
|
|
|
*/
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
static int parse_policy_line(struct file *file, char *buf,
|
2020-07-17 03:52:01 +08:00
|
|
|
struct setid_rule *rule)
|
2019-01-16 23:46:06 +08:00
|
|
|
{
|
2019-04-11 00:55:48 +08:00
|
|
|
char *child_str;
|
2019-01-16 23:46:06 +08:00
|
|
|
int ret;
|
2019-04-11 00:55:48 +08:00
|
|
|
u32 parsed_parent, parsed_child;
|
2019-01-16 23:46:06 +08:00
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
/* Format of |buf| string should be <UID>:<UID> or <GID>:<GID> */
|
2019-04-11 00:55:48 +08:00
|
|
|
child_str = strchr(buf, ':');
|
|
|
|
if (child_str == NULL)
|
|
|
|
return -EINVAL;
|
|
|
|
*child_str = '\0';
|
|
|
|
child_str++;
|
2019-01-16 23:46:06 +08:00
|
|
|
|
2019-04-11 00:55:48 +08:00
|
|
|
ret = kstrtou32(buf, 0, &parsed_parent);
|
2019-01-16 23:46:06 +08:00
|
|
|
if (ret)
|
2019-04-11 00:55:48 +08:00
|
|
|
return ret;
|
2019-01-16 23:46:06 +08:00
|
|
|
|
2019-04-11 00:55:48 +08:00
|
|
|
ret = kstrtou32(child_str, 0, &parsed_child);
|
2019-01-16 23:46:06 +08:00
|
|
|
if (ret)
|
2019-04-11 00:55:48 +08:00
|
|
|
return ret;
|
2019-01-16 23:46:06 +08:00
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
if (rule->type == UID){
|
|
|
|
rule->src_id.uid = make_kuid(file->f_cred->user_ns, parsed_parent);
|
|
|
|
rule->dst_id.uid = make_kuid(file->f_cred->user_ns, parsed_child);
|
|
|
|
if (!uid_valid(rule->src_id.uid) || !uid_valid(rule->dst_id.uid))
|
|
|
|
return -EINVAL;
|
|
|
|
} else if (rule->type == GID){
|
|
|
|
rule->src_id.gid = make_kgid(file->f_cred->user_ns, parsed_parent);
|
|
|
|
rule->dst_id.gid = make_kgid(file->f_cred->user_ns, parsed_child);
|
|
|
|
if (!gid_valid(rule->src_id.gid) || !gid_valid(rule->dst_id.gid))
|
|
|
|
return -EINVAL;
|
|
|
|
} else {
|
|
|
|
/* Error, rule->type is an invalid type */
|
2019-04-11 00:55:48 +08:00
|
|
|
return -EINVAL;
|
2020-07-17 03:52:01 +08:00
|
|
|
}
|
2019-04-11 00:55:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
static void __release_ruleset(struct rcu_head *rcu)
|
2019-04-11 00:55:48 +08:00
|
|
|
{
|
2020-07-17 03:52:01 +08:00
|
|
|
struct setid_ruleset *pol =
|
|
|
|
container_of(rcu, struct setid_ruleset, rcu);
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
int bucket;
|
2020-07-17 03:52:01 +08:00
|
|
|
struct setid_rule *rule;
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
struct hlist_node *tmp;
|
|
|
|
|
|
|
|
hash_for_each_safe(pol->rules, bucket, tmp, rule, next)
|
|
|
|
kfree(rule);
|
2019-04-12 04:11:54 +08:00
|
|
|
kfree(pol->policy_str);
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
kfree(pol);
|
|
|
|
}
|
2019-04-11 00:55:48 +08:00
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
static void release_ruleset(struct setid_ruleset *pol){
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
call_rcu(&pol->rcu, __release_ruleset);
|
|
|
|
}
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
static void insert_rule(struct setid_ruleset *pol, struct setid_rule *rule)
|
2019-04-12 04:12:43 +08:00
|
|
|
{
|
2020-07-17 03:52:01 +08:00
|
|
|
if (pol->type == UID)
|
|
|
|
hash_add(pol->rules, &rule->next, __kuid_val(rule->src_id.uid));
|
|
|
|
else if (pol->type == GID)
|
|
|
|
hash_add(pol->rules, &rule->next, __kgid_val(rule->src_id.gid));
|
|
|
|
else /* Error, pol->type is neither UID or GID */
|
|
|
|
return;
|
2019-04-12 04:12:43 +08:00
|
|
|
}
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
static int verify_ruleset(struct setid_ruleset *pol)
|
2019-04-12 04:12:43 +08:00
|
|
|
{
|
|
|
|
int bucket;
|
2020-07-17 03:52:01 +08:00
|
|
|
struct setid_rule *rule, *nrule;
|
2019-04-12 04:12:43 +08:00
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
hash_for_each(pol->rules, bucket, rule, next) {
|
2020-07-17 03:52:01 +08:00
|
|
|
if (_setid_policy_lookup(pol, rule->dst_id, INVALID_ID) == SIDPOL_DEFAULT) {
|
|
|
|
if (pol->type == UID) {
|
|
|
|
pr_warn("insecure policy detected: uid %d is constrained but transitively unconstrained through uid %d\n",
|
|
|
|
__kuid_val(rule->src_id.uid),
|
|
|
|
__kuid_val(rule->dst_id.uid));
|
|
|
|
} else if (pol->type == GID) {
|
|
|
|
pr_warn("insecure policy detected: gid %d is constrained but transitively unconstrained through gid %d\n",
|
|
|
|
__kgid_val(rule->src_id.gid),
|
|
|
|
__kgid_val(rule->dst_id.gid));
|
|
|
|
} else { /* pol->type is an invalid type */
|
|
|
|
res = -EINVAL;
|
|
|
|
return res;
|
|
|
|
}
|
2019-04-12 04:12:43 +08:00
|
|
|
res = -EINVAL;
|
|
|
|
|
|
|
|
/* fix it up */
|
2020-07-17 03:52:01 +08:00
|
|
|
nrule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL);
|
2019-04-12 04:12:43 +08:00
|
|
|
if (!nrule)
|
|
|
|
return -ENOMEM;
|
2020-07-17 03:52:01 +08:00
|
|
|
if (pol->type == UID){
|
|
|
|
nrule->src_id.uid = rule->dst_id.uid;
|
|
|
|
nrule->dst_id.uid = rule->dst_id.uid;
|
|
|
|
nrule->type = UID;
|
|
|
|
} else { /* pol->type must be GID if we've made it to here */
|
|
|
|
nrule->src_id.gid = rule->dst_id.gid;
|
|
|
|
nrule->dst_id.gid = rule->dst_id.gid;
|
|
|
|
nrule->type = GID;
|
|
|
|
}
|
2019-04-12 04:12:43 +08:00
|
|
|
insert_rule(pol, nrule);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
static ssize_t handle_policy_update(struct file *file,
|
2020-07-17 03:52:01 +08:00
|
|
|
const char __user *ubuf, size_t len, enum setid_type policy_type)
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
{
|
2020-07-17 03:52:01 +08:00
|
|
|
struct setid_ruleset *pol;
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
char *buf, *p, *end;
|
|
|
|
int err;
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
pol = kmalloc(sizeof(struct setid_ruleset), GFP_KERNEL);
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
if (!pol)
|
|
|
|
return -ENOMEM;
|
2019-04-12 04:11:54 +08:00
|
|
|
pol->policy_str = NULL;
|
2020-07-17 03:52:01 +08:00
|
|
|
pol->type = policy_type;
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
hash_init(pol->rules);
|
|
|
|
|
|
|
|
p = buf = memdup_user_nul(ubuf, len);
|
|
|
|
if (IS_ERR(buf)) {
|
|
|
|
err = PTR_ERR(buf);
|
|
|
|
goto out_free_pol;
|
|
|
|
}
|
2019-04-12 04:11:54 +08:00
|
|
|
pol->policy_str = kstrdup(buf, GFP_KERNEL);
|
|
|
|
if (pol->policy_str == NULL) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto out_free_buf;
|
|
|
|
}
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
|
|
|
|
/* policy lines, including the last one, end with \n */
|
|
|
|
while (*p != '\0') {
|
2020-07-17 03:52:01 +08:00
|
|
|
struct setid_rule *rule;
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
|
|
|
|
end = strchr(p, '\n');
|
|
|
|
if (end == NULL) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out_free_buf;
|
|
|
|
}
|
|
|
|
*end = '\0';
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
rule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL);
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
if (!rule) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto out_free_buf;
|
|
|
|
}
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
rule->type = policy_type;
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
err = parse_policy_line(file, p, rule);
|
|
|
|
if (err)
|
|
|
|
goto out_free_rule;
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
if (_setid_policy_lookup(pol, rule->src_id, rule->dst_id) == SIDPOL_ALLOWED) {
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
pr_warn("bad policy: duplicate entry\n");
|
|
|
|
err = -EEXIST;
|
|
|
|
goto out_free_rule;
|
|
|
|
}
|
|
|
|
|
2019-04-12 04:12:43 +08:00
|
|
|
insert_rule(pol, rule);
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
p = end + 1;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
out_free_rule:
|
|
|
|
kfree(rule);
|
|
|
|
goto out_free_buf;
|
|
|
|
}
|
|
|
|
|
2019-04-12 04:12:43 +08:00
|
|
|
err = verify_ruleset(pol);
|
|
|
|
/* bogus policy falls through after fixing it up */
|
|
|
|
if (err && err != -EINVAL)
|
|
|
|
goto out_free_buf;
|
|
|
|
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
/*
|
|
|
|
* Everything looks good, apply the policy and release the old one.
|
|
|
|
* What we really want here is an xchg() wrapper for RCU, but since that
|
|
|
|
* doesn't currently exist, just use a spinlock for now.
|
|
|
|
*/
|
2020-07-17 03:52:01 +08:00
|
|
|
if (policy_type == UID) {
|
|
|
|
mutex_lock(&uid_policy_update_lock);
|
|
|
|
pol = rcu_replace_pointer(safesetid_setuid_rules, pol,
|
|
|
|
lockdep_is_held(&uid_policy_update_lock));
|
|
|
|
mutex_unlock(&uid_policy_update_lock);
|
|
|
|
} else if (policy_type == GID) {
|
|
|
|
mutex_lock(&gid_policy_update_lock);
|
|
|
|
pol = rcu_replace_pointer(safesetid_setgid_rules, pol,
|
|
|
|
lockdep_is_held(&gid_policy_update_lock));
|
|
|
|
mutex_unlock(&gid_policy_update_lock);
|
|
|
|
} else {
|
|
|
|
/* Error, policy type is neither UID or GID */
|
|
|
|
pr_warn("error: bad policy type");
|
|
|
|
}
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
err = len;
|
|
|
|
|
|
|
|
out_free_buf:
|
|
|
|
kfree(buf);
|
|
|
|
out_free_pol:
|
2019-09-18 02:27:05 +08:00
|
|
|
if (pol)
|
2020-07-17 03:52:01 +08:00
|
|
|
release_ruleset(pol);
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
return err;
|
2019-01-16 23:46:06 +08:00
|
|
|
}
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
static ssize_t safesetid_uid_file_write(struct file *file,
|
2019-01-16 23:46:06 +08:00
|
|
|
const char __user *buf,
|
|
|
|
size_t len,
|
|
|
|
loff_t *ppos)
|
|
|
|
{
|
2019-04-11 00:55:58 +08:00
|
|
|
if (!file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN))
|
2019-01-16 23:46:06 +08:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (*ppos != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
return handle_policy_update(file, buf, len, UID);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t safesetid_gid_file_write(struct file *file,
|
|
|
|
const char __user *buf,
|
|
|
|
size_t len,
|
|
|
|
loff_t *ppos)
|
|
|
|
{
|
|
|
|
if (!file_ns_capable(file, &init_user_ns, CAP_MAC_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (*ppos != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return handle_policy_update(file, buf, len, GID);
|
2019-01-16 23:46:06 +08:00
|
|
|
}
|
|
|
|
|
2019-04-12 04:11:54 +08:00
|
|
|
static ssize_t safesetid_file_read(struct file *file, char __user *buf,
|
2020-08-11 23:39:51 +08:00
|
|
|
size_t len, loff_t *ppos, struct mutex *policy_update_lock, struct __rcu setid_ruleset* ruleset)
|
2019-04-12 04:11:54 +08:00
|
|
|
{
|
|
|
|
ssize_t res = 0;
|
2020-07-17 03:52:01 +08:00
|
|
|
struct setid_ruleset *pol;
|
2019-04-12 04:11:54 +08:00
|
|
|
const char *kbuf;
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
mutex_lock(policy_update_lock);
|
|
|
|
pol = rcu_dereference_protected(ruleset, lockdep_is_held(policy_update_lock));
|
2019-04-12 04:11:54 +08:00
|
|
|
if (pol) {
|
|
|
|
kbuf = pol->policy_str;
|
|
|
|
res = simple_read_from_buffer(buf, len, ppos,
|
|
|
|
kbuf, strlen(kbuf));
|
|
|
|
}
|
2020-07-17 03:52:01 +08:00
|
|
|
mutex_unlock(policy_update_lock);
|
|
|
|
|
2019-04-12 04:11:54 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
static ssize_t safesetid_uid_file_read(struct file *file, char __user *buf,
|
|
|
|
size_t len, loff_t *ppos)
|
|
|
|
{
|
|
|
|
return safesetid_file_read(file, buf, len, ppos,
|
|
|
|
&uid_policy_update_lock, safesetid_setuid_rules);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t safesetid_gid_file_read(struct file *file, char __user *buf,
|
|
|
|
size_t len, loff_t *ppos)
|
|
|
|
{
|
|
|
|
return safesetid_file_read(file, buf, len, ppos,
|
|
|
|
&gid_policy_update_lock, safesetid_setgid_rules);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const struct file_operations safesetid_uid_file_fops = {
|
|
|
|
.read = safesetid_uid_file_read,
|
|
|
|
.write = safesetid_uid_file_write,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct file_operations safesetid_gid_file_fops = {
|
|
|
|
.read = safesetid_gid_file_read,
|
|
|
|
.write = safesetid_gid_file_write,
|
2019-01-16 23:46:06 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int __init safesetid_init_securityfs(void)
|
|
|
|
{
|
|
|
|
int ret;
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
struct dentry *policy_dir;
|
2020-07-17 03:52:01 +08:00
|
|
|
struct dentry *uid_policy_file;
|
|
|
|
struct dentry *gid_policy_file;
|
2019-01-16 23:46:06 +08:00
|
|
|
|
|
|
|
if (!safesetid_initialized)
|
|
|
|
return 0;
|
|
|
|
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
policy_dir = securityfs_create_dir("safesetid", NULL);
|
|
|
|
if (IS_ERR(policy_dir)) {
|
|
|
|
ret = PTR_ERR(policy_dir);
|
2019-01-16 23:46:06 +08:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
uid_policy_file = securityfs_create_file("uid_allowlist_policy", 0600,
|
|
|
|
policy_dir, NULL, &safesetid_uid_file_fops);
|
|
|
|
if (IS_ERR(uid_policy_file)) {
|
|
|
|
ret = PTR_ERR(uid_policy_file);
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
goto error;
|
2019-01-16 23:46:06 +08:00
|
|
|
}
|
|
|
|
|
2020-07-17 03:52:01 +08:00
|
|
|
gid_policy_file = securityfs_create_file("gid_allowlist_policy", 0600,
|
|
|
|
policy_dir, NULL, &safesetid_gid_file_fops);
|
|
|
|
if (IS_ERR(gid_policy_file)) {
|
|
|
|
ret = PTR_ERR(gid_policy_file);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-01-16 23:46:06 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
LSM: SafeSetID: rewrite userspace API to atomic updates
The current API of the SafeSetID LSM uses one write() per rule, and applies
each written rule instantly. This has several downsides:
- While a policy is being loaded, once a single parent-child pair has been
loaded, the parent is restricted to that specific child, even if
subsequent rules would allow transitions to other child UIDs. This means
that during policy loading, set*uid() can randomly fail.
- To replace the policy without rebooting, it is necessary to first flush
all old rules. This creates a time window in which no constraints are
placed on the use of CAP_SETUID.
- If we want to perform sanity checks on the final policy, this requires
that the policy isn't constructed in a piecemeal fashion without telling
the kernel when it's done.
Other kernel APIs - including things like the userns code and netfilter -
avoid this problem by performing updates atomically. Luckily, SafeSetID
hasn't landed in a stable (upstream) release yet, so maybe it's not too
late to completely change the API.
The new API for SafeSetID is: If you want to change the policy, open
"safesetid/whitelist_policy" and write the entire policy,
newline-delimited, in there.
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Micah Morton <mortonm@chromium.org>
2019-04-11 00:56:05 +08:00
|
|
|
securityfs_remove(policy_dir);
|
2019-01-16 23:46:06 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
fs_initcall(safesetid_init_securityfs);
|