Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <mmaurer@google.com>
Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>

authored by

Matthew Maurer and committed by
Luis Chamberlain
c92aab81 90f8f312

+82 -43
+82 -43
kernel/module/main.c
··· 1708 1708 return 0; 1709 1709 } 1710 1710 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 + 1711 1792 /* 1712 1793 * Check userspace passed ELF module against our expectations, and cache 1713 1794 * useful variables for further processing as we go. ··· 1818 1737 unsigned int num_info_secs = 0, info_idx; 1819 1738 unsigned int num_sym_secs = 0, sym_idx; 1820 1739 1821 - err = elf_validity_ehdr(info); 1740 + err = elf_validity_cache_sechdrs(info); 1822 1741 if (err < 0) 1823 1742 return err; 1824 - 1825 - if (info->hdr->e_shentsize != sizeof(Elf_Shdr)) { 1826 - pr_err("Invalid ELF section header size\n"); 1827 - goto no_exec; 1828 - } 1829 - 1830 - /* 1831 - * e_shnum is 16 bits, and sizeof(Elf_Shdr) is 1832 - * known and small. So e_shnum * sizeof(Elf_Shdr) 1833 - * will not overflow unsigned long on any platform. 1834 - */ 1835 - if (info->hdr->e_shoff >= info->len 1836 - || (info->hdr->e_shnum * sizeof(Elf_Shdr) > 1837 - info->len - info->hdr->e_shoff)) { 1838 - pr_err("Invalid ELF section header overflow\n"); 1839 - goto no_exec; 1840 - } 1841 - 1842 - info->sechdrs = (void *)info->hdr + info->hdr->e_shoff; 1843 1743 1844 1744 /* 1845 1745 * Verify if the section name table index is valid. ··· 1834 1772 } 1835 1773 1836 1774 strhdr = &info->sechdrs[info->hdr->e_shstrndx]; 1837 - err = validate_section_offset(info, strhdr); 1838 - if (err < 0) { 1839 - pr_err("Invalid ELF section hdr(type %u)\n", strhdr->sh_type); 1840 - return err; 1841 - } 1842 1775 1843 1776 /* 1844 1777 * The section name table must be NUL-terminated, as required ··· 1847 1790 } 1848 1791 if (info->secstrings[strhdr->sh_size - 1] != '\0') { 1849 1792 pr_err("ELF Spec violation: section name table isn't null terminated\n"); 1850 - goto no_exec; 1851 - } 1852 - 1853 - /* 1854 - * The code assumes that section 0 has a length of zero and 1855 - * an addr of zero, so check for it. 1856 - */ 1857 - if (info->sechdrs[0].sh_type != SHT_NULL 1858 - || info->sechdrs[0].sh_size != 0 1859 - || info->sechdrs[0].sh_addr != 0) { 1860 - pr_err("ELF Spec violation: section 0 type(%d)!=SH_NULL or non-zero len or addr\n", 1861 - info->sechdrs[0].sh_type); 1862 1793 goto no_exec; 1863 1794 } 1864 1795 ··· 1868 1823 sym_idx = i; 1869 1824 fallthrough; 1870 1825 default: 1871 - err = validate_section_offset(info, shdr); 1872 - if (err < 0) { 1873 - pr_err("Invalid ELF section in module (section %u type %u)\n", 1874 - i, shdr->sh_type); 1875 - return err; 1876 - } 1877 1826 if (strcmp(info->secstrings + shdr->sh_name, 1878 1827 ".gnu.linkonce.this_module") == 0) { 1879 1828 num_mod_secs++;