Merge 16c54d6a49 ("mm: fix apply_to_existing_page_range()") into android14-6.1-lts

Steps on the way to 6.1.135

Change-Id: I789088e35ba0c1f8c14466c6440828e3249159df
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2025-05-02 11:27:38 +00:00
35 changed files with 384 additions and 85 deletions

View File

@@ -1103,6 +1103,9 @@ KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types)
# Require designated initializers for all marked structures
KBUILD_CFLAGS += $(call cc-option,-Werror=designated-init)
# Ensure compilers do not transform certain loops into calls to wcslen()
KBUILD_CFLAGS += -fno-builtin-wcslen
# change __FILE__ to the relative path from the srctree
KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)

View File

@@ -173,18 +173,6 @@ static __init int setup_node(int pxm)
return acpi_map_pxm_to_node(pxm);
}
/*
* Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for
* I/O localities since SRAT does not list them. I/O localities are
* not supported at this point.
*/
unsigned int numa_distance_cnt;
static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit)
{
return slit->locality_count;
}
void __init numa_set_distance(int from, int to, int distance)
{
if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) {

View File

@@ -142,8 +142,6 @@ static void build_prologue(struct jit_ctx *ctx)
*/
if (seen_tail_call(ctx) && seen_call(ctx))
move_reg(ctx, TCC_SAVED, REG_TCC);
else
emit_insn(ctx, nop);
ctx->stack_size = stack_adjust;
}

View File

@@ -25,11 +25,6 @@ struct jit_data {
struct jit_ctx ctx;
};
static inline void emit_nop(union loongarch_instruction *insn)
{
insn->word = INSN_NOP;
}
#define emit_insn(ctx, func, ...) \
do { \
if (ctx->image != NULL) { \

View File

@@ -25,6 +25,7 @@
#include <linux/reboot.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/nospec.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
@@ -1178,6 +1179,9 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
|| nargs + nret > ARRAY_SIZE(args.args))
return -EINVAL;
nargs = array_index_nospec(nargs, ARRAY_SIZE(args.args));
nret = array_index_nospec(nret, ARRAY_SIZE(args.args) - nargs);
/* Copy in args. */
if (copy_from_user(args.args, uargs->args,
nargs * sizeof(rtas_arg_t)) != 0)

View File

@@ -1204,7 +1204,13 @@ static void __split_lock_reenable(struct work_struct *work)
{
sld_update_msr(true);
}
static DECLARE_DELAYED_WORK(sl_reenable, __split_lock_reenable);
/*
* In order for each CPU to schedule its delayed work independently of the
* others, delayed work struct must be per-CPU. This is not required when
* sysctl_sld_mitigate is enabled because of the semaphore that limits
* the number of simultaneously scheduled delayed works to 1.
*/
static DEFINE_PER_CPU(struct delayed_work, sl_reenable);
/*
* If a CPU goes offline with pending delayed work to re-enable split lock
@@ -1225,7 +1231,7 @@ static int splitlock_cpu_offline(unsigned int cpu)
static void split_lock_warn(unsigned long ip)
{
struct delayed_work *work;
struct delayed_work *work = NULL;
int cpu;
if (!current->reported_split_lock)
@@ -1247,11 +1253,17 @@ static void split_lock_warn(unsigned long ip)
if (down_interruptible(&buslock_sem) == -EINTR)
return;
work = &sl_reenable_unlock;
} else {
work = &sl_reenable;
}
cpu = get_cpu();
if (!work) {
work = this_cpu_ptr(&sl_reenable);
/* Deferred initialization of per-CPU struct */
if (!work->work.func)
INIT_DELAYED_WORK(work, __split_lock_reenable);
}
schedule_delayed_work_on(cpu, work, 2);
/* Disable split lock detection on this CPU to make progress */

View File

@@ -100,7 +100,12 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
xor %edx, %edx
wrmsr
call xen_prepare_pvh
/* Call xen_prepare_pvh() via the kernel virtual mapping */
leaq xen_prepare_pvh(%rip), %rax
subq phys_base(%rip), %rax
addq $__START_KERNEL_map, %rax
ANNOTATE_RETPOLINE_SAFE
call *%rax
/* startup_64 expects boot_params in %rsi. */
mov $_pa(pvh_bootparams), %rsi

View File

@@ -255,6 +255,7 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct gendisk *disk,
blkg->pd[i] = pd;
pd->blkg = blkg;
pd->plid = i;
pd->online = false;
}
return blkg;
@@ -326,8 +327,11 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, struct gendisk *disk,
for (i = 0; i < BLKCG_MAX_POLS; i++) {
struct blkcg_policy *pol = blkcg_policy[i];
if (blkg->pd[i] && pol->pd_online_fn)
pol->pd_online_fn(blkg->pd[i]);
if (blkg->pd[i]) {
if (pol->pd_online_fn)
pol->pd_online_fn(blkg->pd[i]);
blkg->pd[i]->online = true;
}
}
}
blkg->online = true;
@@ -432,8 +436,11 @@ static void blkg_destroy(struct blkcg_gq *blkg)
for (i = 0; i < BLKCG_MAX_POLS; i++) {
struct blkcg_policy *pol = blkcg_policy[i];
if (blkg->pd[i] && pol->pd_offline_fn)
pol->pd_offline_fn(blkg->pd[i]);
if (blkg->pd[i] && blkg->pd[i]->online) {
if (pol->pd_offline_fn)
pol->pd_offline_fn(blkg->pd[i]);
blkg->pd[i]->online = false;
}
}
blkg->online = false;
@@ -1422,6 +1429,7 @@ retry:
blkg->pd[pol->plid] = pd;
pd->blkg = blkg;
pd->plid = pol->plid;
pd->online = false;
}
/* all allocated, init in the same order */
@@ -1429,9 +1437,11 @@ retry:
list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
pol->pd_init_fn(blkg->pd[pol->plid]);
if (pol->pd_online_fn)
list_for_each_entry_reverse(blkg, &q->blkg_list, q_node)
list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) {
if (pol->pd_online_fn)
pol->pd_online_fn(blkg->pd[pol->plid]);
blkg->pd[pol->plid]->online = true;
}
__set_bit(pol->plid, q->blkcg_pols);
ret = 0;
@@ -1493,7 +1503,7 @@ void blkcg_deactivate_policy(struct request_queue *q,
spin_lock(&blkcg->lock);
if (blkg->pd[pol->plid]) {
if (pol->pd_offline_fn)
if (blkg->pd[pol->plid]->online && pol->pd_offline_fn)
pol->pd_offline_fn(blkg->pd[pol->plid]);
pol->pd_free_fn(blkg->pd[pol->plid]);
blkg->pd[pol->plid] = NULL;

View File

@@ -125,6 +125,7 @@ struct blkg_policy_data {
/* the blkg and policy id this per-policy data belongs to */
struct blkcg_gq *blkg;
int plid;
bool online;
};
/*

View File

@@ -1430,8 +1430,11 @@ static void iocg_pay_debt(struct ioc_gq *iocg, u64 abs_vpay,
lockdep_assert_held(&iocg->ioc->lock);
lockdep_assert_held(&iocg->waitq.lock);
/* make sure that nobody messed with @iocg */
WARN_ON_ONCE(list_empty(&iocg->active_list));
/*
* make sure that nobody messed with @iocg. Check iocg->pd.online
* to avoid warn when removing blkcg or disk.
*/
WARN_ON_ONCE(list_empty(&iocg->active_list) && iocg->pd.online);
WARN_ON_ONCE(iocg->inuse > 1);
iocg->abs_vdebt -= min(abs_vpay, iocg->abs_vdebt);

View File

@@ -2698,10 +2698,18 @@ EXPORT_SYMBOL(cpufreq_update_policy);
*/
void cpufreq_update_limits(unsigned int cpu)
{
struct cpufreq_policy *policy;
policy = cpufreq_cpu_get(cpu);
if (!policy)
return;
if (cpufreq_driver->update_limits)
cpufreq_driver->update_limits(cpu);
else
cpufreq_update_policy(cpu);
cpufreq_cpu_put(policy);
}
EXPORT_SYMBOL_GPL(cpufreq_update_limits);

View File

@@ -4499,17 +4499,17 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
}
}
if (link_cnt > (MAX_PIPES * 2)) {
DRM_ERROR(
"KMS: Cannot support more than %d display indexes\n",
MAX_PIPES * 2);
goto fail;
}
/* loops over all connectors on the board */
for (i = 0; i < link_cnt; i++) {
struct dc_link *link = NULL;
if (i > AMDGPU_DM_MAX_DISPLAY_INDEX) {
DRM_ERROR(
"KMS: Cannot support more than %d display indexes\n",
AMDGPU_DM_MAX_DISPLAY_INDEX);
continue;
}
aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
if (!aconnector)
goto fail;

View File

@@ -1192,7 +1192,8 @@ err:
return ret;
}
static
/* clang stack usage explodes if this is inlined */
static noinline_for_stack
void vdec_vp9_slice_map_counts_eob_coef(unsigned int i, unsigned int j, unsigned int k,
struct vdec_vp9_slice_frame_counts *counts,
struct v4l2_vp9_frame_symbol_counts *counts_helper)

View File

@@ -245,7 +245,7 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
return true;
fail:
switch (irq_type) {
switch (test->irq_type) {
case IRQ_TYPE_LEGACY:
dev_err(dev, "Failed to request IRQ %d for Legacy\n",
pci_irq_vector(pdev, i));
@@ -262,6 +262,9 @@ fail:
break;
}
test->num_irqs = i;
pci_endpoint_test_release_irq(test);
return false;
}
@@ -714,6 +717,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
if (!pci_endpoint_test_request_irq(test))
goto err;
irq_type = test->irq_type;
return true;
err:

View File

@@ -173,20 +173,6 @@ struct nvmet_fc_tgt_assoc {
struct rcu_head rcu;
};
static inline int
nvmet_fc_iodnum(struct nvmet_fc_ls_iod *iodptr)
{
return (iodptr - iodptr->tgtport->iod);
}
static inline int
nvmet_fc_fodnum(struct nvmet_fc_fcp_iod *fodptr)
{
return (fodptr - fodptr->queue->fod);
}
/*
* Association and Connection IDs:
*

View File

@@ -112,7 +112,7 @@ static int is_xen_swiotlb_buffer(struct device *dev, dma_addr_t dma_addr)
}
#ifdef CONFIG_X86
int __init xen_swiotlb_fixup(void *buf, unsigned long nslabs)
int xen_swiotlb_fixup(void *buf, unsigned long nslabs)
{
int rc;
unsigned int order = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT);

View File

@@ -1428,6 +1428,7 @@ out_unlock:
locked_page,
clear_bits,
page_ops);
btrfs_qgroup_free_data(inode, NULL, start, cur_alloc_size, NULL);
start += cur_alloc_size;
}
@@ -1441,6 +1442,7 @@ out_unlock:
clear_bits |= EXTENT_CLEAR_DATA_RESV;
extent_clear_unlock_delalloc(inode, start, end, locked_page,
clear_bits, page_ops);
btrfs_qgroup_free_data(inode, NULL, start, end - start + 1, NULL);
}
return ret;
}
@@ -2168,13 +2170,15 @@ error:
if (nocow)
btrfs_dec_nocow_writers(bg);
if (ret && cur_offset < end)
if (ret && cur_offset < end) {
extent_clear_unlock_delalloc(inode, cur_offset, end,
locked_page, EXTENT_LOCKED |
EXTENT_DELALLOC | EXTENT_DEFRAG |
EXTENT_DO_ACCOUNTING, PAGE_UNLOCK |
PAGE_START_WRITEBACK |
PAGE_END_WRITEBACK);
btrfs_qgroup_free_data(inode, NULL, cur_offset, end - cur_offset + 1, NULL);
}
btrfs_free_path(path);
return ret;
}

View File

@@ -1909,6 +1909,9 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group)
device = map->stripes[i].dev;
physical = map->stripes[i].physical;
if (!device->bdev)
continue;
if (device->zone_info->max_active_zones == 0)
continue;
@@ -2052,6 +2055,9 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
struct btrfs_device *device = map->stripes[i].dev;
const u64 physical = map->stripes[i].physical;
if (!device->bdev)
continue;
if (device->zone_info->max_active_zones == 0)
continue;

View File

@@ -258,6 +258,31 @@ compose_mount_options_err:
goto compose_mount_options_out;
}
static int set_dest_addr(struct smb3_fs_context *ctx, const char *full_path)
{
struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
char *str_addr = NULL;
int rc;
rc = dns_resolve_server_name_to_ip(full_path, &str_addr, NULL);
if (rc < 0)
goto out;
rc = cifs_convert_address(addr, str_addr, strlen(str_addr));
if (!rc) {
cifs_dbg(FYI, "%s: failed to convert ip address\n", __func__);
rc = -EINVAL;
goto out;
}
cifs_set_port(addr, ctx->port);
rc = 0;
out:
kfree(str_addr);
return rc;
}
/*
* Create a vfsmount that we can automount
*/
@@ -295,8 +320,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
ctx = smb3_fc2context(fc);
page = alloc_dentry_path();
/* always use tree name prefix */
full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
full_path = dfs_get_automount_devname(mntpt, page);
if (IS_ERR(full_path)) {
mnt = ERR_CAST(full_path);
goto out;
@@ -315,6 +339,12 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
goto out;
}
rc = set_dest_addr(ctx, full_path);
if (rc) {
mnt = ERR_PTR(rc);
goto out;
}
rc = smb3_parse_devname(full_path, ctx);
if (!rc)
mnt = fc_mount(fc);

View File

@@ -57,8 +57,29 @@ extern void exit_cifs_idmap(void);
extern int init_cifs_spnego(void);
extern void exit_cifs_spnego(void);
extern const char *build_path_from_dentry(struct dentry *, void *);
char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
const char *tree, int tree_len,
bool prefix);
extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
void *page, bool prefix);
#ifdef CONFIG_CIFS_DFS_UPCALL
static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct TCP_Server_Info *server = tcon->ses->server;
if (unlikely(!server->origin_fullpath))
return ERR_PTR(-EREMOTE);
return __build_path_from_dentry_optional_prefix(dentry, page,
server->origin_fullpath,
strlen(server->origin_fullpath),
true);
}
#endif
static inline void *alloc_dentry_path(void)
{
return __getname();

View File

@@ -78,14 +78,13 @@ build_path_from_dentry(struct dentry *direntry, void *page)
prefix);
}
char *
build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
bool prefix)
char *__build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
const char *tree, int tree_len,
bool prefix)
{
int dfsplen;
int pplen = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
char dirsep = CIFS_DIR_SEP(cifs_sb);
char *s;
@@ -93,7 +92,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
return ERR_PTR(-ENOMEM);
if (prefix)
dfsplen = strnlen(tcon->tree_name, MAX_TREE_SIZE + 1);
dfsplen = strnlen(tree, tree_len + 1);
else
dfsplen = 0;
@@ -123,7 +122,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
}
if (dfsplen) {
s -= dfsplen;
memcpy(s, tcon->tree_name, dfsplen);
memcpy(s, tree, dfsplen);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
int i;
for (i = 0; i < dfsplen; i++) {
@@ -135,6 +134,16 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
return s;
}
char *build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
bool prefix)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
return __build_path_from_dentry_optional_prefix(direntry, page, tcon->tree_name,
MAX_TREE_SIZE, prefix);
}
/*
* Don't allow path components longer than the server max.
* Don't allow the separator character in a path component.

View File

@@ -1515,7 +1515,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
* @open_req: buffer containing smb2 file open(create) request
* @is_dir: whether leasing file is directory
*
* Return: oplock state, -ENOENT if create lease context not found
* Return: allocated lease context object on success, otherwise NULL
*/
struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir)
{

View File

@@ -3243,7 +3243,7 @@ int smb2_open(struct ksmbd_work *work)
goto err_out1;
}
} else {
if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && lc) {
/*
* Compare parent lease using parent key. If there is no
* a lease that has same parent key, Send lease break

View File

@@ -246,6 +246,7 @@ struct bpf_map {
* same prog type, JITed flag and xdp_has_frags flag.
*/
struct {
const struct btf_type *attach_func_proto;
spinlock_t lock;
enum bpf_prog_type type;
bool jited;

View File

@@ -38,9 +38,11 @@ struct landlock_ruleset_attr {
*
* - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI
* version.
* - %LANDLOCK_CREATE_RULESET_ERRATA: Get a bitmask of fixed issues.
*/
/* clang-format off */
#define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
/* clang-format on */
/**

View File

@@ -2104,6 +2104,7 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
{
enum bpf_prog_type prog_type = resolve_prog_type(fp);
bool ret;
struct bpf_prog_aux *aux = fp->aux;
if (fp->kprobe_override)
return false;
@@ -2115,12 +2116,26 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
*/
map->owner.type = prog_type;
map->owner.jited = fp->jited;
map->owner.xdp_has_frags = fp->aux->xdp_has_frags;
map->owner.xdp_has_frags = aux->xdp_has_frags;
map->owner.attach_func_proto = aux->attach_func_proto;
ret = true;
} else {
ret = map->owner.type == prog_type &&
map->owner.jited == fp->jited &&
map->owner.xdp_has_frags == fp->aux->xdp_has_frags;
map->owner.xdp_has_frags == aux->xdp_has_frags;
if (ret &&
map->owner.attach_func_proto != aux->attach_func_proto) {
switch (prog_type) {
case BPF_PROG_TYPE_TRACING:
case BPF_PROG_TYPE_LSM:
case BPF_PROG_TYPE_EXT:
case BPF_PROG_TYPE_STRUCT_OPS:
ret = false;
break;
default:
break;
}
}
}
spin_unlock(&map->owner.lock);

View File

@@ -793,7 +793,7 @@ static const struct vm_operations_struct bpf_map_default_vmops = {
static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct bpf_map *map = filp->private_data;
int err;
int err = 0;
if (!map->ops->map_mmap || map_value_has_spin_lock(map) ||
map_value_has_timer(map) || map_value_has_kptrs(map))
@@ -818,7 +818,12 @@ static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
err = -EACCES;
goto out;
}
bpf_map_write_active_inc(map);
}
out:
mutex_unlock(&map->freeze_mutex);
if (err)
return err;
/* set default open/close callbacks */
vma->vm_ops = &bpf_map_default_vmops;
@@ -829,13 +834,11 @@ static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
vm_flags_clear(vma, VM_MAYWRITE);
err = map->ops->map_mmap(map, vma);
if (err)
goto out;
if (err) {
if (vma->vm_flags & VM_WRITE)
bpf_map_write_active_dec(map);
}
if (vma->vm_flags & VM_MAYWRITE)
bpf_map_write_active_inc(map);
out:
mutex_unlock(&map->freeze_mutex);
return err;
}

View File

@@ -232,7 +232,7 @@ bool __must_check try_grab_page(struct page *page, unsigned int flags)
* and it is used in a *lot* of places.
*/
if (is_zero_page(page))
return 0;
return true;
/*
* Similar to try_grab_folio(): be sure to *also*

View File

@@ -2684,11 +2684,11 @@ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
if (fn) {
do {
if (create || !pte_none(*pte)) {
err = fn(pte++, addr, data);
err = fn(pte, addr, data);
if (err)
break;
}
} while (addr += PAGE_SIZE, addr != end);
} while (pte++, addr += PAGE_SIZE, addr != end);
}
*mask |= PGTBL_PTE_MODIFIED;

View File

@@ -1266,6 +1266,12 @@ static int mptcp_getsockopt_v4(struct mptcp_sock *msk, int optname,
switch (optname) {
case IP_TOS:
return mptcp_put_int_option(msk, optval, optlen, inet_sk(sk)->tos);
case IP_FREEBIND:
return mptcp_put_int_option(msk, optval, optlen,
inet_sk(sk)->freebind);
case IP_TRANSPARENT:
return mptcp_put_int_option(msk, optval, optlen,
inet_sk(sk)->transparent);
}
return -EOPNOTSUPP;
@@ -1280,6 +1286,12 @@ static int mptcp_getsockopt_v6(struct mptcp_sock *msk, int optname,
case IPV6_V6ONLY:
return mptcp_put_int_option(msk, optval, optlen,
sk->sk_ipv6only);
case IPV6_TRANSPARENT:
return mptcp_put_int_option(msk, optval, optlen,
inet_sk(sk)->transparent);
case IPV6_FREEBIND:
return mptcp_put_int_option(msk, optval, optlen,
inet_sk(sk)->freebind);
}
return -EOPNOTSUPP;

View File

@@ -0,0 +1,87 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Landlock - Errata information
*
* Copyright © 2025 Microsoft Corporation
*/
#ifndef _SECURITY_LANDLOCK_ERRATA_H
#define _SECURITY_LANDLOCK_ERRATA_H
#include <linux/init.h>
struct landlock_erratum {
const int abi;
const u8 number;
};
/* clang-format off */
#define LANDLOCK_ERRATUM(NUMBER) \
{ \
.abi = LANDLOCK_ERRATA_ABI, \
.number = NUMBER, \
},
/* clang-format on */
/*
* Some fixes may require user space to check if they are applied on the running
* kernel before using a specific feature. For instance, this applies when a
* restriction was previously too restrictive and is now getting relaxed (for
* compatibility or semantic reasons). However, non-visible changes for
* legitimate use (e.g. security fixes) do not require an erratum.
*/
static const struct landlock_erratum landlock_errata_init[] __initconst = {
/*
* Only Sparse may not implement __has_include. If a compiler does not
* implement __has_include, a warning will be printed at boot time (see
* setup.c).
*/
#ifdef __has_include
#define LANDLOCK_ERRATA_ABI 1
#if __has_include("errata/abi-1.h")
#include "errata/abi-1.h"
#endif
#undef LANDLOCK_ERRATA_ABI
#define LANDLOCK_ERRATA_ABI 2
#if __has_include("errata/abi-2.h")
#include "errata/abi-2.h"
#endif
#undef LANDLOCK_ERRATA_ABI
#define LANDLOCK_ERRATA_ABI 3
#if __has_include("errata/abi-3.h")
#include "errata/abi-3.h"
#endif
#undef LANDLOCK_ERRATA_ABI
#define LANDLOCK_ERRATA_ABI 4
#if __has_include("errata/abi-4.h")
#include "errata/abi-4.h"
#endif
#undef LANDLOCK_ERRATA_ABI
/*
* For each new erratum, we need to include all the ABI files up to the impacted
* ABI to make all potential future intermediate errata easy to backport.
*
* If such change involves more than one ABI addition, then it must be in a
* dedicated commit with the same Fixes tag as used for the actual fix.
*
* Each commit creating a new security/landlock/errata/abi-*.h file must have a
* Depends-on tag to reference the commit that previously added the line to
* include this new file, except if the original Fixes tag is enough.
*
* Each erratum must be documented in its related ABI file, and a dedicated
* commit must update Documentation/userspace-api/landlock.rst to include this
* erratum. This commit will not be backported.
*/
#endif
{}
};
#endif /* _SECURITY_LANDLOCK_ERRATA_H */

View File

@@ -6,11 +6,13 @@
* Copyright © 2018-2020 ANSSI
*/
#include <linux/bits.h>
#include <linux/init.h>
#include <linux/lsm_hooks.h>
#include "common.h"
#include "cred.h"
#include "errata.h"
#include "fs.h"
#include "ptrace.h"
#include "setup.h"
@@ -23,8 +25,36 @@ struct lsm_blob_sizes landlock_blob_sizes __lsm_ro_after_init = {
.lbs_superblock = sizeof(struct landlock_superblock_security),
};
int landlock_errata __ro_after_init;
static void __init compute_errata(void)
{
size_t i;
#ifndef __has_include
/*
* This is a safeguard to make sure the compiler implements
* __has_include (see errata.h).
*/
WARN_ON_ONCE(1);
return;
#endif
for (i = 0; landlock_errata_init[i].number; i++) {
const int prev_errata = landlock_errata;
if (WARN_ON_ONCE(landlock_errata_init[i].abi >
landlock_abi_version))
continue;
landlock_errata |= BIT(landlock_errata_init[i].number - 1);
WARN_ON_ONCE(prev_errata == landlock_errata);
}
}
static int __init landlock_init(void)
{
compute_errata();
landlock_add_cred_hooks();
landlock_add_ptrace_hooks();
landlock_add_fs_hooks();

View File

@@ -11,7 +11,10 @@
#include <linux/lsm_hooks.h>
extern const int landlock_abi_version;
extern bool landlock_initialized;
extern int landlock_errata;
extern struct lsm_blob_sizes landlock_blob_sizes;

View File

@@ -150,7 +150,9 @@ static const struct file_operations ruleset_fops = {
* the new ruleset.
* @size: Size of the pointed &struct landlock_ruleset_attr (needed for
* backward and forward compatibility).
* @flags: Supported value: %LANDLOCK_CREATE_RULESET_VERSION.
* @flags: Supported value:
* - %LANDLOCK_CREATE_RULESET_VERSION
* - %LANDLOCK_CREATE_RULESET_ERRATA
*
* This system call enables to create a new Landlock ruleset, and returns the
* related file descriptor on success.
@@ -159,6 +161,10 @@ static const struct file_operations ruleset_fops = {
* 0, then the returned value is the highest supported Landlock ABI version
* (starting at 1).
*
* If @flags is %LANDLOCK_CREATE_RULESET_ERRATA and @attr is NULL and @size is
* 0, then the returned value is a bitmask of fixed issues for the current
* Landlock ABI version.
*
* Possible returned errors are:
*
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
@@ -181,9 +187,15 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
return -EOPNOTSUPP;
if (flags) {
if ((flags == LANDLOCK_CREATE_RULESET_VERSION) && !attr &&
!size)
return LANDLOCK_ABI_VERSION;
if (attr || size)
return -EINVAL;
if (flags == LANDLOCK_CREATE_RULESET_VERSION)
return landlock_abi_version;
if (flags == LANDLOCK_CREATE_RULESET_ERRATA)
return landlock_errata;
return -EINVAL;
}
@@ -213,6 +225,8 @@ SYSCALL_DEFINE3(landlock_create_ruleset,
return ruleset_fd;
}
const int landlock_abi_version = LANDLOCK_ABI_VERSION;
/*
* Returns an owned ruleset from a FD. It is thus needed to call
* landlock_put_ruleset() on the return value.

View File

@@ -98,10 +98,54 @@ TEST(abi_version)
ASSERT_EQ(EINVAL, errno);
}
/*
* Old source trees might not have the set of Kselftest fixes related to kernel
* UAPI headers.
*/
#ifndef LANDLOCK_CREATE_RULESET_ERRATA
#define LANDLOCK_CREATE_RULESET_ERRATA (1U << 1)
#endif
TEST(errata)
{
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
};
int errata;
errata = landlock_create_ruleset(NULL, 0,
LANDLOCK_CREATE_RULESET_ERRATA);
/* The errata bitmask will not be backported to tests. */
ASSERT_LE(0, errata);
TH_LOG("errata: 0x%x", errata);
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
LANDLOCK_CREATE_RULESET_ERRATA));
ASSERT_EQ(EINVAL, errno);
ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr),
LANDLOCK_CREATE_RULESET_ERRATA));
ASSERT_EQ(EINVAL, errno);
ASSERT_EQ(-1,
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr),
LANDLOCK_CREATE_RULESET_ERRATA));
ASSERT_EQ(EINVAL, errno);
ASSERT_EQ(-1, landlock_create_ruleset(
NULL, 0,
LANDLOCK_CREATE_RULESET_VERSION |
LANDLOCK_CREATE_RULESET_ERRATA));
ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0,
LANDLOCK_CREATE_RULESET_ERRATA |
1 << 31));
ASSERT_EQ(EINVAL, errno);
}
/* Tests ordering of syscall argument checks. */
TEST(create_ruleset_checks_ordering)
{
const int last_flag = LANDLOCK_CREATE_RULESET_VERSION;
const int last_flag = LANDLOCK_CREATE_RULESET_ERRATA;
const int invalid_flag = last_flag << 1;
int ruleset_fd;
const struct landlock_ruleset_attr ruleset_attr = {