selinux/stable-5.10 PR 20201012

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAl+E9UoUHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXMG2BAApHLKLsfH5gf7gZNjHmQxddg8maCl
 BGt7K1xc9iYBZN56Cbc7v9uKc5pM+UOoOlVmWh+8jaROpX10jJmvhsebQzpcWEEs
 O/BDg/Y/AafoLr5e7gbAnlA7TJXNSR9MG9RB7c9xC14LG/bqBmkaUNsv8isWlLgl
 J2atHLsdlvCbmqJvnc6Fh3VJCbY/I0kt9L04GBQ4pEK3TKOxtORQaQcjVgLhlcw9
 YdMPKYIwy2Ze2HUuyW2o9OuryHhoMrwxpN/35/PAxrRwpO0LVnjjiw6njQqYVGH3
 el8mPXlhHah/7QUKcngSsvcvUcaSencp9sUBrp1vK9C1vkSFyubZweVi4A2TEWnh
 Ctceje7XP/YWDcJ+5BgASvosQdqOBB7huuOOKVpvaBXqgUHFgaxphV4/FDNnlF62
 AteX5RcWb/JiFJ4YnbknPNa/MWxVYuVn78AlNsM2ZponWYWs9JZ17lX4tHAKF1Qm
 x6ZMvMCDJTj8622l8nw3dTZKNDE3nFblDThX8aSrAhCQQE6HvugbKU4Fzo1oiSPl
 84PlCPgb+3tP3OsvZDIOPCJxC6IHgS+meA0IjhjwuCb+U+YWaAIeOlOPSkxUmfLu
 iJVWHmDtsAM3bTBxwQudhgXF3a1oKCEqeqNxM6P6p55jti7xal9FnZNHTbSh2sO1
 Km4oIqTEb1XWNdU=
 =NNLw
 -----END PGP SIGNATURE-----

Merge tag 'selinux-pr-20201012' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:
 "A decent number of SELinux patches for v5.10, twenty two in total. The
  highlights are listed below, but all of the patches pass our test
  suite and merge cleanly.

   - A number of changes to how the SELinux policy is loaded and managed
     inside the kernel with the goal of improving the atomicity of a
     SELinux policy load operation.

     These changes account for the bulk of the diffstat as well as the
     patch count. A special thanks to everyone who contributed patches
     and fixes for this work.

   - Convert the SELinux policy read-write lock to RCU.

   - A tracepoint was added for audited SELinux access control events;
     this should help provide a more unified backtrace across kernel and
     userspace.

   - Allow the removal of security.selinux xattrs when a SELinux policy
     is not loaded.

   - Enable policy capabilities in SELinux policies created with the
     scripts/selinux/mdp tool.

   - Provide some "no sooner than" dates for the SELinux checkreqprot
     sysfs deprecation"

* tag 'selinux-pr-20201012' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: (22 commits)
  selinux: provide a "no sooner than" date for the checkreqprot removal
  selinux: Add helper functions to get and set checkreqprot
  selinux: access policycaps with READ_ONCE/WRITE_ONCE
  selinux: simplify away security_policydb_len()
  selinux: move policy mutex to selinux_state, use in lockdep checks
  selinux: fix error handling bugs in security_load_policy()
  selinux: convert policy read-write lock to RCU
  selinux: delete repeated words in comments
  selinux: add basic filtering for audit trace events
  selinux: add tracepoint on audited events
  selinux: Create new booleans and class dirs out of tree
  selinux: Standardize string literal usage for selinuxfs directory names
  selinux: Refactor selinuxfs directory populating functions
  selinux: Create function for selinuxfs directory cleanup
  selinux: permit removing security.selinux xattr before policy load
  selinux: fix memdup.cocci warnings
  selinux: avoid dereferencing the policy prior to initialization
  selinux: fix allocation failure check on newpolicy->sidtab
  selinux: refactor changing booleans
  selinux: move policy commit after updating selinuxfs
  ...
This commit is contained in:
Linus Torvalds 2020-10-13 16:29:55 -07:00
commit 7b540812cc
21 changed files with 1134 additions and 503 deletions

View File

@ -15,7 +15,7 @@ Description:
actual protection), and Android and Linux distributions have been
explicitly writing a "0" to /sys/fs/selinux/checkreqprot during
initialization for some time. Support for setting checkreqprot to 1
will be removed in a future kernel release, at which point the kernel
will be removed no sooner than June 2021, at which point the kernel
will always cease using checkreqprot internally and will always
check the actual protections being applied upon mmap/mprotect calls.
The checkreqprot selinuxfs node will remain for backward compatibility

View File

@ -15621,6 +15621,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git
F: Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
F: Documentation/ABI/obsolete/sysfs-selinux-disable
F: Documentation/admin-guide/LSM/SELinux.rst
F: include/trace/events/avc.h
F: include/uapi/linux/selinux_netlink.h
F: scripts/selinux/
F: security/selinux/

View File

@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Authors: Thiébaud Weksteen <tweek@google.com>
* Peter Enderborg <Peter.Enderborg@sony.com>
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM avc
#if !defined(_TRACE_SELINUX_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SELINUX_H
#include <linux/tracepoint.h>
TRACE_EVENT(selinux_audited,
TP_PROTO(struct selinux_audit_data *sad,
char *scontext,
char *tcontext,
const char *tclass
),
TP_ARGS(sad, scontext, tcontext, tclass),
TP_STRUCT__entry(
__field(u32, requested)
__field(u32, denied)
__field(u32, audited)
__field(int, result)
__string(scontext, scontext)
__string(tcontext, tcontext)
__string(tclass, tclass)
),
TP_fast_assign(
__entry->requested = sad->requested;
__entry->denied = sad->denied;
__entry->audited = sad->audited;
__entry->result = sad->result;
__assign_str(tcontext, tcontext);
__assign_str(scontext, scontext);
__assign_str(tclass, tclass);
),
TP_printk("requested=0x%x denied=0x%x audited=0x%x result=%d scontext=%s tcontext=%s tclass=%s",
__entry->requested, __entry->denied, __entry->audited, __entry->result,
__get_str(scontext), __get_str(tcontext), __get_str(tclass)
)
);
#endif
/* This part must be outside protection */
#include <trace/define_trace.h>

View File

@ -35,6 +35,9 @@ struct security_class_mapping {
#include "classmap.h"
#include "initial_sid_to_string.h"
#include "policycap_names.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
int main(int argc, char *argv[])
{
@ -115,6 +118,10 @@ int main(int argc, char *argv[])
}
}
/* enable all policy capabilities */
for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
fprintf(fout, "policycap %s;\n", selinux_policycap_names[i]);
/* types, roles, and allows */
fprintf(fout, "type base_t;\n");
fprintf(fout, "role base_r;\n");

View File

@ -31,6 +31,9 @@
#include "avc_ss.h"
#include "classmap.h"
#define CREATE_TRACE_POINTS
#include <trace/events/avc.h>
#define AVC_CACHE_SLOTS 512
#define AVC_DEF_CACHE_THRESHOLD 512
#define AVC_CACHE_RECLAIM 16
@ -702,33 +705,37 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
{
struct common_audit_data *ad = a;
struct selinux_audit_data *sad = ad->selinux_audit_data;
char *scontext;
char *scontext = NULL;
char *tcontext = NULL;
const char *tclass = NULL;
u32 scontext_len;
u32 tcontext_len;
int rc;
rc = security_sid_to_context(sad->state, sad->ssid, &scontext,
&scontext_len);
if (rc)
audit_log_format(ab, " ssid=%d", sad->ssid);
else {
else
audit_log_format(ab, " scontext=%s", scontext);
kfree(scontext);
}
rc = security_sid_to_context(sad->state, sad->tsid, &scontext,
&scontext_len);
rc = security_sid_to_context(sad->state, sad->tsid, &tcontext,
&tcontext_len);
if (rc)
audit_log_format(ab, " tsid=%d", sad->tsid);
else {
audit_log_format(ab, " tcontext=%s", scontext);
kfree(scontext);
}
else
audit_log_format(ab, " tcontext=%s", tcontext);
audit_log_format(ab, " tclass=%s", secclass_map[sad->tclass-1].name);
tclass = secclass_map[sad->tclass-1].name;
audit_log_format(ab, " tclass=%s", tclass);
if (sad->denied)
audit_log_format(ab, " permissive=%u", sad->result ? 0 : 1);
trace_selinux_audited(sad, scontext, tcontext, tclass);
kfree(tcontext);
kfree(scontext);
/* in case of invalid context report also the actual context string */
rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext,
&scontext_len);

View File

@ -1978,7 +1978,7 @@ static inline u32 file_to_av(struct file *file)
}
/*
* Convert a file to an access vector and include the correct open
* Convert a file to an access vector and include the correct
* open permission.
*/
static inline u32 open_file_to_av(struct file *file)
@ -3271,6 +3271,9 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
}
if (!selinux_initialized(&selinux_state))
return 0;
/* No one is allowed to remove a SELinux security label.
You can change the label, but all data must be labeled. */
return -EACCES;
@ -3709,7 +3712,7 @@ static int selinux_mmap_file(struct file *file, unsigned long reqprot,
return rc;
}
if (selinux_state.checkreqprot)
if (checkreqprot_get(&selinux_state))
prot = reqprot;
return file_map_prot_check(file, prot,
@ -3723,7 +3726,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
const struct cred *cred = current_cred();
u32 sid = cred_sid(cred);
if (selinux_state.checkreqprot)
if (checkreqprot_get(&selinux_state))
prot = reqprot;
if (default_noexec &&
@ -4438,7 +4441,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
*
* If @skb_sid is valid then the user:role:type information from @sk_sid is
* combined with the MLS information from @skb_sid in order to create
* @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy
* @conn_sid. If @skb_sid is not valid then @conn_sid is simply a copy
* of @sk_sid. Returns zero on success, negative values on failure.
*
*/
@ -5308,7 +5311,7 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
/* As selinux_sctp_bind_connect() is called by the
* SCTP protocol layer, the socket is already locked,
* therefore selinux_netlbl_socket_connect_locked() is
* therefore selinux_netlbl_socket_connect_locked()
* is called here. The situations handled are:
* sctp_connectx(3), sctp_sendmsg(3), sendmsg(2),
* whenever a new IP address is added or when a new
@ -7225,10 +7228,10 @@ static __init int selinux_init(void)
memset(&selinux_state, 0, sizeof(selinux_state));
enforcing_set(&selinux_state, selinux_enforcing_boot);
selinux_state.checkreqprot = selinux_checkreqprot_boot;
selinux_ss_init(&selinux_state.ss);
checkreqprot_set(&selinux_state, selinux_checkreqprot_boot);
selinux_avc_init(&selinux_state.avc);
mutex_init(&selinux_state.status_lock);
mutex_init(&selinux_state.policy_mutex);
/* Set the security state for the initial task. */
cred_init_security();

View File

@ -13,7 +13,7 @@
#include "security.h"
int security_get_bools(struct selinux_state *state,
int security_get_bools(struct selinux_policy *policy,
u32 *len, char ***names, int **values);
int security_set_bools(struct selinux_state *state, u32 len, int *values);

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _SELINUX_POLICYCAP_H_
#define _SELINUX_POLICYCAP_H_
/* Policy capabilities */
enum {
POLICYDB_CAPABILITY_NETPEER,
POLICYDB_CAPABILITY_OPENPERM,
POLICYDB_CAPABILITY_EXTSOCKCLASS,
POLICYDB_CAPABILITY_ALWAYSNETWORK,
POLICYDB_CAPABILITY_CGROUPSECLABEL,
POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
__POLICYDB_CAPABILITY_MAX
};
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
extern const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
#endif /* _SELINUX_POLICYCAP_H_ */

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _SELINUX_POLICYCAP_NAMES_H_
#define _SELINUX_POLICYCAP_NAMES_H_
#include "policycap.h"
/* Policy capability names */
const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
"network_peer_controls",
"open_perms",
"extended_socket_class",
"always_check_network",
"cgroup_seclabel",
"nnp_nosuid_transition",
"genfs_seclabel_symlinks"
};
#endif /* _SELINUX_POLICYCAP_NAMES_H_ */

View File

@ -13,9 +13,11 @@
#include <linux/dcache.h>
#include <linux/magic.h>
#include <linux/types.h>
#include <linux/rcupdate.h>
#include <linux/refcount.h>
#include <linux/workqueue.h>
#include "flask.h"
#include "policycap.h"
#define SECSID_NULL 0x00000000 /* unspecified SID */
#define SECSID_WILD 0xffffffff /* wildcard SID */
@ -72,21 +74,6 @@ struct netlbl_lsm_secattr;
extern int selinux_enabled_boot;
/* Policy capabilities */
enum {
POLICYDB_CAPABILITY_NETPEER,
POLICYDB_CAPABILITY_OPENPERM,
POLICYDB_CAPABILITY_EXTSOCKCLASS,
POLICYDB_CAPABILITY_ALWAYSNETWORK,
POLICYDB_CAPABILITY_CGROUPSECLABEL,
POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
__POLICYDB_CAPABILITY_MAX
};
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
extern const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
/*
* type_datum properties
* available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
@ -98,7 +85,7 @@ extern const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
#define POLICYDB_BOUNDS_MAXDEPTH 4
struct selinux_avc;
struct selinux_ss;
struct selinux_policy;
struct selinux_state {
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
@ -115,10 +102,10 @@ struct selinux_state {
struct mutex status_lock;
struct selinux_avc *avc;
struct selinux_ss *ss;
struct selinux_policy __rcu *policy;
struct mutex policy_mutex;
} __randomize_layout;
void selinux_ss_init(struct selinux_ss **ss);
void selinux_avc_init(struct selinux_avc **avc);
extern struct selinux_state selinux_state;
@ -156,6 +143,16 @@ static inline void enforcing_set(struct selinux_state *state, bool value)
}
#endif
static inline bool checkreqprot_get(const struct selinux_state *state)
{
return READ_ONCE(state->checkreqprot);
}
static inline void checkreqprot_set(struct selinux_state *state, bool value)
{
WRITE_ONCE(state->checkreqprot, value);
}
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
static inline bool selinux_disabled(struct selinux_state *state)
{
@ -177,57 +174,61 @@ static inline bool selinux_policycap_netpeer(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_NETPEER];
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_NETPEER]);
}
static inline bool selinux_policycap_openperm(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_OPENPERM];
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_OPENPERM]);
}
static inline bool selinux_policycap_extsockclass(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_EXTSOCKCLASS];
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_EXTSOCKCLASS]);
}
static inline bool selinux_policycap_alwaysnetwork(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_ALWAYSNETWORK];
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_ALWAYSNETWORK]);
}
static inline bool selinux_policycap_cgroupseclabel(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_CGROUPSECLABEL];
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_CGROUPSECLABEL]);
}
static inline bool selinux_policycap_nnp_nosuid_transition(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION];
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION]);
}
static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS];
return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]);
}
int security_mls_enabled(struct selinux_state *state);
int security_load_policy(struct selinux_state *state,
void *data, size_t len);
void *data, size_t len,
struct selinux_policy **newpolicyp);
void selinux_policy_commit(struct selinux_state *state,
struct selinux_policy *newpolicy);
void selinux_policy_cancel(struct selinux_state *state,
struct selinux_policy *policy);
int security_read_policy(struct selinux_state *state,
void **data, size_t *len);
size_t security_policydb_len(struct selinux_state *state);
int security_policycap_supported(struct selinux_state *state,
unsigned int req_cap);
@ -358,9 +359,9 @@ int security_net_peersid_resolve(struct selinux_state *state,
u32 xfrm_sid,
u32 *peer_sid);
int security_get_classes(struct selinux_state *state,
int security_get_classes(struct selinux_policy *policy,
char ***classes, int *nclasses);
int security_get_permissions(struct selinux_state *state,
int security_get_permissions(struct selinux_policy *policy,
char *class, char ***perms, int *nperms);
int security_get_reject_unknown(struct selinux_state *state);
int security_get_allow_unknown(struct selinux_state *state);
@ -380,6 +381,10 @@ int security_genfs_sid(struct selinux_state *state,
const char *fstype, char *name, u16 sclass,
u32 *sid);
int selinux_policy_genfs_sid(struct selinux_policy *policy,
const char *fstype, char *name, u16 sclass,
u32 *sid);
#ifdef CONFIG_NETLABEL
int security_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr,

View File

@ -20,6 +20,7 @@
#include <linux/fs_context.h>
#include <linux/mount.h>
#include <linux/mutex.h>
#include <linux/namei.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/security.h>
@ -74,7 +75,6 @@ struct selinux_fs_info {
unsigned long last_class_ino;
bool policy_opened;
struct dentry *policycap_dir;
struct mutex mutex;
unsigned long last_ino;
struct selinux_state *state;
struct super_block *sb;
@ -88,7 +88,6 @@ static int selinux_fs_info_create(struct super_block *sb)
if (!fsi)
return -ENOMEM;
mutex_init(&fsi->mutex);
fsi->last_ino = SEL_INO_NEXT - 1;
fsi->state = &selinux_state;
fsi->sb = sb;
@ -117,6 +116,10 @@ static void selinux_fs_info_free(struct super_block *sb)
#define SEL_POLICYCAP_INO_OFFSET 0x08000000
#define SEL_INO_MASK 0x00ffffff
#define BOOL_DIR_NAME "booleans"
#define CLASS_DIR_NAME "class"
#define POLICYCAP_DIR_NAME "policy_capabilities"
#define TMPBUFLEN 12
static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
@ -346,14 +349,24 @@ static const struct file_operations sel_policyvers_ops = {
};
/* declaration for sel_write_load */
static int sel_make_bools(struct selinux_fs_info *fsi);
static int sel_make_classes(struct selinux_fs_info *fsi);
static int sel_make_policycap(struct selinux_fs_info *fsi);
static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir,
unsigned int *bool_num, char ***bool_pending_names,
unsigned int **bool_pending_values);
static int sel_make_classes(struct selinux_policy *newpolicy,
struct dentry *class_dir,
unsigned long *last_class_ino);
/* declaration for sel_make_class_dirs */
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
unsigned long *ino);
/* declaration for sel_make_policy_nodes */
static struct dentry *sel_make_disconnected_dir(struct super_block *sb,
unsigned long *ino);
/* declaration for sel_make_policy_nodes */
static void sel_remove_entries(struct dentry *de);
static ssize_t sel_read_mls(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
@ -385,7 +398,7 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
BUG_ON(filp->private_data);
mutex_lock(&fsi->mutex);
mutex_lock(&fsi->state->policy_mutex);
rc = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
@ -402,25 +415,25 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
if (!plm)
goto err;
if (i_size_read(inode) != security_policydb_len(state)) {
inode_lock(inode);
i_size_write(inode, security_policydb_len(state));
inode_unlock(inode);
}
rc = security_read_policy(state, &plm->data, &plm->len);
if (rc)
goto err;
if ((size_t)i_size_read(inode) != plm->len) {
inode_lock(inode);
i_size_write(inode, plm->len);
inode_unlock(inode);
}
fsi->policy_opened = 1;
filp->private_data = plm;
mutex_unlock(&fsi->mutex);
mutex_unlock(&fsi->state->policy_mutex);
return 0;
err:
mutex_unlock(&fsi->mutex);
mutex_unlock(&fsi->state->policy_mutex);
if (plm)
vfree(plm->data);
@ -508,29 +521,94 @@ static const struct file_operations sel_policy_ops = {
.llseek = generic_file_llseek,
};
static int sel_make_policy_nodes(struct selinux_fs_info *fsi)
static void sel_remove_old_bool_data(unsigned int bool_num, char **bool_names,
unsigned int *bool_values)
{
int ret;
u32 i;
ret = sel_make_bools(fsi);
/* bool_dir cleanup */
for (i = 0; i < bool_num; i++)
kfree(bool_names[i]);
kfree(bool_names);
kfree(bool_values);
}
static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
struct selinux_policy *newpolicy)
{
int ret = 0;
struct dentry *tmp_parent, *tmp_bool_dir, *tmp_class_dir, *old_dentry;
unsigned int tmp_bool_num, old_bool_num;
char **tmp_bool_names, **old_bool_names;
unsigned int *tmp_bool_values, *old_bool_values;
unsigned long tmp_ino = fsi->last_ino; /* Don't increment last_ino in this function */
tmp_parent = sel_make_disconnected_dir(fsi->sb, &tmp_ino);
if (IS_ERR(tmp_parent))
return PTR_ERR(tmp_parent);
tmp_ino = fsi->bool_dir->d_inode->i_ino - 1; /* sel_make_dir will increment and set */
tmp_bool_dir = sel_make_dir(tmp_parent, BOOL_DIR_NAME, &tmp_ino);
if (IS_ERR(tmp_bool_dir)) {
ret = PTR_ERR(tmp_bool_dir);
goto out;
}
tmp_ino = fsi->class_dir->d_inode->i_ino - 1; /* sel_make_dir will increment and set */
tmp_class_dir = sel_make_dir(tmp_parent, CLASS_DIR_NAME, &tmp_ino);
if (IS_ERR(tmp_class_dir)) {
ret = PTR_ERR(tmp_class_dir);
goto out;
}
ret = sel_make_bools(newpolicy, tmp_bool_dir, &tmp_bool_num,
&tmp_bool_names, &tmp_bool_values);
if (ret) {
pr_err("SELinux: failed to load policy booleans\n");
return ret;
goto out;
}
ret = sel_make_classes(fsi);
ret = sel_make_classes(newpolicy, tmp_class_dir,
&fsi->last_class_ino);
if (ret) {
pr_err("SELinux: failed to load policy classes\n");
return ret;
goto out;
}
ret = sel_make_policycap(fsi);
if (ret) {
pr_err("SELinux: failed to load policy capabilities\n");
return ret;
}
/* booleans */
old_dentry = fsi->bool_dir;
lock_rename(tmp_bool_dir, old_dentry);
d_exchange(tmp_bool_dir, fsi->bool_dir);
return 0;
old_bool_num = fsi->bool_num;
old_bool_names = fsi->bool_pending_names;
old_bool_values = fsi->bool_pending_values;
fsi->bool_num = tmp_bool_num;
fsi->bool_pending_names = tmp_bool_names;
fsi->bool_pending_values = tmp_bool_values;
sel_remove_old_bool_data(old_bool_num, old_bool_names, old_bool_values);
fsi->bool_dir = tmp_bool_dir;
unlock_rename(tmp_bool_dir, old_dentry);
/* classes */
old_dentry = fsi->class_dir;
lock_rename(tmp_class_dir, old_dentry);
d_exchange(tmp_class_dir, fsi->class_dir);
fsi->class_dir = tmp_class_dir;
unlock_rename(tmp_class_dir, old_dentry);
out:
/* Since the other temporary dirs are children of tmp_parent
* this will handle all the cleanup in the case of a failure before
* the swapover
*/
sel_remove_entries(tmp_parent);
dput(tmp_parent); /* d_genocide() only handles the children */
return ret;
}
static ssize_t sel_write_load(struct file *file, const char __user *buf,
@ -538,10 +616,11 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_policy *newpolicy;
ssize_t length;
void *data = NULL;
mutex_lock(&fsi->mutex);
mutex_lock(&fsi->state->policy_mutex);
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
@ -563,15 +642,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (copy_from_user(data, buf, count) != 0)
goto out;
length = security_load_policy(fsi->state, data, count);
length = security_load_policy(fsi->state, data, count, &newpolicy);
if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out;
}
length = sel_make_policy_nodes(fsi);
if (length)
length = sel_make_policy_nodes(fsi, newpolicy);
if (length) {
selinux_policy_cancel(fsi->state, newpolicy);
goto out1;
}
selinux_policy_commit(fsi->state, newpolicy);
length = count;
@ -581,7 +664,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
out:
mutex_unlock(&fsi->mutex);
mutex_unlock(&fsi->state->policy_mutex);
vfree(data);
return length;
}
@ -634,7 +717,8 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u", fsi->state->checkreqprot);
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
checkreqprot_get(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
@ -676,7 +760,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
comm, current->pid);
}
fsi->state->checkreqprot = new_value ? 1 : 0;
checkreqprot_set(fsi->state, (new_value ? 1 : 0));
length = count;
out:
kfree(page);
@ -1186,7 +1270,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
const char *name = filep->f_path.dentry->d_name.name;
mutex_lock(&fsi->mutex);
mutex_lock(&fsi->state->policy_mutex);
ret = -EINVAL;
if (index >= fsi->bool_num || strcmp(name,
@ -1205,14 +1289,14 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
}
length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
fsi->bool_pending_values[index]);
mutex_unlock(&fsi->mutex);
mutex_unlock(&fsi->state->policy_mutex);
ret = simple_read_from_buffer(buf, count, ppos, page, length);
out_free:
free_page((unsigned long)page);
return ret;
out_unlock:
mutex_unlock(&fsi->mutex);
mutex_unlock(&fsi->state->policy_mutex);
goto out_free;
}
@ -1237,7 +1321,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
if (IS_ERR(page))
return PTR_ERR(page);
mutex_lock(&fsi->mutex);
mutex_lock(&fsi->state->policy_mutex);
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
@ -1262,7 +1346,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
length = count;
out:
mutex_unlock(&fsi->mutex);
mutex_unlock(&fsi->state->policy_mutex);
kfree(page);
return length;
}
@ -1293,7 +1377,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
if (IS_ERR(page))
return PTR_ERR(page);
mutex_lock(&fsi->mutex);
mutex_lock(&fsi->state->policy_mutex);
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
@ -1315,7 +1399,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
length = count;
out:
mutex_unlock(&fsi->mutex);
mutex_unlock(&fsi->state->policy_mutex);
kfree(page);
return length;
}
@ -1331,14 +1415,13 @@ static void sel_remove_entries(struct dentry *de)
shrink_dcache_parent(de);
}
#define BOOL_DIR_NAME "booleans"
static int sel_make_bools(struct selinux_fs_info *fsi)
static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir,
unsigned int *bool_num, char ***bool_pending_names,
unsigned int **bool_pending_values)
{
int ret;
ssize_t len;
struct dentry *dentry = NULL;
struct dentry *dir = fsi->bool_dir;
struct inode *inode = NULL;
struct inode_security_struct *isec;
char **names = NULL, *page;
@ -1346,34 +1429,23 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
int *values = NULL;
u32 sid;
/* remove any existing files */
for (i = 0; i < fsi->bool_num; i++)
kfree(fsi->bool_pending_names[i]);
kfree(fsi->bool_pending_names);
kfree(fsi->bool_pending_values);
fsi->bool_num = 0;
fsi->bool_pending_names = NULL;
fsi->bool_pending_values = NULL;
sel_remove_entries(dir);
ret = -ENOMEM;
page = (char *)get_zeroed_page(GFP_KERNEL);
if (!page)
goto out;
ret = security_get_bools(fsi->state, &num, &names, &values);
ret = security_get_bools(newpolicy, &num, &names, &values);
if (ret)
goto out;
for (i = 0; i < num; i++) {
ret = -ENOMEM;
dentry = d_alloc_name(dir, names[i]);
dentry = d_alloc_name(bool_dir, names[i]);
if (!dentry)
goto out;
ret = -ENOMEM;
inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
inode = sel_make_inode(bool_dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
if (!inode) {
dput(dentry);
goto out;
@ -1388,7 +1460,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
}
isec = selinux_inode(inode);
ret = security_genfs_sid(fsi->state, "selinuxfs", page,
ret = selinux_policy_genfs_sid(newpolicy, "selinuxfs", page,
SECCLASS_FILE, &sid);
if (ret) {
pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
@ -1402,9 +1474,9 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
inode->i_ino = i|SEL_BOOL_INO_OFFSET;
d_add(dentry, inode);
}
fsi->bool_num = num;
fsi->bool_pending_names = names;
fsi->bool_pending_values = values;
*bool_num = num;
*bool_pending_names = names;
*bool_pending_values = values;
free_page((unsigned long)page);
return 0;
@ -1417,7 +1489,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
kfree(names);
}
kfree(values);
sel_remove_entries(dir);
sel_remove_entries(bool_dir);
return ret;
}
@ -1791,14 +1863,14 @@ static const struct file_operations sel_policycap_ops = {
.llseek = generic_file_llseek,
};
static int sel_make_perm_files(char *objclass, int classvalue,
static int sel_make_perm_files(struct selinux_policy *newpolicy,
char *objclass, int classvalue,
struct dentry *dir)
{
struct selinux_fs_info *fsi = dir->d_sb->s_fs_info;
int i, rc, nperms;
char **perms;
rc = security_get_permissions(fsi->state, objclass, &perms, &nperms);
rc = security_get_permissions(newpolicy, objclass, &perms, &nperms);
if (rc)
return rc;
@ -1831,7 +1903,8 @@ static int sel_make_perm_files(char *objclass, int classvalue,
return rc;
}
static int sel_make_class_dir_entries(char *classname, int index,
static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
char *classname, int index,
struct dentry *dir)
{
struct super_block *sb = dir->d_sb;
@ -1858,39 +1931,38 @@ static int sel_make_class_dir_entries(char *classname, int index,
if (IS_ERR(dentry))
return PTR_ERR(dentry);
rc = sel_make_perm_files(classname, index, dentry);
rc = sel_make_perm_files(newpolicy, classname, index, dentry);
return rc;
}
static int sel_make_classes(struct selinux_fs_info *fsi)
static int sel_make_classes(struct selinux_policy *newpolicy,
struct dentry *class_dir,
unsigned long *last_class_ino)
{
int rc, nclasses, i;
char **classes;
/* delete any existing entries */
sel_remove_entries(fsi->class_dir);
rc = security_get_classes(fsi->state, &classes, &nclasses);
rc = security_get_classes(newpolicy, &classes, &nclasses);
if (rc)
return rc;
/* +2 since classes are 1-indexed */
fsi->last_class_ino = sel_class_to_ino(nclasses + 2);
*last_class_ino = sel_class_to_ino(nclasses + 2);
for (i = 0; i < nclasses; i++) {
struct dentry *class_name_dir;
class_name_dir = sel_make_dir(fsi->class_dir, classes[i],
&fsi->last_class_ino);
class_name_dir = sel_make_dir(class_dir, classes[i],
last_class_ino);
if (IS_ERR(class_name_dir)) {
rc = PTR_ERR(class_name_dir);
goto out;
}
/* i+1 since class values are 1-indexed */
rc = sel_make_class_dir_entries(classes[i], i + 1,
rc = sel_make_class_dir_entries(newpolicy, classes[i], i + 1,
class_name_dir);
if (rc)
goto out;
@ -1909,8 +1981,6 @@ static int sel_make_policycap(struct selinux_fs_info *fsi)
struct dentry *dentry = NULL;
struct inode *inode = NULL;
sel_remove_entries(fsi->policycap_dir);
for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
if (iter < ARRAY_SIZE(selinux_policycap_names))
dentry = d_alloc_name(fsi->policycap_dir,
@ -1962,6 +2032,22 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
return dentry;
}
static struct dentry *sel_make_disconnected_dir(struct super_block *sb,
unsigned long *ino)
{
struct inode *inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
if (!inode)
return ERR_PTR(-ENOMEM);
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
inode->i_ino = ++(*ino);
/* directory inodes start off with i_nlink == 2 (for "." entry) */
inc_nlink(inode);
return d_obtain_alias(inode);
}
#define NULL_FILE_NAME "null"
static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
@ -2060,14 +2146,14 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
if (ret)
goto err;
fsi->class_dir = sel_make_dir(sb->s_root, "class", &fsi->last_ino);
fsi->class_dir = sel_make_dir(sb->s_root, CLASS_DIR_NAME, &fsi->last_ino);
if (IS_ERR(fsi->class_dir)) {
ret = PTR_ERR(fsi->class_dir);
fsi->class_dir = NULL;
goto err;
}
fsi->policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities",
fsi->policycap_dir = sel_make_dir(sb->s_root, POLICYCAP_DIR_NAME,
&fsi->last_ino);
if (IS_ERR(fsi->policycap_dir)) {
ret = PTR_ERR(fsi->policycap_dir);
@ -2075,9 +2161,12 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
goto err;
}
ret = sel_make_policy_nodes(fsi);
if (ret)
ret = sel_make_policycap(fsi);
if (ret) {
pr_err("SELinux: failed to load policy capabilities\n");
goto err;
}
return 0;
err:
pr_err("SELinux: %s: failed while creating inodes\n",

View File

@ -301,7 +301,6 @@ void avtab_destroy(struct avtab *h)
void avtab_init(struct avtab *h)
{
kvfree(h->htable);
h->htable = NULL;
h->nel = 0;
}
@ -340,6 +339,54 @@ int avtab_alloc(struct avtab *h, u32 nrules)
return 0;
}
int avtab_duplicate(struct avtab *new, struct avtab *orig)
{
int i;
struct avtab_node *node, *tmp, *tail;
memset(new, 0, sizeof(*new));
new->htable = kvcalloc(orig->nslot, sizeof(void *), GFP_KERNEL);
if (!new->htable)
return -ENOMEM;
new->nslot = orig->nslot;
new->mask = orig->mask;
for (i = 0; i < orig->nslot; i++) {
tail = NULL;
for (node = orig->htable[i]; node; node = node->next) {
tmp = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL);
if (!tmp)
goto error;
tmp->key = node->key;
if (tmp->key.specified & AVTAB_XPERMS) {
tmp->datum.u.xperms =
kmem_cache_zalloc(avtab_xperms_cachep,
GFP_KERNEL);
if (!tmp->datum.u.xperms) {
kmem_cache_free(avtab_node_cachep, tmp);
goto error;
}
tmp->datum.u.xperms = node->datum.u.xperms;
} else
tmp->datum.u.data = node->datum.u.data;
if (tail)
tail->next = tmp;
else
new->htable[i] = tmp;
tail = tmp;
new->nel++;
}
}
return 0;
error:
avtab_destroy(new);
return -ENOMEM;
}
void avtab_hash_eval(struct avtab *h, char *tag)
{
int i, chain_len, slots_used, max_chain_len;

View File

@ -89,6 +89,7 @@ struct avtab {
void avtab_init(struct avtab *h);
int avtab_alloc(struct avtab *, u32);
int avtab_duplicate(struct avtab *new, struct avtab *orig);
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
void avtab_destroy(struct avtab *h);
void avtab_hash_eval(struct avtab *h, char *tag);

View File

@ -600,3 +600,158 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
services_compute_xperms_drivers(xperms, node);
}
}
static int cond_dup_av_list(struct cond_av_list *new,
struct cond_av_list *orig,
struct avtab *avtab)
{
struct avtab_node *avnode;
u32 i;
memset(new, 0, sizeof(*new));
new->nodes = kcalloc(orig->len, sizeof(*new->nodes), GFP_KERNEL);
if (!new->nodes)
return -ENOMEM;
for (i = 0; i < orig->len; i++) {
avnode = avtab_search_node(avtab, &orig->nodes[i]->key);
if (WARN_ON(!avnode))
return -EINVAL;
new->nodes[i] = avnode;
new->len++;
}
return 0;
}
static int duplicate_policydb_cond_list(struct policydb *newp,
struct policydb *origp)
{
int rc, i, j;
rc = avtab_duplicate(&newp->te_cond_avtab, &origp->te_cond_avtab);
if (rc)
return rc;
newp->cond_list_len = 0;
newp->cond_list = kcalloc(origp->cond_list_len,
sizeof(*newp->cond_list),
GFP_KERNEL);
if (!newp->cond_list)
goto error;
for (i = 0; i < origp->cond_list_len; i++) {
struct cond_node *newn = &newp->cond_list[i];
struct cond_node *orign = &origp->cond_list[i];
newp->cond_list_len++;
newn->cur_state = orign->cur_state;
newn->expr.nodes = kcalloc(orign->expr.len,
sizeof(*newn->expr.nodes), GFP_KERNEL);
if (!newn->expr.nodes)
goto error;
for (j = 0; j < orign->expr.len; j++)
newn->expr.nodes[j] = orign->expr.nodes[j];
newn->expr.len = orign->expr.len;
rc = cond_dup_av_list(&newn->true_list, &orign->true_list,
&newp->te_cond_avtab);
if (rc)
goto error;
rc = cond_dup_av_list(&newn->false_list, &orign->false_list,
&newp->te_cond_avtab);
if (rc)
goto error;
}
return 0;
error:
avtab_destroy(&newp->te_cond_avtab);
cond_list_destroy(newp);
return -ENOMEM;
}
static int cond_bools_destroy(void *key, void *datum, void *args)
{
/* key was not copied so no need to free here */
kfree(datum);
return 0;
}
static int cond_bools_copy(struct hashtab_node *new, struct hashtab_node *orig, void *args)
{
struct cond_bool_datum *datum;
datum = kmemdup(orig->datum, sizeof(struct cond_bool_datum),
GFP_KERNEL);
if (!datum)
return -ENOMEM;
new->key = orig->key; /* No need to copy, never modified */
new->datum = datum;
return 0;
}
static int cond_bools_index(void *key, void *datum, void *args)
{
struct cond_bool_datum *booldatum, **cond_bool_array;
booldatum = datum;
cond_bool_array = args;
cond_bool_array[booldatum->value - 1] = booldatum;
return 0;
}
static int duplicate_policydb_bools(struct policydb *newdb,
struct policydb *orig)
{
struct cond_bool_datum **cond_bool_array;
int rc;
cond_bool_array = kmalloc_array(orig->p_bools.nprim,
sizeof(*orig->bool_val_to_struct),
GFP_KERNEL);
if (!cond_bool_array)
return -ENOMEM;
rc = hashtab_duplicate(&newdb->p_bools.table, &orig->p_bools.table,
cond_bools_copy, cond_bools_destroy, NULL);
if (rc) {
kfree(cond_bool_array);
return -ENOMEM;
}
hashtab_map(&newdb->p_bools.table, cond_bools_index, cond_bool_array);
newdb->bool_val_to_struct = cond_bool_array;
newdb->p_bools.nprim = orig->p_bools.nprim;
return 0;
}
void cond_policydb_destroy_dup(struct policydb *p)
{
hashtab_map(&p->p_bools.table, cond_bools_destroy, NULL);
hashtab_destroy(&p->p_bools.table);
cond_policydb_destroy(p);
}
int cond_policydb_dup(struct policydb *new, struct policydb *orig)
{
cond_policydb_init(new);
if (duplicate_policydb_bools(new, orig))
return -ENOMEM;
if (duplicate_policydb_cond_list(new, orig)) {
cond_policydb_destroy_dup(new);
return -ENOMEM;
}
return 0;
}

View File

@ -79,5 +79,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
struct extended_perms_decision *xpermd);
void evaluate_cond_nodes(struct policydb *p);
void cond_policydb_destroy_dup(struct policydb *p);
int cond_policydb_dup(struct policydb *new, struct policydb *orig);
#endif /* _CONDITIONAL_H_ */

View File

@ -122,6 +122,59 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
info->max_chain_len = max_chain_len;
}
int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
int (*copy)(struct hashtab_node *new,
struct hashtab_node *orig, void *args),
int (*destroy)(void *k, void *d, void *args),
void *args)
{
struct hashtab_node *cur, *tmp, *tail;
int i, rc;
memset(new, 0, sizeof(*new));
new->htable = kcalloc(orig->size, sizeof(*new->htable), GFP_KERNEL);
if (!new->htable)
return -ENOMEM;
new->size = orig->size;
for (i = 0; i < orig->size; i++) {
tail = NULL;
for (cur = orig->htable[i]; cur; cur = cur->next) {
tmp = kmem_cache_zalloc(hashtab_node_cachep,
GFP_KERNEL);
if (!tmp)
goto error;
rc = copy(tmp, cur, args);
if (rc) {
kmem_cache_free(hashtab_node_cachep, tmp);
goto error;
}
tmp->next = NULL;
if (!tail)
new->htable[i] = tmp;
else
tail->next = tmp;
tail = tmp;
new->nel++;
}
}
return 0;
error:
for (i = 0; i < new->size; i++) {
for (cur = new->htable[i]; cur; cur = tmp) {
tmp = cur->next;
destroy(cur->key, cur->datum, args);
kmem_cache_free(hashtab_node_cachep, cur);
}
}
kmem_cache_free(hashtab_node_cachep, new);
return -ENOMEM;
}
void __init hashtab_cache_init(void)
{
hashtab_node_cachep = kmem_cache_create("hashtab_node",

View File

@ -136,6 +136,12 @@ int hashtab_map(struct hashtab *h,
int (*apply)(void *k, void *d, void *args),
void *args);
int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
int (*copy)(struct hashtab_node *new,
struct hashtab_node *orig, void *args),
int (*destroy)(void *k, void *d, void *args),
void *args);
/* Fill info with some hash table statistics */
void hashtab_stat(struct hashtab *h, struct hashtab_info *info);

File diff suppressed because it is too large Load Diff

View File

@ -22,12 +22,11 @@ struct selinux_map {
u16 size; /* array size of mapping */
};
struct selinux_ss {
struct selinux_policy {
struct sidtab *sidtab;
struct policydb policydb;
rwlock_t policy_rwlock;
u32 latest_granting;
struct selinux_map map;
u32 latest_granting;
} __randomize_layout;
void services_compute_xperms_drivers(struct extended_perms *xperms,

View File

@ -464,6 +464,16 @@ int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params)
return 0;
}
void sidtab_cancel_convert(struct sidtab *s)
{
unsigned long flags;
/* cancelling policy load - disable live convert of sidtab */
spin_lock_irqsave(&s->lock, flags);
s->convert = NULL;
spin_unlock_irqrestore(&s->lock, flags);
}
static void sidtab_destroy_entry(struct sidtab_entry *entry)
{
context_destroy(&entry->context);

View File

@ -123,6 +123,8 @@ static inline struct context *sidtab_search_force(struct sidtab *s, u32 sid)
int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
void sidtab_cancel_convert(struct sidtab *s);
int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
void sidtab_destroy(struct sidtab *s);