/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ /* * Part of Very Secure FTPd * Licence: GPL v2 * Author: Chris Evans * secbuf.c * * Here are some routines providing the (possibly silly) concept of a secure * buffer. A secure buffer may not be overflowed. A single byte overflow * will cause the program to safely terminate. */ #include "secbuf.h" #include "utility.h" #include "sysutil.h" #include "sysdeputil.h" void vsf_secbuf_alloc(char** p_ptr, unsigned int size) { unsigned int page_offset; unsigned int round_up; char* p_mmap; char* p_no_access_page; unsigned int page_size = vsf_sysutil_getpagesize(); /* Free any previous buffer */ vsf_secbuf_free(p_ptr); /* Round up to next page size */ page_offset = size % page_size; if (page_offset) { unsigned int num_pages = size / page_size; num_pages++; round_up = num_pages * page_size; } else { /* Allocation is on a page-size boundary */ round_up = size; } /* Add on another two pages to make inaccessible */ round_up += page_size * 2; p_mmap = vsf_sysutil_map_anon_pages(round_up); /* Map the first and last page inaccessible */ p_no_access_page = p_mmap + round_up - page_size; vsf_sysutil_memprotect(p_no_access_page, page_size, kVSFSysUtilMapProtNone); /* Before we make the "before" page inaccessible, store the size in it. * A little hack so that we don't need to explicitly be passed the size * when freeing an existing secure buffer */ *((unsigned int*)p_mmap) = round_up; p_no_access_page = p_mmap; vsf_sysutil_memprotect(p_no_access_page, page_size, kVSFSysUtilMapProtNone); p_mmap += page_size; if (page_offset) { p_mmap += (page_size - page_offset); } *p_ptr = p_mmap; } void vsf_secbuf_free(char** p_ptr) { unsigned int map_size; unsigned long page_offset; char* p_mmap = *p_ptr; unsigned int page_size = vsf_sysutil_getpagesize(); if (p_mmap == 0) { return; } /* Calculate the actual start of the mmap region */ page_offset = (unsigned long) p_mmap % page_size; if (page_offset) { p_mmap -= page_offset; } p_mmap -= page_size; /* First make the first page readable so we can get the size */ vsf_sysutil_memprotect(p_mmap, page_size, kVSFSysUtilMapProtReadOnly); /* Extract the mapping size */ map_size = *((unsigned int*)p_mmap); /* Lose the mapping */ vsf_sysutil_memunmap(p_mmap, map_size); }