(root)/
libxcrypt-4.4.36/
lib/
alg-yescrypt-platform.c
       1  /*-
       2   * Copyright 2013-2018,2022 Alexander Peslyak
       3   * All rights reserved.
       4   *
       5   * Redistribution and use in source and binary forms, with or without
       6   * modification, are permitted.
       7   *
       8   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
       9   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      10   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      11   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      12   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      13   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      14   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      15   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      16   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      17   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      18   * SUCH DAMAGE.
      19   */
      20  
      21  #ifdef __unix__
      22  #include <sys/mman.h>
      23  #endif
      24  #ifdef __linux__
      25  #include <linux/mman.h> /* for MAP_HUGE_2MB */
      26  #endif
      27  
      28  #define HUGEPAGE_THRESHOLD		(32 * 1024 * 1024)
      29  
      30  #ifdef __x86_64__
      31  #define HUGEPAGE_SIZE			(2 * 1024 * 1024)
      32  #else
      33  #undef HUGEPAGE_SIZE
      34  #endif
      35  
      36  static void *alloc_region(yescrypt_region_t *region, size_t size)
      37  {
      38  	size_t base_size = size;
      39  	uint8_t *base, *aligned;
      40  #ifdef MAP_ANON
      41  	unsigned int flags =
      42  #ifdef MAP_NOCORE
      43  	    MAP_NOCORE |
      44  #endif
      45  	    MAP_ANON | MAP_PRIVATE;
      46  #if defined(MAP_HUGETLB) && defined(MAP_HUGE_2MB) && defined(HUGEPAGE_SIZE)
      47  	size_t new_size = size;
      48  	const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1;
      49  	if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) {
      50  		flags |= MAP_HUGETLB | MAP_HUGE_2MB;
      51  /*
      52   * Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of
      53   * huge page size, so let's round up to huge page size here.
      54   */
      55  		new_size = size + hugepage_mask;
      56  		new_size &= ~hugepage_mask;
      57  	}
      58  	base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, (int)flags, -1, 0);
      59  	if (base != MAP_FAILED) {
      60  		base_size = new_size;
      61  	} else if (flags & MAP_HUGETLB) {
      62  		flags &= ~(unsigned int)(MAP_HUGETLB | MAP_HUGE_2MB);
      63  		base = mmap(NULL, size, PROT_READ | PROT_WRITE, (int)flags, -1, 0);
      64  	}
      65  
      66  #else
      67  	base = mmap(NULL, size, PROT_READ | PROT_WRITE, (int)flags, -1, 0);
      68  #endif
      69  	if (base == MAP_FAILED)
      70  		base = NULL;
      71  	aligned = base;
      72  #else /* mmap not available */
      73  	base = aligned = NULL;
      74  	if (size + 63 < size) {
      75  		errno = ENOMEM;
      76  	} else if ((base = malloc(size + 63)) != NULL) {
      77  		aligned = base + 63;
      78  		aligned -= (uintptr_t)aligned & 63;
      79  	}
      80  #endif
      81  	region->base = base;
      82  	region->aligned = aligned;
      83  	region->base_size = base ? base_size : 0;
      84  	region->aligned_size = base ? size : 0;
      85  	return aligned;
      86  }
      87  
      88  static inline void init_region(yescrypt_region_t *region)
      89  {
      90  	region->base = region->aligned = NULL;
      91  	region->base_size = region->aligned_size = 0;
      92  }
      93  
      94  static int free_region(yescrypt_region_t *region)
      95  {
      96  	if (region->base) {
      97  #ifdef MAP_ANON
      98  		if (munmap(region->base, region->base_size))
      99  			return -1;
     100  #else
     101  		free(region->base);
     102  #endif
     103  	}
     104  	init_region(region);
     105  	return 0;
     106  }