Skip to content

Commit

Permalink
Merge branch 'akpm' (patches from Andrew)
Browse files Browse the repository at this point in the history
Merge final set of updates from Andrew Morton:

 - a series to make IMA play better across kexec

 - a handful of random fixes

* emailed patches from Andrew Morton <[email protected]>:
  printk: fix typo in CONSOLE_LOGLEVEL_DEFAULT help text
  ratelimit: fix WARN_ON_RATELIMIT return value
  kcov: make kcov work properly with KASLR enabled
  arm64: setup: introduce kaslr_offset()
  mm: fadvise: avoid expensive remote LRU cache draining after FADV_DONTNEED
  ima: platform-independent hash value
  ima: define a canonical binary_runtime_measurements list format
  ima: support restoring multiple template formats
  ima: store the builtin/custom template definitions in a list
  ima: on soft reboot, save the measurement list
  powerpc: ima: send the kexec buffer to the next kernel
  ima: maintain memory size needed for serializing the measurement list
  ima: permit duplicate measurement list entries
  ima: on soft reboot, restore the measurement list
  powerpc: ima: get the kexec buffer passed by the previous kernel
  • Loading branch information
torvalds committed Dec 20, 2016
2 parents f95adbc + 50f4d9b commit 3eb8625
Show file tree
Hide file tree
Showing 28 changed files with 942 additions and 47 deletions.
4 changes: 4 additions & 0 deletions Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,10 @@
The builtin appraise policy appraises all files
owned by uid=0.

ima_canonical_fmt [IMA]
Use the canonical format for the binary runtime
measurements, instead of host native format.

ima_hash= [IMA]
Format: { md5 | sha1 | rmd160 | sha256 | sha384
| sha512 | ... }
Expand Down
3 changes: 3 additions & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
config KEXEC_CORE
bool

config HAVE_IMA_KEXEC
bool

config OPROFILE
tristate "OProfile system profiling"
depends on PROFILING
Expand Down
5 changes: 5 additions & 0 deletions arch/arm64/include/asm/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ extern u64 kimage_vaddr;
/* the offset between the kernel virtual and physical mappings */
extern u64 kimage_voffset;

static inline unsigned long kaslr_offset(void)
{
return kimage_vaddr - KIMAGE_VADDR;
}

/*
* Allow all memory at the discovery stage. We will clip it later.
*/
Expand Down
8 changes: 4 additions & 4 deletions arch/arm64/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,11 @@ subsys_initcall(topology_init);
static int dump_kernel_offset(struct notifier_block *self, unsigned long v,
void *p)
{
u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR;
const unsigned long offset = kaslr_offset();

if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) {
pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n",
kaslr_offset, KIMAGE_VADDR);
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && offset > 0) {
pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n",
offset, KIMAGE_VADDR);
} else {
pr_emerg("Kernel Offset: disabled\n");
}
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ config KEXEC
config KEXEC_FILE
bool "kexec file based system call"
select KEXEC_CORE
select HAVE_IMA_KEXEC
select BUILD_BIN2C
depends on PPC64
depends on CRYPTO=y
Expand Down
29 changes: 29 additions & 0 deletions arch/powerpc/include/asm/ima.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef _ASM_POWERPC_IMA_H
#define _ASM_POWERPC_IMA_H

struct kimage;

int ima_get_kexec_buffer(void **addr, size_t *size);
int ima_free_kexec_buffer(void);

#ifdef CONFIG_IMA
void remove_ima_buffer(void *fdt, int chosen_node);
#else
static inline void remove_ima_buffer(void *fdt, int chosen_node) {}
#endif

#ifdef CONFIG_IMA_KEXEC
int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
size_t size);

int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node);
#else
static inline int setup_ima_buffer(const struct kimage *image, void *fdt,
int chosen_node)
{
remove_ima_buffer(fdt, chosen_node);
return 0;
}
#endif /* CONFIG_IMA_KEXEC */

#endif /* _ASM_POWERPC_IMA_H */
15 changes: 13 additions & 2 deletions arch/powerpc/include/asm/kexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,22 @@ static inline bool kdump_in_progress(void)
#ifdef CONFIG_KEXEC_FILE
extern struct kexec_file_ops kexec_elf64_ops;

#ifdef CONFIG_IMA_KEXEC
#define ARCH_HAS_KIMAGE_ARCH

struct kimage_arch {
phys_addr_t ima_buffer_addr;
size_t ima_buffer_size;
};
#endif

int setup_purgatory(struct kimage *image, const void *slave_code,
const void *fdt, unsigned long kernel_load_addr,
unsigned long fdt_load_addr);
int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
unsigned long initrd_len, const char *cmdline);
int setup_new_fdt(const struct kimage *image, void *fdt,
unsigned long initrd_load_addr, unsigned long initrd_len,
const char *cmdline);
int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size);
#endif /* CONFIG_KEXEC_FILE */

#else /* !CONFIG_KEXEC_CORE */
Expand Down
4 changes: 4 additions & 0 deletions arch/powerpc/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o crash.o \
machine_kexec_$(BITS).o
obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file_$(BITS).o kexec_elf_$(BITS).o
ifeq ($(CONFIG_HAVE_IMA_KEXEC)$(CONFIG_IMA),yy)
obj-y += ima_kexec.o
endif

obj-$(CONFIG_AUDIT) += audit.o
obj64-$(CONFIG_AUDIT) += compat_audit.o

Expand Down
223 changes: 223 additions & 0 deletions arch/powerpc/kernel/ima_kexec.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
* Copyright (C) 2016 IBM Corporation
*
* Authors:
* Thiago Jung Bauermann <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#include <linux/slab.h>
#include <linux/kexec.h>
#include <linux/of.h>
#include <linux/memblock.h>
#include <linux/libfdt.h>

static int get_addr_size_cells(int *addr_cells, int *size_cells)
{
struct device_node *root;

root = of_find_node_by_path("/");
if (!root)
return -EINVAL;

*addr_cells = of_n_addr_cells(root);
*size_cells = of_n_size_cells(root);

of_node_put(root);

return 0;
}

static int do_get_kexec_buffer(const void *prop, int len, unsigned long *addr,
size_t *size)
{
int ret, addr_cells, size_cells;

ret = get_addr_size_cells(&addr_cells, &size_cells);
if (ret)
return ret;

if (len < 4 * (addr_cells + size_cells))
return -ENOENT;

*addr = of_read_number(prop, addr_cells);
*size = of_read_number(prop + 4 * addr_cells, size_cells);

return 0;
}

/**
* ima_get_kexec_buffer - get IMA buffer from the previous kernel
* @addr: On successful return, set to point to the buffer contents.
* @size: On successful return, set to the buffer size.
*
* Return: 0 on success, negative errno on error.
*/
int ima_get_kexec_buffer(void **addr, size_t *size)
{
int ret, len;
unsigned long tmp_addr;
size_t tmp_size;
const void *prop;

prop = of_get_property(of_chosen, "linux,ima-kexec-buffer", &len);
if (!prop)
return -ENOENT;

ret = do_get_kexec_buffer(prop, len, &tmp_addr, &tmp_size);
if (ret)
return ret;

*addr = __va(tmp_addr);
*size = tmp_size;

return 0;
}

/**
* ima_free_kexec_buffer - free memory used by the IMA buffer
*/
int ima_free_kexec_buffer(void)
{
int ret;
unsigned long addr;
size_t size;
struct property *prop;

prop = of_find_property(of_chosen, "linux,ima-kexec-buffer", NULL);
if (!prop)
return -ENOENT;

ret = do_get_kexec_buffer(prop->value, prop->length, &addr, &size);
if (ret)
return ret;

ret = of_remove_property(of_chosen, prop);
if (ret)
return ret;

return memblock_free(addr, size);

}

/**
* remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
*
* The IMA measurement buffer is of no use to a subsequent kernel, so we always
* remove it from the device tree.
*/
void remove_ima_buffer(void *fdt, int chosen_node)
{
int ret, len;
unsigned long addr;
size_t size;
const void *prop;

prop = fdt_getprop(fdt, chosen_node, "linux,ima-kexec-buffer", &len);
if (!prop)
return;

ret = do_get_kexec_buffer(prop, len, &addr, &size);
fdt_delprop(fdt, chosen_node, "linux,ima-kexec-buffer");
if (ret)
return;

ret = delete_fdt_mem_rsv(fdt, addr, size);
if (!ret)
pr_debug("Removed old IMA buffer reservation.\n");
}

#ifdef CONFIG_IMA_KEXEC
/**
* arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer
*
* Architectures should use this function to pass on the IMA buffer
* information to the next kernel.
*
* Return: 0 on success, negative errno on error.
*/
int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
size_t size)
{
image->arch.ima_buffer_addr = load_addr;
image->arch.ima_buffer_size = size;

return 0;
}

static int write_number(void *p, u64 value, int cells)
{
if (cells == 1) {
u32 tmp;

if (value > U32_MAX)
return -EINVAL;

tmp = cpu_to_be32(value);
memcpy(p, &tmp, sizeof(tmp));
} else if (cells == 2) {
u64 tmp;

tmp = cpu_to_be64(value);
memcpy(p, &tmp, sizeof(tmp));
} else
return -EINVAL;

return 0;
}

/**
* setup_ima_buffer - add IMA buffer information to the fdt
* @image: kexec image being loaded.
* @fdt: Flattened device tree for the next kernel.
* @chosen_node: Offset to the chosen node.
*
* Return: 0 on success, or negative errno on error.
*/
int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
{
int ret, addr_cells, size_cells, entry_size;
u8 value[16];

remove_ima_buffer(fdt, chosen_node);
if (!image->arch.ima_buffer_size)
return 0;

ret = get_addr_size_cells(&addr_cells, &size_cells);
if (ret)
return ret;

entry_size = 4 * (addr_cells + size_cells);

if (entry_size > sizeof(value))
return -EINVAL;

ret = write_number(value, image->arch.ima_buffer_addr, addr_cells);
if (ret)
return ret;

ret = write_number(value + 4 * addr_cells, image->arch.ima_buffer_size,
size_cells);
if (ret)
return ret;

ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value,
entry_size);
if (ret < 0)
return -EINVAL;

ret = fdt_add_mem_rsv(fdt, image->arch.ima_buffer_addr,
image->arch.ima_buffer_size);
if (ret)
return -EINVAL;

pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
image->arch.ima_buffer_addr, image->arch.ima_buffer_size);

return 0;
}
#endif /* CONFIG_IMA_KEXEC */
2 changes: 1 addition & 1 deletion arch/powerpc/kernel/kexec_elf_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
goto out;
}

ret = setup_new_fdt(fdt, initrd_load_addr, initrd_len, cmdline);
ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline);
if (ret)
goto out;

Expand Down
Loading

0 comments on commit 3eb8625

Please sign in to comment.