2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

selinux/stable-6.17 PR 20250725

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCgAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmiD08EUHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXOFzRAAwTbLKcFggDs0bG6AfqT5KCQHRtRW
 z/0+kvDZeKzJvmJ4XvNMdW3orC2iIYgGCYJgj8umEXh1BOGIOSd4edpGaUKvJB9Z
 S4py0I3udGjlchInmDBZqW2qGaN0EAl/s0AWBbf6QLYmMV1r9+nb5lH71pVBbEQv
 4Vltg61KkQPc6PuDpk7F+BD7yYKSCqxxWyy7zEJsFMntg4jCyoI2PfRhrHM5xuCE
 RRqctblhCc4nNqzhPvse4Vt9PD+cVQx0Pi7arxvSD8M7mVrFTsUV17OoSKlCcLGh
 1LlFk7heoDNC/UQy7xFg5hsy8GeI6gYYY/Fomu7Ue3SYJL2fqqr7xsbJyCCNg8kC
 S17gRPBxqftzl/2SE76V8y5toIRMtT7b+6aXudtukfFbxtBq09XNflq1G3iR9fTo
 o6f9MGpyWW3t/e8wk2yPYfXNXrLe3yJoxV6lIsDaHejOwGi098ArcahKKuxNzRit
 AikIoqn8GEO+j3/X/4YS1xbdS/HkG7N3t+Rbr2GNO4XsmU6iqZRBkmz5UlCcL8u1
 OTQNjzqqSy/DKAfrPAyqN7wiBVXt5siBPwAXIcPbh9JfAI/kRN7LUxAQeGnUps+o
 kJn2zCV3G4kD2qtCVCQ7VifIYGCMxa1PTYsiwu5S4Wgm1Ducvtsx4r3TVKiCuObC
 bwv/1k9kpkvLy/E=
 =M55j
 -----END PGP SIGNATURE-----

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

Pull selinux updates from Paul Moore:

 - Introduce the concept of a SELinux "neveraudit" type which prevents
   all auditing of the given type/domain.

   Taken by itself, the benefit of marking a SELinux domain with the
   "neveraudit" tag is likely not very interesting, especially given the
   significant overlap with the "dontaudit" tag.

   However, given that the "neveraudit" tag applies to *all* auditing of
   the tagged domain, we can do some fairly interesting optimizations
   when a SELinux domain is marked as both "permissive" and "dontaudit"
   (think of the unconfined_t domain).

   While this pull request includes optimized inode permission and
   getattr hooks, these optimizations require SELinux policy changes,
   therefore the improvements may not be visible on standard downstream
   Linux distos for a period of time.

 - Continue the deprecation process of /sys/fs/selinux/user.

   After removing the associated userspace code in 2020, we marked the
   /sys/fs/selinux/user interface as deprecated in Linux v6.13 with
   pr_warn() and the usual documention update.

   This adds a five second sleep after the pr_warn(), following a
   previous deprecation process pattern that has worked well for us in
   the past in helping identify any existing users that we haven't yet
   reached.

 - Add a __GFP_NOWARN flag to our initial hash table allocation.

   Fuzzers such a syzbot often attempt abnormally large SELinux policy
   loads, which the SELinux code gracefully handles by checking for
   allocation failures, but not before the allocator emits a warning
   which causes the automated fuzzing to flag this as an error and
   report it to the list. While we want to continue to support the work
   done by the fuzzing teams, we want to focus on proper issues and not
   an error case that is already handled safely. Add a NOWARN flag to
   quiet the allocator and prevent syzbot from tripping on this again.

 - Remove some unnecessary selinuxfs cleanup code, courtesy of Al.

 - Update the SELinux in-kernel documentation with pointers to
   additional information.

* tag 'selinux-pr-20250725' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: don't bother with selinuxfs_info_free() on failures
  selinux: add __GFP_NOWARN to hashtab_init() allocations
  selinux: optimize selinux_inode_getattr/permission() based on neveraudit|permissive
  selinux: introduce neveraudit types
  documentation: add links to SELinux resources
  selinux: add a 5 second sleep to /sys/fs/selinux/user
This commit is contained in:
Linus Torvalds 2025-07-28 18:25:57 -07:00
commit dffb641bea
10 changed files with 83 additions and 5 deletions

View File

@ -2,6 +2,17 @@
SELinux SELinux
======= =======
Information about the SELinux kernel subsystem can be found at the
following links:
https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git/tree/README.md
https://github.com/selinuxproject/selinux-kernel/wiki
Information about the SELinux userspace can be found at:
https://github.com/SELinuxProject/selinux/wiki
If you want to use SELinux, chances are you will want If you want to use SELinux, chances are you will want
to use the distro-provided policies, or install the to use the distro-provided policies, or install the
latest reference policy release from latest reference policy release from

View File

@ -3181,6 +3181,8 @@ static inline void task_avdcache_update(struct task_security_struct *tsec,
tsec->avdcache.dir[spot].audited = audited; tsec->avdcache.dir[spot].audited = audited;
tsec->avdcache.dir[spot].allowed = avd->allowed; tsec->avdcache.dir[spot].allowed = avd->allowed;
tsec->avdcache.dir[spot].permissive = avd->flags & AVD_FLAGS_PERMISSIVE; tsec->avdcache.dir[spot].permissive = avd->flags & AVD_FLAGS_PERMISSIVE;
tsec->avdcache.permissive_neveraudit =
(avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT));
} }
/** /**
@ -3207,10 +3209,13 @@ static int selinux_inode_permission(struct inode *inode, int requested)
if (!mask) if (!mask)
return 0; return 0;
tsec = selinux_cred(current_cred());
if (task_avdcache_permnoaudit(tsec))
return 0;
isec = inode_security_rcu(inode, requested & MAY_NOT_BLOCK); isec = inode_security_rcu(inode, requested & MAY_NOT_BLOCK);
if (IS_ERR(isec)) if (IS_ERR(isec))
return PTR_ERR(isec); return PTR_ERR(isec);
tsec = selinux_cred(current_cred());
perms = file_mask_to_av(inode->i_mode, mask); perms = file_mask_to_av(inode->i_mode, mask);
rc = task_avdcache_search(tsec, isec, &avdc); rc = task_avdcache_search(tsec, isec, &avdc);
@ -3274,6 +3279,13 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
static int selinux_inode_getattr(const struct path *path) static int selinux_inode_getattr(const struct path *path)
{ {
struct task_security_struct *tsec;
tsec = selinux_cred(current_cred());
if (task_avdcache_permnoaudit(tsec))
return 0;
return path_has_perm(current_cred(), path, FILE__GETATTR); return path_has_perm(current_cred(), path, FILE__GETATTR);
} }

View File

@ -65,6 +65,10 @@ static inline u32 avc_audit_required(u32 requested, struct av_decision *avd,
int result, u32 auditdeny, u32 *deniedp) int result, u32 auditdeny, u32 *deniedp)
{ {
u32 denied, audited; u32 denied, audited;
if (avd->flags & AVD_FLAGS_NEVERAUDIT)
return 0;
denied = requested & ~avd->allowed; denied = requested & ~avd->allowed;
if (unlikely(denied)) { if (unlikely(denied)) {
audited = denied & avd->auditdeny; audited = denied & avd->auditdeny;

View File

@ -49,9 +49,17 @@ struct task_security_struct {
u32 seqno; /* AVC sequence number */ u32 seqno; /* AVC sequence number */
unsigned int dir_spot; /* dir cache index to check first */ unsigned int dir_spot; /* dir cache index to check first */
struct avdc_entry dir[TSEC_AVDC_DIR_SIZE]; /* dir entries */ struct avdc_entry dir[TSEC_AVDC_DIR_SIZE]; /* dir entries */
bool permissive_neveraudit; /* permissive and neveraudit */
} avdcache; } avdcache;
} __randomize_layout; } __randomize_layout;
static inline bool task_avdcache_permnoaudit(struct task_security_struct *tsec)
{
return (tsec->avdcache.permissive_neveraudit &&
tsec->sid == tsec->avdcache.sid &&
tsec->avdcache.seqno == avc_policy_seqno());
}
enum label_initialized { enum label_initialized {
LABEL_INVALID, /* invalid or not initialized */ LABEL_INVALID, /* invalid or not initialized */
LABEL_INITIALIZED, /* initialized */ LABEL_INITIALIZED, /* initialized */

View File

@ -47,10 +47,11 @@
#define POLICYDB_VERSION_GLBLUB 32 #define POLICYDB_VERSION_GLBLUB 32
#define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */ #define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */
#define POLICYDB_VERSION_COND_XPERMS 34 /* extended permissions in conditional policies */ #define POLICYDB_VERSION_COND_XPERMS 34 /* extended permissions in conditional policies */
#define POLICYDB_VERSION_NEVERAUDIT 35 /* neveraudit types */
/* Range of policy versions we understand*/ /* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COND_XPERMS #define POLICYDB_VERSION_MAX POLICYDB_VERSION_NEVERAUDIT
/* Mask for just the mount related flags */ /* Mask for just the mount related flags */
#define SE_MNTMASK 0x0f #define SE_MNTMASK 0x0f
@ -260,6 +261,7 @@ struct extended_perms {
/* definitions of av_decision.flags */ /* definitions of av_decision.flags */
#define AVD_FLAGS_PERMISSIVE 0x0001 #define AVD_FLAGS_PERMISSIVE 0x0001
#define AVD_FLAGS_NEVERAUDIT 0x0002
void security_compute_av(u32 ssid, u32 tsid, u16 tclass, void security_compute_av(u32 ssid, u32 tsid, u16 tclass,
struct av_decision *avd, struct av_decision *avd,

View File

@ -1072,6 +1072,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
pr_warn_ratelimited("SELinux: %s (%d) wrote to /sys/fs/selinux/user!" pr_warn_ratelimited("SELinux: %s (%d) wrote to /sys/fs/selinux/user!"
" This will not be supported in the future; please update your" " This will not be supported in the future; please update your"
" userspace.\n", current->comm, current->pid); " userspace.\n", current->comm, current->pid);
ssleep(5);
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER, SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
@ -2097,8 +2098,6 @@ err:
pr_err("SELinux: %s: failed while creating inodes\n", pr_err("SELinux: %s: failed while creating inodes\n",
__func__); __func__);
selinux_fs_info_free(sb);
return ret; return ret;
} }

View File

@ -40,7 +40,8 @@ int hashtab_init(struct hashtab *h, u32 nel_hint)
h->htable = NULL; h->htable = NULL;
if (size) { if (size) {
h->htable = kcalloc(size, sizeof(*h->htable), GFP_KERNEL); h->htable = kcalloc(size, sizeof(*h->htable),
GFP_KERNEL | __GFP_NOWARN);
if (!h->htable) if (!h->htable)
return -ENOMEM; return -ENOMEM;
h->size = size; h->size = size;

View File

@ -160,6 +160,11 @@ static const struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM, .sym_num = SYM_NUM,
.ocon_num = OCON_NUM, .ocon_num = OCON_NUM,
}, },
{
.version = POLICYDB_VERSION_NEVERAUDIT,
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
}; };
static const struct policydb_compat_info * static const struct policydb_compat_info *
@ -531,6 +536,7 @@ static void policydb_init(struct policydb *p)
ebitmap_init(&p->filename_trans_ttypes); ebitmap_init(&p->filename_trans_ttypes);
ebitmap_init(&p->policycaps); ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map); ebitmap_init(&p->permissive_map);
ebitmap_init(&p->neveraudit_map);
} }
/* /*
@ -852,6 +858,7 @@ void policydb_destroy(struct policydb *p)
ebitmap_destroy(&p->filename_trans_ttypes); ebitmap_destroy(&p->filename_trans_ttypes);
ebitmap_destroy(&p->policycaps); ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map); ebitmap_destroy(&p->permissive_map);
ebitmap_destroy(&p->neveraudit_map);
} }
/* /*
@ -2538,6 +2545,12 @@ int policydb_read(struct policydb *p, struct policy_file *fp)
goto bad; goto bad;
} }
if (p->policyvers >= POLICYDB_VERSION_NEVERAUDIT) {
rc = ebitmap_read(&p->neveraudit_map, fp);
if (rc)
goto bad;
}
rc = -EINVAL; rc = -EINVAL;
info = policydb_lookup_compat(p->policyvers); info = policydb_lookup_compat(p->policyvers);
if (!info) { if (!info) {
@ -3723,6 +3736,12 @@ int policydb_write(struct policydb *p, struct policy_file *fp)
return rc; return rc;
} }
if (p->policyvers >= POLICYDB_VERSION_NEVERAUDIT) {
rc = ebitmap_write(&p->neveraudit_map, fp);
if (rc)
return rc;
}
num_syms = info->sym_num; num_syms = info->sym_num;
for (i = 0; i < num_syms; i++) { for (i = 0; i < num_syms; i++) {
struct policy_data pd; struct policy_data pd;

View File

@ -300,6 +300,8 @@ struct policydb {
struct ebitmap permissive_map; struct ebitmap permissive_map;
struct ebitmap neveraudit_map;
/* length of this policy when it was loaded */ /* length of this policy when it was loaded */
size_t len; size_t len;

View File

@ -1153,6 +1153,14 @@ void security_compute_av(u32 ssid,
if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
avd->flags |= AVD_FLAGS_PERMISSIVE; avd->flags |= AVD_FLAGS_PERMISSIVE;
/* neveraudit domain? */
if (ebitmap_get_bit(&policydb->neveraudit_map, scontext->type))
avd->flags |= AVD_FLAGS_NEVERAUDIT;
/* both permissive and neveraudit => allow */
if (avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT))
goto allow;
tcontext = sidtab_search(sidtab, tsid); tcontext = sidtab_search(sidtab, tsid);
if (!tcontext) { if (!tcontext) {
pr_err("SELinux: %s: unrecognized SID %d\n", pr_err("SELinux: %s: unrecognized SID %d\n",
@ -1172,6 +1180,8 @@ void security_compute_av(u32 ssid,
policydb->allow_unknown); policydb->allow_unknown);
out: out:
rcu_read_unlock(); rcu_read_unlock();
if (avd->flags & AVD_FLAGS_NEVERAUDIT)
avd->auditallow = avd->auditdeny = 0;
return; return;
allow: allow:
avd->allowed = 0xffffffff; avd->allowed = 0xffffffff;
@ -1208,6 +1218,14 @@ void security_compute_av_user(u32 ssid,
if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
avd->flags |= AVD_FLAGS_PERMISSIVE; avd->flags |= AVD_FLAGS_PERMISSIVE;
/* neveraudit domain? */
if (ebitmap_get_bit(&policydb->neveraudit_map, scontext->type))
avd->flags |= AVD_FLAGS_NEVERAUDIT;
/* both permissive and neveraudit => allow */
if (avd->flags == (AVD_FLAGS_PERMISSIVE|AVD_FLAGS_NEVERAUDIT))
goto allow;
tcontext = sidtab_search(sidtab, tsid); tcontext = sidtab_search(sidtab, tsid);
if (!tcontext) { if (!tcontext) {
pr_err("SELinux: %s: unrecognized SID %d\n", pr_err("SELinux: %s: unrecognized SID %d\n",
@ -1225,6 +1243,8 @@ void security_compute_av_user(u32 ssid,
NULL); NULL);
out: out:
rcu_read_unlock(); rcu_read_unlock();
if (avd->flags & AVD_FLAGS_NEVERAUDIT)
avd->auditallow = avd->auditdeny = 0;
return; return;
allow: allow:
avd->allowed = 0xffffffff; avd->allowed = 0xffffffff;