Import of kernel-6.12.0-211.22.1.el10_2

This commit is contained in:
almalinux-bot-kernel 2026-06-12 05:40:16 +00:00
parent c23a26575f
commit 3d57f395f9
68 changed files with 2286 additions and 1285 deletions

View File

@ -219,6 +219,7 @@ config ARM64
if DYNAMIC_FTRACE_WITH_ARGS
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
select HAVE_BUILDTIME_MCOUNT_SORT
select HAVE_EFFICIENT_UNALIGNED_ACCESS
select HAVE_GUP_FAST
select HAVE_FTRACE_MCOUNT_RECORD

View File

@ -187,7 +187,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev)
* is unbound or probed and that userspace can't access its
* configuration space while we perform recovery.
*/
pci_dev_lock(pdev);
device_lock(&pdev->dev);
if (pdev->error_state == pci_channel_io_perm_failure) {
ers_res = PCI_ERS_RESULT_DISCONNECT;
goto out_unlock;
@ -254,7 +254,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev)
if (driver->err_handler->resume)
driver->err_handler->resume(pdev);
out_unlock:
pci_dev_unlock(pdev);
device_unlock(&pdev->dev);
zpci_report_status(zdev, "recovery", status_str);
return ers_res;

View File

@ -9076,6 +9076,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9128,6 +9130,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -9022,6 +9022,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9073,6 +9075,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -9084,6 +9084,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9136,6 +9138,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -9055,6 +9055,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9107,6 +9109,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -9001,6 +9001,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9052,6 +9054,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -9062,6 +9062,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9114,6 +9116,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -9008,6 +9008,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9059,6 +9061,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -9030,6 +9030,8 @@ CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACER_MAX_TRACE=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
@ -9081,6 +9083,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m
# CONFIG_FTRACE_RECORD_RECURSION is not set
# CONFIG_FTRACE_VALIDATE_RCU_IS_WATCHING is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_FTRACE_SORT_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set

View File

@ -737,8 +737,8 @@ r535_gsp_acpi_caps(acpi_handle handle, CAPS_METHOD_DATA *caps)
if (!obj)
goto done;
if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
WARN_ON(obj->buffer.length != 4))
if (obj->type != ACPI_TYPE_BUFFER ||
obj->buffer.length != 4)
goto done;
caps->status = 0;
@ -773,8 +773,8 @@ r535_gsp_acpi_jt(acpi_handle handle, JT_METHOD_DATA *jt)
if (!obj)
goto done;
if (WARN_ON(obj->type != ACPI_TYPE_BUFFER) ||
WARN_ON(obj->buffer.length != 4))
if (obj->type != ACPI_TYPE_BUFFER ||
obj->buffer.length != 4)
goto done;
jt->status = 0;
@ -861,8 +861,8 @@ r535_gsp_acpi_dod(acpi_handle handle, DOD_METHOD_DATA *dod)
_DOD = output.pointer;
if (WARN_ON(_DOD->type != ACPI_TYPE_PACKAGE) ||
WARN_ON(_DOD->package.count > ARRAY_SIZE(dod->acpiIdList)))
if (_DOD->type != ACPI_TYPE_PACKAGE ||
_DOD->package.count > ARRAY_SIZE(dod->acpiIdList))
return;
for (int i = 0; i < _DOD->package.count; i++) {

View File

@ -5401,7 +5401,7 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb,
if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP))
continue;
if (bond_is_last_slave(bond, slave)) {
if (i + 1 == slaves_count) {
skb2 = skb;
skb_used = true;
} else {

View File

@ -3015,7 +3015,7 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi,
* ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones
* @vsi: VSI pointer
*/
static int
int
ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
{
u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq;

View File

@ -66,6 +66,7 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked);
void ice_vsi_decfg(struct ice_vsi *vsi);
void ice_dis_vsi(struct ice_vsi *vsi, bool locked);
int ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi);
int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags);
int ice_vsi_cfg(struct ice_vsi *vsi);
struct ice_vsi *ice_vsi_alloc(struct ice_pf *pf);

View File

@ -268,6 +268,13 @@ static int ice_vf_reconfig_vsi(struct ice_vf *vf)
vsi->flags = ICE_VSI_FLAG_NO_INIT;
vsi->req_txq = vf->num_req_qs;
vsi->req_rxq = vf->num_req_qs;
err = ice_vsi_realloc_stat_arrays(vsi);
if (err)
return err;
ice_vsi_decfg(vsi);
ice_fltr_remove_all(vsi);

View File

@ -6145,10 +6145,12 @@ static void copy_pair_set_active(struct dasd_copy_relation *copy, char *new_busi
static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid,
char *sec_busid)
{
struct dasd_eckd_private *prim_priv, *sec_priv;
struct dasd_device *primary, *secondary;
struct dasd_copy_relation *copy;
struct dasd_block *block;
struct gendisk *gdp;
int rc;
copy = device->copy;
if (!copy)
@ -6164,6 +6166,9 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
if (!secondary)
return DASD_COPYPAIRSWAP_SECONDARY;
prim_priv = primary->private;
sec_priv = secondary->private;
/*
* usually the device should be quiesced for swap
* for paranoia stop device and requeue requests again
@ -6183,6 +6188,25 @@ static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid
/* swap blocklayer device link */
gdp = block->gdp;
dasd_add_link_to_gendisk(gdp, secondary);
rc = device_move(disk_to_dev(gdp), &secondary->cdev->dev, DPM_ORDER_NONE);
if (rc) {
dev_err(&primary->cdev->dev,
"copy_pair_swap: moving blockdevice parent %s->%s failed (%d)\n",
dev_name(&primary->cdev->dev),
dev_name(&secondary->cdev->dev), rc);
}
if (primary->stopped & DASD_STOPPED_QUIESCE) {
dasd_device_set_stop_bits(secondary, DASD_STOPPED_QUIESCE);
dasd_device_remove_stop_bits(primary, DASD_STOPPED_QUIESCE);
}
/*
* The secondary device never got through format detection, but since it
* is a copy of the primary device, the format is exactly the same;
* therefore, the detected layout can simply be copied.
*/
sec_priv->uses_cdl = prim_priv->uses_cdl;
/* re-enable device */
dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC);

View File

@ -12,6 +12,7 @@
#include <linux/backing-file.h>
#include <linux/splice.h>
#include <linux/mm.h>
#include <linux/security.h>
#include "internal.h"
@ -29,19 +30,20 @@
* returned file into a container structure that also stores the stacked
* file's path, which can be retrieved using backing_file_user_path().
*/
struct file *backing_file_open(const struct path *user_path, int flags,
struct file *backing_file_open(const struct file *user_file, int flags,
const struct path *real_path,
const struct cred *cred)
{
const struct path *user_path = &user_file->f_path;
struct file *f;
int error;
f = alloc_empty_backing_file(flags, cred);
f = alloc_empty_backing_file(flags, cred, user_file);
if (IS_ERR(f))
return f;
path_get(user_path);
*backing_file_user_path(f) = *user_path;
backing_file_set_user_path(f, user_path);
error = vfs_open(real_path, f);
if (error) {
fput(f);
@ -52,20 +54,21 @@ struct file *backing_file_open(const struct path *user_path, int flags,
}
EXPORT_SYMBOL_GPL(backing_file_open);
struct file *backing_tmpfile_open(const struct path *user_path, int flags,
struct file *backing_tmpfile_open(const struct file *user_file, int flags,
const struct path *real_parentpath,
umode_t mode, const struct cred *cred)
{
struct mnt_idmap *real_idmap = mnt_idmap(real_parentpath->mnt);
const struct path *user_path = &user_file->f_path;
struct file *f;
int error;
f = alloc_empty_backing_file(flags, cred);
f = alloc_empty_backing_file(flags, cred, user_file);
if (IS_ERR(f))
return f;
path_get(user_path);
*backing_file_user_path(f) = *user_path;
backing_file_set_user_path(f, user_path);
error = vfs_tmpfile(real_idmap, real_parentpath, f, mode);
if (error) {
fput(f);
@ -339,6 +342,11 @@ int backing_file_mmap(struct file *file, struct vm_area_struct *vma,
vma_set_file(vma, file);
old_cred = override_creds(ctx->cred);
ret = security_mmap_backing_file(vma, file, ctx->user_file);
if (ret) {
revert_creds(old_cred);
return ret;
}
ret = call_mmap(vma->vm_file, vma);
revert_creds(old_cred);

View File

@ -1337,6 +1337,7 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
int bios)
{
struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
int gfp_flag;
/* wake up the caller thread for sync decompression */
if (io->sync) {
@ -1370,7 +1371,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
return;
}
gfp_flag = memalloc_noio_save();
z_erofs_decompressqueue_work(&io->u.work);
memalloc_noio_restore(gfp_flag);
}
static void z_erofs_fill_bio_vec(struct bio_vec *bvec,

View File

@ -51,19 +51,44 @@ struct backing_file {
struct path user_path;
freeptr_t bf_freeptr;
};
#ifdef CONFIG_SECURITY
void *security;
#endif
};
static inline struct backing_file *backing_file(struct file *f)
{
return container_of(f, struct backing_file, file);
}
#define backing_file(f) container_of(f, struct backing_file, file)
struct path *backing_file_user_path(struct file *f)
struct path *backing_file_user_path(const struct file *f)
{
return &backing_file(f)->user_path;
}
EXPORT_SYMBOL_GPL(backing_file_user_path);
void backing_file_set_user_path(struct file *f, const struct path *path)
{
backing_file(f)->user_path = *path;
}
EXPORT_SYMBOL_GPL(backing_file_set_user_path);
#ifdef CONFIG_SECURITY
void *backing_file_security(const struct file *f)
{
return backing_file(f)->security;
}
void backing_file_set_security(struct file *f, void *security)
{
backing_file(f)->security = security;
}
#endif /* CONFIG_SECURITY */
static inline void backing_file_free(struct backing_file *ff)
{
security_backing_file_free(&ff->file);
path_put(&ff->user_path);
kmem_cache_free(bfilp_cachep, ff);
}
static inline void file_free(struct file *f)
{
security_file_free(f);
@ -71,8 +96,7 @@ static inline void file_free(struct file *f)
percpu_counter_dec(&nr_files);
put_cred(f->f_cred);
if (unlikely(f->f_mode & FMODE_BACKING)) {
path_put(backing_file_user_path(f));
kmem_cache_free(bfilp_cachep, backing_file(f));
backing_file_free(backing_file(f));
} else {
kmem_cache_free(filp_cachep, f);
}
@ -275,6 +299,14 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)
return f;
}
static int init_backing_file(struct backing_file *ff,
const struct file *user_file)
{
memset(&ff->user_path, 0, sizeof(ff->user_path));
backing_file_set_security(&ff->file, NULL);
return security_backing_file_alloc(&ff->file, user_file);
}
/*
* Variant of alloc_empty_file() that allocates a backing_file container
* and doesn't check and modify nr_files.
@ -282,7 +314,8 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)
* This is only for kernel internal use, and the allocate file must not be
* installed into file tables or such.
*/
struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
struct file *alloc_empty_backing_file(int flags, const struct cred *cred,
const struct file *user_file)
{
struct backing_file *ff;
int error;
@ -297,7 +330,14 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
return ERR_PTR(error);
}
/* The f_mode flags must be set before fput(). */
ff->file.f_mode |= FMODE_BACKING | FMODE_NOACCOUNT;
error = init_backing_file(ff, user_file);
if (unlikely(error)) {
fput(&ff->file);
return ERR_PTR(error);
}
return &ff->file;
}

View File

@ -321,7 +321,7 @@ struct fuse_backing *fuse_passthrough_open(struct file *file,
goto out;
/* Allocate backing file per fuse file to store fuse path */
backing_file = backing_file_open(&file->f_path, file->f_flags,
backing_file = backing_file_open(file, file->f_flags,
&fb->file->f_path, fb->cred);
err = PTR_ERR(backing_file);
if (IS_ERR(backing_file)) {

View File

@ -99,7 +99,9 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
*/
struct file *alloc_empty_file(int flags, const struct cred *cred);
struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
struct file *alloc_empty_backing_file(int flags, const struct cred *cred,
const struct file *user_file);
void backing_file_set_user_path(struct file *f, const struct path *path);
static inline void file_put_write_access(struct file *file)
{

View File

@ -1320,7 +1320,7 @@ static int ovl_create_tmpfile(struct file *file, struct dentry *dentry,
goto out_revert_creds;
ovl_path_upper(dentry->d_parent, &realparentpath);
realfile = backing_tmpfile_open(&file->f_path, flags, &realparentpath,
realfile = backing_tmpfile_open(file, flags, &realparentpath,
mode, current_cred());
err = PTR_ERR_OR_ZERO(realfile);
pr_debug("tmpfile/open(%pd2, 0%o) = %i\n", realparentpath.dentry, mode, err);

View File

@ -48,7 +48,7 @@ static struct file *ovl_open_realfile(const struct file *file,
if (!inode_owner_or_capable(real_idmap, realinode))
flags &= ~O_NOATIME;
realfile = backing_file_open(&file->f_path, flags, realpath,
realfile = backing_file_open(file, flags, realpath,
current_cred());
}
revert_creds(old_cred);

View File

View File

@ -2240,6 +2240,7 @@ CONFIG_NLS_MAC_CYRILLIC=m
CONFIG_BT_BCM=m
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_BUILDTIME_MCOUNT_SORT=y
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_PWM_TIEHRPWM=m
CONFIG_HAS_IOMEM=y
@ -4483,6 +4484,7 @@ CONFIG_SND_CTL_LED=m
CONFIG_NUMA_BALANCING=y
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
CONFIG_CLK_TEGRA_BPMP=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_FWCTL=m
CONFIG_QUOTACTL=y
CONFIG_BRIDGE_NF_EBTABLES=m

View File

@ -2240,6 +2240,7 @@
#define CONFIG_BT_BCM_MODULE 1
#define CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC 1
#define CONFIG_HARDENED_USERCOPY 1
#define CONFIG_BUILDTIME_MCOUNT_SORT 1
#define CONFIG_NETFILTER_XT_TARGET_MARK_MODULE 1
#define CONFIG_PWM_TIEHRPWM_MODULE 1
#define CONFIG_HAS_IOMEM 1
@ -4483,6 +4484,7 @@
#define CONFIG_NUMA_BALANCING 1
#define CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE 1
#define CONFIG_CLK_TEGRA_BPMP 1
#define CONFIG_HAVE_BUILDTIME_MCOUNT_SORT 1
#define CONFIG_FWCTL_MODULE 1
#define CONFIG_QUOTACTL 1
#define CONFIG_BRIDGE_NF_EBTABLES_MODULE 1

View File

@ -4397,6 +4397,8 @@
--cfg=CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC="y"
--cfg=CONFIG_HARDENED_USERCOPY
--cfg=CONFIG_HARDENED_USERCOPY="y"
--cfg=CONFIG_BUILDTIME_MCOUNT_SORT
--cfg=CONFIG_BUILDTIME_MCOUNT_SORT="y"
--cfg=CONFIG_NETFILTER_XT_TARGET_MARK
--cfg=CONFIG_NETFILTER_XT_TARGET_MARK="m"
--cfg=CONFIG_PWM_TIEHRPWM
@ -8820,6 +8822,8 @@
--cfg=CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE="y"
--cfg=CONFIG_CLK_TEGRA_BPMP
--cfg=CONFIG_CLK_TEGRA_BPMP="y"
--cfg=CONFIG_HAVE_BUILDTIME_MCOUNT_SORT
--cfg=CONFIG_HAVE_BUILDTIME_MCOUNT_SORT="y"
--cfg=CONFIG_FWCTL
--cfg=CONFIG_FWCTL="m"
--cfg=CONFIG_QUOTACTL

View File

@ -19,10 +19,10 @@ struct backing_file_ctx {
void (*end_write)(struct file *, loff_t, ssize_t);
};
struct file *backing_file_open(const struct path *user_path, int flags,
struct file *backing_file_open(const struct file *user_file, int flags,
const struct path *real_path,
const struct cred *cred);
struct file *backing_tmpfile_open(const struct path *user_path, int flags,
struct file *backing_tmpfile_open(const struct file *user_file, int flags,
const struct path *real_parentpath,
umode_t mode, const struct cred *cred);
ssize_t backing_file_read_iter(struct file *file, struct iov_iter *iter,

View File

@ -2790,7 +2790,20 @@ struct file *dentry_open(const struct path *path, int flags,
const struct cred *creds);
struct file *dentry_create(const struct path *path, int flags, umode_t mode,
const struct cred *cred);
struct path *backing_file_user_path(struct file *f);
struct path *backing_file_user_path(const struct file *f);
#ifdef CONFIG_SECURITY
void *backing_file_security(const struct file *f);
void backing_file_set_security(struct file *f, void *security);
#else
static inline void *backing_file_security(const struct file *f)
{
return NULL;
}
static inline void backing_file_set_security(struct file *f, void *security)
{
}
#endif /* CONFIG_SECURITY */
/*
* When mmapping a file on a stackable filesystem (e.g., overlayfs), the file
@ -2802,14 +2815,14 @@ struct path *backing_file_user_path(struct file *f);
* by fstat() on that same fd.
*/
/* Get the path to display in /proc/<pid>/maps */
static inline const struct path *file_user_path(struct file *f)
static inline const struct path *file_user_path(const struct file *f)
{
if (unlikely(f->f_mode & FMODE_BACKING))
return backing_file_user_path(f);
return &f->f_path;
}
/* Get the inode whose inode number to display in /proc/<pid>/maps */
static inline const struct inode *file_user_inode(struct file *f)
static inline const struct inode *file_user_inode(const struct file *f)
{
if (unlikely(f->f_mode & FMODE_BACKING))
return d_inode(backing_file_user_path(f)->dentry);

View File

@ -93,7 +93,7 @@ struct common_audit_data {
#endif
char *kmod_name;
struct lsm_ioctlop_audit *op;
struct file *file;
const struct file *file;
struct lsm_ibpkey_audit *ibpkey;
struct lsm_ibendport_audit *ibendport;
int reason;

View File

@ -188,6 +188,9 @@ LSM_HOOK(int, 0, file_permission, struct file *file, int mask)
LSM_HOOK(int, 0, file_alloc_security, struct file *file)
LSM_HOOK(void, LSM_RET_VOID, file_release, struct file *file)
LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file)
LSM_HOOK(int, 0, backing_file_alloc, struct file *backing_file,
const struct file *user_file)
LSM_HOOK(void, LSM_RET_VOID, backing_file_free, struct file *backing_file)
LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd,
unsigned long arg)
LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd,
@ -195,6 +198,8 @@ LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd,
LSM_HOOK(int, 0, mmap_addr, unsigned long addr)
LSM_HOOK(int, 0, mmap_file, struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags)
LSM_HOOK(int, 0, mmap_backing_file, struct vm_area_struct *vma,
struct file *backing_file, struct file *user_file)
LSM_HOOK(int, 0, file_mprotect, struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot)
LSM_HOOK(int, 0, file_lock, struct file *file, unsigned int cmd)

View File

@ -102,20 +102,21 @@ struct security_hook_list {
* Security blob size or offset data.
*/
struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
int lbs_ib;
int lbs_inode;
int lbs_sock;
int lbs_superblock;
int lbs_ipc;
int lbs_key;
int lbs_msg_msg;
int lbs_perf_event;
int lbs_task;
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
int lbs_tun_dev;
int lbs_bdev;
unsigned int lbs_cred;
unsigned int lbs_file;
unsigned int lbs_backing_file;
unsigned int lbs_ib;
unsigned int lbs_inode;
unsigned int lbs_sock;
unsigned int lbs_superblock;
unsigned int lbs_ipc;
unsigned int lbs_key;
unsigned int lbs_msg_msg;
unsigned int lbs_perf_event;
unsigned int lbs_task;
unsigned int lbs_xattr_count; /* num xattr slots in new_xattrs array */
unsigned int lbs_tun_dev;
unsigned int lbs_bdev;
};
/*
@ -149,7 +150,7 @@ enum lsm_order {
};
struct lsm_info {
const char *name; /* Required. */
const struct lsm_id *id;
enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
unsigned long flags; /* Optional: flags describing LSM */
int *enabled; /* Optional: controlled by CONFIG_LSM */
@ -167,11 +168,9 @@ struct lsm_info {
__used __section(".early_lsm_info.init") \
__aligned(sizeof(unsigned long))
/* DO NOT tamper with these variables outside of the LSM framework */
extern char *lsm_names;
extern struct lsm_static_calls_table static_calls_table __ro_after_init;
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
/**
* lsm_get_xattr_slot - Return the next available slot and increment the index

View File

@ -153,8 +153,6 @@ enum lockdown_reason {
};
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
extern u32 lsm_active_cnt;
extern const struct lsm_id *lsm_idlist[];
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
@ -420,11 +418,17 @@ int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_release(struct file *file);
void security_file_free(struct file *file);
int security_backing_file_alloc(struct file *backing_file,
const struct file *user_file);
void security_backing_file_free(struct file *backing_file);
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int security_file_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg);
int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags);
int security_mmap_backing_file(struct vm_area_struct *vma,
struct file *backing_file,
struct file *user_file);
int security_mmap_addr(unsigned long addr);
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot);
@ -1065,6 +1069,15 @@ static inline void security_file_release(struct file *file)
static inline void security_file_free(struct file *file)
{ }
static inline int security_backing_file_alloc(struct file *backing_file,
const struct file *user_file)
{
return 0;
}
static inline void security_backing_file_free(struct file *backing_file)
{ }
static inline int security_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@ -1084,6 +1097,13 @@ static inline int security_mmap_file(struct file *file, unsigned long prot,
return 0;
}
static inline int security_mmap_backing_file(struct vm_area_struct *vma,
struct file *backing_file,
struct file *user_file)
{
return 0;
}
static inline int security_mmap_addr(unsigned long addr)
{
return cap_mmap_addr(addr);

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.20.1.el10.x86_64,mailto:security@almalinux.org
kernel.almalinux,1,AlmaLinux,kernel-core,6.12.0-211.22.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -1122,7 +1122,6 @@ struct ftrace_page {
};
#define ENTRY_SIZE sizeof(struct dyn_ftrace)
#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE)
static struct ftrace_page *ftrace_pages_start;
static struct ftrace_page *ftrace_pages;
@ -3741,7 +3740,8 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
return 0;
}
static int ftrace_allocate_records(struct ftrace_page *pg, int count)
static int ftrace_allocate_records(struct ftrace_page *pg, int count,
unsigned long *num_pages)
{
int order;
int pages;
@ -3751,7 +3751,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
return -EINVAL;
/* We want to fill as much as possible, with no empty pages */
pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);
pages = DIV_ROUND_UP(count * ENTRY_SIZE, PAGE_SIZE);
order = fls(pages) - 1;
again:
@ -3766,6 +3766,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count)
}
ftrace_number_of_pages += 1 << order;
*num_pages += 1 << order;
ftrace_number_of_groups++;
cnt = (PAGE_SIZE << order) / ENTRY_SIZE;
@ -3794,12 +3795,14 @@ static void ftrace_free_pages(struct ftrace_page *pages)
}
static struct ftrace_page *
ftrace_allocate_pages(unsigned long num_to_init)
ftrace_allocate_pages(unsigned long num_to_init, unsigned long *num_pages)
{
struct ftrace_page *start_pg;
struct ftrace_page *pg;
int cnt;
*num_pages = 0;
if (!num_to_init)
return NULL;
@ -3813,7 +3816,7 @@ ftrace_allocate_pages(unsigned long num_to_init)
* waste as little space as possible.
*/
for (;;) {
cnt = ftrace_allocate_records(pg, num_to_init);
cnt = ftrace_allocate_records(pg, num_to_init, num_pages);
if (cnt < 0)
goto free_pages;
@ -7019,6 +7022,7 @@ static int ftrace_process_locs(struct module *mod,
unsigned long *p;
unsigned long addr;
unsigned long flags = 0; /* Shut up gcc */
unsigned long pages;
int ret = -ENOMEM;
count = end - start;
@ -7038,7 +7042,7 @@ static int ftrace_process_locs(struct module *mod,
test_is_sorted(start, count);
}
start_pg = ftrace_allocate_pages(count);
start_pg = ftrace_allocate_pages(count, &pages);
if (!start_pg)
return -ENOMEM;
@ -7070,7 +7074,9 @@ static int ftrace_process_locs(struct module *mod,
pg = start_pg;
while (p < end) {
unsigned long end_offset;
addr = ftrace_call_adjust(*p++);
addr = *p++;
/*
* Some architecture linkers will pad between
* the different mcount_loc sections of different
@ -7082,6 +7088,19 @@ static int ftrace_process_locs(struct module *mod,
continue;
}
/*
* If this is core kernel, make sure the address is in core
* or inittext, as weak functions get zeroed and KASLR can
* move them to something other than zero. It just will not
* move it to an area where kernel text is.
*/
if (!mod && !(is_kernel_text(addr) || is_kernel_inittext(addr))) {
skipped++;
continue;
}
addr = ftrace_call_adjust(addr);
end_offset = (pg->index+1) * sizeof(pg->records[0]);
if (end_offset > PAGE_SIZE << pg->order) {
/* We should have allocated enough */
@ -7121,11 +7140,41 @@ static int ftrace_process_locs(struct module *mod,
/* We should have used all pages unless we skipped some */
if (pg_unuse) {
WARN_ON(!skipped);
unsigned long pg_remaining, remaining = 0;
long skip;
/* Count the number of entries unused and compare it to skipped. */
pg_remaining = (PAGE_SIZE << pg->order) / ENTRY_SIZE - pg->index;
if (!WARN(skipped < pg_remaining, "Extra allocated pages for ftrace")) {
skip = skipped - pg_remaining;
for (pg = pg_unuse; pg && skip > 0; pg = pg->next) {
remaining += 1 << pg->order;
skip -= (PAGE_SIZE << pg->order) / ENTRY_SIZE;
}
pages -= remaining;
/*
* Check to see if the number of pages remaining would
* just fit the number of entries skipped.
*/
WARN(pg || skip > 0, "Extra allocated pages for ftrace: %lu with %lu skipped",
remaining, skipped);
}
/* Need to synchronize with ftrace_location_range() */
synchronize_rcu();
ftrace_free_pages(pg_unuse);
}
if (!mod) {
count -= skipped;
pr_info("ftrace: allocating %ld entries in %ld pages\n",
count, pages);
}
return ret;
}
@ -7775,9 +7824,6 @@ void __init ftrace_init(void)
goto failed;
}
pr_info("ftrace: allocating %ld entries in %ld pages\n",
count, DIV_ROUND_UP(count, ENTRIES_PER_PAGE));
ret = ftrace_process_locs(NULL,
__start_mcount_loc,
__stop_mcount_loc);

View File

@ -360,6 +360,14 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg,
return NOTIFY_DONE;
}
static void raw_sock_destruct(struct sock *sk)
{
struct raw_sock *ro = raw_sk(sk);
free_percpu(ro->uniq);
can_sock_destruct(sk);
}
static int raw_init(struct sock *sk)
{
struct raw_sock *ro = raw_sk(sk);
@ -386,6 +394,8 @@ static int raw_init(struct sock *sk)
if (unlikely(!ro->uniq))
return -ENOMEM;
sk->sk_destruct = raw_sock_destruct;
/* set notifier */
spin_lock(&raw_notifier_lock);
list_add_tail(&ro->notifier, &raw_notifier_list);
@ -433,7 +443,6 @@ static int raw_release(struct socket *sock)
ro->bound = 0;
ro->dev = NULL;
ro->count = 0;
free_percpu(ro->uniq);
sock_orphan(sk);
sock->sk = NULL;

View File

@ -486,6 +486,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
struct net *net = dev_net(skb->dev);
struct inet6_dev *idev;
struct ipv6hdr *oldhdr;
unsigned int chdr_len;
unsigned char *buf;
int accept_rpl_seg;
int i, err;
@ -589,8 +590,10 @@ looped_back:
skb_pull(skb, ((hdr->hdrlen + 1) << 3));
skb_postpull_rcsum(skb, oldhdr,
sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3));
if (unlikely(!hdr->segments_left)) {
if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0,
chdr_len = sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3);
if (unlikely(!hdr->segments_left ||
skb_headroom(skb) < chdr_len + skb->mac_len)) {
if (pskb_expand_head(skb, chdr_len + skb->mac_len, 0,
GFP_ATOMIC)) {
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
@ -600,7 +603,7 @@ looped_back:
oldhdr = ipv6_hdr(skb);
}
skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr));
skb_push(skb, chdr_len);
skb_reset_network_header(skb);
skb_mac_header_rebuild(skb);
skb_set_transport_header(skb, sizeof(struct ipv6hdr));

View File

@ -602,11 +602,16 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (!skb2)
return 0;
/* Remove debris left by IPv6 stack. */
memset(IPCB(skb2), 0, sizeof(*IPCB(skb2)));
skb_dst_drop(skb2);
skb_pull(skb2, offset);
skb_reset_network_header(skb2);
eiph = ip_hdr(skb2);
if (eiph->version != 4 || eiph->ihl < 5)
goto out;
/* Try to guess incoming interface */
rt = ip_route_output_ports(dev_net(skb->dev), &fl4, NULL, eiph->saddr,

View File

@ -174,12 +174,14 @@ mksysmap()
sorttable()
{
${objtree}/scripts/sorttable ${1}
${NM} -S ${1} > .tmp_vmlinux.nm-sort
${objtree}/scripts/sorttable -s .tmp_vmlinux.nm-sort ${1}
}
cleanup()
{
rm -f .btf.*
rm -f .tmp_vmlinux.nm-sort
rm -f System.map
rm -f vmlinux
rm -f vmlinux.map

File diff suppressed because it is too large Load Diff

View File

@ -1,497 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* sorttable.h
*
* Added ORC unwind tables sort support and other updates:
* Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
* Shile Zhang <shile.zhang@linux.alibaba.com>
*
* Copyright 2011 - 2012 Cavium, Inc.
*
* Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
* Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
*
* Some of this code was taken out of recordmcount.h written by:
*
* Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
* Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
*/
#undef extable_ent_size
#undef compare_extable
#undef get_mcount_loc
#undef sort_mcount_loc
#undef elf_mcount_loc
#undef do_sort
#undef Elf_Addr
#undef Elf_Ehdr
#undef Elf_Shdr
#undef Elf_Rel
#undef Elf_Rela
#undef Elf_Sym
#undef ELF_R_SYM
#undef Elf_r_sym
#undef ELF_R_INFO
#undef Elf_r_info
#undef ELF_ST_BIND
#undef ELF_ST_TYPE
#undef fn_ELF_R_SYM
#undef fn_ELF_R_INFO
#undef uint_t
#undef _r
#undef _w
#ifdef SORTTABLE_64
# define extable_ent_size 16
# define compare_extable compare_extable_64
# define get_mcount_loc get_mcount_loc_64
# define sort_mcount_loc sort_mcount_loc_64
# define elf_mcount_loc elf_mcount_loc_64
# define do_sort do_sort_64
# define Elf_Addr Elf64_Addr
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Shdr Elf64_Shdr
# define Elf_Rel Elf64_Rel
# define Elf_Rela Elf64_Rela
# define Elf_Sym Elf64_Sym
# define ELF_R_SYM ELF64_R_SYM
# define Elf_r_sym Elf64_r_sym
# define ELF_R_INFO ELF64_R_INFO
# define Elf_r_info Elf64_r_info
# define ELF_ST_BIND ELF64_ST_BIND
# define ELF_ST_TYPE ELF64_ST_TYPE
# define fn_ELF_R_SYM fn_ELF64_R_SYM
# define fn_ELF_R_INFO fn_ELF64_R_INFO
# define uint_t uint64_t
# define _r r8
# define _w w8
#else
# define extable_ent_size 8
# define compare_extable compare_extable_32
# define get_mcount_loc get_mcount_loc_32
# define sort_mcount_loc sort_mcount_loc_32
# define elf_mcount_loc elf_mcount_loc_32
# define do_sort do_sort_32
# define Elf_Addr Elf32_Addr
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Shdr Elf32_Shdr
# define Elf_Rel Elf32_Rel
# define Elf_Rela Elf32_Rela
# define Elf_Sym Elf32_Sym
# define ELF_R_SYM ELF32_R_SYM
# define Elf_r_sym Elf32_r_sym
# define ELF_R_INFO ELF32_R_INFO
# define Elf_r_info Elf32_r_info
# define ELF_ST_BIND ELF32_ST_BIND
# define ELF_ST_TYPE ELF32_ST_TYPE
# define fn_ELF_R_SYM fn_ELF32_R_SYM
# define fn_ELF_R_INFO fn_ELF32_R_INFO
# define uint_t uint32_t
# define _r r
# define _w w
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* ORC unwinder only support X86_64 */
#include <asm/orc_types.h>
#define ERRSTR_MAXSZ 256
char g_err[ERRSTR_MAXSZ];
int *g_orc_ip_table;
struct orc_entry *g_orc_table;
pthread_t orc_sort_thread;
static inline unsigned long orc_ip(const int *ip)
{
return (unsigned long)ip + *ip;
}
static int orc_sort_cmp(const void *_a, const void *_b)
{
struct orc_entry *orc_a;
const int *a = g_orc_ip_table + *(int *)_a;
const int *b = g_orc_ip_table + *(int *)_b;
unsigned long a_val = orc_ip(a);
unsigned long b_val = orc_ip(b);
if (a_val > b_val)
return 1;
if (a_val < b_val)
return -1;
/*
* The "weak" section terminator entries need to always be on the left
* to ensure the lookup code skips them in favor of real entries.
* These terminator entries exist to handle any gaps created by
* whitelisted .o files which didn't get objtool generation.
*/
orc_a = g_orc_table + (a - g_orc_ip_table);
return orc_a->type == ORC_TYPE_UNDEFINED ? -1 : 1;
}
static void *sort_orctable(void *arg)
{
int i;
int *idxs = NULL;
int *tmp_orc_ip_table = NULL;
struct orc_entry *tmp_orc_table = NULL;
unsigned int *orc_ip_size = (unsigned int *)arg;
unsigned int num_entries = *orc_ip_size / sizeof(int);
unsigned int orc_size = num_entries * sizeof(struct orc_entry);
idxs = (int *)malloc(*orc_ip_size);
if (!idxs) {
snprintf(g_err, ERRSTR_MAXSZ, "malloc idxs: %s",
strerror(errno));
pthread_exit(g_err);
}
tmp_orc_ip_table = (int *)malloc(*orc_ip_size);
if (!tmp_orc_ip_table) {
snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_ip_table: %s",
strerror(errno));
pthread_exit(g_err);
}
tmp_orc_table = (struct orc_entry *)malloc(orc_size);
if (!tmp_orc_table) {
snprintf(g_err, ERRSTR_MAXSZ, "malloc tmp_orc_table: %s",
strerror(errno));
pthread_exit(g_err);
}
/* initialize indices array, convert ip_table to absolute address */
for (i = 0; i < num_entries; i++) {
idxs[i] = i;
tmp_orc_ip_table[i] = g_orc_ip_table[i] + i * sizeof(int);
}
memcpy(tmp_orc_table, g_orc_table, orc_size);
qsort(idxs, num_entries, sizeof(int), orc_sort_cmp);
for (i = 0; i < num_entries; i++) {
if (idxs[i] == i)
continue;
/* convert back to relative address */
g_orc_ip_table[i] = tmp_orc_ip_table[idxs[i]] - i * sizeof(int);
g_orc_table[i] = tmp_orc_table[idxs[i]];
}
free(idxs);
free(tmp_orc_ip_table);
free(tmp_orc_table);
pthread_exit(NULL);
}
#endif
static int compare_extable(const void *a, const void *b)
{
Elf_Addr av = _r(a);
Elf_Addr bv = _r(b);
if (av < bv)
return -1;
if (av > bv)
return 1;
return 0;
}
#ifdef MCOUNT_SORT_ENABLED
pthread_t mcount_sort_thread;
struct elf_mcount_loc {
Elf_Ehdr *ehdr;
Elf_Shdr *init_data_sec;
uint_t start_mcount_loc;
uint_t stop_mcount_loc;
};
/* Sort the addresses stored between __start_mcount_loc to __stop_mcount_loc in vmlinux */
static void *sort_mcount_loc(void *arg)
{
struct elf_mcount_loc *emloc = (struct elf_mcount_loc *)arg;
uint_t offset = emloc->start_mcount_loc - _r(&(emloc->init_data_sec)->sh_addr)
+ _r(&(emloc->init_data_sec)->sh_offset);
uint_t count = emloc->stop_mcount_loc - emloc->start_mcount_loc;
unsigned char *start_loc = (void *)emloc->ehdr + offset;
qsort(start_loc, count/sizeof(uint_t), sizeof(uint_t), compare_extable);
return NULL;
}
/* Get the address of __start_mcount_loc and __stop_mcount_loc in System.map */
static void get_mcount_loc(uint_t *_start, uint_t *_stop)
{
FILE *file_start, *file_stop;
char start_buff[20];
char stop_buff[20];
int len = 0;
file_start = popen(" grep start_mcount System.map | awk '{print $1}' ", "r");
if (!file_start) {
fprintf(stderr, "get start_mcount_loc error!");
return;
}
file_stop = popen(" grep stop_mcount System.map | awk '{print $1}' ", "r");
if (!file_stop) {
fprintf(stderr, "get stop_mcount_loc error!");
pclose(file_start);
return;
}
while (fgets(start_buff, sizeof(start_buff), file_start) != NULL) {
len = strlen(start_buff);
start_buff[len - 1] = '\0';
}
*_start = strtoul(start_buff, NULL, 16);
while (fgets(stop_buff, sizeof(stop_buff), file_stop) != NULL) {
len = strlen(stop_buff);
stop_buff[len - 1] = '\0';
}
*_stop = strtoul(stop_buff, NULL, 16);
pclose(file_start);
pclose(file_stop);
}
#endif
static int do_sort(Elf_Ehdr *ehdr,
char const *const fname,
table_sort_t custom_sort)
{
int rc = -1;
Elf_Shdr *s, *shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
Elf_Shdr *strtab_sec = NULL;
Elf_Shdr *symtab_sec = NULL;
Elf_Shdr *extab_sec = NULL;
Elf_Sym *sym;
const Elf_Sym *symtab;
Elf32_Word *symtab_shndx = NULL;
Elf_Sym *sort_needed_sym = NULL;
Elf_Shdr *sort_needed_sec;
Elf_Rel *relocs = NULL;
int relocs_size = 0;
uint32_t *sort_needed_loc;
const char *secstrings;
const char *strtab;
char *extab_image;
int extab_index = 0;
int i;
int idx;
unsigned int shnum;
unsigned int shstrndx;
#ifdef MCOUNT_SORT_ENABLED
struct elf_mcount_loc mstruct = {0};
uint_t _start_mcount_loc = 0;
uint_t _stop_mcount_loc = 0;
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
unsigned int orc_ip_size = 0;
unsigned int orc_size = 0;
unsigned int orc_num_entries = 0;
#endif
shstrndx = r2(&ehdr->e_shstrndx);
if (shstrndx == SHN_XINDEX)
shstrndx = r(&shdr[0].sh_link);
secstrings = (const char *)ehdr + _r(&shdr[shstrndx].sh_offset);
shnum = r2(&ehdr->e_shnum);
if (shnum == SHN_UNDEF)
shnum = _r(&shdr[0].sh_size);
for (i = 0, s = shdr; s < shdr + shnum; i++, s++) {
idx = r(&s->sh_name);
if (!strcmp(secstrings + idx, "__ex_table")) {
extab_sec = s;
extab_index = i;
}
if (!strcmp(secstrings + idx, ".symtab"))
symtab_sec = s;
if (!strcmp(secstrings + idx, ".strtab"))
strtab_sec = s;
if ((r(&s->sh_type) == SHT_REL ||
r(&s->sh_type) == SHT_RELA) &&
r(&s->sh_info) == extab_index) {
relocs = (void *)ehdr + _r(&s->sh_offset);
relocs_size = _r(&s->sh_size);
}
if (r(&s->sh_type) == SHT_SYMTAB_SHNDX)
symtab_shndx = (Elf32_Word *)((const char *)ehdr +
_r(&s->sh_offset));
#ifdef MCOUNT_SORT_ENABLED
/* locate the .init.data section in vmlinux */
if (!strcmp(secstrings + idx, ".init.data")) {
get_mcount_loc(&_start_mcount_loc, &_stop_mcount_loc);
mstruct.ehdr = ehdr;
mstruct.init_data_sec = s;
mstruct.start_mcount_loc = _start_mcount_loc;
mstruct.stop_mcount_loc = _stop_mcount_loc;
}
#endif
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
/* locate the ORC unwind tables */
if (!strcmp(secstrings + idx, ".orc_unwind_ip")) {
orc_ip_size = s->sh_size;
g_orc_ip_table = (int *)((void *)ehdr +
s->sh_offset);
}
if (!strcmp(secstrings + idx, ".orc_unwind")) {
orc_size = s->sh_size;
g_orc_table = (struct orc_entry *)((void *)ehdr +
s->sh_offset);
}
#endif
} /* for loop */
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
if (!g_orc_ip_table || !g_orc_table) {
fprintf(stderr,
"incomplete ORC unwind tables in file: %s\n", fname);
goto out;
}
orc_num_entries = orc_ip_size / sizeof(int);
if (orc_ip_size % sizeof(int) != 0 ||
orc_size % sizeof(struct orc_entry) != 0 ||
orc_num_entries != orc_size / sizeof(struct orc_entry)) {
fprintf(stderr,
"inconsistent ORC unwind table entries in file: %s\n",
fname);
goto out;
}
/* create thread to sort ORC unwind tables concurrently */
if (pthread_create(&orc_sort_thread, NULL,
sort_orctable, &orc_ip_size)) {
fprintf(stderr,
"pthread_create orc_sort_thread failed '%s': %s\n",
strerror(errno), fname);
goto out;
}
#endif
#ifdef MCOUNT_SORT_ENABLED
if (!mstruct.init_data_sec || !_start_mcount_loc || !_stop_mcount_loc) {
fprintf(stderr,
"incomplete mcount's sort in file: %s\n",
fname);
goto out;
}
/* create thread to sort mcount_loc concurrently */
if (pthread_create(&mcount_sort_thread, NULL, &sort_mcount_loc, &mstruct)) {
fprintf(stderr,
"pthread_create mcount_sort_thread failed '%s': %s\n",
strerror(errno), fname);
goto out;
}
#endif
if (!extab_sec) {
fprintf(stderr, "no __ex_table in file: %s\n", fname);
goto out;
}
if (!symtab_sec) {
fprintf(stderr, "no .symtab in file: %s\n", fname);
goto out;
}
if (!strtab_sec) {
fprintf(stderr, "no .strtab in file: %s\n", fname);
goto out;
}
extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
symtab = (const Elf_Sym *)((const char *)ehdr +
_r(&symtab_sec->sh_offset));
if (custom_sort) {
custom_sort(extab_image, _r(&extab_sec->sh_size));
} else {
int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
qsort(extab_image, num_entries,
extable_ent_size, compare_extable);
}
/* If there were relocations, we no longer need them. */
if (relocs)
memset(relocs, 0, relocs_size);
/* find the flag main_extable_sort_needed */
for (sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
sym < sym + _r(&symtab_sec->sh_size) / sizeof(Elf_Sym);
sym++) {
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
continue;
if (!strcmp(strtab + r(&sym->st_name),
"main_extable_sort_needed")) {
sort_needed_sym = sym;
break;
}
}
if (!sort_needed_sym) {
fprintf(stderr,
"no main_extable_sort_needed symbol in file: %s\n",
fname);
goto out;
}
sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
sort_needed_sym - symtab,
symtab_shndx)];
sort_needed_loc = (void *)ehdr +
_r(&sort_needed_sec->sh_offset) +
_r(&sort_needed_sym->st_value) -
_r(&sort_needed_sec->sh_addr);
/* extable has been sorted, clear the flag */
w(0, sort_needed_loc);
rc = 0;
out:
#if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
if (orc_sort_thread) {
void *retval = NULL;
/* wait for ORC tables sort done */
rc = pthread_join(orc_sort_thread, &retval);
if (rc) {
fprintf(stderr,
"pthread_join failed '%s': %s\n",
strerror(errno), fname);
} else if (retval) {
rc = -1;
fprintf(stderr,
"failed to sort ORC tables '%s': %s\n",
(char *)retval, fname);
}
}
#endif
#ifdef MCOUNT_SORT_ENABLED
if (mcount_sort_thread) {
void *retval = NULL;
/* wait for mcount sort done */
rc = pthread_join(mcount_sort_thread, &retval);
if (rc) {
fprintf(stderr,
"pthread_join failed '%s': %s\n",
strerror(errno), fname);
} else if (retval) {
rc = -1;
fprintf(stderr,
"failed to sort mcount '%s': %s\n",
(char *)retval, fname);
}
}
#endif
return rc;
}

View File

@ -11,7 +11,7 @@ obj-$(CONFIG_SECURITY) += lsm_syscalls.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
obj-$(CONFIG_SECURITY) += security.o
obj-$(CONFIG_SECURITY) += security.o lsm_notifier.o lsm_init.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/

View File

@ -2267,7 +2267,7 @@ alloc_out:
}
DEFINE_LSM(apparmor) = {
.name = "apparmor",
.id = &apparmor_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,

View File

@ -33,7 +33,7 @@ struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(bpf) = {
.name = "bpf",
.id = &bpf_lsmid,
.init = bpf_lsm_init,
.blobs = &bpf_lsm_blob_sizes
};

View File

@ -1470,7 +1470,7 @@ static int __init capability_init(void)
}
DEFINE_LSM(capability) = {
.name = "capability",
.id = &capability_lsmid,
.order = LSM_ORDER_FIRST,
.init = capability_init,
};

View File

@ -22,6 +22,8 @@
#include <linux/lsm_hooks.h>
#include <linux/magic.h>
#include "lsm.h"
static struct vfsmount *mount;
static int mount_count;
@ -339,12 +341,49 @@ void securityfs_recursive_remove(struct dentry *dentry)
EXPORT_SYMBOL_GPL(securityfs_recursive_remove);
#ifdef CONFIG_SECURITY
#include <linux/spinlock.h>
static struct dentry *lsm_dentry;
static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
loff_t *ppos)
{
return simple_read_from_buffer(buf, count, ppos, lsm_names,
strlen(lsm_names));
int i;
static char *str;
static size_t len;
static DEFINE_SPINLOCK(lock);
/* NOTE: we never free or modify the string once it is set */
if (unlikely(!str || !len)) {
char *str_tmp;
size_t len_tmp = 0;
for (i = 0; i < lsm_active_cnt; i++)
/* the '+ 1' accounts for either a comma or a NUL */
len_tmp += strlen(lsm_idlist[i]->name) + 1;
str_tmp = kmalloc(len_tmp, GFP_KERNEL);
if (!str_tmp)
return -ENOMEM;
str_tmp[0] = '\0';
for (i = 0; i < lsm_active_cnt; i++) {
if (i > 0)
strcat(str_tmp, ",");
strcat(str_tmp, lsm_idlist[i]->name);
}
spin_lock(&lock);
if (!str) {
str = str_tmp;
len = len_tmp - 1;
} else
kfree(str_tmp);
spin_unlock(&lock);
}
return simple_read_from_buffer(buf, count, ppos, str, len);
}
static const struct file_operations lsm_ops = {

View File

@ -1175,7 +1175,7 @@ struct lsm_blob_sizes evm_blob_sizes __ro_after_init = {
};
DEFINE_LSM(evm) = {
.name = "evm",
.id = &evm_lsmid,
.init = init_evm_lsm,
.order = LSM_ORDER_LAST,
.blobs = &evm_blob_sizes,

View File

@ -1222,7 +1222,7 @@ struct lsm_blob_sizes ima_blob_sizes __ro_after_init = {
};
DEFINE_LSM(ima) = {
.name = "ima",
.id = &ima_lsmid,
.init = init_ima_lsm,
.order = LSM_ORDER_LAST,
.blobs = &ima_blob_sizes,

View File

@ -92,7 +92,7 @@ static int __init ipe_init(void)
}
DEFINE_LSM(ipe) = {
.name = "ipe",
.id = &ipe_lsmid,
.init = ipe_init,
.blobs = &ipe_blobs,
};

View File

@ -43,7 +43,7 @@ static int __init landlock_init(void)
}
DEFINE_LSM(LANDLOCK_NAME) = {
.name = LANDLOCK_NAME,
.id = &landlock_lsmid,
.init = landlock_init,
.blobs = &landlock_blob_sizes,
};

View File

@ -271,7 +271,7 @@ static int __init loadpin_init(void)
}
DEFINE_LSM(loadpin) = {
.name = "loadpin",
.id = &loadpin_lsmid,
.init = loadpin_init,
};

View File

@ -169,6 +169,6 @@ DEFINE_EARLY_LSM(lockdown) = {
#else
DEFINE_LSM(lockdown) = {
#endif
.name = "lockdown",
.id = &lockdown_lsmid,
.init = lockdown_lsm_init,
};

39
security/lsm.h Normal file
View File

@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LSM functions
*/
#ifndef _LSM_H_
#define _LSM_H_
#include <linux/printk.h>
#include <linux/lsm_hooks.h>
#include <linux/lsm_count.h>
/* LSM debugging */
extern bool lsm_debug;
#define lsm_pr(...) pr_info(__VA_ARGS__)
#define lsm_pr_cont(...) pr_cont(__VA_ARGS__)
#define lsm_pr_dbg(...) \
do { \
if (lsm_debug) \
pr_info(__VA_ARGS__); \
} while (0)
/* List of configured LSMs */
extern unsigned int lsm_active_cnt;
extern const struct lsm_id *lsm_idlist[];
/* LSM blob configuration */
extern struct lsm_blob_sizes blob_sizes;
/* LSM blob caches */
extern struct kmem_cache *lsm_file_cache;
extern struct kmem_cache *lsm_backing_file_cache;
extern struct kmem_cache *lsm_inode_cache;
/* LSM blob allocators */
int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
int lsm_task_alloc(struct task_struct *task);
#endif /* _LSM_H_ */

454
security/lsm_init.c Normal file
View File

@ -0,0 +1,454 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LSM initialization functions
*/
#define pr_fmt(fmt) "LSM: " fmt
#include <linux/init.h>
#include <linux/lsm_hooks.h>
#include "lsm.h"
/* LSM enabled constants. */
static __initdata int lsm_enabled_true = 1;
static __initdata int lsm_enabled_false = 0;
/* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
/* Number of "early" LSMs */
static __initdata unsigned int lsm_count_early;
/* Build and boot-time LSM ordering. */
static __initconst const char *const lsm_order_builtin = CONFIG_LSM;
static __initdata const char *lsm_order_cmdline;
static __initdata const char *lsm_order_legacy;
/* Ordered list of LSMs to initialize. */
static __initdata struct lsm_info *lsm_order[MAX_LSM_COUNT + 1];
static __initdata struct lsm_info *lsm_exclusive;
#define lsm_order_for_each(iter) \
for ((iter) = lsm_order; *(iter); (iter)++)
#define lsm_for_each_raw(iter) \
for ((iter) = __start_lsm_info; \
(iter) < __end_lsm_info; (iter)++)
#define lsm_early_for_each_raw(iter) \
for ((iter) = __start_early_lsm_info; \
(iter) < __end_early_lsm_info; (iter)++)
/**
* lsm_choose_security - Legacy "major" LSM selection
* @str: kernel command line parameter
*/
static int __init lsm_choose_security(char *str)
{
lsm_order_legacy = str;
return 1;
}
__setup("security=", lsm_choose_security);
/**
* lsm_choose_lsm - Modern LSM selection
* @str: kernel command line parameter
*/
static int __init lsm_choose_lsm(char *str)
{
lsm_order_cmdline = str;
return 1;
}
__setup("lsm=", lsm_choose_lsm);
/**
* lsm_debug_enable - Enable LSM framework debugging
* @str: kernel command line parameter
*
* Currently we only provide debug info during LSM initialization, but we may
* want to expand this in the future.
*/
static int __init lsm_debug_enable(char *str)
{
lsm_debug = true;
return 1;
}
__setup("lsm.debug", lsm_debug_enable);
/**
* lsm_enabled_set - Mark a LSM as enabled
* @lsm: LSM definition
* @enabled: enabled flag
*/
static void __init lsm_enabled_set(struct lsm_info *lsm, bool enabled)
{
/*
* When an LSM hasn't configured an enable variable, we can use
* a hard-coded location for storing the default enabled state.
*/
if (!lsm->enabled ||
lsm->enabled == &lsm_enabled_true ||
lsm->enabled == &lsm_enabled_false) {
lsm->enabled = enabled ? &lsm_enabled_true : &lsm_enabled_false;
} else {
*lsm->enabled = enabled;
}
}
/**
* lsm_is_enabled - Determine if a LSM is enabled
* @lsm: LSM definition
*/
static inline bool lsm_is_enabled(struct lsm_info *lsm)
{
return (lsm->enabled ? *lsm->enabled : false);
}
/**
* lsm_order_exists - Determine if a LSM exists in the ordered list
* @lsm: LSM definition
*/
static bool __init lsm_order_exists(struct lsm_info *lsm)
{
struct lsm_info **check;
lsm_order_for_each(check) {
if (*check == lsm)
return true;
}
return false;
}
/**
* lsm_order_append - Append a LSM to the ordered list
* @lsm: LSM definition
* @src: source of the addition
*
* Append @lsm to the enabled LSM array after ensuring that it hasn't been
* explicitly disabled, is a duplicate entry, or would run afoul of the
* LSM_FLAG_EXCLUSIVE logic.
*/
static void __init lsm_order_append(struct lsm_info *lsm, const char *src)
{
/* Ignore duplicate selections. */
if (lsm_order_exists(lsm))
return;
/* Skip explicitly disabled LSMs. */
if (lsm->enabled && !lsm_is_enabled(lsm)) {
lsm_pr_dbg("skip previously disabled LSM %s:%s\n",
src, lsm->id->name);
return;
}
if (lsm_active_cnt == MAX_LSM_COUNT) {
pr_warn("exceeded maximum LSM count on %s:%s\n",
src, lsm->id->name);
lsm_enabled_set(lsm, false);
return;
}
if (lsm->flags & LSM_FLAG_EXCLUSIVE) {
if (lsm_exclusive) {
lsm_pr_dbg("skip exclusive LSM conflict %s:%s\n",
src, lsm->id->name);
lsm_enabled_set(lsm, false);
return;
} else {
lsm_pr_dbg("select exclusive LSM %s:%s\n",
src, lsm->id->name);
lsm_exclusive = lsm;
}
}
lsm_enabled_set(lsm, true);
lsm_order[lsm_active_cnt] = lsm;
lsm_idlist[lsm_active_cnt++] = lsm->id;
lsm_pr_dbg("enabling LSM %s:%s\n", src, lsm->id->name);
}
/**
* lsm_blob_size_update - Update the LSM blob size and offset information
* @sz_req: the requested additional blob size
* @sz_cur: the existing blob size
*/
static void __init lsm_blob_size_update(unsigned int *sz_req,
unsigned int *sz_cur)
{
unsigned int offset;
if (*sz_req == 0)
return;
offset = ALIGN(*sz_cur, sizeof(void *));
*sz_cur = offset + *sz_req;
*sz_req = offset;
}
/**
* lsm_prepare - Prepare the LSM framework for a new LSM
* @lsm: LSM definition
*/
static void __init lsm_prepare(struct lsm_info *lsm)
{
struct lsm_blob_sizes *blobs = lsm->blobs;
if (!blobs)
return;
/* Register the LSM blob sizes. */
blobs = lsm->blobs;
lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred);
lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file);
lsm_blob_size_update(&blobs->lbs_backing_file,
&blob_sizes.lbs_backing_file);
lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib);
/* inode blob gets an rcu_head in addition to LSM blobs. */
if (blobs->lbs_inode && blob_sizes.lbs_inode == 0)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
lsm_blob_size_update(&blobs->lbs_inode, &blob_sizes.lbs_inode);
lsm_blob_size_update(&blobs->lbs_ipc, &blob_sizes.lbs_ipc);
lsm_blob_size_update(&blobs->lbs_key, &blob_sizes.lbs_key);
lsm_blob_size_update(&blobs->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
lsm_blob_size_update(&blobs->lbs_perf_event,
&blob_sizes.lbs_perf_event);
lsm_blob_size_update(&blobs->lbs_sock, &blob_sizes.lbs_sock);
lsm_blob_size_update(&blobs->lbs_superblock,
&blob_sizes.lbs_superblock);
lsm_blob_size_update(&blobs->lbs_task, &blob_sizes.lbs_task);
lsm_blob_size_update(&blobs->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
lsm_blob_size_update(&blobs->lbs_xattr_count,
&blob_sizes.lbs_xattr_count);
lsm_blob_size_update(&blobs->lbs_bdev, &blob_sizes.lbs_bdev);
}
/**
* lsm_init_single - Initialize a given LSM
* @lsm: LSM definition
*/
static void __init lsm_init_single(struct lsm_info *lsm)
{
int ret;
if (!lsm_is_enabled(lsm))
return;
lsm_pr_dbg("initializing %s\n", lsm->id->name);
ret = lsm->init();
WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret);
}
/**
* lsm_order_parse - Parse the comma delimited LSM list
* @list: LSM list
* @src: source of the list
*/
static void __init lsm_order_parse(const char *list, const char *src)
{
struct lsm_info *lsm;
char *sep, *name, *next;
/* Handle any Legacy LSM exclusions if one was specified. */
if (lsm_order_legacy) {
/*
* To match the original "security=" behavior, this explicitly
* does NOT fallback to another Legacy Major if the selected
* one was separately disabled: disable all non-matching
* Legacy Major LSMs.
*/
lsm_for_each_raw(lsm) {
if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(lsm->id->name, lsm_order_legacy)) {
lsm_enabled_set(lsm, false);
lsm_pr_dbg("skip legacy LSM conflict %s:%s\n",
src, lsm->id->name);
}
}
}
/* LSM_ORDER_FIRST */
lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_FIRST)
lsm_order_append(lsm, "first");
}
/* Normal or "mutable" LSMs */
sep = kstrdup(list, GFP_KERNEL);
next = sep;
/* Walk the list, looking for matching LSMs. */
while ((name = strsep(&next, ",")) != NULL) {
lsm_for_each_raw(lsm) {
if (!strcmp(lsm->id->name, name) &&
lsm->order == LSM_ORDER_MUTABLE)
lsm_order_append(lsm, src);
}
}
kfree(sep);
/* Legacy LSM if specified. */
if (lsm_order_legacy) {
lsm_for_each_raw(lsm) {
if (!strcmp(lsm->id->name, lsm_order_legacy))
lsm_order_append(lsm, src);
}
}
/* LSM_ORDER_LAST */
lsm_for_each_raw(lsm) {
if (lsm->order == LSM_ORDER_LAST)
lsm_order_append(lsm, "last");
}
/* Disable all LSMs not previously enabled. */
lsm_for_each_raw(lsm) {
if (lsm_order_exists(lsm))
continue;
lsm_enabled_set(lsm, false);
lsm_pr_dbg("skip disabled LSM %s:%s\n", src, lsm->id->name);
}
}
/**
* lsm_static_call_init - Initialize a LSM's static calls
* @hl: LSM hook list
*/
static int __init lsm_static_call_init(struct security_hook_list *hl)
{
struct lsm_static_call *scall = hl->scalls;
int i;
for (i = 0; i < MAX_LSM_COUNT; i++) {
/* Update the first static call that is not used yet */
if (!scall->hl) {
__static_call_update(scall->key, scall->trampoline,
hl->hook.lsm_func_addr);
scall->hl = hl;
static_branch_enable(scall->active);
return 0;
}
scall++;
}
return -ENOSPC;
}
/**
* security_add_hooks - Add a LSM's hooks to the LSM framework's hook lists
* @hooks: LSM hooks to add
* @count: number of hooks to add
* @lsmid: identification information for the LSM
*
* Each LSM has to register its hooks with the LSM framework.
*/
void __init security_add_hooks(struct security_hook_list *hooks, int count,
const struct lsm_id *lsmid)
{
int i;
for (i = 0; i < count; i++) {
hooks[i].lsmid = lsmid;
if (lsm_static_call_init(&hooks[i]))
panic("exhausted LSM callback slots with LSM %s\n",
lsmid->name);
}
}
/**
* early_security_init - Initialize the early LSMs
*/
int __init early_security_init(void)
{
struct lsm_info *lsm;
static bool early_security_initialized;
if (early_security_initialized)
return 0;
lsm_early_for_each_raw(lsm) {
lsm_enabled_set(lsm, true);
lsm_order_append(lsm, "early");
lsm_prepare(lsm);
lsm_init_single(lsm);
lsm_count_early++;
}
early_security_initialized = true;
return 0;
}
/**
* security_init - Initializes the LSM framework
*
* This should be called early in the kernel initialization sequence.
*/
int __init security_init(void)
{
unsigned int cnt;
struct lsm_info **lsm;
if (lsm_debug) {
lsm_pr("built-in LSM list: %s\n", lsm_order_builtin);
lsm_pr("legacy LSM parameter: %s\n", lsm_order_legacy);
lsm_pr("boot LSM parameter: %s\n", lsm_order_cmdline);
}
if (lsm_order_cmdline) {
if (lsm_order_legacy)
lsm_order_legacy = NULL;
lsm_order_parse(lsm_order_cmdline, "cmdline");
} else
lsm_order_parse(lsm_order_builtin, "builtin");
lsm_order_for_each(lsm)
lsm_prepare(*lsm);
if (lsm_debug) {
lsm_pr("blob(cred) size %d\n", blob_sizes.lbs_cred);
lsm_pr("blob(file) size %d\n", blob_sizes.lbs_file);
lsm_pr("blob(backing_file) size %d\n",
blob_sizes.lbs_backing_file);
lsm_pr("blob(ib) size %d\n", blob_sizes.lbs_ib);
lsm_pr("blob(inode) size %d\n", blob_sizes.lbs_inode);
lsm_pr("blob(ipc) size %d\n", blob_sizes.lbs_ipc);
lsm_pr("blob(key) size %d\n", blob_sizes.lbs_key);
lsm_pr("blob(msg_msg)_size %d\n", blob_sizes.lbs_msg_msg);
lsm_pr("blob(sock) size %d\n", blob_sizes.lbs_sock);
lsm_pr("blob(superblock) size %d\n", blob_sizes.lbs_superblock);
lsm_pr("blob(perf_event) size %d\n", blob_sizes.lbs_perf_event);
lsm_pr("blob(task) size %d\n", blob_sizes.lbs_task);
lsm_pr("blob(tun_dev) size %d\n", blob_sizes.lbs_tun_dev);
lsm_pr("blob(xattr) count %d\n", blob_sizes.lbs_xattr_count);
lsm_pr("blob(bdev) size %d\n", blob_sizes.lbs_bdev);
}
if (blob_sizes.lbs_file)
lsm_file_cache = kmem_cache_create("lsm_file_cache",
blob_sizes.lbs_file, 0,
SLAB_PANIC, NULL);
if (blob_sizes.lbs_backing_file)
lsm_backing_file_cache = kmem_cache_create(
"lsm_backing_file_cache",
blob_sizes.lbs_backing_file,
0, SLAB_PANIC, NULL);
if (blob_sizes.lbs_inode)
lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
blob_sizes.lbs_inode, 0,
SLAB_PANIC, NULL);
if (lsm_cred_alloc((struct cred __rcu *)current->cred, GFP_KERNEL))
panic("early LSM cred alloc failed\n");
if (lsm_task_alloc(current))
panic("early LSM task alloc failed\n");
cnt = 0;
lsm_order_for_each(lsm) {
/* skip the "early" LSMs as they have already been setup */
if (cnt++ < lsm_count_early)
continue;
lsm_init_single(*lsm);
}
return 0;
}

31
security/lsm_notifier.c Normal file
View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LSM notifier functions
*
*/
#include <linux/notifier.h>
#include <linux/security.h>
static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
int call_blocking_lsm_notifier(enum lsm_event event, void *data)
{
return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
event, data);
}
EXPORT_SYMBOL(call_blocking_lsm_notifier);
int register_blocking_lsm_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
nb);
}
EXPORT_SYMBOL(register_blocking_lsm_notifier);
int unregister_blocking_lsm_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
nb);
}
EXPORT_SYMBOL(unregister_blocking_lsm_notifier);

View File

@ -17,6 +17,8 @@
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>
#include "lsm.h"
/**
* lsm_name_to_attr - map an LSM attribute name to its ID
* @name: name of the attribute

View File

@ -287,6 +287,6 @@ static int __init safesetid_security_init(void)
}
DEFINE_LSM(safesetid_security_init) = {
.id = &safesetid_lsmid,
.init = safesetid_security_init,
.name = "safesetid",
};

View File

@ -33,24 +33,7 @@
#include <net/flow.h>
#include <net/sock.h>
#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
/*
* Identifier for the LSM static calls.
* HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
* IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
*/
#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
/*
* Call the macro M for each LSM hook MAX_LSM_COUNT times.
*/
#define LSM_LOOP_UNROLL(M, ...) \
do { \
UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) \
} while (0)
#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
#include "lsm.h"
/*
* These are descriptions of the reasons that can be passed to the
@ -91,23 +74,35 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
bool lsm_debug __ro_after_init;
static struct kmem_cache *lsm_file_cache;
static struct kmem_cache *lsm_inode_cache;
unsigned int lsm_active_cnt __ro_after_init;
const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
char *lsm_names;
static struct lsm_blob_sizes blob_sizes __ro_after_init;
struct lsm_blob_sizes blob_sizes;
/* Boot-time LSM user choice */
static __initdata const char *chosen_lsm_order;
static __initdata const char *chosen_major_lsm;
struct kmem_cache *lsm_file_cache;
struct kmem_cache *lsm_backing_file_cache;
struct kmem_cache *lsm_inode_cache;
static __initconst const char *const builtin_lsm_order = CONFIG_LSM;
#define SECURITY_HOOK_ACTIVE_KEY(HOOK, IDX) security_hook_active_##HOOK##_##IDX
/* Ordered list of LSMs to initialize. */
static __initdata struct lsm_info *ordered_lsms[MAX_LSM_COUNT + 1];
static __initdata struct lsm_info *exclusive;
/*
* Identifier for the LSM static calls.
* HOOK is an LSM hook as defined in linux/lsm_hookdefs.h
* IDX is the index of the static call. 0 <= NUM < MAX_LSM_COUNT
*/
#define LSM_STATIC_CALL(HOOK, IDX) lsm_static_call_##HOOK##_##IDX
/*
* Call the macro M for each LSM hook MAX_LSM_COUNT times.
*/
#define LSM_LOOP_UNROLL(M, ...) \
do { \
UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__) \
} while (0)
#define LSM_DEFINE_UNROLL(M, ...) UNROLL(MAX_LSM_COUNT, M, __VA_ARGS__)
#ifdef CONFIG_HAVE_STATIC_CALL
#define LSM_HOOK_TRAMP(NAME, NUM) \
@ -158,518 +153,51 @@ struct lsm_static_calls_table
#undef INIT_LSM_STATIC_CALL
};
static __initdata bool debug;
#define init_debug(...) \
do { \
if (debug) \
pr_info(__VA_ARGS__); \
} while (0)
static bool __init is_enabled(struct lsm_info *lsm)
{
if (!lsm->enabled)
return false;
return *lsm->enabled;
}
/* Mark an LSM's enabled flag. */
static int lsm_enabled_true __initdata = 1;
static int lsm_enabled_false __initdata = 0;
static void __init set_enabled(struct lsm_info *lsm, bool enabled)
{
/*
* When an LSM hasn't configured an enable variable, we can use
* a hard-coded location for storing the default enabled state.
*/
if (!lsm->enabled) {
if (enabled)
lsm->enabled = &lsm_enabled_true;
else
lsm->enabled = &lsm_enabled_false;
} else if (lsm->enabled == &lsm_enabled_true) {
if (!enabled)
lsm->enabled = &lsm_enabled_false;
} else if (lsm->enabled == &lsm_enabled_false) {
if (enabled)
lsm->enabled = &lsm_enabled_true;
} else {
*lsm->enabled = enabled;
}
}
/* Is an LSM already listed in the ordered LSMs list? */
static bool __init exists_ordered_lsm(struct lsm_info *lsm)
{
struct lsm_info **check;
for (check = ordered_lsms; *check; check++)
if (*check == lsm)
return true;
return false;
}
/* Append an LSM to the list of ordered LSMs to initialize. */
static int last_lsm __initdata;
static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
{
/* Ignore duplicate selections. */
if (exists_ordered_lsm(lsm))
return;
if (WARN(last_lsm == MAX_LSM_COUNT, "%s: out of LSM static calls!?\n", from))
return;
/* Enable this LSM, if it is not already set. */
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
ordered_lsms[last_lsm++] = lsm;
init_debug("%s ordered: %s (%s)\n", from, lsm->name,
is_enabled(lsm) ? "enabled" : "disabled");
}
/* Is an LSM allowed to be initialized? */
static bool __init lsm_allowed(struct lsm_info *lsm)
{
/* Skip if the LSM is disabled. */
if (!is_enabled(lsm))
return false;
/* Not allowed if another exclusive LSM already initialized. */
if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
init_debug("exclusive disabled: %s\n", lsm->name);
return false;
}
return true;
}
static void __init lsm_set_blob_size(int *need, int *lbs)
{
int offset;
if (*need <= 0)
return;
offset = ALIGN(*lbs, sizeof(void *));
*lbs = offset + *need;
*need = offset;
}
static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
{
if (!needed)
return;
lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
lsm_set_blob_size(&needed->lbs_ib, &blob_sizes.lbs_ib);
/*
* The inode blob gets an rcu_head in addition to
* what the modules might need.
*/
if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
lsm_set_blob_size(&needed->lbs_key, &blob_sizes.lbs_key);
lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
lsm_set_blob_size(&needed->lbs_perf_event, &blob_sizes.lbs_perf_event);
lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
lsm_set_blob_size(&needed->lbs_tun_dev, &blob_sizes.lbs_tun_dev);
lsm_set_blob_size(&needed->lbs_xattr_count,
&blob_sizes.lbs_xattr_count);
lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
}
/* Prepare LSM for initialization. */
static void __init prepare_lsm(struct lsm_info *lsm)
{
int enabled = lsm_allowed(lsm);
/* Record enablement (to handle any following exclusive LSMs). */
set_enabled(lsm, enabled);
/* If enabled, do pre-initialization work. */
if (enabled) {
if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
exclusive = lsm;
init_debug("exclusive chosen: %s\n", lsm->name);
}
lsm_set_blob_sizes(lsm->blobs);
}
}
/* Initialize a given LSM, if it is enabled. */
static void __init initialize_lsm(struct lsm_info *lsm)
{
if (is_enabled(lsm)) {
int ret;
init_debug("initializing %s\n", lsm->name);
ret = lsm->init();
WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
}
}
/*
* Current index to use while initializing the lsm id list.
/**
* lsm_file_alloc - allocate a composite file blob
* @file: the file that needs a blob
*
* Allocate the file blob for all the modules
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
u32 lsm_active_cnt __ro_after_init;
const struct lsm_id *lsm_idlist[MAX_LSM_COUNT];
/* Populate ordered LSMs list from comma-separated LSM name list. */
static void __init ordered_lsm_parse(const char *order, const char *origin)
static int lsm_file_alloc(struct file *file)
{
struct lsm_info *lsm;
char *sep, *name, *next;
/* LSM_ORDER_FIRST is always first. */
for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
if (lsm->order == LSM_ORDER_FIRST)
append_ordered_lsm(lsm, " first");
}
/* Process "security=", if given. */
if (chosen_major_lsm) {
struct lsm_info *major;
/*
* To match the original "security=" behavior, this
* explicitly does NOT fallback to another Legacy Major
* if the selected one was separately disabled: disable
* all non-matching Legacy Major LSMs.
*/
for (major = __start_lsm_info; major < __end_lsm_info;
major++) {
if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
strcmp(major->name, chosen_major_lsm) != 0) {
set_enabled(major, false);
init_debug("security=%s disabled: %s (only one legacy major LSM)\n",
chosen_major_lsm, major->name);
}
}
}
sep = kstrdup(order, GFP_KERNEL);
next = sep;
/* Walk the list, looking for matching LSMs. */
while ((name = strsep(&next, ",")) != NULL) {
bool found = false;
for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
if (strcmp(lsm->name, name) == 0) {
if (lsm->order == LSM_ORDER_MUTABLE)
append_ordered_lsm(lsm, origin);
found = true;
}
}
if (!found)
init_debug("%s ignored: %s (not built into kernel)\n",
origin, name);
}
/* Process "security=", if given. */
if (chosen_major_lsm) {
for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
if (exists_ordered_lsm(lsm))
continue;
if (strcmp(lsm->name, chosen_major_lsm) == 0)
append_ordered_lsm(lsm, "security=");
}
}
/* LSM_ORDER_LAST is always last. */
for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
if (lsm->order == LSM_ORDER_LAST)
append_ordered_lsm(lsm, " last");
}
/* Disable all LSMs not in the ordered list. */
for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
if (exists_ordered_lsm(lsm))
continue;
set_enabled(lsm, false);
init_debug("%s skipped: %s (not in requested order)\n",
origin, lsm->name);
}
kfree(sep);
}
static void __init lsm_static_call_init(struct security_hook_list *hl)
{
struct lsm_static_call *scall = hl->scalls;
int i;
for (i = 0; i < MAX_LSM_COUNT; i++) {
/* Update the first static call that is not used yet */
if (!scall->hl) {
__static_call_update(scall->key, scall->trampoline,
hl->hook.lsm_func_addr);
scall->hl = hl;
static_branch_enable(scall->active);
return;
}
scall++;
}
panic("%s - Ran out of static slots.\n", __func__);
}
static void __init lsm_early_cred(struct cred *cred);
static void __init lsm_early_task(struct task_struct *task);
static int lsm_append(const char *new, char **result);
static void __init report_lsm_order(void)
{
struct lsm_info **lsm, *early;
int first = 0;
pr_info("initializing lsm=");
/* Report each enabled LSM name, comma separated. */
for (early = __start_early_lsm_info;
early < __end_early_lsm_info; early++)
if (is_enabled(early))
pr_cont("%s%s", first++ == 0 ? "" : ",", early->name);
for (lsm = ordered_lsms; *lsm; lsm++)
if (is_enabled(*lsm))
pr_cont("%s%s", first++ == 0 ? "" : ",", (*lsm)->name);
pr_cont("\n");
}
static void __init ordered_lsm_init(void)
{
struct lsm_info **lsm;
if (chosen_lsm_order) {
if (chosen_major_lsm) {
pr_warn("security=%s is ignored because it is superseded by lsm=%s\n",
chosen_major_lsm, chosen_lsm_order);
chosen_major_lsm = NULL;
}
ordered_lsm_parse(chosen_lsm_order, "cmdline");
} else
ordered_lsm_parse(builtin_lsm_order, "builtin");
for (lsm = ordered_lsms; *lsm; lsm++)
prepare_lsm(*lsm);
report_lsm_order();
init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
init_debug("file blob size = %d\n", blob_sizes.lbs_file);
init_debug("ib blob size = %d\n", blob_sizes.lbs_ib);
init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
#ifdef CONFIG_KEYS
init_debug("key blob size = %d\n", blob_sizes.lbs_key);
#endif /* CONFIG_KEYS */
init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
init_debug("sock blob size = %d\n", blob_sizes.lbs_sock);
init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
init_debug("perf event blob size = %d\n", blob_sizes.lbs_perf_event);
init_debug("task blob size = %d\n", blob_sizes.lbs_task);
init_debug("tun device blob size = %d\n", blob_sizes.lbs_tun_dev);
init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);
/*
* Create any kmem_caches needed for blobs
*/
if (blob_sizes.lbs_file)
lsm_file_cache = kmem_cache_create("lsm_file_cache",
blob_sizes.lbs_file, 0,
SLAB_PANIC, NULL);
if (blob_sizes.lbs_inode)
lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
blob_sizes.lbs_inode, 0,
SLAB_PANIC, NULL);
lsm_early_cred((struct cred *) current->cred);
lsm_early_task(current);
for (lsm = ordered_lsms; *lsm; lsm++)
initialize_lsm(*lsm);
}
int __init early_security_init(void)
{
struct lsm_info *lsm;
static bool early_security_initialized;
if (early_security_initialized)
if (!lsm_file_cache) {
file->f_security = NULL;
return 0;
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
if (!lsm->enabled)
lsm->enabled = &lsm_enabled_true;
prepare_lsm(lsm);
initialize_lsm(lsm);
}
early_security_initialized = true;
file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
if (file->f_security == NULL)
return -ENOMEM;
return 0;
}
/**
* security_init - initializes the security framework
* lsm_backing_file_alloc - allocate a composite backing file blob
* @backing_file: the backing file
*
* This should be called early in the kernel initialization sequence.
* Allocate the backing file blob for all the modules.
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
int __init security_init(void)
static int lsm_backing_file_alloc(struct file *backing_file)
{
struct lsm_info *lsm;
void *blob;
init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*");
init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order);
init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*");
/*
* Append the names of the early LSM modules now that kmalloc() is
* available
*/
for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) {
init_debug(" early started: %s (%s)\n", lsm->name,
is_enabled(lsm) ? "enabled" : "disabled");
if (lsm->enabled)
lsm_append(lsm->name, &lsm_names);
if (!lsm_backing_file_cache) {
backing_file_set_security(backing_file, NULL);
return 0;
}
/* Load LSMs in specified order. */
ordered_lsm_init();
blob = kmem_cache_zalloc(lsm_backing_file_cache, GFP_KERNEL);
backing_file_set_security(backing_file, blob);
if (!blob)
return -ENOMEM;
return 0;
}
/* Save user chosen LSM */
static int __init choose_major_lsm(char *str)
{
chosen_major_lsm = str;
return 1;
}
__setup("security=", choose_major_lsm);
/* Explicitly choose LSM initialization order. */
static int __init choose_lsm_order(char *str)
{
chosen_lsm_order = str;
return 1;
}
__setup("lsm=", choose_lsm_order);
/* Enable LSM order debugging. */
static int __init enable_debug(char *str)
{
debug = true;
return 1;
}
__setup("lsm.debug", enable_debug);
static bool match_last_lsm(const char *list, const char *lsm)
{
const char *last;
if (WARN_ON(!list || !lsm))
return false;
last = strrchr(list, ',');
if (last)
/* Pass the comma, strcmp() will check for '\0' */
last++;
else
last = list;
return !strcmp(last, lsm);
}
static int lsm_append(const char *new, char **result)
{
char *cp;
if (*result == NULL) {
*result = kstrdup(new, GFP_KERNEL);
if (*result == NULL)
return -ENOMEM;
} else {
/* Check if it is the last registered name */
if (match_last_lsm(*result, new))
return 0;
cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
if (cp == NULL)
return -ENOMEM;
kfree(*result);
*result = cp;
}
return 0;
}
/**
* security_add_hooks - Add a modules hooks to the hook lists.
* @hooks: the hooks to add
* @count: the number of hooks to add
* @lsmid: the identification information for the security module
*
* Each LSM has to register its hooks with the infrastructure.
*/
void __init security_add_hooks(struct security_hook_list *hooks, int count,
const struct lsm_id *lsmid)
{
int i;
/*
* A security module may call security_add_hooks() more
* than once during initialization, and LSM initialization
* is serialized. Landlock is one such case.
* Look at the previous entry, if there is one, for duplication.
*/
if (lsm_active_cnt == 0 || lsm_idlist[lsm_active_cnt - 1] != lsmid) {
if (lsm_active_cnt >= MAX_LSM_COUNT)
panic("%s Too many LSMs registered.\n", __func__);
lsm_idlist[lsm_active_cnt++] = lsmid;
}
for (i = 0; i < count; i++) {
hooks[i].lsmid = lsmid;
lsm_static_call_init(&hooks[i]);
}
/*
* Don't try to append during early_security_init(), we'll come back
* and fix this up afterwards.
*/
if (slab_is_available()) {
if (lsm_append(lsmid->name, &lsm_names) < 0)
panic("%s - Cannot get early memory.\n", __func__);
}
}
int call_blocking_lsm_notifier(enum lsm_event event, void *data)
{
return blocking_notifier_call_chain(&blocking_lsm_notifier_chain,
event, data);
}
EXPORT_SYMBOL(call_blocking_lsm_notifier);
int register_blocking_lsm_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&blocking_lsm_notifier_chain,
nb);
}
EXPORT_SYMBOL(register_blocking_lsm_notifier);
int unregister_blocking_lsm_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&blocking_lsm_notifier_chain,
nb);
}
EXPORT_SYMBOL(unregister_blocking_lsm_notifier);
/**
* lsm_blob_alloc - allocate a composite blob
* @dest: the destination for the blob
@ -702,46 +230,11 @@ static int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
{
return lsm_blob_alloc(&cred->security, blob_sizes.lbs_cred, gfp);
}
/**
* lsm_early_cred - during initialization allocate a composite cred blob
* @cred: the cred that needs a blob
*
* Allocate the cred blob for all the modules
*/
static void __init lsm_early_cred(struct cred *cred)
{
int rc = lsm_cred_alloc(cred, GFP_KERNEL);
if (rc)
panic("%s: Early cred alloc failed.\n", __func__);
}
/**
* lsm_file_alloc - allocate a composite file blob
* @file: the file that needs a blob
*
* Allocate the file blob for all the modules
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
static int lsm_file_alloc(struct file *file)
{
if (!lsm_file_cache) {
file->f_security = NULL;
return 0;
}
file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
if (file->f_security == NULL)
return -ENOMEM;
return 0;
}
/**
* lsm_inode_alloc - allocate a composite inode blob
* @inode: the inode that needs a blob
@ -772,7 +265,7 @@ static int lsm_inode_alloc(struct inode *inode, gfp_t gfp)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
static int lsm_task_alloc(struct task_struct *task)
int lsm_task_alloc(struct task_struct *task)
{
return lsm_blob_alloc(&task->security, blob_sizes.lbs_task, GFP_KERNEL);
}
@ -841,20 +334,6 @@ static int lsm_bdev_alloc(struct block_device *bdev)
return 0;
}
/**
* lsm_early_task - during initialization allocate a composite task blob
* @task: the task that needs a blob
*
* Allocate the task blob for all the modules
*/
static void __init lsm_early_task(struct task_struct *task)
{
int rc = lsm_task_alloc(task);
if (rc)
panic("%s: Early task alloc failed.\n", __func__);
}
/**
* lsm_superblock_alloc - allocate a composite superblock blob
* @sb: the superblock that needs a blob
@ -2897,6 +2376,57 @@ void security_file_free(struct file *file)
}
}
/**
* security_backing_file_alloc() - Allocate and setup a backing file blob
* @backing_file: the backing file
* @user_file: the associated user visible file
*
* Allocate a backing file LSM blob and perform any necessary initialization of
* the LSM blob. There will be some operations where the LSM will not have
* access to @user_file after this point, so any important state associated
* with @user_file that is important to the LSM should be captured in the
* backing file's LSM blob.
*
* LSM's should avoid taking a reference to @user_file in this hook as it will
* result in problems later when the system attempts to drop/put the file
* references due to a circular dependency.
*
* Return: Return 0 if the hook is successful, negative values otherwise.
*/
int security_backing_file_alloc(struct file *backing_file,
const struct file *user_file)
{
int rc;
rc = lsm_backing_file_alloc(backing_file);
if (rc)
return rc;
rc = call_int_hook(backing_file_alloc, backing_file, user_file);
if (unlikely(rc))
security_backing_file_free(backing_file);
return rc;
}
/**
* security_backing_file_free() - Free a backing file blob
* @backing_file: the backing file
*
* Free any LSM state associate with a backing file's LSM blob, including the
* blob itself.
*/
void security_backing_file_free(struct file *backing_file)
{
void *blob = backing_file_security(backing_file);
call_void_hook(backing_file_free, backing_file);
if (blob) {
backing_file_set_security(backing_file, NULL);
kmem_cache_free(lsm_backing_file_cache, blob);
}
}
/**
* security_file_ioctl() - Check if an ioctl is allowed
* @file: associated file
@ -2985,6 +2515,32 @@ int security_mmap_file(struct file *file, unsigned long prot,
flags);
}
/**
* security_mmap_backing_file - Check if mmap'ing a backing file is allowed
* @vma: the vm_area_struct for the mmap'd region
* @backing_file: the backing file being mmap'd
* @user_file: the user file being mmap'd
*
* Check permissions for a mmap operation on a stacked filesystem. This hook
* is called after the security_mmap_file() and is responsible for authorizing
* the mmap on @backing_file. It is important to note that the mmap operation
* on @user_file has already been authorized and the @vma->vm_file has been
* set to @backing_file.
*
* Return: Returns 0 if permission is granted.
*/
int security_mmap_backing_file(struct vm_area_struct *vma,
struct file *backing_file,
struct file *user_file)
{
/* recommended by the stackable filesystem devs */
if (WARN_ON_ONCE(!(backing_file->f_mode & FMODE_BACKING)))
return -EIO;
return call_int_hook(mmap_backing_file, vma, backing_file, user_file);
}
EXPORT_SYMBOL_GPL(security_mmap_backing_file);
/**
* security_mmap_addr() - Check if mmap'ing an address is allowed
* @addr: address

View File

@ -1724,6 +1724,60 @@ static inline int file_path_has_perm(const struct cred *cred,
static int bpf_fd_pass(const struct file *file, u32 sid);
#endif
static int __file_has_perm(const struct cred *cred, const struct file *file,
u32 av, bool bf_user_file)
{
struct common_audit_data ad;
struct inode *inode;
u32 ssid = cred_sid(cred);
u32 tsid_fd;
int rc;
if (bf_user_file) {
struct backing_file_security_struct *bfsec;
const struct path *path;
if (WARN_ON(!(file->f_mode & FMODE_BACKING)))
return -EIO;
bfsec = selinux_backing_file(file);
path = backing_file_user_path(file);
tsid_fd = bfsec->uf_sid;
inode = d_inode(path->dentry);
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = *path;
} else {
struct file_security_struct *fsec = selinux_file(file);
tsid_fd = fsec->sid;
inode = file_inode(file);
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
}
if (ssid != tsid_fd) {
rc = avc_has_perm(ssid, tsid_fd, SECCLASS_FD, FD__USE, &ad);
if (rc)
return rc;
}
#ifdef CONFIG_BPF_SYSCALL
/* regardless of backing vs user file, use the underlying file here */
rc = bpf_fd_pass(file, ssid);
if (rc)
return rc;
#endif
/* av is zero if only checking access to the descriptor. */
if (av)
return inode_has_perm(cred, inode, av, &ad);
return 0;
}
/* Check whether a task can use an open file descriptor to
access an inode in a given way. Check access to the
descriptor itself, and then use dentry_has_perm to
@ -1732,41 +1786,10 @@ static int bpf_fd_pass(const struct file *file, u32 sid);
has the same SID as the process. If av is zero, then
access to the file is not checked, e.g. for cases
where only the descriptor is affected like seek. */
static int file_has_perm(const struct cred *cred,
struct file *file,
u32 av)
static inline int file_has_perm(const struct cred *cred,
const struct file *file, u32 av)
{
struct file_security_struct *fsec = selinux_file(file);
struct inode *inode = file_inode(file);
struct common_audit_data ad;
u32 sid = cred_sid(cred);
int rc;
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
if (rc)
goto out;
}
#ifdef CONFIG_BPF_SYSCALL
rc = bpf_fd_pass(file, cred_sid(cred));
if (rc)
return rc;
#endif
/* av is zero if only checking access to the descriptor. */
rc = 0;
if (av)
rc = inode_has_perm(cred, inode, av, &ad);
out:
return rc;
return __file_has_perm(cred, file, av, false);
}
/*
@ -3655,6 +3678,17 @@ static int selinux_file_alloc_security(struct file *file)
return 0;
}
static int selinux_backing_file_alloc(struct file *backing_file,
const struct file *user_file)
{
struct backing_file_security_struct *bfsec;
bfsec = selinux_backing_file(backing_file);
bfsec->uf_sid = selinux_file(user_file)->sid;
return 0;
}
/*
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
@ -3772,42 +3806,55 @@ static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd,
static int default_noexec __ro_after_init;
static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
static int __file_map_prot_check(const struct cred *cred,
const struct file *file, unsigned long prot,
bool shared, bool bf_user_file)
{
const struct cred *cred = current_cred();
u32 sid = cred_sid(cred);
int rc = 0;
struct inode *inode = NULL;
bool prot_exec = prot & PROT_EXEC;
bool prot_write = prot & PROT_WRITE;
if (file) {
if (bf_user_file)
inode = d_inode(backing_file_user_path(file)->dentry);
else
inode = file_inode(file);
}
if (default_noexec && prot_exec &&
(!file || IS_PRIVATE(inode) || (!shared && prot_write))) {
int rc;
u32 sid = cred_sid(cred);
if (default_noexec &&
(prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
(!shared && (prot & PROT_WRITE)))) {
/*
* We are making executable an anonymous mapping or a
* private file mapping that will also be writable.
* This has an additional check.
* We are making executable an anonymous mapping or a private
* file mapping that will also be writable.
*/
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECMEM, NULL);
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__EXECMEM,
NULL);
if (rc)
goto error;
return rc;
}
if (file) {
/* read access is always possible with a mapping */
/* "read" always possible, "write" only if shared */
u32 av = FILE__READ;
/* write access only matters if the mapping is shared */
if (shared && (prot & PROT_WRITE))
if (shared && prot_write)
av |= FILE__WRITE;
if (prot & PROT_EXEC)
if (prot_exec)
av |= FILE__EXECUTE;
return file_has_perm(cred, file, av);
return __file_has_perm(cred, file, av, bf_user_file);
}
error:
return rc;
return 0;
}
static inline int file_map_prot_check(const struct cred *cred,
const struct file *file,
unsigned long prot, bool shared)
{
return __file_map_prot_check(cred, file, prot, shared, false);
}
static int selinux_mmap_addr(unsigned long addr)
@ -3823,36 +3870,80 @@ static int selinux_mmap_addr(unsigned long addr)
return rc;
}
static int selinux_mmap_file(struct file *file,
unsigned long reqprot __always_unused,
unsigned long prot, unsigned long flags)
static int selinux_mmap_file_common(const struct cred *cred, struct file *file,
unsigned long prot, bool shared)
{
struct common_audit_data ad;
int rc;
if (file) {
int rc;
struct common_audit_data ad;
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
rc = inode_has_perm(current_cred(), file_inode(file),
FILE__MAP, &ad);
rc = inode_has_perm(cred, file_inode(file), FILE__MAP, &ad);
if (rc)
return rc;
}
return file_map_prot_check(file, prot,
(flags & MAP_TYPE) == MAP_SHARED);
return file_map_prot_check(cred, file, prot, shared);
}
static int selinux_mmap_file(struct file *file,
unsigned long reqprot __always_unused,
unsigned long prot, unsigned long flags)
{
return selinux_mmap_file_common(current_cred(), file, prot,
(flags & MAP_TYPE) == MAP_SHARED);
}
/**
* selinux_mmap_backing_file - Check mmap permissions on a backing file
* @vma: memory region
* @backing_file: stacked filesystem backing file
* @user_file: user visible file
*
* This is called after selinux_mmap_file() on stacked filesystems, and it
* is this function's responsibility to verify access to @backing_file and
* setup the SELinux state for possible later use in the mprotect() code path.
*
* By the time this function is called, mmap() access to @user_file has already
* been authorized and @vma->vm_file has been set to point to @backing_file.
*
* Return zero on success, negative values otherwise.
*/
static int selinux_mmap_backing_file(struct vm_area_struct *vma,
struct file *backing_file,
struct file *user_file __always_unused)
{
unsigned long prot = 0;
/* translate vma->vm_flags perms into PROT perms */
if (vma->vm_flags & VM_READ)
prot |= PROT_READ;
if (vma->vm_flags & VM_WRITE)
prot |= PROT_WRITE;
if (vma->vm_flags & VM_EXEC)
prot |= PROT_EXEC;
return selinux_mmap_file_common(backing_file->f_cred, backing_file,
prot, vma->vm_flags & VM_SHARED);
}
static int selinux_file_mprotect(struct vm_area_struct *vma,
unsigned long reqprot __always_unused,
unsigned long prot)
{
int rc;
const struct cred *cred = current_cred();
u32 sid = cred_sid(cred);
const struct file *file = vma->vm_file;
bool backing_file;
bool shared = vma->vm_flags & VM_SHARED;
/* check if we need to trigger the "backing files are awful" mode */
backing_file = file && (file->f_mode & FMODE_BACKING);
if (default_noexec &&
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
int rc = 0;
/*
* We don't use the vma_is_initial_heap() helper as it has
* a history of problems and is currently broken on systems
@ -3866,11 +3957,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
vma->vm_end <= vma->vm_mm->brk) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
if (rc)
return rc;
} else if (!file && (vma_is_initial_stack(vma) ||
vma_is_stack_for_current(vma))) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL);
} else if (vma->vm_file && vma->anon_vma) {
if (rc)
return rc;
} else if (file && vma->anon_vma) {
/*
* We are making executable a file mapping that has
* had some COW done. Since pages might have been
@ -3878,13 +3973,29 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
* modified content. This typically should only
* occur for text relocations.
*/
rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
rc = __file_has_perm(cred, file, FILE__EXECMOD,
backing_file);
if (rc)
return rc;
if (backing_file) {
rc = file_has_perm(file->f_cred, file,
FILE__EXECMOD);
if (rc)
return rc;
}
}
}
rc = __file_map_prot_check(cred, file, prot, shared, backing_file);
if (rc)
return rc;
if (backing_file) {
rc = file_map_prot_check(file->f_cred, file, prot, shared);
if (rc)
return rc;
}
return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
return 0;
}
static int selinux_file_lock(struct file *file, unsigned int cmd)
@ -6963,6 +7074,7 @@ static void selinux_bpf_token_free(struct bpf_token *token)
struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_cred = sizeof(struct task_security_struct),
.lbs_file = sizeof(struct file_security_struct),
.lbs_backing_file = sizeof(struct backing_file_security_struct),
.lbs_inode = sizeof(struct inode_security_struct),
.lbs_ipc = sizeof(struct ipc_security_struct),
.lbs_key = sizeof(struct key_security_struct),
@ -7168,9 +7280,11 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
LSM_HOOK_INIT(backing_file_alloc, selinux_backing_file_alloc),
LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
LSM_HOOK_INIT(mmap_backing_file, selinux_mmap_backing_file),
LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
LSM_HOOK_INIT(file_lock, selinux_file_lock),
@ -7440,7 +7554,7 @@ void selinux_complete_init(void)
/* SELinux requires early initialization in order to label
all processes and objects when they are created. */
DEFINE_LSM(selinux) = {
.name = "selinux",
.id = &selinux_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &selinux_enabled_boot,
.blobs = &selinux_blob_sizes,

View File

@ -61,6 +61,10 @@ struct file_security_struct {
u32 pseqno; /* Policy seqno at the time of file open */
};
struct backing_file_security_struct {
u32 uf_sid; /* associated user file fsec->sid */
};
struct superblock_security_struct {
u32 sid; /* SID of file system superblock */
u32 def_sid; /* default SID for labeling */
@ -159,6 +163,13 @@ static inline struct file_security_struct *selinux_file(const struct file *file)
return file->f_security + selinux_blob_sizes.lbs_file;
}
static inline struct backing_file_security_struct *
selinux_backing_file(const struct file *backing_file)
{
void *blob = backing_file_security(backing_file);
return blob + selinux_blob_sizes.lbs_backing_file;
}
static inline struct inode_security_struct *
selinux_inode(const struct inode *inode)
{

View File

@ -5278,7 +5278,7 @@ static __init int smack_init(void)
* all processes and objects when they are created.
*/
DEFINE_LSM(smack) = {
.name = "smack",
.id = &smack_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.blobs = &smack_blob_sizes,
.init = smack_init,

View File

@ -615,7 +615,7 @@ static int __init tomoyo_init(void)
}
DEFINE_LSM(tomoyo) = {
.name = "tomoyo",
.id = &tomoyo_lsmid,
.enabled = &tomoyo_enabled,
.flags = LSM_FLAG_LEGACY_MAJOR,
.blobs = &tomoyo_blob_sizes,

View File

@ -483,6 +483,6 @@ static int __init yama_init(void)
}
DEFINE_LSM(yama) = {
.name = "yama",
.id = &yama_lsmid,
.init = yama_init,
};

View File

@ -53,11 +53,6 @@ static void usb6fire_chip_abort(struct sfire_chip *chip)
usb6fire_comm_abort(chip);
if (chip->control)
usb6fire_control_abort(chip);
if (chip->card) {
snd_card_disconnect(chip->card);
snd_card_free_when_closed(chip->card);
chip->card = NULL;
}
}
}
@ -168,6 +163,7 @@ destroy_chip:
static void usb6fire_chip_disconnect(struct usb_interface *intf)
{
struct sfire_chip *chip;
struct snd_card *card;
chip = usb_get_intfdata(intf);
if (chip) { /* if !chip, fw upload has been performed */
@ -178,8 +174,19 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf)
chips[chip->regidx] = NULL;
}
/*
* Save card pointer before teardown.
* snd_card_free_when_closed() may free card (and
* the embedded chip) immediately, so it must be
* called last and chip must not be accessed after.
*/
card = chip->card;
chip->shutdown = true;
if (card)
snd_card_disconnect(card);
usb6fire_chip_abort(chip);
if (card)
snd_card_free_when_closed(card);
}
}
}

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.20.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-211.22.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -1,2 +1,2 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.20.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-211.22.1.el10.x86_64,mailto:security@almalinux.org