svn commit: r340053 - stable/11/sys/kern

Bjoern A. Zeeb bz at FreeBSD.org
Fri Nov 2 14:13:33 UTC 2018


Author: bz
Date: Fri Nov  2 14:13:31 2018
New Revision: 340053
URL: https://svnweb.freebsd.org/changeset/base/340053

Log:
  MFC r339431:
  
    In r78161 the lookup_set linker method was introduced which optionally
    returns the section start and stop locations as well as a count if the
    caller asks for them.
    There was only one out-of-file consumer of count which did not actually
    use it and hence was eliminated in r339407.
    In r194784 parse_dpcpu(), and in r195699 parse_vnet() (a copy of the
    former) started to use the link_elf_lookup_set() interface internally
    also asking for the count.
  
    count is computed as the difference of the void **stop - void **start
    locations and as such, if the absoulte numbers
    	(stop - start) % sizeof(void *) != 0
    a round-down happens, e.g., **stop 0x1003 - **start 0x1000 => count 0.
  
    To get the section size instead of "count is the number of pointer
    elements in the section", the parse_*() functions do a
    	count *= sizeof(void *).
    They use the result to allocate memory and copy the section data
    into the "master" and per-instance memory regions with a size of
    count.
  
    As a result of count possibly round-down this can miss the last
    bytes of the section.  The good news is that we do not touch
    out of bounds memory during these operations (we may at a later stage
    if the last bytes would overflow the master sections).
    Given relocation in elf_relocaddr() works based on the absolute
    numbers of start and stop, this means that we can possibly try to
    access relocated data which was never copied and hence we get
    random garbage or at best zeroed memory.
  
    Stop the two (last) consumers of count (the parse_*() functions)
    from using count as well, and calculate the section size based on
    the absolute numbers of stop and start and use the proper size for
    the memory allocation and data copies.  This will make the symbols
    in the last bytes of the pcpu or vnet sections be presented as
    expected.
  
  PR:			232289

Modified:
  stable/11/sys/kern/link_elf.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/kern/link_elf.c
==============================================================================
--- stable/11/sys/kern/link_elf.c	Fri Nov  2 14:10:29 2018	(r340052)
+++ stable/11/sys/kern/link_elf.c	Fri Nov  2 14:13:31 2018	(r340053)
@@ -611,27 +611,29 @@ parse_dynamic(elf_file_t ef)
 static int
 parse_dpcpu(elf_file_t ef)
 {
-	int count;
-	int error;
+	int error, size;
 
 	ef->pcpu_start = 0;
 	ef->pcpu_stop = 0;
 	error = link_elf_lookup_set(&ef->lf, "pcpu", (void ***)&ef->pcpu_start,
-	    (void ***)&ef->pcpu_stop, &count);
+	    (void ***)&ef->pcpu_stop, NULL);
 	/* Error just means there is no pcpu set to relocate. */
 	if (error != 0)
 		return (0);
-	count *= sizeof(void *);
+	size = (uintptr_t)ef->pcpu_stop - (uintptr_t)ef->pcpu_start;
+	/* Empty set? */
+	if (size < 1)
+		return (0);
 	/*
 	 * Allocate space in the primary pcpu area.  Copy in our
 	 * initialization from the data section and then initialize
 	 * all per-cpu storage from that.
 	 */
-	ef->pcpu_base = (Elf_Addr)(uintptr_t)dpcpu_alloc(count);
+	ef->pcpu_base = (Elf_Addr)(uintptr_t)dpcpu_alloc(size);
 	if (ef->pcpu_base == 0)
 		return (ENOSPC);
-	memcpy((void *)ef->pcpu_base, (void *)ef->pcpu_start, count);
-	dpcpu_copy((void *)ef->pcpu_base, count);
+	memcpy((void *)ef->pcpu_base, (void *)ef->pcpu_start, size);
+	dpcpu_copy((void *)ef->pcpu_base, size);
 	elf_set_add(&set_pcpu_list, ef->pcpu_start, ef->pcpu_stop,
 	    ef->pcpu_base);
 
@@ -642,27 +644,29 @@ parse_dpcpu(elf_file_t ef)
 static int
 parse_vnet(elf_file_t ef)
 {
-	int count;
-	int error;
+	int error, size;
 
 	ef->vnet_start = 0;
 	ef->vnet_stop = 0;
 	error = link_elf_lookup_set(&ef->lf, "vnet", (void ***)&ef->vnet_start,
-	    (void ***)&ef->vnet_stop, &count);
+	    (void ***)&ef->vnet_stop, NULL);
 	/* Error just means there is no vnet data set to relocate. */
 	if (error != 0)
 		return (0);
-	count *= sizeof(void *);
+	size = (uintptr_t)ef->vnet_stop - (uintptr_t)ef->vnet_start;
+	/* Empty set? */
+	if (size < 1)
+		return (0);
 	/*
 	 * Allocate space in the primary vnet area.  Copy in our
 	 * initialization from the data section and then initialize
 	 * all per-vnet storage from that.
 	 */
-	ef->vnet_base = (Elf_Addr)(uintptr_t)vnet_data_alloc(count);
+	ef->vnet_base = (Elf_Addr)(uintptr_t)vnet_data_alloc(size);
 	if (ef->vnet_base == 0)
 		return (ENOSPC);
-	memcpy((void *)ef->vnet_base, (void *)ef->vnet_start, count);
-	vnet_data_copy((void *)ef->vnet_base, count);
+	memcpy((void *)ef->vnet_base, (void *)ef->vnet_start, size);
+	vnet_data_copy((void *)ef->vnet_base, size);
 	elf_set_add(&set_vnet_list, ef->vnet_start, ef->vnet_stop,
 	    ef->vnet_base);
 


More information about the svn-src-all mailing list