Skip to content

Commit c92aab8

Browse files
maurermcgrof
authored andcommitted
module: Factor out elf_validity_cache_sechdrs
Factor out and document the validation of section headers. Because we now validate all section offsets and lengths before accessing them, we can remove the ad-hoc checks. Signed-off-by: Matthew Maurer <[email protected]> Reviewed-by: Sami Tolvanen <[email protected]> Signed-off-by: Luis Chamberlain <[email protected]>
1 parent 90f8f31 commit c92aab8

File tree

1 file changed

+82
-43
lines changed

1 file changed

+82
-43
lines changed

kernel/module/main.c

Lines changed: 82 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,87 @@ static int elf_validity_ehdr(const struct load_info *info)
17081708
return 0;
17091709
}
17101710

1711+
/**
1712+
* elf_validity_cache_sechdrs() - Cache section headers if valid
1713+
* @info: Load info to compute section headers from
1714+
*
1715+
* Checks:
1716+
*
1717+
* * ELF header is valid (see elf_validity_ehdr())
1718+
* * Section headers are the size we expect
1719+
* * Section array fits in the user provided data
1720+
* * Section index 0 is NULL
1721+
* * Section contents are inbounds
1722+
*
1723+
* Then updates @info with a &load_info->sechdrs pointer if valid.
1724+
*
1725+
* Return: %0 if valid, negative error code if validation failed.
1726+
*/
1727+
static int elf_validity_cache_sechdrs(struct load_info *info)
1728+
{
1729+
Elf_Shdr *sechdrs;
1730+
Elf_Shdr *shdr;
1731+
int i;
1732+
int err;
1733+
1734+
err = elf_validity_ehdr(info);
1735+
if (err < 0)
1736+
return err;
1737+
1738+
if (info->hdr->e_shentsize != sizeof(Elf_Shdr)) {
1739+
pr_err("Invalid ELF section header size\n");
1740+
return -ENOEXEC;
1741+
}
1742+
1743+
/*
1744+
* e_shnum is 16 bits, and sizeof(Elf_Shdr) is
1745+
* known and small. So e_shnum * sizeof(Elf_Shdr)
1746+
* will not overflow unsigned long on any platform.
1747+
*/
1748+
if (info->hdr->e_shoff >= info->len
1749+
|| (info->hdr->e_shnum * sizeof(Elf_Shdr) >
1750+
info->len - info->hdr->e_shoff)) {
1751+
pr_err("Invalid ELF section header overflow\n");
1752+
return -ENOEXEC;
1753+
}
1754+
1755+
sechdrs = (void *)info->hdr + info->hdr->e_shoff;
1756+
1757+
/*
1758+
* The code assumes that section 0 has a length of zero and
1759+
* an addr of zero, so check for it.
1760+
*/
1761+
if (sechdrs[0].sh_type != SHT_NULL
1762+
|| sechdrs[0].sh_size != 0
1763+
|| sechdrs[0].sh_addr != 0) {
1764+
pr_err("ELF Spec violation: section 0 type(%d)!=SH_NULL or non-zero len or addr\n",
1765+
sechdrs[0].sh_type);
1766+
return -ENOEXEC;
1767+
}
1768+
1769+
/* Validate contents are inbounds */
1770+
for (i = 1; i < info->hdr->e_shnum; i++) {
1771+
shdr = &sechdrs[i];
1772+
switch (shdr->sh_type) {
1773+
case SHT_NULL:
1774+
case SHT_NOBITS:
1775+
/* No contents, offset/size don't mean anything */
1776+
continue;
1777+
default:
1778+
err = validate_section_offset(info, shdr);
1779+
if (err < 0) {
1780+
pr_err("Invalid ELF section in module (section %u type %u)\n",
1781+
i, shdr->sh_type);
1782+
return err;
1783+
}
1784+
}
1785+
}
1786+
1787+
info->sechdrs = sechdrs;
1788+
1789+
return 0;
1790+
}
1791+
17111792
/*
17121793
* Check userspace passed ELF module against our expectations, and cache
17131794
* useful variables for further processing as we go.
@@ -1737,29 +1818,10 @@ static int elf_validity_cache_copy(struct load_info *info, int flags)
17371818
unsigned int num_info_secs = 0, info_idx;
17381819
unsigned int num_sym_secs = 0, sym_idx;
17391820

1740-
err = elf_validity_ehdr(info);
1821+
err = elf_validity_cache_sechdrs(info);
17411822
if (err < 0)
17421823
return err;
17431824

1744-
if (info->hdr->e_shentsize != sizeof(Elf_Shdr)) {
1745-
pr_err("Invalid ELF section header size\n");
1746-
goto no_exec;
1747-
}
1748-
1749-
/*
1750-
* e_shnum is 16 bits, and sizeof(Elf_Shdr) is
1751-
* known and small. So e_shnum * sizeof(Elf_Shdr)
1752-
* will not overflow unsigned long on any platform.
1753-
*/
1754-
if (info->hdr->e_shoff >= info->len
1755-
|| (info->hdr->e_shnum * sizeof(Elf_Shdr) >
1756-
info->len - info->hdr->e_shoff)) {
1757-
pr_err("Invalid ELF section header overflow\n");
1758-
goto no_exec;
1759-
}
1760-
1761-
info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
1762-
17631825
/*
17641826
* Verify if the section name table index is valid.
17651827
*/
@@ -1772,11 +1834,6 @@ static int elf_validity_cache_copy(struct load_info *info, int flags)
17721834
}
17731835

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

17811838
/*
17821839
* The section name table must be NUL-terminated, as required
@@ -1793,18 +1850,6 @@ static int elf_validity_cache_copy(struct load_info *info, int flags)
17931850
goto no_exec;
17941851
}
17951852

1796-
/*
1797-
* The code assumes that section 0 has a length of zero and
1798-
* an addr of zero, so check for it.
1799-
*/
1800-
if (info->sechdrs[0].sh_type != SHT_NULL
1801-
|| info->sechdrs[0].sh_size != 0
1802-
|| info->sechdrs[0].sh_addr != 0) {
1803-
pr_err("ELF Spec violation: section 0 type(%d)!=SH_NULL or non-zero len or addr\n",
1804-
info->sechdrs[0].sh_type);
1805-
goto no_exec;
1806-
}
1807-
18081853
for (i = 1; i < info->hdr->e_shnum; i++) {
18091854
shdr = &info->sechdrs[i];
18101855
switch (shdr->sh_type) {
@@ -1823,12 +1868,6 @@ static int elf_validity_cache_copy(struct load_info *info, int flags)
18231868
sym_idx = i;
18241869
fallthrough;
18251870
default:
1826-
err = validate_section_offset(info, shdr);
1827-
if (err < 0) {
1828-
pr_err("Invalid ELF section in module (section %u type %u)\n",
1829-
i, shdr->sh_type);
1830-
return err;
1831-
}
18321871
if (strcmp(info->secstrings + shdr->sh_name,
18331872
".gnu.linkonce.this_module") == 0) {
18341873
num_mod_secs++;

0 commit comments

Comments
 (0)