// SPDX-License-Identifier: GPL-2.0-only
/*
- * NSA Security-Enhanced Linux (SELinux) security module
+ * Security-Enhanced Linux (SELinux) security module
*
* This file contains the SELinux hook function implementations.
*
return tsec->sid;
}
+ static void __ad_net_init(struct common_audit_data *ad,
+ struct lsm_network_audit *net,
+ int ifindex, struct sock *sk, u16 family)
+ {
+ ad->type = LSM_AUDIT_DATA_NET;
+ ad->u.net = net;
+ net->netif = ifindex;
+ net->sk = sk;
+ net->family = family;
+ }
+
+ static void ad_net_init_from_sk(struct common_audit_data *ad,
+ struct lsm_network_audit *net,
+ struct sock *sk)
+ {
+ __ad_net_init(ad, net, 0, sk, 0);
+ }
+
+ static void ad_net_init_from_iif(struct common_audit_data *ad,
+ struct lsm_network_audit *net,
+ int ifindex, u16 family)
+ {
+ __ad_net_init(ad, net, ifindex, NULL, family);
+ }
+
/*
* get the objective security ID of a task
*/
static inline u16 socket_type_to_security_class(int family, int type, int protocol)
{
- int extsockclass = selinux_policycap_extsockclass();
+ bool extsockclass = selinux_policycap_extsockclass();
switch (family) {
case PF_UNIX:
FILESYSTEM__UNMOUNT, NULL);
}
+static int selinux_fs_context_submount(struct fs_context *fc,
+ struct super_block *reference)
+{
+ const struct superblock_security_struct *sbsec;
+ struct selinux_mnt_opts *opts;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ sbsec = selinux_superblock(reference);
+ if (sbsec->flags & FSCONTEXT_MNT)
+ opts->fscontext_sid = sbsec->sid;
+ if (sbsec->flags & CONTEXT_MNT)
+ opts->context_sid = sbsec->mntpoint_sid;
+ if (sbsec->flags & DEFCONTEXT_MNT)
+ opts->defcontext_sid = sbsec->def_sid;
+ fc->security = opts;
+ return 0;
+}
+
static int selinux_fs_context_dup(struct fs_context *fc,
struct fs_context *src_fc)
{
struct inode_security_struct *context_isec =
selinux_inode(context_inode);
if (context_isec->initialized != LABEL_INITIALIZED) {
- pr_err("SELinux: context_inode is not initialized");
+ pr_err("SELinux: context_inode is not initialized\n");
return -EACCES;
}
if (default_noexec &&
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
int rc = 0;
- if (vma->vm_start >= vma->vm_mm->start_brk &&
- vma->vm_end <= vma->vm_mm->brk) {
+ if (vma_is_initial_heap(vma)) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
- } else if (!vma->vm_file &&
- ((vma->vm_start <= vma->vm_mm->start_stack &&
- vma->vm_end >= vma->vm_mm->start_stack) ||
+ } else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL);
{
struct sk_security_struct *sksec = sk->sk_security;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
if (sksec->sid == SECINITSID_KERNEL)
return 0;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->sk = sk;
+ ad_net_init_from_sk(&ad, &net, sk);
return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
&ad);
struct sk_security_struct *sksec_other = other->sk_security;
struct sk_security_struct *sksec_new = newsk->sk_security;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
int err;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->sk = other;
+ ad_net_init_from_sk(&ad, &net, other);
err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
sksec_other->sclass,
struct sk_security_struct *ssec = sock->sk->sk_security;
struct sk_security_struct *osec = other->sk->sk_security;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->sk = other->sk;
+ ad_net_init_from_sk(&ad, &net, other->sk);
return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
&ad);
struct sk_security_struct *sksec = sk->sk_security;
u32 sk_sid = sksec->sid;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
char *addrp;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->netif = skb->skb_iif;
- ad.u.net->family = family;
+ ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
if (err)
return err;
static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- int err;
+ int err, peerlbl_active, secmark_active;
struct sk_security_struct *sksec = sk->sk_security;
u16 family = sk->sk_family;
u32 sk_sid = sksec->sid;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
char *addrp;
- u8 secmark_active;
- u8 peerlbl_active;
if (family != PF_INET && family != PF_INET6)
return 0;
if (!secmark_active && !peerlbl_active)
return 0;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->netif = skb->skb_iif;
- ad.u.net->family = family;
+ ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
if (err)
return err;
selinux_netlbl_sk_security_reset(newsksec);
}
-static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
+static void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
{
if (!sk)
*secid = SECINITSID_ANY_SOCKET;
else {
- struct sk_security_struct *sksec = sk->sk_security;
+ const struct sk_security_struct *sksec = sk->sk_security;
*secid = sksec->sid;
}
u16 family = sk->sk_family;
struct sk_security_struct *sksec = sk->sk_security;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
int err;
/* handle mapped IPv4 packets arriving via IPv6 sockets */
/* Other association peer SIDs are checked to enforce
* consistency among the peer SIDs.
*/
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->sk = asoc->base.sk;
+ ad_net_init_from_sk(&ad, &net, asoc->base.sk);
err = avc_has_perm(sksec->peer_sid, asoc->peer_secid,
sksec->sclass, SCTP_SOCKET__ASSOCIATION,
&ad);
static int selinux_secmark_relabel_packet(u32 sid)
{
- const struct task_security_struct *__tsec;
+ const struct task_security_struct *tsec;
u32 tsid;
- __tsec = selinux_cred(current_cred());
- tsid = __tsec->sid;
+ tsec = selinux_cred(current_cred());
+ tsid = tsec->sid;
return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
NULL);
char *addrp;
u32 peer_sid;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
int secmark_active, peerlbl_active;
if (!selinux_policycap_netpeer())
return NF_DROP;
ifindex = state->in->ifindex;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->netif = ifindex;
- ad.u.net->family = family;
+ ad_net_init_from_iif(&ad, &net, ifindex, family);
if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
return NF_DROP;
struct sock *sk;
struct sk_security_struct *sksec;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
u8 proto = 0;
sk = skb_to_full_sk(skb);
return NF_ACCEPT;
sksec = sk->sk_security;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->netif = state->out->ifindex;
- ad.u.net->family = state->pf;
+ ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
return NF_DROP;
int ifindex;
struct sock *sk;
struct common_audit_data ad;
- struct lsm_network_audit net = {0,};
+ struct lsm_network_audit net;
char *addrp;
int secmark_active, peerlbl_active;
}
ifindex = state->out->ifindex;
- ad.type = LSM_AUDIT_DATA_NET;
- ad.u.net = &net;
- ad.u.net->netif = ifindex;
- ad.u.net->family = family;
+ ad_net_init_from_iif(&ad, &net, ifindex, family);
if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
return NF_DROP;
static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
{
- int err;
- int perms;
+ u32 perms;
switch (cmd) {
case IPC_INFO:
return 0;
}
- err = ipc_has_perm(msq, perms);
- return err;
+ return ipc_has_perm(msq, perms);
}
static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
/* Note, at this point, shp is locked down */
static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
{
- int perms;
- int err;
+ u32 perms;
switch (cmd) {
case IPC_INFO:
return 0;
}
- err = ipc_has_perm(shp, perms);
- return err;
+ return ipc_has_perm(shp, perms);
}
static int selinux_shm_shmat(struct kern_ipc_perm *shp,
*/
static int selinux_uring_sqpoll(void)
{
- int sid = current_sid();
+ u32 sid = current_sid();
return avc_has_perm(sid, sid,
SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
* hooks ("allocating" hooks).
*
* Please follow block comment delimiters in the list to keep this order.
- *
- * This ordering is needed for SELinux runtime disable to work at least somewhat
- * safely. Breaking the ordering rules above might lead to NULL pointer derefs
- * when disabling SELinux at runtime.
*/
static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
/*
* PUT "CLONING" (ACCESSING + ALLOCATING) HOOKS HERE
*/
+ LSM_HOOK_INIT(fs_context_submount, selinux_fs_context_submount),
LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
cred_init_security();
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
+ if (!default_noexec)
+ pr_notice("SELinux: virtual memory is executable by default\n");
avc_init();
/*
* Implementation of the policy database.
*
*/
/*
#include "mls.h"
#include "services.h"
- #ifdef DEBUG_HASHES
+ #ifdef CONFIG_SECURITY_SELINUX_DEBUG
static const char *const symtab_name[SYM_NUM] = {
"common prefixes",
"classes",
#endif
struct policydb_compat_info {
- int version;
- int sym_num;
- int ocon_num;
+ unsigned int version;
+ unsigned int sym_num;
+ unsigned int ocon_num;
};
/* These need to be updated if SYM_NUM or OCON_NUM changes */
},
};
- static const struct policydb_compat_info *policydb_lookup_compat(int version)
+ static const struct policydb_compat_info *policydb_lookup_compat(unsigned int version)
{
- int i;
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(policydb_compat); i++) {
if (policydb_compat[i].version == version)
return 0;
}
- static void ocontext_destroy(struct ocontext *c, int i)
+ static void ocontext_destroy(struct ocontext *c, unsigned int i)
{
if (!c)
return;
cat_index,
};
- #ifdef DEBUG_HASHES
+ #ifdef CONFIG_SECURITY_SELINUX_DEBUG
static void hash_eval(struct hashtab *h, const char *hash_name)
{
struct hashtab_info info;
static inline void hash_eval(struct hashtab *h, const char *hash_name)
{
}
- #endif
+ static inline void symtab_hash_eval(struct symtab *s)
+ {
+ }
+ #endif /* CONFIG_SECURITY_SELINUX_DEBUG */
/*
* Define the other val_to_name and val_to_struct arrays
pr_debug("SELinux: %d classes, %d rules\n",
p->p_classes.nprim, p->te_avtab.nel);
- #ifdef DEBUG_HASHES
avtab_hash_eval(&p->te_avtab, "rules");
symtab_hash_eval(p->symtab);
- #endif
p->class_val_to_struct = kcalloc(p->p_classes.nprim,
sizeof(*p->class_val_to_struct),
{
struct ocontext *c, *ctmp;
struct genfs *g, *gtmp;
- int i;
+ u32 i;
struct role_allow *ra, *lra = NULL;
for (i = 0; i < SYM_NUM; i++) {
char *key = NULL;
struct common_datum *comdatum;
__le32 buf[4];
- u32 len, nel;
- int i, rc;
+ u32 i, len, nel;
+ int rc;
comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
if (!comdatum)
static int read_cons_helper(struct policydb *p,
struct constraint_node **nodep,
- int ncons, int allowxtarget, void *fp)
+ u32 ncons, int allowxtarget, void *fp)
{
struct constraint_node *c, *lc;
struct constraint_expr *e, *le;
__le32 buf[3];
- u32 nexpr;
- int rc, i, j, depth;
+ u32 i, j, nexpr;
+ int rc, depth;
lc = NULL;
for (i = 0; i < ncons; i++) {
char *key = NULL;
struct class_datum *cladatum;
__le32 buf[6];
- u32 len, len2, ncons, nel;
- int i, rc;
+ u32 i, len, len2, ncons, nel;
+ int rc;
cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
if (!cladatum)
{
char *key = NULL;
struct role_datum *role;
- int rc, to_read = 2;
+ int rc;
+ unsigned int to_read = 2;
__le32 buf[3];
u32 len;
{
char *key = NULL;
struct type_datum *typdatum;
- int rc, to_read = 3;
+ int rc;
+ unsigned int to_read = 3;
__le32 buf[4];
u32 len;
{
char *key = NULL;
struct user_datum *usrdatum;
- int rc, to_read = 2;
+ int rc;
+ unsigned int to_read = 2;
__le32 buf[3];
u32 len;
__le32 buf[2];
u32 len;
- levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC);
+ levdatum = kzalloc(sizeof(*levdatum), GFP_KERNEL);
if (!levdatum)
return -ENOMEM;
len = le32_to_cpu(buf[0]);
levdatum->isalias = le32_to_cpu(buf[1]);
- rc = str_read(&key, GFP_ATOMIC, fp, len);
+ rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
goto bad;
rc = -ENOMEM;
- levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_ATOMIC);
+ levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_KERNEL);
if (!levdatum->level)
goto bad;
__le32 buf[3];
u32 len;
- catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC);
+ catdatum = kzalloc(sizeof(*catdatum), GFP_KERNEL);
if (!catdatum)
return -ENOMEM;
catdatum->value = le32_to_cpu(buf[1]);
catdatum->isalias = le32_to_cpu(buf[2]);
- rc = str_read(&key, GFP_ATOMIC, fp, len);
+ rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
goto bad;
upper = user = datum;
while (upper->bounds) {
struct ebitmap_node *node;
- unsigned long bit;
+ u32 bit;
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
pr_err("SELinux: user %s: "
- "too deep or looped boundary",
+ "too deep or looped boundary\n",
(char *) key);
return -EINVAL;
}
upper = role = datum;
while (upper->bounds) {
struct ebitmap_node *node;
- unsigned long bit;
+ u32 bit;
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
pr_err("SELinux: role %s: "
if (upper->attribute) {
pr_err("SELinux: type %s: "
- "bounded by attribute %s",
+ "bounded by attribute %s\n",
(char *) key,
sym_name(p, SYM_TYPES, upper->value - 1));
return -EINVAL;
{
struct range_trans *rt = NULL;
struct mls_range *r = NULL;
- int i, rc;
+ int rc;
__le32 buf[2];
- u32 nel;
+ u32 i, nel;
if (p->policyvers < POLICYDB_VERSION_MLS)
return 0;
if (!datum)
goto out;
+ datum->next = NULL;
*dst = datum;
/* ebitmap_read() will at least init the bitmap */
goto out;
datum->otype = le32_to_cpu(buf[0]);
- datum->next = NULL;
dst = &datum->next;
}
static int filename_trans_read(struct policydb *p, void *fp)
{
- u32 nel;
+ u32 nel, i;
__le32 buf[1];
- int rc, i;
+ int rc;
if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
return 0;
static int genfs_read(struct policydb *p, void *fp)
{
- int i, j, rc;
- u32 nel, nel2, len, len2;
+ int rc;
+ u32 i, j, nel, nel2, len, len2;
__le32 buf[1];
struct ocontext *l, *c;
struct ocontext *newc = NULL;
static int ocontext_read(struct policydb *p, const struct policydb_compat_info *info,
void *fp)
{
- int i, j, rc;
- u32 nel, len;
+ int rc;
+ unsigned int i;
+ u32 j, nel, len;
__be64 prefixbuf[1];
__le32 buf[3];
struct ocontext *l, *c;
struct role_allow *ra, *lra;
struct role_trans_key *rtk = NULL;
struct role_trans_datum *rtd = NULL;
- int i, j, rc;
+ int rc;
__le32 buf[4];
- u32 len, nprim, nel, perm;
+ u32 i, j, len, nprim, nel, perm;
char *policydb_str;
const struct policydb_compat_info *info;
static int ocontext_write(struct policydb *p, const struct policydb_compat_info *info,
void *fp)
{
- unsigned int i, j, rc;
+ unsigned int i, j;
+ int rc;
size_t nel, len;
__be64 prefixbuf[1];
__le32 buf[3];
*/
int policydb_write(struct policydb *p, void *fp)
{
- unsigned int i, num_syms;
+ unsigned int num_syms;
int rc;
__le32 buf[4];
- u32 config;
+ u32 config, i;
size_t len;
const struct policydb_compat_info *info;
info = policydb_lookup_compat(p->policyvers);
if (!info) {
pr_err("SELinux: compatibility lookup failed for policy "
- "version %d", p->policyvers);
+ "version %d\n", p->policyvers);
return -EINVAL;
}