Skip to content

Commit

Permalink
Merge tag 'selinux-pr-20250121' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:

 - Extended permissions supported in conditional policy

   The SELinux extended permissions, aka "xperms", allow security admins
   to target individuals ioctls, and recently netlink messages, with
   their SELinux policy. Adding support for conditional policies allows
   admins to toggle the granular xperms using SELinux booleans, helping
   pave the way for greater use of xperms in general purpose SELinux
   policies. This change bumps the maximum SELinux policy version to 34.

 - Fix a SCTP/SELinux error return code inconsistency

   Depending on the loaded SELinux policy, specifically it's
   EXTSOCKCLASS support, the bind(2) LSM/SELinux hook could return
   different error codes due to the SELinux code checking the socket's
   SELinux object class (which can vary depending on EXTSOCKCLASS) and
   not the socket's sk_protocol field. We fix this by doing the obvious,
   and looking at the sock->sk_protocol field instead of the object
   class.

 - Makefile fixes to properly cleanup av_permissions.h

   Add av_permissions.h to "targets" so that it is properly cleaned up
   using the kbuild infrastructure.

 - A number of smaller improvements by Christian Göttsche

   A variety of straightforward changes to reduce code duplication,
   reduce pointer lookups, migrate void pointers to defined types,
   simplify code, constify function parameters, and correct iterator
   types.

* tag 'selinux-pr-20250121' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: make more use of str_read() when loading the policy
  selinux: avoid unnecessary indirection in struct level_datum
  selinux: use known type instead of void pointer
  selinux: rename comparison functions for clarity
  selinux: rework match_ipv6_addrmask()
  selinux: constify and reconcile function parameter names
  selinux: avoid using types indicating user space interaction
  selinux: supply missing field initializers
  selinux: add netlink nlmsg_type audit message
  selinux: add support for xperms in conditional policies
  selinux: Fix SCTP error inconsistency in selinux_socket_bind()
  selinux: use native iterator types
  selinux: add generated av_permissions.h to targets
  • Loading branch information
torvalds committed Jan 22, 2025
2 parents f96a974 + 01c2253 commit 690ffcd
Show file tree
Hide file tree
Showing 22 changed files with 170 additions and 165 deletions.
2 changes: 2 additions & 0 deletions include/linux/lsm_audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_LOCKDOWN 15
#define LSM_AUDIT_DATA_NOTIFICATION 16
#define LSM_AUDIT_DATA_ANONINODE 17
#define LSM_AUDIT_DATA_NLMSGTYPE 18
union {
struct path path;
struct dentry *dentry;
Expand All @@ -98,6 +99,7 @@ struct common_audit_data {
struct lsm_ibendport_audit *ibendport;
int reason;
const char *anonclass;
u16 nlmsg_type;
} u;
/* this union contains LSM specific data */
union {
Expand Down
3 changes: 3 additions & 0 deletions security/lsm_audit.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@ static void dump_common_audit_data(struct audit_buffer *ab,
case LSM_AUDIT_DATA_ANONINODE:
audit_log_format(ab, " anonclass=%s", a->u.anonclass);
break;
case LSM_AUDIT_DATA_NLMSGTYPE:
audit_log_format(ab, " nl-msgtype=%hu", a->u.nlmsg_type);
break;
} /* switch (a->type) */
}

Expand Down
7 changes: 3 additions & 4 deletions security/selinux/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
quiet_cmd_genhdrs = GEN $(addprefix $(obj)/,$(genhdrs))
cmd_genhdrs = $< $(addprefix $(obj)/,$(genhdrs))

# see the note above, replace the $targets and 'flask.h' rule with the lines
# below:
# targets += $(genhdrs)
targets += $(genhdrs)

# see the note above, replace the 'flask.h' rule with the line below:
# $(addprefix $(obj)/,$(genhdrs)) &: $(obj)/genheaders FORCE
targets += flask.h
$(obj)/flask.h: $(obj)/genheaders FORCE
$(call if_changed,genhdrs)

Expand Down
10 changes: 5 additions & 5 deletions security/selinux/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ static const struct {

static int match_opt_prefix(char *s, int l, char **arg)
{
int i;
unsigned int i;

for (i = 0; i < ARRAY_SIZE(tokens); i++) {
size_t len = tokens[i].len;
Expand Down Expand Up @@ -3135,7 +3135,7 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
const struct cred *cred = current_cred();
struct inode *inode = d_backing_inode(dentry);
unsigned int ia_valid = iattr->ia_valid;
__u32 av = FILE__WRITE;
u32 av = FILE__WRITE;

/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
if (ia_valid & ATTR_FORCE) {
Expand Down Expand Up @@ -4835,7 +4835,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
return err;
err_af:
/* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */
if (sksec->sclass == SECCLASS_SCTP_SOCKET)
if (sk->sk_protocol == IPPROTO_SCTP)
return -EINVAL;
return -EAFNOSUPPORT;
}
Expand Down Expand Up @@ -5939,14 +5939,14 @@ static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_t
{
struct sk_security_struct *sksec = sk->sk_security;
struct common_audit_data ad;
struct lsm_network_audit net;
u8 driver;
u8 xperm;

if (sock_skip_has_perm(sksec->sid))
return 0;

ad_net_init_from_sk(&ad, &net, sk);
ad.type = LSM_AUDIT_DATA_NLMSGTYPE;
ad.u.nlmsg_type = nlmsg_type;

driver = nlmsg_type >> 8;
xperm = nlmsg_type & 0xff;
Expand Down
2 changes: 1 addition & 1 deletion security/selinux/include/classmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ const struct security_class_mapping secclass_map[] = {
{ "anon_inode", { COMMON_FILE_PERMS, NULL } },
{ "io_uring", { "override_creds", "sqpoll", "cmd", NULL } },
{ "user_namespace", { "create", NULL } },
{ NULL }
/* last one */ { NULL, {} }
};

#ifdef __KERNEL__ /* avoid this check when building host programs */
Expand Down
2 changes: 1 addition & 1 deletion security/selinux/include/conditional.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
int security_get_bools(struct selinux_policy *policy, u32 *len, char ***names,
int **values);

int security_set_bools(u32 len, int *values);
int security_set_bools(u32 len, const int *values);

int security_get_bool_value(u32 index);

Expand Down
7 changes: 4 additions & 3 deletions security/selinux/include/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@
#define POLICYDB_VERSION_INFINIBAND 31
#define POLICYDB_VERSION_GLBLUB 32
#define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */
#define POLICYDB_VERSION_COND_XPERMS 34 /* extended permissions in conditional policies */

/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COMP_FTRANS
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COND_XPERMS

/* Mask for just the mount related flags */
#define SE_MNTMASK 0x0f
Expand Down Expand Up @@ -292,7 +293,7 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
int security_context_to_sid_force(const char *scontext, u32 scontext_len,
u32 *sid);

int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel);
int security_get_user_sids(u32 fromsid, const char *username, u32 **sids, u32 *nel);

int security_port_sid(u8 protocol, u16 port, u32 *out_sid);

Expand All @@ -310,7 +311,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass);

int security_bounded_transition(u32 oldsid, u32 newsid);
int security_bounded_transition(u32 old_sid, u32 new_sid);

int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);

Expand Down
4 changes: 2 additions & 2 deletions security/selinux/selinuxfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1515,7 +1515,7 @@ static const struct file_operations sel_avc_hash_stats_ops = {
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
{
int cpu;
loff_t cpu;

for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
if (!cpu_possible(cpu))
Expand Down Expand Up @@ -2001,7 +2001,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
S_IWUGO},
/* last one */ {""}
/* last one */ {"", NULL, 0}
};

ret = selinux_fs_info_create(sb);
Expand Down
19 changes: 13 additions & 6 deletions security/selinux/ss/avtab.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,10 @@ static const uint16_t spec_order[] = {
};
/* clang-format on */

int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *pol,
int (*insertf)(struct avtab *a, const struct avtab_key *k,
const struct avtab_datum *d, void *p),
void *p)
void *p, bool conditional)
{
__le16 buf16[4];
u16 enabled;
Expand Down Expand Up @@ -457,6 +457,13 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
"was specified\n",
vers);
return -EINVAL;
} else if ((vers < POLICYDB_VERSION_COND_XPERMS) &&
(key.specified & AVTAB_XPERMS) && conditional) {
pr_err("SELinux: avtab: policy version %u does not "
"support extended permissions rules in conditional "
"policies and one was specified\n",
vers);
return -EINVAL;
} else if (key.specified & AVTAB_XPERMS) {
memset(&xperms, 0, sizeof(struct avtab_extended_perms));
rc = next_entry(&xperms.specified, fp, sizeof(u8));
Expand Down Expand Up @@ -500,7 +507,7 @@ static int avtab_insertf(struct avtab *a, const struct avtab_key *k,
return avtab_insert(a, k, d);
}

int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
int avtab_read(struct avtab *a, struct policy_file *fp, struct policydb *pol)
{
int rc;
__le32 buf[1];
Expand All @@ -523,7 +530,7 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
goto bad;

for (i = 0; i < nel; i++) {
rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL, false);
if (rc) {
if (rc == -ENOMEM)
pr_err("SELinux: avtab: out of memory\n");
Expand All @@ -543,7 +550,7 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
goto out;
}

int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp)
int avtab_write_item(struct policydb *p, const struct avtab_node *cur, struct policy_file *fp)
{
__le16 buf16[4];
__le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)];
Expand Down Expand Up @@ -579,7 +586,7 @@ int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp)
return 0;
}

int avtab_write(struct policydb *p, struct avtab *a, void *fp)
int avtab_write(struct policydb *p, struct avtab *a, struct policy_file *fp)
{
u32 i;
int rc = 0;
Expand Down
13 changes: 7 additions & 6 deletions security/selinux/ss/avtab.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ struct avtab {
};

void avtab_init(struct avtab *h);
int avtab_alloc(struct avtab *, u32);
int avtab_alloc(struct avtab *h, u32 nrules);
int avtab_alloc_dup(struct avtab *new, const struct avtab *orig);
void avtab_destroy(struct avtab *h);

Expand All @@ -105,15 +105,16 @@ static inline void avtab_hash_eval(struct avtab *h, const char *tag)
#endif

struct policydb;
int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
struct policy_file;
int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *pol,
int (*insert)(struct avtab *a, const struct avtab_key *k,
const struct avtab_datum *d, void *p),
void *p);
void *p, bool conditional);

int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
int avtab_read(struct avtab *a, struct policy_file *fp, struct policydb *pol);
int avtab_write_item(struct policydb *p, const struct avtab_node *cur,
void *fp);
int avtab_write(struct policydb *p, struct avtab *a, void *fp);
struct policy_file *fp);
int avtab_write(struct policydb *p, struct avtab *a, struct policy_file *fp);

struct avtab_node *avtab_insert_nonunique(struct avtab *h,
const struct avtab_key *key,
Expand Down
24 changes: 9 additions & 15 deletions security/selinux/ss/conditional.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ static int bool_isvalid(struct cond_bool_datum *b)
return 1;
}

int cond_read_bool(struct policydb *p, struct symtab *s, void *fp)
int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct cond_bool_datum *booldatum;
Expand All @@ -230,17 +230,11 @@ int cond_read_bool(struct policydb *p, struct symtab *s, void *fp)
goto err;

len = le32_to_cpu(buf[2]);
if (((len == 0) || (len == (u32)-1)))
goto err;

rc = -ENOMEM;
key = kmalloc(len + 1, GFP_KERNEL);
if (!key)
goto err;
rc = next_entry(key, fp, len);
rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
goto err;
key[len] = '\0';

rc = symtab_insert(s, key, booldatum);
if (rc)
goto err;
Expand Down Expand Up @@ -323,7 +317,7 @@ static int cond_insertf(struct avtab *a, const struct avtab_key *k,
return 0;
}

static int cond_read_av_list(struct policydb *p, void *fp,
static int cond_read_av_list(struct policydb *p, struct policy_file *fp,
struct cond_av_list *list,
struct cond_av_list *other)
{
Expand All @@ -349,7 +343,7 @@ static int cond_read_av_list(struct policydb *p, void *fp,
for (i = 0; i < len; i++) {
data.dst = &list->nodes[i];
rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
&data);
&data, true);
if (rc) {
kfree(list->nodes);
list->nodes = NULL;
Expand All @@ -375,7 +369,7 @@ static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
return 1;
}

static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
static int cond_read_node(struct policydb *p, struct cond_node *node, struct policy_file *fp)
{
__le32 buf[2];
u32 i, len;
Expand Down Expand Up @@ -415,7 +409,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
return cond_read_av_list(p, fp, &node->false_list, &node->true_list);
}

int cond_read_list(struct policydb *p, void *fp)
int cond_read_list(struct policydb *p, struct policy_file *fp)
{
__le32 buf[1];
u32 i, len;
Expand Down Expand Up @@ -453,7 +447,7 @@ int cond_write_bool(void *vkey, void *datum, void *ptr)
char *key = vkey;
struct cond_bool_datum *booldatum = datum;
struct policy_data *pd = ptr;
void *fp = pd->fp;
struct policy_file *fp = pd->fp;
__le32 buf[3];
u32 len;
int rc;
Expand Down Expand Up @@ -536,7 +530,7 @@ static int cond_write_node(struct policydb *p, struct cond_node *node,
return 0;
}

int cond_write_list(struct policydb *p, void *fp)
int cond_write_list(struct policydb *p, struct policy_file *fp)
{
u32 i;
__le32 buf[1];
Expand Down
6 changes: 3 additions & 3 deletions security/selinux/ss/conditional.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ int cond_destroy_bool(void *key, void *datum, void *p);

int cond_index_bool(void *key, void *datum, void *datap);

int cond_read_bool(struct policydb *p, struct symtab *s, void *fp);
int cond_read_list(struct policydb *p, void *fp);
int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp);
int cond_read_list(struct policydb *p, struct policy_file *fp);
int cond_write_bool(void *key, void *datum, void *ptr);
int cond_write_list(struct policydb *p, void *fp);
int cond_write_list(struct policydb *p, struct policy_file *fp);

void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
struct av_decision *avd, struct extended_perms *xperms);
Expand Down
2 changes: 1 addition & 1 deletion security/selinux/ss/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ u32 context_compute_hash(const struct context *c)
* context struct with only the len & str set (and vice versa)
* under a given policy. Since context structs from different
* policies should never meet, it is safe to hash valid and
* invalid contexts differently. The context_cmp() function
* invalid contexts differently. The context_equal() function
* already operates under the same assumption.
*/
if (c->len)
Expand Down
14 changes: 7 additions & 7 deletions security/selinux/ss/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,13 @@ static inline int mls_context_glblub(struct context *dst,
return rc;
}

static inline int mls_context_cmp(const struct context *c1,
const struct context *c2)
static inline bool mls_context_equal(const struct context *c1,
const struct context *c2)
{
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
ebitmap_equal(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
(c1->range.level[1].sens == c2->range.level[1].sens) &&
ebitmap_cmp(&c1->range.level[1].cat, &c2->range.level[1].cat));
ebitmap_equal(&c1->range.level[1].cat, &c2->range.level[1].cat));
}

static inline void mls_context_destroy(struct context *c)
Expand Down Expand Up @@ -188,15 +188,15 @@ static inline void context_destroy(struct context *c)
mls_context_destroy(c);
}

static inline int context_cmp(const struct context *c1,
const struct context *c2)
static inline bool context_equal(const struct context *c1,
const struct context *c2)
{
if (c1->len && c2->len)
return (c1->len == c2->len && !strcmp(c1->str, c2->str));
if (c1->len || c2->len)
return 0;
return ((c1->user == c2->user) && (c1->role == c2->role) &&
(c1->type == c2->type) && mls_context_cmp(c1, c2));
(c1->type == c2->type) && mls_context_equal(c1, c2));
}

u32 context_compute_hash(const struct context *c);
Expand Down
Loading

0 comments on commit 690ffcd

Please sign in to comment.