Merge b9ff774548 ("Merge tag 'tpmdd-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd") into android-mainline
Steps on the way to 6.7-rc1 Change-Id: Ib1c6be397d6fe67dc3e698697f10248168b7f691 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -76,7 +76,7 @@ kmsg_size
|
||||
~~~~~~~~~
|
||||
|
||||
The chunk size in KB for oops/panic front-end. It **MUST** be a multiple of 4.
|
||||
It's optional if you do not care oops/panic log.
|
||||
It's optional if you do not care about the oops/panic log.
|
||||
|
||||
There are multiple chunks for oops/panic front-end depending on the remaining
|
||||
space except other pstore front-ends.
|
||||
@@ -88,7 +88,7 @@ pmsg_size
|
||||
~~~~~~~~~
|
||||
|
||||
The chunk size in KB for pmsg front-end. It **MUST** be a multiple of 4.
|
||||
It's optional if you do not care pmsg log.
|
||||
It's optional if you do not care about the pmsg log.
|
||||
|
||||
Unlike oops/panic front-end, there is only one chunk for pmsg front-end.
|
||||
|
||||
@@ -100,7 +100,7 @@ console_size
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The chunk size in KB for console front-end. It **MUST** be a multiple of 4.
|
||||
It's optional if you do not care console log.
|
||||
It's optional if you do not care about the console log.
|
||||
|
||||
Similar to pmsg front-end, there is only one chunk for console front-end.
|
||||
|
||||
@@ -111,7 +111,7 @@ ftrace_size
|
||||
~~~~~~~~~~~
|
||||
|
||||
The chunk size in KB for ftrace front-end. It **MUST** be a multiple of 4.
|
||||
It's optional if you do not care console log.
|
||||
It's optional if you do not care about the ftrace log.
|
||||
|
||||
Similar to oops front-end, there are multiple chunks for ftrace front-end
|
||||
depending on the count of cpu processors. Each chunk size is equal to
|
||||
|
||||
@@ -8649,6 +8649,8 @@ L: linux-hardening@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: Documentation/kbuild/gcc-plugins.rst
|
||||
F: include/linux/stackleak.h
|
||||
F: kernel/stackleak.c
|
||||
F: scripts/Makefile.gcc-plugins
|
||||
F: scripts/gcc-plugins/
|
||||
|
||||
@@ -11422,16 +11424,20 @@ F: usr/
|
||||
|
||||
KERNEL HARDENING (not covered by other areas)
|
||||
M: Kees Cook <keescook@chromium.org>
|
||||
R: Gustavo A. R. Silva <gustavoars@kernel.org>
|
||||
L: linux-hardening@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: Documentation/ABI/testing/sysfs-kernel-oops_count
|
||||
F: Documentation/ABI/testing/sysfs-kernel-warn_count
|
||||
F: arch/*/configs/hardening.config
|
||||
F: include/linux/overflow.h
|
||||
F: include/linux/randomize_kstack.h
|
||||
F: kernel/configs/hardening.config
|
||||
F: mm/usercopy.c
|
||||
K: \b(add|choose)_random_kstack_offset\b
|
||||
K: \b__check_(object_size|heap_object)\b
|
||||
K: \b__counted_by\b
|
||||
|
||||
KERNEL JANITORS
|
||||
L: kernel-janitors@vger.kernel.org
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Basic kernel hardening options (specific to arm)
|
||||
|
||||
# Make sure PXN/PAN emulation is enabled.
|
||||
CONFIG_CPU_SW_DOMAIN_PAN=y
|
||||
|
||||
# Dangerous; old interfaces and needless additional attack surface.
|
||||
# CONFIG_OABI_COMPAT is not set
|
||||
@@ -0,0 +1,22 @@
|
||||
# Basic kernel hardening options (specific to arm64)
|
||||
|
||||
# Make sure PAN emulation is enabled.
|
||||
CONFIG_ARM64_SW_TTBR0_PAN=y
|
||||
|
||||
# Software Shadow Stack or PAC
|
||||
CONFIG_SHADOW_CALL_STACK=y
|
||||
|
||||
# Pointer authentication (ARMv8.3 and later). If hardware actually supports
|
||||
# it, one can turn off CONFIG_STACKPROTECTOR_STRONG with this enabled.
|
||||
CONFIG_ARM64_PTR_AUTH=y
|
||||
CONFIG_ARM64_PTR_AUTH_KERNEL=y
|
||||
|
||||
# Available in ARMv8.5 and later.
|
||||
CONFIG_ARM64_BTI=y
|
||||
CONFIG_ARM64_BTI_KERNEL=y
|
||||
CONFIG_ARM64_MTE=y
|
||||
CONFIG_KASAN_HW_TAGS=y
|
||||
CONFIG_ARM64_E0PD=y
|
||||
|
||||
# Available in ARMv8.7 and later.
|
||||
CONFIG_ARM64_EPAN=y
|
||||
@@ -0,0 +1,10 @@
|
||||
# PowerPC specific hardening options
|
||||
|
||||
# Block kernel from unexpectedly reading userspace memory.
|
||||
CONFIG_PPC_KUAP=y
|
||||
|
||||
# Attack surface reduction.
|
||||
# CONFIG_SCOM_DEBUGFS is not set
|
||||
|
||||
# Disable internal kernel debugger.
|
||||
# CONFIG_XMON is not set
|
||||
@@ -50,7 +50,7 @@ struct cpuinfo_tree {
|
||||
|
||||
/* Offsets into nodes[] for each level of the tree */
|
||||
struct cpuinfo_level level[CPUINFO_LVL_MAX];
|
||||
struct cpuinfo_node nodes[];
|
||||
struct cpuinfo_node nodes[] __counted_by(total_nodes);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ static int etap_tramp(char *dev, char *gate, int control_me,
|
||||
sprintf(data_fd_buf, "%d", data_remote);
|
||||
sprintf(version_buf, "%d", UML_NET_VERSION);
|
||||
if (gate != NULL) {
|
||||
strncpy(gate_buf, gate, 15);
|
||||
strscpy(gate_buf, gate, sizeof(gate_buf));
|
||||
args = setup_args;
|
||||
}
|
||||
else args = nosetup_args;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Basic kernel hardening options (specific to x86)
|
||||
|
||||
# Modern libc no longer needs a fixed-position mapping in userspace, remove
|
||||
# it as a possible target.
|
||||
CONFIG_LEGACY_VSYSCALL_NONE=y
|
||||
|
||||
# Enable chip-specific IOMMU support.
|
||||
CONFIG_INTEL_IOMMU=y
|
||||
CONFIG_INTEL_IOMMU_DEFAULT_ON=y
|
||||
CONFIG_INTEL_IOMMU_SVM=y
|
||||
CONFIG_AMD_IOMMU=y
|
||||
|
||||
# Enable CET Shadow Stack for userspace.
|
||||
CONFIG_X86_USER_SHADOW_STACK=y
|
||||
@@ -51,7 +51,7 @@ struct ivpu_job {
|
||||
u32 job_id;
|
||||
u32 engine_idx;
|
||||
size_t bo_count;
|
||||
struct ivpu_bo *bos[];
|
||||
struct ivpu_bo *bos[] __counted_by(bo_count);
|
||||
};
|
||||
|
||||
int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file);
|
||||
|
||||
@@ -1449,10 +1449,9 @@ static struct logical_input *panel_bind_key(const char *name, const char *press,
|
||||
key->rise_time = 1;
|
||||
key->fall_time = 1;
|
||||
|
||||
strncpy(key->u.kbd.press_str, press, sizeof(key->u.kbd.press_str));
|
||||
strncpy(key->u.kbd.repeat_str, repeat, sizeof(key->u.kbd.repeat_str));
|
||||
strncpy(key->u.kbd.release_str, release,
|
||||
sizeof(key->u.kbd.release_str));
|
||||
strtomem_pad(key->u.kbd.press_str, press, '\0');
|
||||
strtomem_pad(key->u.kbd.repeat_str, repeat, '\0');
|
||||
strtomem_pad(key->u.kbd.release_str, release, '\0');
|
||||
list_add(&key->list, &logical_inputs);
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -555,7 +555,7 @@ struct fifo_buffer {
|
||||
unsigned int head_index;
|
||||
unsigned int size;
|
||||
int total; /* sum of all values */
|
||||
int values[];
|
||||
int values[] __counted_by(size);
|
||||
};
|
||||
extern struct fifo_buffer *fifo_alloc(unsigned int fifo_size);
|
||||
|
||||
|
||||
@@ -450,10 +450,8 @@ int dprc_get_obj(struct fsl_mc_io *mc_io,
|
||||
obj_desc->ver_major = le16_to_cpu(rsp_params->version_major);
|
||||
obj_desc->ver_minor = le16_to_cpu(rsp_params->version_minor);
|
||||
obj_desc->flags = le16_to_cpu(rsp_params->flags);
|
||||
strncpy(obj_desc->type, rsp_params->type, 16);
|
||||
obj_desc->type[15] = '\0';
|
||||
strncpy(obj_desc->label, rsp_params->label, 16);
|
||||
obj_desc->label[15] = '\0';
|
||||
strscpy_pad(obj_desc->type, rsp_params->type, 16);
|
||||
strscpy_pad(obj_desc->label, rsp_params->label, 16);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dprc_get_obj);
|
||||
@@ -491,8 +489,7 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io,
|
||||
cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr);
|
||||
cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num);
|
||||
cmd_params->obj_id = cpu_to_le32(obj_id);
|
||||
strncpy(cmd_params->obj_type, obj_type, 16);
|
||||
cmd_params->obj_type[15] = '\0';
|
||||
strscpy_pad(cmd_params->obj_type, obj_type, 16);
|
||||
|
||||
/* send command to mc*/
|
||||
return mc_send_command(mc_io, &cmd);
|
||||
@@ -564,8 +561,7 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io,
|
||||
cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params;
|
||||
cmd_params->obj_id = cpu_to_le32(obj_id);
|
||||
cmd_params->region_index = region_index;
|
||||
strncpy(cmd_params->obj_type, obj_type, 16);
|
||||
cmd_params->obj_type[15] = '\0';
|
||||
strscpy_pad(cmd_params->obj_type, obj_type, 16);
|
||||
|
||||
/* send command to mc*/
|
||||
err = mc_send_command(mc_io, &cmd);
|
||||
|
||||
@@ -106,7 +106,7 @@ struct port_buffer {
|
||||
unsigned int sgpages;
|
||||
|
||||
/* sg is used if spages > 0. sg must be the last in is struct */
|
||||
struct scatterlist sg[];
|
||||
struct scatterlist sg[] __counted_by(sgpages);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1661,7 +1661,7 @@ static void __cpufreq_offline(unsigned int cpu, struct cpufreq_policy *policy)
|
||||
}
|
||||
|
||||
if (has_target())
|
||||
strncpy(policy->last_governor, policy->governor->name,
|
||||
strscpy(policy->last_governor, policy->governor->name,
|
||||
CPUFREQ_NAME_LEN);
|
||||
else
|
||||
policy->last_policy = policy->policy;
|
||||
@@ -3007,7 +3007,7 @@ static int __init cpufreq_core_init(void)
|
||||
BUG_ON(!cpufreq_global_kobject);
|
||||
|
||||
if (!strlen(default_governor))
|
||||
strncpy(default_governor, gov->name, CPUFREQ_NAME_LEN);
|
||||
strscpy(default_governor, gov->name, CPUFREQ_NAME_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ static int init_state_node(struct cpuidle_state *idle_state,
|
||||
* replace with kstrdup and pointer assignment when name
|
||||
* and desc become string pointers
|
||||
*/
|
||||
strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN - 1);
|
||||
strncpy(idle_state->desc, desc, CPUIDLE_DESC_LEN - 1);
|
||||
strscpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN);
|
||||
strscpy(idle_state->desc, desc, CPUIDLE_DESC_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ static ssize_t channel_dimm_label_store(struct device *dev,
|
||||
if (copy_count == 0 || copy_count >= sizeof(rank->dimm->label))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(rank->dimm->label, data, copy_count);
|
||||
memcpy(rank->dimm->label, data, copy_count);
|
||||
rank->dimm->label[copy_count] = '\0';
|
||||
|
||||
return count;
|
||||
@@ -535,7 +535,7 @@ static ssize_t dimmdev_label_store(struct device *dev,
|
||||
if (copy_count == 0 || copy_count >= sizeof(dimm->label))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(dimm->label, data, copy_count);
|
||||
memcpy(dimm->label, data, copy_count);
|
||||
dimm->label[copy_count] = '\0';
|
||||
|
||||
return count;
|
||||
|
||||
@@ -610,7 +610,7 @@ static int debugfs_show(struct seq_file *m, void *p)
|
||||
}
|
||||
|
||||
len = strlen(filename);
|
||||
strncpy(namevirt, filename, namesize);
|
||||
strscpy_pad(namevirt, filename, namesize);
|
||||
|
||||
err = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize,
|
||||
&nbytes);
|
||||
@@ -661,7 +661,7 @@ static ssize_t debugfs_store(struct file *file, const char __user *buf,
|
||||
}
|
||||
|
||||
len = strlen(filename);
|
||||
strncpy(namevirt, filename, namesize);
|
||||
strscpy_pad(namevirt, filename, namesize);
|
||||
|
||||
if (copy_from_user(datavirt, buf, count)) {
|
||||
err = -EFAULT;
|
||||
|
||||
@@ -503,7 +503,7 @@ int gud_pipe_check(struct drm_simple_display_pipe *pipe,
|
||||
return -ENOENT;
|
||||
|
||||
len = struct_size(req, properties,
|
||||
GUD_PROPERTIES_MAX_NUM + GUD_CONNECTOR_PROPERTIES_MAX_NUM);
|
||||
size_add(GUD_PROPERTIES_MAX_NUM, GUD_CONNECTOR_PROPERTIES_MAX_NUM));
|
||||
req = kzalloc(len, GFP_KERNEL);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -67,7 +67,7 @@ struct nouveau_svm {
|
||||
struct nouveau_svmm *svmm;
|
||||
} **fault;
|
||||
int fault_nr;
|
||||
} buffer[1];
|
||||
} buffer[];
|
||||
};
|
||||
|
||||
#define FAULT_ACCESS_READ 0
|
||||
@@ -1063,7 +1063,8 @@ nouveau_svm_init(struct nouveau_drm *drm)
|
||||
if (drm->client.device.info.family > NV_DEVICE_INFO_V0_PASCAL)
|
||||
return;
|
||||
|
||||
if (!(drm->svm = svm = kzalloc(sizeof(*drm->svm), GFP_KERNEL)))
|
||||
drm->svm = svm = kzalloc(struct_size(drm->svm, buffer, 1), GFP_KERNEL);
|
||||
if (!drm->svm)
|
||||
return;
|
||||
|
||||
drm->svm->drm = drm;
|
||||
|
||||
@@ -639,9 +639,9 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
strncpy(card->driver, shortname, sizeof(card->driver));
|
||||
strncpy(card->shortname, shortname, sizeof(card->shortname));
|
||||
strncpy(card->longname, longname, sizeof(card->longname));
|
||||
strscpy(card->driver, shortname, sizeof(card->driver));
|
||||
strscpy(card->shortname, shortname, sizeof(card->shortname));
|
||||
strscpy(card->longname, longname, sizeof(card->longname));
|
||||
|
||||
/* Set up rawmidi */
|
||||
err = snd_rawmidi_new(card, card->shortname, 0,
|
||||
@@ -652,7 +652,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
|
||||
goto fail;
|
||||
}
|
||||
pm->rwmidi = rwmidi;
|
||||
strncpy(rwmidi->name, card->shortname, sizeof(rwmidi->name));
|
||||
strscpy(rwmidi->name, card->shortname, sizeof(rwmidi->name));
|
||||
rwmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT;
|
||||
rwmidi->private_data = pm;
|
||||
|
||||
|
||||
@@ -796,14 +796,13 @@ static int read_capabilities(struct acpi_power_meter_resource *resource)
|
||||
goto error;
|
||||
}
|
||||
|
||||
*str = kcalloc(element->string.length + 1, sizeof(u8),
|
||||
GFP_KERNEL);
|
||||
*str = kmemdup_nul(element->string.pointer, element->string.length,
|
||||
GFP_KERNEL);
|
||||
if (!*str) {
|
||||
res = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
strncpy(*str, element->string.pointer, element->string.length);
|
||||
str++;
|
||||
}
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ static int asus_wmi_sensor_info(int index, struct asus_wmi_sensor_info *s)
|
||||
goto out_free_obj;
|
||||
}
|
||||
|
||||
strncpy(s->name, name_obj.string.pointer, sizeof(s->name) - 1);
|
||||
strscpy(s->name, name_obj.string.pointer, sizeof(s->name));
|
||||
|
||||
data_type_obj = obj->package.elements[1];
|
||||
if (data_type_obj.type != ACPI_TYPE_INTEGER) {
|
||||
|
||||
@@ -234,7 +234,7 @@ static int get_sensor_index_attr(const char *name, u32 *index, char *attr)
|
||||
if (copy_len >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(buf, hash_pos + 1, copy_len);
|
||||
memcpy(buf, hash_pos + 1, copy_len);
|
||||
|
||||
err = kstrtou32(buf, 10, index);
|
||||
if (err)
|
||||
|
||||
@@ -73,7 +73,7 @@ struct intmux_data {
|
||||
void __iomem *regs;
|
||||
struct clk *ipg_clk;
|
||||
int channum;
|
||||
struct intmux_irqchip_data irqchip_data[];
|
||||
struct intmux_irqchip_data irqchip_data[] __counted_by(channum);
|
||||
};
|
||||
|
||||
static void imx_intmux_irq_mask(struct irq_data *d)
|
||||
|
||||
@@ -732,7 +732,7 @@ u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN])
|
||||
u16 ret;
|
||||
|
||||
if (contr == 0) {
|
||||
strncpy(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
|
||||
strscpy_pad(buf, capi_manufakturer, CAPI_MANUFACTURER_LEN);
|
||||
return CAPI_NOERROR;
|
||||
}
|
||||
|
||||
@@ -740,7 +740,7 @@ u16 capi20_get_manufacturer(u32 contr, u8 buf[CAPI_MANUFACTURER_LEN])
|
||||
|
||||
ctr = get_capi_ctr_by_nr(contr);
|
||||
if (ctr && ctr->state == CAPI_CTR_RUNNING) {
|
||||
strncpy(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
|
||||
strscpy_pad(buf, ctr->manu, CAPI_MANUFACTURER_LEN);
|
||||
ret = CAPI_NOERROR;
|
||||
} else
|
||||
ret = CAPI_REGNOTINSTALLED;
|
||||
|
||||
@@ -96,7 +96,7 @@ struct mISDNclock
|
||||
printk(KERN_ERR "%s: No memory for clock entry.\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
strncpy(iclock->name, name, sizeof(iclock->name) - 1);
|
||||
strscpy(iclock->name, name, sizeof(iclock->name));
|
||||
iclock->pri = pri;
|
||||
iclock->priv = priv;
|
||||
iclock->ctl = ctl;
|
||||
|
||||
@@ -108,7 +108,7 @@ struct zynqmp_ipi_pdata {
|
||||
unsigned int method;
|
||||
u32 local_id;
|
||||
int num_mboxes;
|
||||
struct zynqmp_ipi_mbox ipi_mboxes[];
|
||||
struct zynqmp_ipi_mbox ipi_mboxes[] __counted_by(num_mboxes);
|
||||
};
|
||||
|
||||
static struct device_driver zynqmp_ipi_mbox_driver = {
|
||||
|
||||
@@ -26,7 +26,7 @@ struct prison_region {
|
||||
struct dm_bio_prison {
|
||||
mempool_t cell_pool;
|
||||
unsigned int num_locks;
|
||||
struct prison_region regions[];
|
||||
struct prison_region regions[] __counted_by(num_locks);
|
||||
};
|
||||
|
||||
static struct kmem_cache *_cell_cache;
|
||||
|
||||
@@ -224,7 +224,7 @@ struct crypt_config {
|
||||
struct mutex bio_alloc_lock;
|
||||
|
||||
u8 *authenc_key; /* space for keys in authenc() format (if used) */
|
||||
u8 key[];
|
||||
u8 key[] __counted_by(key_size);
|
||||
};
|
||||
|
||||
#define MIN_IOS 64
|
||||
|
||||
@@ -254,7 +254,7 @@ struct raid_set {
|
||||
int mode;
|
||||
} journal_dev;
|
||||
|
||||
struct raid_dev dev[];
|
||||
struct raid_dev dev[] __counted_by(raid_disks);
|
||||
};
|
||||
|
||||
static void rs_config_backup(struct raid_set *rs, struct rs_layout *l)
|
||||
|
||||
@@ -56,7 +56,7 @@ struct dm_stat {
|
||||
size_t percpu_alloc_size;
|
||||
size_t histogram_alloc_size;
|
||||
struct dm_stat_percpu *stat_percpu[NR_CPUS];
|
||||
struct dm_stat_shared stat_shared[];
|
||||
struct dm_stat_shared stat_shared[] __counted_by(n_entries);
|
||||
};
|
||||
|
||||
#define STAT_PRECISE_TIMESTAMPS 1
|
||||
|
||||
@@ -44,7 +44,7 @@ struct stripe_c {
|
||||
/* Work struct used for triggering events*/
|
||||
struct work_struct trigger_event;
|
||||
|
||||
struct stripe stripe[];
|
||||
struct stripe stripe[] __counted_by(stripes);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
* test source files.
|
||||
*/
|
||||
#include "lkdtm.h"
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stop_machine.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_X86_32) && !IS_ENABLED(CONFIG_UML)
|
||||
#include <asm/desc.h>
|
||||
@@ -73,6 +75,31 @@ static void lkdtm_PANIC(void)
|
||||
panic("dumptest");
|
||||
}
|
||||
|
||||
static int panic_stop_irqoff_fn(void *arg)
|
||||
{
|
||||
atomic_t *v = arg;
|
||||
|
||||
/*
|
||||
* As stop_machine() disables interrupts, all CPUs within this function
|
||||
* have interrupts disabled and cannot take a regular IPI.
|
||||
*
|
||||
* The last CPU which enters here will trigger a panic, and as all CPUs
|
||||
* cannot take a regular IPI, we'll only be able to stop secondaries if
|
||||
* smp_send_stop() or crash_smp_send_stop() uses an NMI.
|
||||
*/
|
||||
if (atomic_inc_return(v) == num_online_cpus())
|
||||
panic("panic stop irqoff test");
|
||||
|
||||
for (;;)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static void lkdtm_PANIC_STOP_IRQOFF(void)
|
||||
{
|
||||
atomic_t v = ATOMIC_INIT(0);
|
||||
stop_machine(panic_stop_irqoff_fn, &v, cpu_online_mask);
|
||||
}
|
||||
|
||||
static void lkdtm_BUG(void)
|
||||
{
|
||||
BUG();
|
||||
@@ -638,6 +665,7 @@ static noinline void lkdtm_CORRUPT_PAC(void)
|
||||
|
||||
static struct crashtype crashtypes[] = {
|
||||
CRASHTYPE(PANIC),
|
||||
CRASHTYPE(PANIC_STOP_IRQOFF),
|
||||
CRASHTYPE(BUG),
|
||||
CRASHTYPE(WARNING),
|
||||
CRASHTYPE(WARNING_MESSAGE),
|
||||
|
||||
@@ -60,7 +60,7 @@ struct reset_control {
|
||||
struct reset_control_array {
|
||||
struct reset_control base;
|
||||
unsigned int num_rstcs;
|
||||
struct reset_control *rstc[];
|
||||
struct reset_control *rstc[] __counted_by(num_rstcs);
|
||||
};
|
||||
|
||||
static const char *rcdev_name(struct reset_controller_dev *rcdev)
|
||||
@@ -1185,6 +1185,7 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional,
|
||||
resets = kzalloc(struct_size(resets, rstc, num), GFP_KERNEL);
|
||||
if (!resets)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
resets->num_rstcs = num;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
rstc = __of_reset_control_get(np, NULL, i, shared, optional,
|
||||
@@ -1193,7 +1194,6 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional,
|
||||
goto err_rst;
|
||||
resets->rstc[i] = rstc;
|
||||
}
|
||||
resets->num_rstcs = num;
|
||||
resets->base.array = true;
|
||||
|
||||
return &resets->base;
|
||||
|
||||
@@ -585,7 +585,7 @@ struct tsens_priv {
|
||||
struct dentry *debug_root;
|
||||
struct dentry *debug;
|
||||
|
||||
struct tsens_sensor sensor[];
|
||||
struct tsens_sensor sensor[] __counted_by(num_sensors);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1018,7 +1018,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
|
||||
size_t size;
|
||||
|
||||
/* instance init */
|
||||
size = struct_size(instance, urbs, num_rcv_urbs + num_snd_urbs);
|
||||
size = struct_size(instance, urbs,
|
||||
size_add(num_rcv_urbs, num_snd_urbs));
|
||||
instance = kzalloc(size, GFP_KERNEL);
|
||||
if (!instance)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -202,7 +202,7 @@ struct ffs_epfile {
|
||||
struct ffs_buffer {
|
||||
size_t length;
|
||||
char *data;
|
||||
char storage[];
|
||||
char storage[] __counted_by(length);
|
||||
};
|
||||
|
||||
/* ffs_io_data structure ***************************************************/
|
||||
|
||||
@@ -99,7 +99,7 @@ struct f_midi {
|
||||
unsigned int in_last_port;
|
||||
unsigned char free_ref;
|
||||
|
||||
struct gmidi_in_port in_ports_array[/* in_ports */];
|
||||
struct gmidi_in_port in_ports_array[] __counted_by(in_ports);
|
||||
};
|
||||
|
||||
static inline struct f_midi *func_to_midi(struct usb_function *f)
|
||||
@@ -1414,6 +1414,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
|
||||
status = -ENOMEM;
|
||||
goto setup_fail;
|
||||
}
|
||||
midi->in_ports = opts->in_ports;
|
||||
|
||||
for (i = 0; i < opts->in_ports; i++)
|
||||
midi->in_ports_array[i].cable = i;
|
||||
@@ -1424,7 +1425,6 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
|
||||
status = -ENOMEM;
|
||||
goto midi_free;
|
||||
}
|
||||
midi->in_ports = opts->in_ports;
|
||||
midi->out_ports = opts->out_ports;
|
||||
midi->index = opts->index;
|
||||
midi->buflen = opts->buflen;
|
||||
|
||||
@@ -337,7 +337,7 @@ typedef struct urb_priv {
|
||||
u16 length; // # tds in this request
|
||||
u16 td_cnt; // tds already serviced
|
||||
struct list_head pending;
|
||||
struct td *td[]; // all TDs in this request
|
||||
struct td *td[] __counted_by(length); // all TDs in this request
|
||||
|
||||
} urb_priv_t;
|
||||
|
||||
|
||||
@@ -1666,7 +1666,7 @@ struct xhci_scratchpad {
|
||||
struct urb_priv {
|
||||
int num_tds;
|
||||
int num_tds_done;
|
||||
struct xhci_td td[];
|
||||
struct xhci_td td[] __counted_by(num_tds);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -60,7 +60,7 @@ struct vm_memory_region_batch {
|
||||
u16 reserved[3];
|
||||
u32 regions_num;
|
||||
u64 regions_gpa;
|
||||
struct vm_memory_region_op regions_op[];
|
||||
struct vm_memory_region_op regions_op[] __counted_by(regions_num);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -250,11 +250,11 @@ int acrn_vm_ram_map(struct acrn_vm *vm, struct acrn_vm_memmap *memmap)
|
||||
ret = -ENOMEM;
|
||||
goto unmap_kernel_map;
|
||||
}
|
||||
regions_info->regions_num = nr_regions;
|
||||
|
||||
/* Fill each vm_memory_region_op */
|
||||
vm_region = regions_info->regions_op;
|
||||
regions_info->vmid = vm->vmid;
|
||||
regions_info->regions_num = nr_regions;
|
||||
regions_info->regions_gpa = virt_to_phys(vm_region);
|
||||
user_vm_pa = memmap->user_vm_pa;
|
||||
i = 0;
|
||||
|
||||
+2
-2
@@ -87,7 +87,7 @@ struct afs_addr_list {
|
||||
enum dns_lookup_status status:8;
|
||||
unsigned long failed; /* Mask of addrs that failed locally/ICMP */
|
||||
unsigned long responded; /* Mask of addrs that responded */
|
||||
struct sockaddr_rxrpc addrs[];
|
||||
struct sockaddr_rxrpc addrs[] __counted_by(max_addrs);
|
||||
#define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8))
|
||||
};
|
||||
|
||||
@@ -705,7 +705,7 @@ struct afs_permits {
|
||||
refcount_t usage;
|
||||
unsigned short nr_permits; /* Number of records */
|
||||
bool invalidated; /* Invalidated due to key change */
|
||||
struct afs_permit permits[]; /* List of permits sorted by key pointer */
|
||||
struct afs_permit permits[] __counted_by(nr_permits); /* List of permits sorted by key pointer */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+75
-140
@@ -110,38 +110,19 @@ static struct linux_binfmt elf_format = {
|
||||
|
||||
#define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE))
|
||||
|
||||
static int set_brk(unsigned long start, unsigned long end, int prot)
|
||||
{
|
||||
start = ELF_PAGEALIGN(start);
|
||||
end = ELF_PAGEALIGN(end);
|
||||
if (end > start) {
|
||||
/*
|
||||
* Map the last of the bss segment.
|
||||
* If the header is requesting these pages to be
|
||||
* executable, honour that (ppc32 needs this).
|
||||
*/
|
||||
int error = vm_brk_flags(start, end - start,
|
||||
prot & PROT_EXEC ? VM_EXEC : 0);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
current->mm->start_brk = current->mm->brk = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We need to explicitly zero any fractional pages
|
||||
after the data section (i.e. bss). This would
|
||||
contain the junk from the file that should not
|
||||
be in memory
|
||||
/*
|
||||
* We need to explicitly zero any trailing portion of the page that follows
|
||||
* p_filesz when it ends before the page ends (e.g. bss), otherwise this
|
||||
* memory will contain the junk from the file that should not be present.
|
||||
*/
|
||||
static int padzero(unsigned long elf_bss)
|
||||
static int padzero(unsigned long address)
|
||||
{
|
||||
unsigned long nbyte;
|
||||
|
||||
nbyte = ELF_PAGEOFFSET(elf_bss);
|
||||
nbyte = ELF_PAGEOFFSET(address);
|
||||
if (nbyte) {
|
||||
nbyte = ELF_MIN_ALIGN - nbyte;
|
||||
if (clear_user((void __user *) elf_bss, nbyte))
|
||||
if (clear_user((void __user *)address, nbyte))
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
@@ -367,6 +348,11 @@ create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map "eppnt->p_filesz" bytes from "filep" offset "eppnt->p_offset"
|
||||
* into memory at "addr". (Note that p_filesz is rounded up to the
|
||||
* next page, so any extra bytes from the file must be wiped.)
|
||||
*/
|
||||
static unsigned long elf_map(struct file *filep, unsigned long addr,
|
||||
const struct elf_phdr *eppnt, int prot, int type,
|
||||
unsigned long total_size)
|
||||
@@ -406,6 +392,60 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
|
||||
return(map_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map "eppnt->p_filesz" bytes from "filep" offset "eppnt->p_offset"
|
||||
* into memory at "addr". Memory from "p_filesz" through "p_memsz"
|
||||
* rounded up to the next page is zeroed.
|
||||
*/
|
||||
static unsigned long elf_load(struct file *filep, unsigned long addr,
|
||||
const struct elf_phdr *eppnt, int prot, int type,
|
||||
unsigned long total_size)
|
||||
{
|
||||
unsigned long zero_start, zero_end;
|
||||
unsigned long map_addr;
|
||||
|
||||
if (eppnt->p_filesz) {
|
||||
map_addr = elf_map(filep, addr, eppnt, prot, type, total_size);
|
||||
if (BAD_ADDR(map_addr))
|
||||
return map_addr;
|
||||
if (eppnt->p_memsz > eppnt->p_filesz) {
|
||||
zero_start = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) +
|
||||
eppnt->p_filesz;
|
||||
zero_end = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) +
|
||||
eppnt->p_memsz;
|
||||
|
||||
/*
|
||||
* Zero the end of the last mapped page but ignore
|
||||
* any errors if the segment isn't writable.
|
||||
*/
|
||||
if (padzero(zero_start) && (prot & PROT_WRITE))
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
map_addr = zero_start = ELF_PAGESTART(addr);
|
||||
zero_end = zero_start + ELF_PAGEOFFSET(eppnt->p_vaddr) +
|
||||
eppnt->p_memsz;
|
||||
}
|
||||
if (eppnt->p_memsz > eppnt->p_filesz) {
|
||||
/*
|
||||
* Map the last of the segment.
|
||||
* If the header is requesting these pages to be
|
||||
* executable, honour that (ppc32 needs this).
|
||||
*/
|
||||
int error;
|
||||
|
||||
zero_start = ELF_PAGEALIGN(zero_start);
|
||||
zero_end = ELF_PAGEALIGN(zero_end);
|
||||
|
||||
error = vm_brk_flags(zero_start, zero_end - zero_start,
|
||||
prot & PROT_EXEC ? VM_EXEC : 0);
|
||||
if (error)
|
||||
map_addr = error;
|
||||
}
|
||||
return map_addr;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long total_mapping_size(const struct elf_phdr *phdr, int nr)
|
||||
{
|
||||
elf_addr_t min_addr = -1;
|
||||
@@ -596,8 +636,6 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
|
||||
struct elf_phdr *eppnt;
|
||||
unsigned long load_addr = 0;
|
||||
int load_addr_set = 0;
|
||||
unsigned long last_bss = 0, elf_bss = 0;
|
||||
int bss_prot = 0;
|
||||
unsigned long error = ~0UL;
|
||||
unsigned long total_size;
|
||||
int i;
|
||||
@@ -634,7 +672,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
|
||||
else if (no_base && interp_elf_ex->e_type == ET_DYN)
|
||||
load_addr = -vaddr;
|
||||
|
||||
map_addr = elf_map(interpreter, load_addr + vaddr,
|
||||
map_addr = elf_load(interpreter, load_addr + vaddr,
|
||||
eppnt, elf_prot, elf_type, total_size);
|
||||
total_size = 0;
|
||||
error = map_addr;
|
||||
@@ -660,51 +698,9 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the end of the file mapping for this phdr, and
|
||||
* keep track of the largest address we see for this.
|
||||
*/
|
||||
k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
|
||||
if (k > elf_bss)
|
||||
elf_bss = k;
|
||||
|
||||
/*
|
||||
* Do the same thing for the memory mapping - between
|
||||
* elf_bss and last_bss is the bss section.
|
||||
*/
|
||||
k = load_addr + eppnt->p_vaddr + eppnt->p_memsz;
|
||||
if (k > last_bss) {
|
||||
last_bss = k;
|
||||
bss_prot = elf_prot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now fill out the bss section: first pad the last page from
|
||||
* the file up to the page boundary, and zero it from elf_bss
|
||||
* up to the end of the page.
|
||||
*/
|
||||
if (padzero(elf_bss)) {
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* Next, align both the file and mem bss up to the page size,
|
||||
* since this is where elf_bss was just zeroed up to, and where
|
||||
* last_bss will end after the vm_brk_flags() below.
|
||||
*/
|
||||
elf_bss = ELF_PAGEALIGN(elf_bss);
|
||||
last_bss = ELF_PAGEALIGN(last_bss);
|
||||
/* Finally, if there is still more bss to allocate, do it. */
|
||||
if (last_bss > elf_bss) {
|
||||
error = vm_brk_flags(elf_bss, last_bss - elf_bss,
|
||||
bss_prot & PROT_EXEC ? VM_EXEC : 0);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = load_addr;
|
||||
out:
|
||||
return error;
|
||||
@@ -828,8 +824,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
|
||||
unsigned long error;
|
||||
struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
|
||||
struct elf_phdr *elf_property_phdata = NULL;
|
||||
unsigned long elf_bss, elf_brk;
|
||||
int bss_prot = 0;
|
||||
unsigned long elf_brk;
|
||||
int retval, i;
|
||||
unsigned long elf_entry;
|
||||
unsigned long e_entry;
|
||||
@@ -1020,7 +1015,6 @@ out_free_interp:
|
||||
if (retval < 0)
|
||||
goto out_free_dentry;
|
||||
|
||||
elf_bss = 0;
|
||||
elf_brk = 0;
|
||||
|
||||
start_code = ~0UL;
|
||||
@@ -1040,33 +1034,6 @@ out_free_interp:
|
||||
if (elf_ppnt->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (unlikely (elf_brk > elf_bss)) {
|
||||
unsigned long nbyte;
|
||||
|
||||
/* There was a PT_LOAD segment with p_memsz > p_filesz
|
||||
before this one. Map anonymous pages, if needed,
|
||||
and clear the area. */
|
||||
retval = set_brk(elf_bss + load_bias,
|
||||
elf_brk + load_bias,
|
||||
bss_prot);
|
||||
if (retval)
|
||||
goto out_free_dentry;
|
||||
nbyte = ELF_PAGEOFFSET(elf_bss);
|
||||
if (nbyte) {
|
||||
nbyte = ELF_MIN_ALIGN - nbyte;
|
||||
if (nbyte > elf_brk - elf_bss)
|
||||
nbyte = elf_brk - elf_bss;
|
||||
if (clear_user((void __user *)elf_bss +
|
||||
load_bias, nbyte)) {
|
||||
/*
|
||||
* This bss-zeroing can fail if the ELF
|
||||
* file specifies odd protections. So
|
||||
* we don't check the return value
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elf_prot = make_prot(elf_ppnt->p_flags, &arch_state,
|
||||
!!interpreter, false);
|
||||
|
||||
@@ -1162,7 +1129,7 @@ out_free_interp:
|
||||
}
|
||||
}
|
||||
|
||||
error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt,
|
||||
error = elf_load(bprm->file, load_bias + vaddr, elf_ppnt,
|
||||
elf_prot, elf_flags, total_size);
|
||||
if (BAD_ADDR(error)) {
|
||||
retval = IS_ERR_VALUE(error) ?
|
||||
@@ -1210,40 +1177,24 @@ out_free_interp:
|
||||
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
|
||||
|
||||
if (k > elf_bss)
|
||||
elf_bss = k;
|
||||
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
|
||||
end_code = k;
|
||||
if (end_data < k)
|
||||
end_data = k;
|
||||
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
|
||||
if (k > elf_brk) {
|
||||
bss_prot = elf_prot;
|
||||
if (k > elf_brk)
|
||||
elf_brk = k;
|
||||
}
|
||||
}
|
||||
|
||||
e_entry = elf_ex->e_entry + load_bias;
|
||||
phdr_addr += load_bias;
|
||||
elf_bss += load_bias;
|
||||
elf_brk += load_bias;
|
||||
start_code += load_bias;
|
||||
end_code += load_bias;
|
||||
start_data += load_bias;
|
||||
end_data += load_bias;
|
||||
|
||||
/* Calling set_brk effectively mmaps the pages that we need
|
||||
* for the bss and break sections. We must do this before
|
||||
* mapping in the interpreter, to make sure it doesn't wind
|
||||
* up getting placed where the bss needs to go.
|
||||
*/
|
||||
retval = set_brk(elf_bss, elf_brk, bss_prot);
|
||||
if (retval)
|
||||
goto out_free_dentry;
|
||||
if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) {
|
||||
retval = -EFAULT; /* Nobody gets to see this, but.. */
|
||||
goto out_free_dentry;
|
||||
}
|
||||
current->mm->start_brk = current->mm->brk = ELF_PAGEALIGN(elf_brk);
|
||||
|
||||
if (interpreter) {
|
||||
elf_entry = load_elf_interp(interp_elf_ex,
|
||||
@@ -1369,7 +1320,6 @@ static int load_elf_library(struct file *file)
|
||||
{
|
||||
struct elf_phdr *elf_phdata;
|
||||
struct elf_phdr *eppnt;
|
||||
unsigned long elf_bss, bss, len;
|
||||
int retval, error, i, j;
|
||||
struct elfhdr elf_ex;
|
||||
|
||||
@@ -1414,30 +1364,15 @@ static int load_elf_library(struct file *file)
|
||||
eppnt++;
|
||||
|
||||
/* Now use mmap to map the library into memory. */
|
||||
error = vm_mmap(file,
|
||||
ELF_PAGESTART(eppnt->p_vaddr),
|
||||
(eppnt->p_filesz +
|
||||
ELF_PAGEOFFSET(eppnt->p_vaddr)),
|
||||
error = elf_load(file, ELF_PAGESTART(eppnt->p_vaddr),
|
||||
eppnt,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_FIXED_NOREPLACE | MAP_PRIVATE,
|
||||
(eppnt->p_offset -
|
||||
ELF_PAGEOFFSET(eppnt->p_vaddr)));
|
||||
0);
|
||||
|
||||
if (error != ELF_PAGESTART(eppnt->p_vaddr))
|
||||
goto out_free_ph;
|
||||
|
||||
elf_bss = eppnt->p_vaddr + eppnt->p_filesz;
|
||||
if (padzero(elf_bss)) {
|
||||
error = -EFAULT;
|
||||
goto out_free_ph;
|
||||
}
|
||||
|
||||
len = ELF_PAGEALIGN(eppnt->p_filesz + eppnt->p_vaddr);
|
||||
bss = ELF_PAGEALIGN(eppnt->p_memsz + eppnt->p_vaddr);
|
||||
if (bss > len) {
|
||||
error = vm_brk(len, bss - len);
|
||||
if (error)
|
||||
goto out_free_ph;
|
||||
}
|
||||
error = 0;
|
||||
|
||||
out_free_ph:
|
||||
|
||||
+12
-8
@@ -899,10 +899,12 @@ static int elf_fdpic_map_file(struct elf_fdpic_params *params,
|
||||
kdebug("- DYNAMIC[]: %lx", params->dynamic_addr);
|
||||
seg = loadmap->segs;
|
||||
for (loop = 0; loop < loadmap->nsegs; loop++, seg++)
|
||||
kdebug("- LOAD[%d] : %08x-%08x [va=%x ms=%x]",
|
||||
kdebug("- LOAD[%d] : %08llx-%08llx [va=%llx ms=%llx]",
|
||||
loop,
|
||||
seg->addr, seg->addr + seg->p_memsz - 1,
|
||||
seg->p_vaddr, seg->p_memsz);
|
||||
(unsigned long long) seg->addr,
|
||||
(unsigned long long) seg->addr + seg->p_memsz - 1,
|
||||
(unsigned long long) seg->p_vaddr,
|
||||
(unsigned long long) seg->p_memsz);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1081,9 +1083,10 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
|
||||
maddr = vm_mmap(file, maddr, phdr->p_memsz + disp, prot, flags,
|
||||
phdr->p_offset - disp);
|
||||
|
||||
kdebug("mmap[%d] <file> sz=%lx pr=%x fl=%x of=%lx --> %08lx",
|
||||
loop, phdr->p_memsz + disp, prot, flags,
|
||||
phdr->p_offset - disp, maddr);
|
||||
kdebug("mmap[%d] <file> sz=%llx pr=%x fl=%x of=%llx --> %08lx",
|
||||
loop, (unsigned long long) phdr->p_memsz + disp,
|
||||
prot, flags, (unsigned long long) phdr->p_offset - disp,
|
||||
maddr);
|
||||
|
||||
if (IS_ERR_VALUE(maddr))
|
||||
return (int) maddr;
|
||||
@@ -1145,8 +1148,9 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
|
||||
|
||||
#else
|
||||
if (excess > 0) {
|
||||
kdebug("clear[%d] ad=%lx sz=%lx",
|
||||
loop, maddr + phdr->p_filesz, excess);
|
||||
kdebug("clear[%d] ad=%llx sz=%lx", loop,
|
||||
(unsigned long long) maddr + phdr->p_filesz,
|
||||
excess);
|
||||
if (clear_user((void *) maddr + phdr->p_filesz, excess))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
+320
-66
@@ -40,9 +40,6 @@ enum {
|
||||
VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
|
||||
};
|
||||
|
||||
static LIST_HEAD(entries);
|
||||
static int enabled = 1;
|
||||
|
||||
enum {Enabled, Magic};
|
||||
#define MISC_FMT_PRESERVE_ARGV0 (1UL << 31)
|
||||
#define MISC_FMT_OPEN_BINARY (1UL << 30)
|
||||
@@ -60,12 +57,10 @@ typedef struct {
|
||||
char *name;
|
||||
struct dentry *dentry;
|
||||
struct file *interp_file;
|
||||
refcount_t users; /* sync removal with load_misc_binary() */
|
||||
} Node;
|
||||
|
||||
static DEFINE_RWLOCK(entries_lock);
|
||||
static struct file_system_type bm_fs_type;
|
||||
static struct vfsmount *bm_mnt;
|
||||
static int entry_count;
|
||||
|
||||
/*
|
||||
* Max length of the register string. Determined by:
|
||||
@@ -82,19 +77,24 @@ static int entry_count;
|
||||
*/
|
||||
#define MAX_REGISTER_LENGTH 1920
|
||||
|
||||
/*
|
||||
* Check if we support the binfmt
|
||||
* if we do, return the node, else NULL
|
||||
* locking is done in load_misc_binary
|
||||
/**
|
||||
* search_binfmt_handler - search for a binary handler for @bprm
|
||||
* @misc: handle to binfmt_misc instance
|
||||
* @bprm: binary for which we are looking for a handler
|
||||
*
|
||||
* Search for a binary type handler for @bprm in the list of registered binary
|
||||
* type handlers.
|
||||
*
|
||||
* Return: binary type list entry on success, NULL on failure
|
||||
*/
|
||||
static Node *check_file(struct linux_binprm *bprm)
|
||||
static Node *search_binfmt_handler(struct binfmt_misc *misc,
|
||||
struct linux_binprm *bprm)
|
||||
{
|
||||
char *p = strrchr(bprm->interp, '.');
|
||||
struct list_head *l;
|
||||
Node *e;
|
||||
|
||||
/* Walk all the registered handlers. */
|
||||
list_for_each(l, &entries) {
|
||||
Node *e = list_entry(l, Node, list);
|
||||
list_for_each_entry(e, &misc->entries, list) {
|
||||
char *s;
|
||||
int j;
|
||||
|
||||
@@ -123,9 +123,79 @@ static Node *check_file(struct linux_binprm *bprm)
|
||||
if (j == e->size)
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_binfmt_handler - try to find a binary type handler
|
||||
* @misc: handle to binfmt_misc instance
|
||||
* @bprm: binary for which we are looking for a handler
|
||||
*
|
||||
* Try to find a binfmt handler for the binary type. If one is found take a
|
||||
* reference to protect against removal via bm_{entry,status}_write().
|
||||
*
|
||||
* Return: binary type list entry on success, NULL on failure
|
||||
*/
|
||||
static Node *get_binfmt_handler(struct binfmt_misc *misc,
|
||||
struct linux_binprm *bprm)
|
||||
{
|
||||
Node *e;
|
||||
|
||||
read_lock(&misc->entries_lock);
|
||||
e = search_binfmt_handler(misc, bprm);
|
||||
if (e)
|
||||
refcount_inc(&e->users);
|
||||
read_unlock(&misc->entries_lock);
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* put_binfmt_handler - put binary handler node
|
||||
* @e: node to put
|
||||
*
|
||||
* Free node syncing with load_misc_binary() and defer final free to
|
||||
* load_misc_binary() in case it is using the binary type handler we were
|
||||
* requested to remove.
|
||||
*/
|
||||
static void put_binfmt_handler(Node *e)
|
||||
{
|
||||
if (refcount_dec_and_test(&e->users)) {
|
||||
if (e->flags & MISC_FMT_OPEN_FILE)
|
||||
filp_close(e->interp_file, NULL);
|
||||
kfree(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load_binfmt_misc - load the binfmt_misc of the caller's user namespace
|
||||
*
|
||||
* To be called in load_misc_binary() to load the relevant struct binfmt_misc.
|
||||
* If a user namespace doesn't have its own binfmt_misc mount it can make use
|
||||
* of its ancestor's binfmt_misc handlers. This mimicks the behavior of
|
||||
* pre-namespaced binfmt_misc where all registered binfmt_misc handlers where
|
||||
* available to all user and user namespaces on the system.
|
||||
*
|
||||
* Return: the binfmt_misc instance of the caller's user namespace
|
||||
*/
|
||||
static struct binfmt_misc *load_binfmt_misc(void)
|
||||
{
|
||||
const struct user_namespace *user_ns;
|
||||
struct binfmt_misc *misc;
|
||||
|
||||
user_ns = current_user_ns();
|
||||
while (user_ns) {
|
||||
/* Pairs with smp_store_release() in bm_fill_super(). */
|
||||
misc = smp_load_acquire(&user_ns->binfmt_misc);
|
||||
if (misc)
|
||||
return misc;
|
||||
|
||||
user_ns = user_ns->parent;
|
||||
}
|
||||
|
||||
return &init_binfmt_misc;
|
||||
}
|
||||
|
||||
/*
|
||||
* the loader itself
|
||||
*/
|
||||
@@ -133,18 +203,14 @@ static int load_misc_binary(struct linux_binprm *bprm)
|
||||
{
|
||||
Node *fmt;
|
||||
struct file *interp_file = NULL;
|
||||
int retval;
|
||||
int retval = -ENOEXEC;
|
||||
struct binfmt_misc *misc;
|
||||
|
||||
retval = -ENOEXEC;
|
||||
if (!enabled)
|
||||
misc = load_binfmt_misc();
|
||||
if (!misc->enabled)
|
||||
return retval;
|
||||
|
||||
/* to keep locking time low, we copy the interpreter string */
|
||||
read_lock(&entries_lock);
|
||||
fmt = check_file(bprm);
|
||||
if (fmt)
|
||||
dget(fmt->dentry);
|
||||
read_unlock(&entries_lock);
|
||||
fmt = get_binfmt_handler(misc, bprm);
|
||||
if (!fmt)
|
||||
return retval;
|
||||
|
||||
@@ -198,7 +264,16 @@ static int load_misc_binary(struct linux_binprm *bprm)
|
||||
|
||||
retval = 0;
|
||||
ret:
|
||||
dput(fmt->dentry);
|
||||
|
||||
/*
|
||||
* If we actually put the node here all concurrent calls to
|
||||
* load_misc_binary() will have finished. We also know
|
||||
* that for the refcount to be zero someone must have concurently
|
||||
* removed the binary type handler from the list and it's our job to
|
||||
* free it.
|
||||
*/
|
||||
put_binfmt_handler(fmt);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -287,7 +362,7 @@ static Node *create_entry(const char __user *buffer, size_t count)
|
||||
|
||||
err = -ENOMEM;
|
||||
memsize = sizeof(Node) + count + 8;
|
||||
e = kmalloc(memsize, GFP_KERNEL);
|
||||
e = kmalloc(memsize, GFP_KERNEL_ACCOUNT);
|
||||
if (!e)
|
||||
goto out;
|
||||
|
||||
@@ -399,7 +474,7 @@ static Node *create_entry(const char __user *buffer, size_t count)
|
||||
|
||||
if (e->mask) {
|
||||
int i;
|
||||
char *masked = kmalloc(e->size, GFP_KERNEL);
|
||||
char *masked = kmalloc(e->size, GFP_KERNEL_ACCOUNT);
|
||||
|
||||
print_hex_dump_bytes(
|
||||
KBUILD_MODNAME ": register: mask[decoded]: ",
|
||||
@@ -552,30 +627,109 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
|
||||
return inode;
|
||||
}
|
||||
|
||||
/**
|
||||
* i_binfmt_misc - retrieve struct binfmt_misc from a binfmt_misc inode
|
||||
* @inode: inode of the relevant binfmt_misc instance
|
||||
*
|
||||
* This helper retrieves struct binfmt_misc from a binfmt_misc inode. This can
|
||||
* be done without any memory barriers because we are guaranteed that
|
||||
* user_ns->binfmt_misc is fully initialized. It was fully initialized when the
|
||||
* binfmt_misc mount was first created.
|
||||
*
|
||||
* Return: struct binfmt_misc of the relevant binfmt_misc instance
|
||||
*/
|
||||
static struct binfmt_misc *i_binfmt_misc(struct inode *inode)
|
||||
{
|
||||
return inode->i_sb->s_user_ns->binfmt_misc;
|
||||
}
|
||||
|
||||
/**
|
||||
* bm_evict_inode - cleanup data associated with @inode
|
||||
* @inode: inode to which the data is attached
|
||||
*
|
||||
* Cleanup the binary type handler data associated with @inode if a binary type
|
||||
* entry is removed or the filesystem is unmounted and the super block is
|
||||
* shutdown.
|
||||
*
|
||||
* If the ->evict call was not caused by a super block shutdown but by a write
|
||||
* to remove the entry or all entries via bm_{entry,status}_write() the entry
|
||||
* will have already been removed from the list. We keep the list_empty() check
|
||||
* to make that explicit.
|
||||
*/
|
||||
static void bm_evict_inode(struct inode *inode)
|
||||
{
|
||||
Node *e = inode->i_private;
|
||||
|
||||
if (e && e->flags & MISC_FMT_OPEN_FILE)
|
||||
filp_close(e->interp_file, NULL);
|
||||
|
||||
clear_inode(inode);
|
||||
kfree(e);
|
||||
|
||||
if (e) {
|
||||
struct binfmt_misc *misc;
|
||||
|
||||
misc = i_binfmt_misc(inode);
|
||||
write_lock(&misc->entries_lock);
|
||||
if (!list_empty(&e->list))
|
||||
list_del_init(&e->list);
|
||||
write_unlock(&misc->entries_lock);
|
||||
put_binfmt_handler(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void kill_node(Node *e)
|
||||
/**
|
||||
* unlink_binfmt_dentry - remove the dentry for the binary type handler
|
||||
* @dentry: dentry associated with the binary type handler
|
||||
*
|
||||
* Do the actual filesystem work to remove a dentry for a registered binary
|
||||
* type handler. Since binfmt_misc only allows simple files to be created
|
||||
* directly under the root dentry of the filesystem we ensure that we are
|
||||
* indeed passed a dentry directly beneath the root dentry, that the inode
|
||||
* associated with the root dentry is locked, and that it is a regular file we
|
||||
* are asked to remove.
|
||||
*/
|
||||
static void unlink_binfmt_dentry(struct dentry *dentry)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct dentry *parent = dentry->d_parent;
|
||||
struct inode *inode, *parent_inode;
|
||||
|
||||
write_lock(&entries_lock);
|
||||
/* All entries are immediate descendants of the root dentry. */
|
||||
if (WARN_ON_ONCE(dentry->d_sb->s_root != parent))
|
||||
return;
|
||||
|
||||
/* We only expect to be called on regular files. */
|
||||
inode = d_inode(dentry);
|
||||
if (WARN_ON_ONCE(!S_ISREG(inode->i_mode)))
|
||||
return;
|
||||
|
||||
/* The parent inode must be locked. */
|
||||
parent_inode = d_inode(parent);
|
||||
if (WARN_ON_ONCE(!inode_is_locked(parent_inode)))
|
||||
return;
|
||||
|
||||
if (simple_positive(dentry)) {
|
||||
dget(dentry);
|
||||
simple_unlink(parent_inode, dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove_binfmt_handler - remove a binary type handler
|
||||
* @misc: handle to binfmt_misc instance
|
||||
* @e: binary type handler to remove
|
||||
*
|
||||
* Remove a binary type handler from the list of binary type handlers and
|
||||
* remove its associated dentry. This is called from
|
||||
* binfmt_{entry,status}_write(). In the future, we might want to think about
|
||||
* adding a proper ->unlink() method to binfmt_misc instead of forcing caller's
|
||||
* to use writes to files in order to delete binary type handlers. But it has
|
||||
* worked for so long that it's not a pressing issue.
|
||||
*/
|
||||
static void remove_binfmt_handler(struct binfmt_misc *misc, Node *e)
|
||||
{
|
||||
write_lock(&misc->entries_lock);
|
||||
list_del_init(&e->list);
|
||||
write_unlock(&entries_lock);
|
||||
|
||||
dentry = e->dentry;
|
||||
drop_nlink(d_inode(dentry));
|
||||
d_drop(dentry);
|
||||
dput(dentry);
|
||||
simple_release_fs(&bm_mnt, &entry_count);
|
||||
write_unlock(&misc->entries_lock);
|
||||
unlink_binfmt_dentry(e->dentry);
|
||||
}
|
||||
|
||||
/* /<entry> */
|
||||
@@ -602,8 +756,8 @@ bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
|
||||
static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct dentry *root;
|
||||
Node *e = file_inode(file)->i_private;
|
||||
struct inode *inode = file_inode(file);
|
||||
Node *e = inode->i_private;
|
||||
int res = parse_command(buffer, count);
|
||||
|
||||
switch (res) {
|
||||
@@ -617,13 +771,22 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
|
||||
break;
|
||||
case 3:
|
||||
/* Delete this handler. */
|
||||
root = file_inode(file)->i_sb->s_root;
|
||||
inode_lock(d_inode(root));
|
||||
inode = d_inode(inode->i_sb->s_root);
|
||||
inode_lock(inode);
|
||||
|
||||
/*
|
||||
* In order to add new element or remove elements from the list
|
||||
* via bm_{entry,register,status}_write() inode_lock() on the
|
||||
* root inode must be held.
|
||||
* The lock is exclusive ensuring that the list can't be
|
||||
* modified. Only load_misc_binary() can access but does so
|
||||
* read-only. So we only need to take the write lock when we
|
||||
* actually remove the entry from the list.
|
||||
*/
|
||||
if (!list_empty(&e->list))
|
||||
kill_node(e);
|
||||
remove_binfmt_handler(i_binfmt_misc(inode), e);
|
||||
|
||||
inode_unlock(d_inode(root));
|
||||
inode_unlock(inode);
|
||||
break;
|
||||
default:
|
||||
return res;
|
||||
@@ -647,6 +810,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
|
||||
struct inode *inode;
|
||||
struct super_block *sb = file_inode(file)->i_sb;
|
||||
struct dentry *root = sb->s_root, *dentry;
|
||||
struct binfmt_misc *misc;
|
||||
int err = 0;
|
||||
struct file *f = NULL;
|
||||
|
||||
@@ -656,7 +820,18 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
|
||||
return PTR_ERR(e);
|
||||
|
||||
if (e->flags & MISC_FMT_OPEN_FILE) {
|
||||
const struct cred *old_cred;
|
||||
|
||||
/*
|
||||
* Now that we support unprivileged binfmt_misc mounts make
|
||||
* sure we use the credentials that the register @file was
|
||||
* opened with to also open the interpreter. Before that this
|
||||
* didn't matter much as only a privileged process could open
|
||||
* the register file.
|
||||
*/
|
||||
old_cred = override_creds(file->f_cred);
|
||||
f = open_exec(e->interpreter);
|
||||
revert_creds(old_cred);
|
||||
if (IS_ERR(f)) {
|
||||
pr_notice("register: failed to install interpreter file %s\n",
|
||||
e->interpreter);
|
||||
@@ -682,21 +857,16 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
|
||||
if (!inode)
|
||||
goto out2;
|
||||
|
||||
err = simple_pin_fs(&bm_fs_type, &bm_mnt, &entry_count);
|
||||
if (err) {
|
||||
iput(inode);
|
||||
inode = NULL;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
refcount_set(&e->users, 1);
|
||||
e->dentry = dget(dentry);
|
||||
inode->i_private = e;
|
||||
inode->i_fop = &bm_entry_operations;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
write_lock(&entries_lock);
|
||||
list_add(&e->list, &entries);
|
||||
write_unlock(&entries_lock);
|
||||
misc = i_binfmt_misc(inode);
|
||||
write_lock(&misc->entries_lock);
|
||||
list_add(&e->list, &misc->entries);
|
||||
write_unlock(&misc->entries_lock);
|
||||
|
||||
err = 0;
|
||||
out2:
|
||||
@@ -723,35 +893,50 @@ static const struct file_operations bm_register_operations = {
|
||||
static ssize_t
|
||||
bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
|
||||
{
|
||||
char *s = enabled ? "enabled\n" : "disabled\n";
|
||||
struct binfmt_misc *misc;
|
||||
char *s;
|
||||
|
||||
misc = i_binfmt_misc(file_inode(file));
|
||||
s = misc->enabled ? "enabled\n" : "disabled\n";
|
||||
return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
|
||||
}
|
||||
|
||||
static ssize_t bm_status_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct binfmt_misc *misc;
|
||||
int res = parse_command(buffer, count);
|
||||
struct dentry *root;
|
||||
Node *e, *next;
|
||||
struct inode *inode;
|
||||
|
||||
misc = i_binfmt_misc(file_inode(file));
|
||||
switch (res) {
|
||||
case 1:
|
||||
/* Disable all handlers. */
|
||||
enabled = 0;
|
||||
misc->enabled = false;
|
||||
break;
|
||||
case 2:
|
||||
/* Enable all handlers. */
|
||||
enabled = 1;
|
||||
misc->enabled = true;
|
||||
break;
|
||||
case 3:
|
||||
/* Delete all handlers. */
|
||||
root = file_inode(file)->i_sb->s_root;
|
||||
inode_lock(d_inode(root));
|
||||
inode = d_inode(file_inode(file)->i_sb->s_root);
|
||||
inode_lock(inode);
|
||||
|
||||
while (!list_empty(&entries))
|
||||
kill_node(list_first_entry(&entries, Node, list));
|
||||
/*
|
||||
* In order to add new element or remove elements from the list
|
||||
* via bm_{entry,register,status}_write() inode_lock() on the
|
||||
* root inode must be held.
|
||||
* The lock is exclusive ensuring that the list can't be
|
||||
* modified. Only load_misc_binary() can access but does so
|
||||
* read-only. So we only need to take the write lock when we
|
||||
* actually remove the entry from the list.
|
||||
*/
|
||||
list_for_each_entry_safe(e, next, &misc->entries, list)
|
||||
remove_binfmt_handler(misc, e);
|
||||
|
||||
inode_unlock(d_inode(root));
|
||||
inode_unlock(inode);
|
||||
break;
|
||||
default:
|
||||
return res;
|
||||
@@ -768,32 +953,100 @@ static const struct file_operations bm_status_operations = {
|
||||
|
||||
/* Superblock handling */
|
||||
|
||||
static void bm_put_super(struct super_block *sb)
|
||||
{
|
||||
struct user_namespace *user_ns = sb->s_fs_info;
|
||||
|
||||
sb->s_fs_info = NULL;
|
||||
put_user_ns(user_ns);
|
||||
}
|
||||
|
||||
static const struct super_operations s_ops = {
|
||||
.statfs = simple_statfs,
|
||||
.evict_inode = bm_evict_inode,
|
||||
.put_super = bm_put_super,
|
||||
};
|
||||
|
||||
static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
{
|
||||
int err;
|
||||
struct user_namespace *user_ns = sb->s_user_ns;
|
||||
struct binfmt_misc *misc;
|
||||
static const struct tree_descr bm_files[] = {
|
||||
[2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
|
||||
[3] = {"register", &bm_register_operations, S_IWUSR},
|
||||
/* last one */ {""}
|
||||
};
|
||||
|
||||
if (WARN_ON(user_ns != current_user_ns()))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Lazily allocate a new binfmt_misc instance for this namespace, i.e.
|
||||
* do it here during the first mount of binfmt_misc. We don't need to
|
||||
* waste memory for every user namespace allocation. It's likely much
|
||||
* more common to not mount a separate binfmt_misc instance than it is
|
||||
* to mount one.
|
||||
*
|
||||
* While multiple superblocks can exist they are keyed by userns in
|
||||
* s_fs_info for binfmt_misc. Hence, the vfs guarantees that
|
||||
* bm_fill_super() is called exactly once whenever a binfmt_misc
|
||||
* superblock for a userns is created. This in turn lets us conclude
|
||||
* that when a binfmt_misc superblock is created for the first time for
|
||||
* a userns there's no one racing us. Therefore we don't need any
|
||||
* barriers when we dereference binfmt_misc.
|
||||
*/
|
||||
misc = user_ns->binfmt_misc;
|
||||
if (!misc) {
|
||||
/*
|
||||
* If it turns out that most user namespaces actually want to
|
||||
* register their own binary type handler and therefore all
|
||||
* create their own separate binfm_misc mounts we should
|
||||
* consider turning this into a kmem cache.
|
||||
*/
|
||||
misc = kzalloc(sizeof(struct binfmt_misc), GFP_KERNEL);
|
||||
if (!misc)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&misc->entries);
|
||||
rwlock_init(&misc->entries_lock);
|
||||
|
||||
/* Pairs with smp_load_acquire() in load_binfmt_misc(). */
|
||||
smp_store_release(&user_ns->binfmt_misc, misc);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the binfmt_misc superblock for this userns is shutdown
|
||||
* ->enabled might have been set to false and we don't reinitialize
|
||||
* ->enabled again in put_super() as someone might already be mounting
|
||||
* binfmt_misc again. It also would be pointless since by the time
|
||||
* ->put_super() is called we know that the binary type list for this
|
||||
* bintfmt_misc mount is empty making load_misc_binary() return
|
||||
* -ENOEXEC independent of whether ->enabled is true. Instead, if
|
||||
* someone mounts binfmt_misc for the first time or again we simply
|
||||
* reset ->enabled to true.
|
||||
*/
|
||||
misc->enabled = true;
|
||||
|
||||
err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
|
||||
if (!err)
|
||||
sb->s_op = &s_ops;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bm_free(struct fs_context *fc)
|
||||
{
|
||||
if (fc->s_fs_info)
|
||||
put_user_ns(fc->s_fs_info);
|
||||
}
|
||||
|
||||
static int bm_get_tree(struct fs_context *fc)
|
||||
{
|
||||
return get_tree_single(fc, bm_fill_super);
|
||||
return get_tree_keyed(fc, bm_fill_super, get_user_ns(fc->user_ns));
|
||||
}
|
||||
|
||||
static const struct fs_context_operations bm_context_ops = {
|
||||
.free = bm_free,
|
||||
.get_tree = bm_get_tree,
|
||||
};
|
||||
|
||||
@@ -812,6 +1065,7 @@ static struct file_system_type bm_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "binfmt_misc",
|
||||
.init_fs_context = bm_init_fs_context,
|
||||
.fs_flags = FS_USERNS_MOUNT,
|
||||
.kill_sb = kill_litter_super,
|
||||
};
|
||||
MODULE_ALIAS_FS("binfmt_misc");
|
||||
|
||||
@@ -51,7 +51,7 @@ struct nfs4_file_layout_dsaddr {
|
||||
u32 stripe_count;
|
||||
u8 *stripe_indices;
|
||||
u32 ds_num;
|
||||
struct nfs4_pnfs_ds *ds_list[];
|
||||
struct nfs4_pnfs_ds *ds_list[] __counted_by(ds_num);
|
||||
};
|
||||
|
||||
struct nfs4_filelayout_segment {
|
||||
|
||||
@@ -99,7 +99,7 @@ struct nfs4_ff_layout_segment {
|
||||
u64 stripe_unit;
|
||||
u32 flags;
|
||||
u32 mirror_array_cnt;
|
||||
struct nfs4_ff_layout_mirror *mirror_array[];
|
||||
struct nfs4_ff_layout_mirror *mirror_array[] __counted_by(mirror_array_cnt);
|
||||
};
|
||||
|
||||
struct nfs4_flexfile_layout {
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ struct ocfs2_slot_info {
|
||||
unsigned int si_blocks;
|
||||
struct buffer_head **si_bh;
|
||||
unsigned int si_num_slots;
|
||||
struct ocfs2_slot si_slots[];
|
||||
struct ocfs2_slot si_slots[] __counted_by(si_num_slots);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -464,6 +464,8 @@ out:
|
||||
*/
|
||||
int pstore_register(struct pstore_info *psi)
|
||||
{
|
||||
char *new_backend;
|
||||
|
||||
if (backend && strcmp(backend, psi->name)) {
|
||||
pr_warn("backend '%s' already in use: ignoring '%s'\n",
|
||||
backend, psi->name);
|
||||
@@ -484,11 +486,16 @@ int pstore_register(struct pstore_info *psi)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
new_backend = kstrdup(psi->name, GFP_KERNEL);
|
||||
if (!new_backend)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&psinfo_lock);
|
||||
if (psinfo) {
|
||||
pr_warn("backend '%s' already loaded: ignoring '%s'\n",
|
||||
psinfo->name, psi->name);
|
||||
mutex_unlock(&psinfo_lock);
|
||||
kfree(new_backend);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -521,7 +528,7 @@ int pstore_register(struct pstore_info *psi)
|
||||
* Update the module parameter backend, so it is visible
|
||||
* through /sys/module/pstore/parameters/backend
|
||||
*/
|
||||
backend = kstrdup(psi->name, GFP_KERNEL);
|
||||
backend = new_backend;
|
||||
|
||||
pr_info("Registered %s as persistent store backend\n", psi->name);
|
||||
|
||||
|
||||
@@ -90,6 +90,16 @@ struct linux_binfmt {
|
||||
#endif
|
||||
} __randomize_layout;
|
||||
|
||||
#if IS_ENABLED(CONFIG_BINFMT_MISC)
|
||||
struct binfmt_misc {
|
||||
struct list_head entries;
|
||||
rwlock_t entries_lock;
|
||||
bool enabled;
|
||||
} __randomize_layout;
|
||||
|
||||
extern struct binfmt_misc init_binfmt_misc;
|
||||
#endif
|
||||
|
||||
extern void __register_binfmt(struct linux_binfmt *fmt, int insert);
|
||||
|
||||
/* Registration of default binfmt handlers */
|
||||
|
||||
@@ -278,7 +278,7 @@ struct ceph_osd_request {
|
||||
int r_attempts;
|
||||
u32 r_map_dne_bound;
|
||||
|
||||
struct ceph_osd_req_op r_ops[];
|
||||
struct ceph_osd_req_op r_ops[] __counted_by(r_num_ops);
|
||||
};
|
||||
|
||||
struct ceph_request_redirect {
|
||||
|
||||
@@ -92,7 +92,7 @@ int parse_crashkernel_low(char *cmdline, unsigned long long system_ram,
|
||||
struct crash_mem {
|
||||
unsigned int max_nr_ranges;
|
||||
unsigned int nr_ranges;
|
||||
struct range ranges[];
|
||||
struct range ranges[] __counted_by(max_nr_ranges);
|
||||
};
|
||||
|
||||
extern int crash_exclude_mem_range(struct crash_mem *mem,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/key.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/user.h>
|
||||
@@ -23,7 +24,7 @@ struct inode;
|
||||
* COW Supplementary groups list
|
||||
*/
|
||||
struct group_info {
|
||||
atomic_t usage;
|
||||
refcount_t usage;
|
||||
int ngroups;
|
||||
kgid_t gid[];
|
||||
} __randomize_layout;
|
||||
@@ -39,7 +40,7 @@ struct group_info {
|
||||
*/
|
||||
static inline struct group_info *get_group_info(struct group_info *gi)
|
||||
{
|
||||
atomic_inc(&gi->usage);
|
||||
refcount_inc(&gi->usage);
|
||||
return gi;
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ static inline struct group_info *get_group_info(struct group_info *gi)
|
||||
*/
|
||||
#define put_group_info(group_info) \
|
||||
do { \
|
||||
if (atomic_dec_and_test(&(group_info)->usage)) \
|
||||
if (refcount_dec_and_test(&(group_info)->usage)) \
|
||||
groups_free(group_info); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -664,7 +664,7 @@ struct kvm_irq_routing_table {
|
||||
* Array indexed by gsi. Each entry contains list of irq chips
|
||||
* the gsi is connected to.
|
||||
*/
|
||||
struct hlist_head map[];
|
||||
struct hlist_head map[] __counted_by(nr_rt_entries);
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
+1
-2
@@ -3308,8 +3308,7 @@ static inline void mm_populate(unsigned long addr, unsigned long len)
|
||||
static inline void mm_populate(unsigned long addr, unsigned long len) {}
|
||||
#endif
|
||||
|
||||
/* These take the mm semaphore themselves */
|
||||
extern int __must_check vm_brk(unsigned long, unsigned long);
|
||||
/* This takes the mm semaphore itself */
|
||||
extern int __must_check vm_brk_flags(unsigned long, unsigned long, unsigned long);
|
||||
extern int vm_munmap(unsigned long, size_t);
|
||||
extern unsigned long __must_check vm_mmap(struct file *, unsigned long,
|
||||
|
||||
@@ -40,6 +40,6 @@ struct gsc_hwmon_platform_data {
|
||||
unsigned int resolution;
|
||||
unsigned int vreference;
|
||||
unsigned int fan_base;
|
||||
struct gsc_hwmon_channel channels[];
|
||||
struct gsc_hwmon_channel channels[] __counted_by(nchannels);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -277,10 +277,12 @@ void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
|
||||
*/
|
||||
#define strtomem_pad(dest, src, pad) do { \
|
||||
const size_t _dest_len = __builtin_object_size(dest, 1); \
|
||||
const size_t _src_len = __builtin_object_size(src, 1); \
|
||||
\
|
||||
BUILD_BUG_ON(!__builtin_constant_p(_dest_len) || \
|
||||
_dest_len == (size_t)-1); \
|
||||
memcpy_and_pad(dest, _dest_len, src, strnlen(src, _dest_len), pad); \
|
||||
memcpy_and_pad(dest, _dest_len, src, \
|
||||
strnlen(src, min(_src_len, _dest_len)), pad); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
@@ -298,10 +300,11 @@ void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count,
|
||||
*/
|
||||
#define strtomem(dest, src) do { \
|
||||
const size_t _dest_len = __builtin_object_size(dest, 1); \
|
||||
const size_t _src_len = __builtin_object_size(src, 1); \
|
||||
\
|
||||
BUILD_BUG_ON(!__builtin_constant_p(_dest_len) || \
|
||||
_dest_len == (size_t)-1); \
|
||||
memcpy(dest, src, min(_dest_len, strnlen(src, _dest_len))); \
|
||||
memcpy(dest, src, strnlen(src, min(_src_len, _dest_len))); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,6 +65,10 @@ enum rlimit_type {
|
||||
UCOUNT_RLIMIT_COUNTS,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_BINFMT_MISC)
|
||||
struct binfmt_misc;
|
||||
#endif
|
||||
|
||||
struct user_namespace {
|
||||
struct uid_gid_map uid_map;
|
||||
struct uid_gid_map gid_map;
|
||||
@@ -102,6 +106,10 @@ struct user_namespace {
|
||||
struct ucounts *ucounts;
|
||||
long ucount_max[UCOUNT_COUNTS];
|
||||
long rlimit_max[UCOUNT_RLIMIT_COUNTS];
|
||||
|
||||
#if IS_ENABLED(CONFIG_BINFMT_MISC)
|
||||
struct binfmt_misc *binfmt_misc;
|
||||
#endif
|
||||
} __randomize_layout;
|
||||
|
||||
struct ucounts {
|
||||
|
||||
@@ -140,7 +140,7 @@ typedef __s64 Elf64_Sxword;
|
||||
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
|
||||
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
|
||||
|
||||
typedef struct dynamic {
|
||||
typedef struct {
|
||||
Elf32_Sword d_tag;
|
||||
union {
|
||||
Elf32_Sword d_val;
|
||||
|
||||
+3
-3
@@ -21,10 +21,10 @@ static int __init early_hostname(char *arg)
|
||||
{
|
||||
size_t bufsize = sizeof(init_uts_ns.name.nodename);
|
||||
size_t maxlen = bufsize - 1;
|
||||
size_t arglen;
|
||||
ssize_t arglen;
|
||||
|
||||
arglen = strlcpy(init_uts_ns.name.nodename, arg, bufsize);
|
||||
if (arglen > maxlen) {
|
||||
arglen = strscpy(init_uts_ns.name.nodename, arg, bufsize);
|
||||
if (arglen < 0) {
|
||||
pr_warn("hostname parameter exceeds %zd characters and will be truncated",
|
||||
maxlen);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# Help: Basic kernel hardening options
|
||||
#
|
||||
# These are considered the basic kernel hardening, self-protection, and
|
||||
# attack surface reduction options. They are expected to have low (or
|
||||
# no) performance impact on most workloads, and have a reasonable level
|
||||
# of legacy API removals.
|
||||
|
||||
# Make sure reporting of various hardening actions is possible.
|
||||
CONFIG_BUG=y
|
||||
|
||||
# Basic kernel memory permission enforcement.
|
||||
CONFIG_STRICT_KERNEL_RWX=y
|
||||
CONFIG_STRICT_MODULE_RWX=y
|
||||
CONFIG_VMAP_STACK=y
|
||||
|
||||
# Kernel image and memory ASLR.
|
||||
CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_RANDOMIZE_MEMORY=y
|
||||
|
||||
# Randomize allocator freelists, harden metadata.
|
||||
CONFIG_SLAB_FREELIST_RANDOM=y
|
||||
CONFIG_SLAB_FREELIST_HARDENED=y
|
||||
CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
|
||||
CONFIG_RANDOM_KMALLOC_CACHES=y
|
||||
|
||||
# Randomize kernel stack offset on syscall entry.
|
||||
CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y
|
||||
|
||||
# Basic stack frame overflow protection.
|
||||
CONFIG_STACKPROTECTOR=y
|
||||
CONFIG_STACKPROTECTOR_STRONG=y
|
||||
|
||||
# Basic buffer length bounds checking.
|
||||
CONFIG_HARDENED_USERCOPY=y
|
||||
CONFIG_FORTIFY_SOURCE=y
|
||||
|
||||
# Basic array index bounds checking.
|
||||
CONFIG_UBSAN=y
|
||||
CONFIG_UBSAN_TRAP=y
|
||||
CONFIG_UBSAN_BOUNDS=y
|
||||
# CONFIG_UBSAN_SHIFT is not set
|
||||
# CONFIG_UBSAN_DIV_ZERO
|
||||
# CONFIG_UBSAN_UNREACHABLE
|
||||
# CONFIG_UBSAN_BOOL
|
||||
# CONFIG_UBSAN_ENUM
|
||||
# CONFIG_UBSAN_ALIGNMENT
|
||||
CONFIG_UBSAN_SANITIZE_ALL=y
|
||||
|
||||
# Linked list integrity checking.
|
||||
CONFIG_LIST_HARDENED=y
|
||||
|
||||
# Initialize all heap variables to zero on allocation.
|
||||
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
|
||||
|
||||
# Initialize all stack variables to zero on function entry.
|
||||
CONFIG_INIT_STACK_ALL_ZERO=y
|
||||
|
||||
# Wipe RAM at reboot via EFI. For more details, see:
|
||||
# https://trustedcomputinggroup.org/resource/pc-client-work-group-platform-reset-attack-mitigation-specification/
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1532058
|
||||
CONFIG_RESET_ATTACK_MITIGATION=y
|
||||
|
||||
# Disable DMA between EFI hand-off and the kernel's IOMMU setup.
|
||||
CONFIG_EFI_DISABLE_PCI_DMA=y
|
||||
|
||||
# Force IOMMU TLB invalidation so devices will never be able to access stale
|
||||
# data content.
|
||||
CONFIG_IOMMU_SUPPORT=y
|
||||
CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
|
||||
|
||||
# Do not allow direct physical memory access to non-device memory.
|
||||
CONFIG_STRICT_DEVMEM=y
|
||||
CONFIG_IO_STRICT_DEVMEM=y
|
||||
|
||||
# Provide userspace with seccomp BPF API for syscall attack surface reduction.
|
||||
CONFIG_SECCOMP=y
|
||||
CONFIG_SECCOMP_FILTER=y
|
||||
|
||||
# Provides some protections against SYN flooding.
|
||||
CONFIG_SYN_COOKIES=y
|
||||
|
||||
# Attack surface reduction: do not autoload TTY line disciplines.
|
||||
# CONFIG_LDISC_AUTOLOAD is not set
|
||||
|
||||
# Dangerous; enabling this disables userspace brk ASLR.
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
|
||||
# Dangerous; exposes kernel text image layout.
|
||||
# CONFIG_PROC_KCORE is not set
|
||||
|
||||
# Dangerous; enabling this disables userspace VDSO ASLR.
|
||||
# CONFIG_COMPAT_VDSO is not set
|
||||
|
||||
# Attack surface reduction: Use the modern PTY interface (devpts) only.
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
|
||||
# Attack surface reduction: Use only modesetting video drivers.
|
||||
# CONFIG_DRM_LEGACY is not set
|
||||
+1
-1
@@ -36,7 +36,7 @@ do { \
|
||||
static struct kmem_cache *cred_jar;
|
||||
|
||||
/* init to 2 - one for init_task, one to ensure it is never freed */
|
||||
static struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
|
||||
static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) };
|
||||
|
||||
/*
|
||||
* The initial credentials for the initial task
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ struct group_info *groups_alloc(int gidsetsize)
|
||||
if (!gi)
|
||||
return NULL;
|
||||
|
||||
atomic_set(&gi->usage, 1);
|
||||
refcount_set(&gi->usage, 1);
|
||||
gi->ngroups = gidsetsize;
|
||||
return gi;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,18 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/proc_ns.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_BINFMT_MISC)
|
||||
struct binfmt_misc init_binfmt_misc = {
|
||||
.entries = LIST_HEAD_INIT(init_binfmt_misc.entries),
|
||||
.enabled = true,
|
||||
.entries_lock = __RW_LOCK_UNLOCKED(init_binfmt_misc.entries_lock),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(init_binfmt_misc);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* userns count is 1 for root user, 1 for init_uts_ns,
|
||||
* and 1 for... ?
|
||||
@@ -67,6 +77,9 @@ struct user_namespace init_user_ns = {
|
||||
.keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list),
|
||||
.keyring_sem = __RWSEM_INITIALIZER(init_user_ns.keyring_sem),
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_BINFMT_MISC)
|
||||
.binfmt_misc = &init_binfmt_misc,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(init_user_ns);
|
||||
|
||||
|
||||
@@ -213,6 +213,9 @@ static void free_user_ns(struct work_struct *work)
|
||||
kfree(ns->projid_map.forward);
|
||||
kfree(ns->projid_map.reverse);
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_BINFMT_MISC)
|
||||
kfree(ns->binfmt_misc);
|
||||
#endif
|
||||
retire_userns_sysctls(ns);
|
||||
key_free_user_ns(ns);
|
||||
ns_free_inum(&ns->ns);
|
||||
|
||||
@@ -254,10 +254,10 @@ static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem)
|
||||
int buffer_size = sizeof(env->buf) - env->buflen;
|
||||
int len;
|
||||
|
||||
len = strlcpy(&env->buf[env->buflen], subsystem, buffer_size);
|
||||
if (len >= buffer_size) {
|
||||
pr_warn("init_uevent_argv: buffer size of %d too small, needed %d\n",
|
||||
buffer_size, len);
|
||||
len = strscpy(&env->buf[env->buflen], subsystem, buffer_size);
|
||||
if (len < 0) {
|
||||
pr_warn("%s: insufficient buffer space (%u left) for %s\n",
|
||||
__func__, buffer_size, subsystem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
@@ -3195,12 +3195,6 @@ limits_failed:
|
||||
}
|
||||
EXPORT_SYMBOL(vm_brk_flags);
|
||||
|
||||
int vm_brk(unsigned long addr, unsigned long len)
|
||||
{
|
||||
return vm_brk_flags(addr, len, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(vm_brk);
|
||||
|
||||
/* Release all mmaps. */
|
||||
void exit_mmap(struct mm_struct *mm)
|
||||
{
|
||||
|
||||
@@ -1531,11 +1531,6 @@ void exit_mmap(struct mm_struct *mm)
|
||||
mmap_write_unlock(mm);
|
||||
}
|
||||
|
||||
int vm_brk(unsigned long addr, unsigned long len)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* expand (or shrink) an existing mapping, potentially moving it at the same
|
||||
* time (controlled by the MREMAP_MAYMOVE flag and available VM space)
|
||||
|
||||
@@ -191,12 +191,14 @@ static void partition_struct(tree *fields, unsigned long length, struct partitio
|
||||
|
||||
static void performance_shuffle(tree *newtree, unsigned long length, ranctx *prng_state)
|
||||
{
|
||||
unsigned long i, x;
|
||||
unsigned long i, x, index;
|
||||
struct partition_group size_group[length];
|
||||
unsigned long num_groups = 0;
|
||||
unsigned long randnum;
|
||||
|
||||
partition_struct(newtree, length, (struct partition_group *)&size_group, &num_groups);
|
||||
|
||||
/* FIXME: this group shuffle is currently a no-op. */
|
||||
for (i = num_groups - 1; i > 0; i--) {
|
||||
struct partition_group tmp;
|
||||
randnum = ranval(prng_state) % (i + 1);
|
||||
@@ -206,11 +208,14 @@ static void performance_shuffle(tree *newtree, unsigned long length, ranctx *prn
|
||||
}
|
||||
|
||||
for (x = 0; x < num_groups; x++) {
|
||||
for (i = size_group[x].start + size_group[x].length - 1; i > size_group[x].start; i--) {
|
||||
for (index = size_group[x].length - 1; index > 0; index--) {
|
||||
tree tmp;
|
||||
|
||||
i = size_group[x].start + index;
|
||||
if (DECL_BIT_FIELD_TYPE(newtree[i]))
|
||||
continue;
|
||||
randnum = ranval(prng_state) % (i + 1);
|
||||
randnum = ranval(prng_state) % (index + 1);
|
||||
randnum += size_group[x].start;
|
||||
// we could handle this case differently if desired
|
||||
if (DECL_BIT_FIELD_TYPE(newtree[randnum]))
|
||||
continue;
|
||||
|
||||
@@ -68,8 +68,6 @@ config INTEGRITY_MACHINE_KEYRING
|
||||
depends on INTEGRITY_ASYMMETRIC_KEYS
|
||||
depends on SYSTEM_BLACKLIST_KEYRING
|
||||
depends on LOAD_UEFI_KEYS || LOAD_PPC_KEYS
|
||||
select INTEGRITY_CA_MACHINE_KEYRING if LOAD_PPC_KEYS
|
||||
select INTEGRITY_CA_MACHINE_KEYRING_MAX if LOAD_PPC_KEYS
|
||||
help
|
||||
If set, provide a keyring to which Machine Owner Keys (MOK) may
|
||||
be added. This keyring shall contain just MOK keys. Unlike keys
|
||||
|
||||
@@ -29,7 +29,7 @@ struct modsig {
|
||||
* storing the signature.
|
||||
*/
|
||||
int raw_pkcs7_len;
|
||||
u8 raw_pkcs7[];
|
||||
u8 raw_pkcs7[] __counted_by(raw_pkcs7_len);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -65,10 +65,11 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||
buf_len -= sig_len + sizeof(*sig);
|
||||
|
||||
/* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
|
||||
hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
|
||||
hdr = kzalloc(struct_size(hdr, raw_pkcs7, sig_len), GFP_KERNEL);
|
||||
if (!hdr)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr->raw_pkcs7_len = sig_len;
|
||||
hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
|
||||
if (IS_ERR(hdr->pkcs7_msg)) {
|
||||
rc = PTR_ERR(hdr->pkcs7_msg);
|
||||
@@ -77,7 +78,6 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
|
||||
}
|
||||
|
||||
memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len);
|
||||
hdr->raw_pkcs7_len = sig_len;
|
||||
|
||||
/* We don't know the hash algorithm yet. */
|
||||
hdr->hash_algo = HASH_ALGO__LAST;
|
||||
|
||||
@@ -109,13 +109,6 @@ extern void __key_link_end(struct key *keyring,
|
||||
extern key_ref_t find_key_to_update(key_ref_t keyring_ref,
|
||||
const struct keyring_index_key *index_key);
|
||||
|
||||
extern struct key *keyring_search_instkey(struct key *keyring,
|
||||
key_serial_t target_id);
|
||||
|
||||
extern int iterate_over_keyring(const struct key *keyring,
|
||||
int (*func)(const struct key *key, void *data),
|
||||
void *data);
|
||||
|
||||
struct keyring_search_context {
|
||||
struct keyring_index_key index_key;
|
||||
const struct cred *cred;
|
||||
|
||||
@@ -358,17 +358,17 @@ static int __init init_trusted(void)
|
||||
if (!get_random)
|
||||
get_random = kernel_get_random;
|
||||
|
||||
static_call_update(trusted_key_seal,
|
||||
trusted_key_sources[i].ops->seal);
|
||||
static_call_update(trusted_key_unseal,
|
||||
trusted_key_sources[i].ops->unseal);
|
||||
static_call_update(trusted_key_get_random,
|
||||
get_random);
|
||||
trusted_key_exit = trusted_key_sources[i].ops->exit;
|
||||
migratable = trusted_key_sources[i].ops->migratable;
|
||||
|
||||
ret = trusted_key_sources[i].ops->init();
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
static_call_update(trusted_key_seal, trusted_key_sources[i].ops->seal);
|
||||
static_call_update(trusted_key_unseal, trusted_key_sources[i].ops->unseal);
|
||||
static_call_update(trusted_key_get_random, get_random);
|
||||
|
||||
trusted_key_exit = trusted_key_sources[i].ops->exit;
|
||||
migratable = trusted_key_sources[i].ops->migratable;
|
||||
}
|
||||
|
||||
if (!ret || ret != -ENODEV)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,24 +65,16 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
|
||||
int ret;
|
||||
struct tee_ioctl_invoke_arg inv_arg;
|
||||
struct tee_param param[4];
|
||||
struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL;
|
||||
struct tee_shm *reg_shm = NULL;
|
||||
|
||||
memset(&inv_arg, 0, sizeof(inv_arg));
|
||||
memset(¶m, 0, sizeof(param));
|
||||
|
||||
reg_shm_in = tee_shm_register_kernel_buf(pvt_data.ctx, p->key,
|
||||
p->key_len);
|
||||
if (IS_ERR(reg_shm_in)) {
|
||||
dev_err(pvt_data.dev, "key shm register failed\n");
|
||||
return PTR_ERR(reg_shm_in);
|
||||
}
|
||||
|
||||
reg_shm_out = tee_shm_register_kernel_buf(pvt_data.ctx, p->blob,
|
||||
sizeof(p->blob));
|
||||
if (IS_ERR(reg_shm_out)) {
|
||||
dev_err(pvt_data.dev, "blob shm register failed\n");
|
||||
ret = PTR_ERR(reg_shm_out);
|
||||
goto out;
|
||||
reg_shm = tee_shm_register_kernel_buf(pvt_data.ctx, p->key,
|
||||
sizeof(p->key) + sizeof(p->blob));
|
||||
if (IS_ERR(reg_shm)) {
|
||||
dev_err(pvt_data.dev, "shm register failed\n");
|
||||
return PTR_ERR(reg_shm);
|
||||
}
|
||||
|
||||
inv_arg.func = TA_CMD_SEAL;
|
||||
@@ -90,13 +82,13 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
|
||||
inv_arg.num_params = 4;
|
||||
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
|
||||
param[0].u.memref.shm = reg_shm_in;
|
||||
param[0].u.memref.shm = reg_shm;
|
||||
param[0].u.memref.size = p->key_len;
|
||||
param[0].u.memref.shm_offs = 0;
|
||||
param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
|
||||
param[1].u.memref.shm = reg_shm_out;
|
||||
param[1].u.memref.shm = reg_shm;
|
||||
param[1].u.memref.size = sizeof(p->blob);
|
||||
param[1].u.memref.shm_offs = 0;
|
||||
param[1].u.memref.shm_offs = sizeof(p->key);
|
||||
|
||||
ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param);
|
||||
if ((ret < 0) || (inv_arg.ret != 0)) {
|
||||
@@ -107,11 +99,7 @@ static int trusted_tee_seal(struct trusted_key_payload *p, char *datablob)
|
||||
p->blob_len = param[1].u.memref.size;
|
||||
}
|
||||
|
||||
out:
|
||||
if (reg_shm_out)
|
||||
tee_shm_free(reg_shm_out);
|
||||
if (reg_shm_in)
|
||||
tee_shm_free(reg_shm_in);
|
||||
tee_shm_free(reg_shm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -124,24 +112,16 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
|
||||
int ret;
|
||||
struct tee_ioctl_invoke_arg inv_arg;
|
||||
struct tee_param param[4];
|
||||
struct tee_shm *reg_shm_in = NULL, *reg_shm_out = NULL;
|
||||
struct tee_shm *reg_shm = NULL;
|
||||
|
||||
memset(&inv_arg, 0, sizeof(inv_arg));
|
||||
memset(¶m, 0, sizeof(param));
|
||||
|
||||
reg_shm_in = tee_shm_register_kernel_buf(pvt_data.ctx, p->blob,
|
||||
p->blob_len);
|
||||
if (IS_ERR(reg_shm_in)) {
|
||||
dev_err(pvt_data.dev, "blob shm register failed\n");
|
||||
return PTR_ERR(reg_shm_in);
|
||||
}
|
||||
|
||||
reg_shm_out = tee_shm_register_kernel_buf(pvt_data.ctx, p->key,
|
||||
sizeof(p->key));
|
||||
if (IS_ERR(reg_shm_out)) {
|
||||
dev_err(pvt_data.dev, "key shm register failed\n");
|
||||
ret = PTR_ERR(reg_shm_out);
|
||||
goto out;
|
||||
reg_shm = tee_shm_register_kernel_buf(pvt_data.ctx, p->key,
|
||||
sizeof(p->key) + sizeof(p->blob));
|
||||
if (IS_ERR(reg_shm)) {
|
||||
dev_err(pvt_data.dev, "shm register failed\n");
|
||||
return PTR_ERR(reg_shm);
|
||||
}
|
||||
|
||||
inv_arg.func = TA_CMD_UNSEAL;
|
||||
@@ -149,11 +129,11 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
|
||||
inv_arg.num_params = 4;
|
||||
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
|
||||
param[0].u.memref.shm = reg_shm_in;
|
||||
param[0].u.memref.shm = reg_shm;
|
||||
param[0].u.memref.size = p->blob_len;
|
||||
param[0].u.memref.shm_offs = 0;
|
||||
param[0].u.memref.shm_offs = sizeof(p->key);
|
||||
param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
|
||||
param[1].u.memref.shm = reg_shm_out;
|
||||
param[1].u.memref.shm = reg_shm;
|
||||
param[1].u.memref.size = sizeof(p->key);
|
||||
param[1].u.memref.shm_offs = 0;
|
||||
|
||||
@@ -166,11 +146,7 @@ static int trusted_tee_unseal(struct trusted_key_payload *p, char *datablob)
|
||||
p->key_len = param[1].u.memref.size;
|
||||
}
|
||||
|
||||
out:
|
||||
if (reg_shm_out)
|
||||
tee_shm_free(reg_shm_out);
|
||||
if (reg_shm_in)
|
||||
tee_shm_free(reg_shm_in);
|
||||
tee_shm_free(reg_shm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ CONFIG_INIT_ON_FREE_DEFAULT_ON=y
|
||||
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
|
||||
CONFIG_UBSAN=y
|
||||
CONFIG_UBSAN_BOUNDS=y
|
||||
CONFIG_UBSAN_TRAP=y
|
||||
CONFIG_STACKPROTECTOR_STRONG=y
|
||||
CONFIG_SLUB_DEBUG=y
|
||||
CONFIG_SLUB_DEBUG_ON=y
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#PANIC
|
||||
#PANIC_STOP_IRQOFF Crashes entire system
|
||||
BUG kernel BUG at
|
||||
WARNING WARNING:
|
||||
WARNING_MESSAGE message trigger
|
||||
@@ -7,7 +8,7 @@ EXCEPTION
|
||||
#EXHAUST_STACK Corrupts memory on failure
|
||||
#CORRUPT_STACK Crashes entire system on success
|
||||
#CORRUPT_STACK_STRONG Crashes entire system on success
|
||||
ARRAY_BOUNDS
|
||||
ARRAY_BOUNDS call trace:|UBSAN: array-index-out-of-bounds
|
||||
CORRUPT_LIST_ADD list_add corruption
|
||||
CORRUPT_LIST_DEL list_del corruption
|
||||
STACK_GUARD_PAGE_LEADING
|
||||
|
||||
Reference in New Issue
Block a user