1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18 * Part of Very Secure FTPd
19 * Licence: GPL v2
20 * Author: Chris Evans
21 * secbuf.c
22 *
23 * Here are some routines providing the (possibly silly) concept of a secure
24 * buffer. A secure buffer may not be overflowed. A single byte overflow
25 * will cause the program to safely terminate.
26 */
27
28#include "secbuf.h"
29#include "utility.h"
30#include "sysutil.h"
31#include "sysdeputil.h"
32
33void
34vsf_secbuf_alloc(char** p_ptr, unsigned int size)
35{
36  unsigned int page_offset;
37  unsigned int round_up;
38  char* p_mmap;
39  char* p_no_access_page;
40  unsigned int page_size = vsf_sysutil_getpagesize();
41
42  /* Free any previous buffer */
43  vsf_secbuf_free(p_ptr);
44  /* Round up to next page size */
45  page_offset = size % page_size;
46  if (page_offset)
47  {
48    unsigned int num_pages = size / page_size;
49    num_pages++;
50    round_up = num_pages * page_size;
51  }
52  else
53  {
54    /* Allocation is on a page-size boundary */
55    round_up = size;
56  }
57  /* Add on another two pages to make inaccessible */
58  round_up += page_size * 2;
59
60  p_mmap = vsf_sysutil_map_anon_pages(round_up);
61  /* Map the first and last page inaccessible */
62  p_no_access_page = p_mmap + round_up - page_size;
63  vsf_sysutil_memprotect(p_no_access_page, page_size, kVSFSysUtilMapProtNone);
64  /* Before we make the "before" page inaccessible, store the size in it.
65   * A little hack so that we don't need to explicitly be passed the size
66   * when freeing an existing secure buffer
67   */
68  *((unsigned int*)p_mmap) = round_up;
69  p_no_access_page = p_mmap;
70  vsf_sysutil_memprotect(p_no_access_page, page_size, kVSFSysUtilMapProtNone);
71
72  p_mmap += page_size;
73  if (page_offset)
74  {
75    p_mmap += (page_size - page_offset);
76  }
77  *p_ptr = p_mmap;
78}
79
80void
81vsf_secbuf_free(char** p_ptr)
82{
83  unsigned int map_size;
84  unsigned long page_offset;
85  char* p_mmap = *p_ptr;
86  unsigned int page_size = vsf_sysutil_getpagesize();
87  if (p_mmap == 0)
88  {
89    return;
90  }
91  /* Calculate the actual start of the mmap region */
92  page_offset = (unsigned long) p_mmap % page_size;
93  if (page_offset)
94  {
95    p_mmap -= page_offset;
96  }
97  p_mmap -= page_size;
98  /* First make the first page readable so we can get the size */
99  vsf_sysutil_memprotect(p_mmap, page_size, kVSFSysUtilMapProtReadOnly);
100  /* Extract the mapping size */
101  map_size = *((unsigned int*)p_mmap);
102  /* Lose the mapping */
103  vsf_sysutil_memunmap(p_mmap, map_size);
104}
105
106