Commit 67b7e1f2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull module updates from Luis Chamberlain:
 "As requested by Jessica I'm stepping in to help with modules
  maintenance. This is my first pull request to you.

  I've collected only two patches for modules for the 5.16-rc1 merge
  window. These patches are from Shuah Khan as she debugged some corner
  case error with modules. The error messages are improved for
  elf_validity_check(). While doing this work a corner case fix was
  spotted on validate_section_offset() due to a possible overflow bug on
  64-bit. The impact of this fix is low given this just limits module
  section headers placed within the 32-bit boundary, and we obviously
  don't have insane module sizes. Even if a specially crafted module is
  constructed later checks would invalidate the module right away.

  I've let this sit through 0-day testing since October 15th with no
  issues found"

* tag 'modules-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux:
  module: change to print useful messages from elf_validity_check()
  module: fix validate_section_offset() overflow bug on 64-bit
parents c107fb9b 7fd982f3
Loading
Loading
Loading
Loading
+58 −21
Original line number Diff line number Diff line
@@ -2942,7 +2942,11 @@ static int module_sig_check(struct load_info *info, int flags)

static int validate_section_offset(struct load_info *info, Elf_Shdr *shdr)
{
#if defined(CONFIG_64BIT)
	unsigned long long secend;
#else
	unsigned long secend;
#endif

	/*
	 * Check for both overflow and offset/size being
@@ -2967,14 +2971,29 @@ static int elf_validity_check(struct load_info *info)
	Elf_Shdr *shdr, *strhdr;
	int err;

	if (info->len < sizeof(*(info->hdr)))
		return -ENOEXEC;
	if (info->len < sizeof(*(info->hdr))) {
		pr_err("Invalid ELF header len %lu\n", info->len);
		goto no_exec;
	}

	if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
	    || info->hdr->e_type != ET_REL
	    || !elf_check_arch(info->hdr)
	    || info->hdr->e_shentsize != sizeof(Elf_Shdr))
		return -ENOEXEC;
	if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0) {
		pr_err("Invalid ELF header magic: != %s\n", ELFMAG);
		goto no_exec;
	}
	if (info->hdr->e_type != ET_REL) {
		pr_err("Invalid ELF header type: %u != %u\n",
		       info->hdr->e_type, ET_REL);
		goto no_exec;
	}
	if (!elf_check_arch(info->hdr)) {
		pr_err("Invalid architecture in ELF header: %u\n",
		       info->hdr->e_machine);
		goto no_exec;
	}
	if (info->hdr->e_shentsize != sizeof(Elf_Shdr)) {
		pr_err("Invalid ELF section header size\n");
		goto no_exec;
	}

	/*
	 * e_shnum is 16 bits, and sizeof(Elf_Shdr) is
@@ -2983,8 +3002,10 @@ static int elf_validity_check(struct load_info *info)
	 */
	if (info->hdr->e_shoff >= info->len
	    || (info->hdr->e_shnum * sizeof(Elf_Shdr) >
		info->len - info->hdr->e_shoff))
		return -ENOEXEC;
		info->len - info->hdr->e_shoff)) {
		pr_err("Invalid ELF section header overflow\n");
		goto no_exec;
	}

	info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;

@@ -2992,13 +3013,19 @@ static int elf_validity_check(struct load_info *info)
	 * Verify if the section name table index is valid.
	 */
	if (info->hdr->e_shstrndx == SHN_UNDEF
	    || info->hdr->e_shstrndx >= info->hdr->e_shnum)
		return -ENOEXEC;
	    || info->hdr->e_shstrndx >= info->hdr->e_shnum) {
		pr_err("Invalid ELF section name index: %d || e_shstrndx (%d) >= e_shnum (%d)\n",
		       info->hdr->e_shstrndx, info->hdr->e_shstrndx,
		       info->hdr->e_shnum);
		goto no_exec;
	}

	strhdr = &info->sechdrs[info->hdr->e_shstrndx];
	err = validate_section_offset(info, strhdr);
	if (err < 0)
	if (err < 0) {
		pr_err("Invalid ELF section hdr(type %u)\n", strhdr->sh_type);
		return err;
	}

	/*
	 * The section name table must be NUL-terminated, as required
@@ -3006,8 +3033,10 @@ static int elf_validity_check(struct load_info *info)
	 * strings in the section safe.
	 */
	info->secstrings = (void *)info->hdr + strhdr->sh_offset;
	if (info->secstrings[strhdr->sh_size - 1] != '\0')
		return -ENOEXEC;
	if (info->secstrings[strhdr->sh_size - 1] != '\0') {
		pr_err("ELF Spec violation: section name table isn't null terminated\n");
		goto no_exec;
	}

	/*
	 * The code assumes that section 0 has a length of zero and
@@ -3015,8 +3044,11 @@ static int elf_validity_check(struct load_info *info)
	 */
	if (info->sechdrs[0].sh_type != SHT_NULL
	    || info->sechdrs[0].sh_size != 0
	    || info->sechdrs[0].sh_addr != 0)
		return -ENOEXEC;
	    || info->sechdrs[0].sh_addr != 0) {
		pr_err("ELF Spec violation: section 0 type(%d)!=SH_NULL or non-zero len or addr\n",
		       info->sechdrs[0].sh_type);
		goto no_exec;
	}

	for (i = 1; i < info->hdr->e_shnum; i++) {
		shdr = &info->sechdrs[i];
@@ -3026,8 +3058,12 @@ static int elf_validity_check(struct load_info *info)
			continue;
		case SHT_SYMTAB:
			if (shdr->sh_link == SHN_UNDEF
			    || shdr->sh_link >= info->hdr->e_shnum)
				return -ENOEXEC;
			    || shdr->sh_link >= info->hdr->e_shnum) {
				pr_err("Invalid ELF sh_link!=SHN_UNDEF(%d) or (sh_link(%d) >= hdr->e_shnum(%d)\n",
				       shdr->sh_link, shdr->sh_link,
				       info->hdr->e_shnum);
				goto no_exec;
			}
			fallthrough;
		default:
			err = validate_section_offset(info, shdr);
@@ -3049,6 +3085,9 @@ static int elf_validity_check(struct load_info *info)
	}

	return 0;

no_exec:
	return -ENOEXEC;
}

#define COPY_CHUNK_SIZE (16*PAGE_SIZE)
@@ -3940,10 +3979,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
	 * sections.
	 */
	err = elf_validity_check(info);
	if (err) {
		pr_err("Module has invalid ELF structures\n");
	if (err)
		goto free_copy;
	}

	/*
	 * Everything checks out, so set up the section info