1 |
#include <stdlib.h> |
#include <stdlib.h> |
2 |
|
#include <stdlib.h> |
3 |
#include <unistd.h> |
#include <unistd.h> |
|
#include <sys/types.h> |
|
4 |
#include <string.h> |
#include <string.h> |
5 |
#include <errno.h> |
#include <errno.h> |
6 |
#include <sys/mman.h> |
#include <sys/types.h> /* For POSIX.1-2001 non-conformant systems. */ |
7 |
#include <sys/time.h> |
#include <sys/time.h> /* For POSIX.1-2001 non-conformant systems. */ |
8 |
#include <sys/resource.h> |
#include <sys/resource.h> |
9 |
|
|
|
|
|
10 |
#include "config.h" |
#include "config.h" |
11 |
#include "imapfilter.h" |
#include "imapfilter.h" |
12 |
|
|
13 |
|
|
14 |
|
/* Secure memory information. */ |
15 |
|
typedef struct secmem { |
16 |
|
void *buf; /* Allocated memory buffer. */ |
17 |
|
size_t size; /* Size of the buffer. */ |
18 |
|
struct secmem *prev, *next; /* Previous/next node of doubly linked |
19 |
|
* list. */ |
20 |
|
} secmem_t; |
21 |
|
|
22 |
|
|
23 |
extern unsigned int options; |
extern unsigned int options; |
|
#ifdef MEMORY_LOCK |
|
|
extern uid_t ruid, euid; |
|
|
#endif |
|
24 |
|
|
25 |
static secmem_t *smem = NULL; /* First node of secure memory linked list. */ |
static secmem_t *secmem = NULL; /* First node of secure memory linked list. */ |
26 |
|
|
27 |
|
|
28 |
|
void secmem_append(secmem_t * sm); |
29 |
|
secmem_t *secmem_find(void *ptr); |
30 |
|
void secmem_remove(secmem_t * sm); |
31 |
|
|
32 |
|
|
33 |
/* |
/* |
34 |
* A malloc() that checks the results and dies in case of error. |
* A malloc() that checks the results and dies in case of error. |
35 |
*/ |
*/ |
36 |
void *xmalloc(size_t size) |
void * |
37 |
|
xmalloc(size_t size) |
38 |
{ |
{ |
39 |
void *ptr; |
void *ptr; |
40 |
|
|
41 |
ptr = (void *)malloc(size); |
ptr = (void *)malloc(size); |
42 |
|
|
43 |
if (!ptr) |
if (ptr == NULL) |
44 |
fatal(ERROR_MEMORY_ALLOCATION, |
fatal(ERROR_MEMALLOC, |
45 |
"imapfilter: allocating memory; %s\n", strerror(errno)); |
"allocating memory; %s\n", strerror(errno)); |
46 |
|
|
47 |
return ptr; |
return ptr; |
48 |
} |
} |
49 |
|
|
50 |
|
|
51 |
/* |
/* |
52 |
* A realloc() that checks the results and dies in case of error. |
* A realloc() that checks the results and dies in case of error. |
53 |
*/ |
*/ |
54 |
void *xrealloc(void *ptr, size_t size) |
void * |
55 |
|
xrealloc(void *ptr, size_t size) |
56 |
{ |
{ |
57 |
ptr = (void *)realloc(ptr, size); |
ptr = (void *)realloc(ptr, size); |
58 |
|
|
59 |
if (!ptr) |
if (ptr == NULL) |
60 |
fatal(ERROR_MEMORY_ALLOCATION, |
fatal(ERROR_MEMALLOC, |
61 |
"imapfilter: allocating memory; %s\n", strerror(errno)); |
"allocating memory; %s\n", strerror(errno)); |
62 |
|
|
63 |
return ptr; |
return ptr; |
64 |
} |
} |
65 |
|
|
66 |
|
|
67 |
/* |
/* |
68 |
* A free() that dies if fed with NULL pointer. |
* A free() that dies if fed with NULL pointer. |
69 |
*/ |
*/ |
70 |
void xfree(void *ptr) |
void |
71 |
|
xfree(void *ptr) |
72 |
{ |
{ |
73 |
if (!ptr) |
|
74 |
fatal(ERROR_MEMORY_ALLOCATION, |
if (ptr == NULL) |
75 |
"imapfilter: NULL pointer given as argument"); |
fatal(ERROR_MEMALLOC, |
76 |
free(ptr); |
"NULL pointer given as argument"); |
77 |
|
free(ptr); |
78 |
} |
} |
79 |
|
|
80 |
|
|
81 |
/* |
/* |
82 |
* A strdup() that checks the results and dies in case of error. |
* A strdup() that checks the results and dies in case of error. |
83 |
*/ |
*/ |
84 |
char *xstrdup(const char *s) |
char * |
85 |
|
xstrdup(const char *s) |
86 |
{ |
{ |
87 |
char *cp; |
char *cp; |
88 |
|
|
89 |
cp = strdup(s); |
cp = strdup(s); |
90 |
|
|
91 |
if (!cp) |
if (cp == NULL) |
92 |
fatal(ERROR_MEMORY_ALLOCATION, |
fatal(ERROR_MEMALLOC, "allocating memory; %s\n", |
93 |
"imapfilter: allocating memory; %s\n", strerror(errno)); |
strerror(errno)); |
94 |
|
|
95 |
return cp; |
return cp; |
96 |
} |
} |
97 |
|
|
98 |
|
|
100 |
* Secure memory malloc(). Locks memory and keeps information about the |
* Secure memory malloc(). Locks memory and keeps information about the |
101 |
* chunk that was allocated. |
* chunk that was allocated. |
102 |
*/ |
*/ |
103 |
void *smalloc(size_t size) |
void * |
104 |
|
smalloc(size_t size) |
105 |
{ |
{ |
106 |
#ifdef MEMORY_LOCK |
void *ptr; |
107 |
int r; |
secmem_t *sm; |
|
static int w = 0; |
|
|
#endif |
|
|
void *ptr; |
|
|
secmem_t *node; |
|
|
|
|
|
ptr = xmalloc(size); |
|
|
|
|
|
#ifdef MEMORY_LOCK |
|
|
seteuid(euid); /* Gain root privileges. */ |
|
|
r = mlock(ptr, size); |
|
|
seteuid(ruid); /* Drop root privileges. */ |
|
|
|
|
|
if (getuid() != geteuid()) |
|
|
fatal(ERROR_SETUID, "imapfilter: failed to drop privileges\n"); |
|
108 |
|
|
109 |
|
ptr = xmalloc(size); |
110 |
|
|
111 |
if (options & OPTION_WARNING && r && !w) { |
sm = (secmem_t *) xmalloc(sizeof(secmem_t)); |
|
error("imapfilter: warning: using insecure memory\n"); |
|
|
w = 1; |
|
|
} |
|
|
#endif |
|
|
node = (secmem_t *) xmalloc(sizeof(secmem_t)); |
|
112 |
|
|
113 |
node->buf = ptr; |
sm->buf = ptr; |
114 |
node->size = size; |
sm->size = size; |
115 |
node->prev = node->next = NULL; |
sm->prev = sm->next = NULL; |
116 |
|
|
117 |
secmem_append(node); |
secmem_append(sm); |
118 |
|
|
119 |
return ptr; |
return ptr; |
120 |
} |
} |
121 |
|
|
122 |
|
|
124 |
* Secure memory realloc(). Resize memory by allocating a new memory chunk |
* Secure memory realloc(). Resize memory by allocating a new memory chunk |
125 |
* and NULL fill old memory, in order to protect sensitive data. |
* and NULL fill old memory, in order to protect sensitive data. |
126 |
*/ |
*/ |
127 |
void *srealloc(void *ptr, size_t size) |
void * |
128 |
|
srealloc(void *ptr, size_t size) |
129 |
{ |
{ |
130 |
void *p; |
void *p; |
131 |
secmem_t *node; |
secmem_t *sm; |
132 |
|
|
133 |
if (!(node = (secmem_t *) secmem_find(ptr))) { |
if (!(sm = (secmem_t *) secmem_find(ptr))) { |
134 |
ptr = xrealloc(ptr, size); |
ptr = xrealloc(ptr, size); |
135 |
return ptr; |
return ptr; |
136 |
} |
} |
137 |
p = smalloc(size); |
p = smalloc(size); |
138 |
memcpy(p, node->buf, min(node->size, size)); |
memcpy(p, sm->buf, min(sm->size, size)); |
139 |
|
|
140 |
memset(node->buf, 0, node->size); |
memset(sm->buf, 0, sm->size); |
141 |
secmem_remove(node); |
secmem_remove(sm); |
142 |
xfree(node->buf); |
xfree(sm->buf); |
143 |
xfree(node); |
xfree(sm); |
144 |
|
|
145 |
return p; |
return p; |
146 |
} |
} |
147 |
|
|
148 |
|
|
149 |
/* |
/* |
150 |
* Secure memory free(). NULL fill memory before freeing it. |
* Secure memory free(). NULL fill memory before freeing it. |
151 |
*/ |
*/ |
152 |
void sfree(void *ptr) |
void |
153 |
|
sfree(void *ptr) |
154 |
{ |
{ |
155 |
secmem_t *node; |
secmem_t *sm; |
156 |
|
|
157 |
if (!(node = (secmem_t *) secmem_find(ptr))) { |
if (!(sm = (secmem_t *) secmem_find(ptr))) { |
158 |
xfree(ptr); |
xfree(ptr); |
159 |
return; |
return; |
160 |
} |
} |
161 |
|
memset(sm->buf, 0, sm->size); |
162 |
memset(node->buf, 0, node->size); |
secmem_remove(sm); |
163 |
secmem_remove(node); |
xfree(sm->buf); |
164 |
xfree(node->buf); |
xfree(sm); |
|
xfree(node); |
|
165 |
} |
} |
166 |
|
|
167 |
|
|
168 |
/* |
/* |
169 |
* Secure memory strdup(). Uses secure memory allocation. |
* Secure memory strdup(). Uses secure memory allocation. |
170 |
*/ |
*/ |
171 |
char *sstrdup(const char *s) |
char * |
172 |
|
sstrdup(const char *s) |
173 |
{ |
{ |
174 |
char *p; |
char *p; |
175 |
|
|
176 |
p = (char *)smalloc(strlen(s) + 1); |
p = (char *)smalloc(strlen(s) + 1); |
177 |
xstrncpy(p, s, strlen(s)); |
xstrncpy(p, s, strlen(s)); |
178 |
|
|
179 |
return p; |
return p; |
180 |
} |
} |
181 |
|
|
182 |
|
|
183 |
/* |
/* |
184 |
* Append information about the newly allocated memory buffer. |
* Append information about the newly allocated memory buffer. |
185 |
*/ |
*/ |
186 |
void secmem_append(secmem_t * node) |
void |
187 |
|
secmem_append(secmem_t * sm) |
188 |
{ |
{ |
189 |
secmem_t *pos; |
secmem_t *pos; |
190 |
secmem_t **app; |
secmem_t **app; |
191 |
|
|
192 |
app = &smem; |
app = &secmem; |
193 |
pos = smem; |
pos = secmem; |
194 |
|
|
195 |
while (pos) { |
while (pos) { |
196 |
node->prev = pos; |
sm->prev = pos; |
197 |
app = &(pos->next); |
app = &(pos->next); |
198 |
pos = pos->next; |
pos = pos->next; |
199 |
} |
} |
200 |
|
|
201 |
*app = node; |
*app = sm; |
202 |
} |
} |
203 |
|
|
204 |
|
|
205 |
/* |
/* |
206 |
* Find the record of a memory buffer in the secure memory linked list. |
* Find the record of a memory buffer in the secure memory linked list. |
207 |
*/ |
*/ |
208 |
secmem_t *secmem_find(void *ptr) |
secmem_t * |
209 |
|
secmem_find(void *ptr) |
210 |
{ |
{ |
211 |
secmem_t *pos; |
secmem_t *pos; |
212 |
|
|
213 |
pos = smem; |
pos = secmem; |
214 |
|
|
215 |
while (pos && pos->buf != ptr) |
while (pos != NULL && pos->buf != ptr) |
216 |
pos = pos->next; |
pos = pos->next; |
217 |
|
|
218 |
return pos; |
return pos; |
219 |
} |
} |
220 |
|
|
221 |
|
|
222 |
/* |
/* |
223 |
* Remove a record of a secure memory buffer. |
* Remove a record of a secure memory buffer. |
224 |
*/ |
*/ |
225 |
void secmem_remove(secmem_t * node) |
void |
226 |
|
secmem_remove(secmem_t * sm) |
227 |
{ |
{ |
|
if (node->prev) |
|
|
node->prev->next = node->next; |
|
|
if (node->next) |
|
|
node->next->prev = node->prev; |
|
|
if (smem == node) |
|
|
smem = node->next; |
|
|
|
|
|
} |
|
|
|
|
228 |
|
|
229 |
/* |
if (sm->prev != NULL) |
230 |
* Overwrite/clear all secure memory. |
sm->prev->next = sm->next; |
231 |
*/ |
if (sm->next != NULL) |
232 |
void secmem_clear(void) |
sm->next->prev = sm->prev; |
233 |
{ |
if (secmem == sm) |
234 |
secmem_t *p, *t; |
secmem = sm->next; |
235 |
|
|
|
for (p = smem; p; p = t) { |
|
|
t = p->next; |
|
|
sfree(p->buf); |
|
|
} |
|
236 |
} |
} |
237 |
|
|
238 |
|
|
|
#ifdef MEMORY_LOCK |
|
239 |
/* |
/* |
240 |
* Lock memory of allocated buffers. |
* Overwrite/clear all secure memory. |
241 |
*/ |
*/ |
242 |
void secmem_lock(void) |
void |
243 |
|
secmem_clear(void) |
244 |
{ |
{ |
245 |
secmem_t *p; |
secmem_t *p, *t; |
|
|
|
|
seteuid(euid); /* Gain root privileges. */ |
|
|
for (p = smem; p; p = p->next) |
|
|
mlock(p->buf, p->size); |
|
|
seteuid(ruid); /* Drop root privileges. */ |
|
246 |
|
|
247 |
if (getuid() != geteuid()) |
for (p = secmem; p != NULL; p = t) { |
248 |
fatal(ERROR_SETUID, "imapfilter: failed to drop privileges\n"); |
t = p->next; |
249 |
|
sfree(p->buf); |
250 |
|
} |
251 |
} |
} |
252 |
|
|
|
#endif |
|
|
|
|
253 |
|
|
254 |
/* |
/* |
255 |
* Disable core file dumping. |
* Disable core file dumping. |
256 |
*/ |
*/ |
257 |
void corefile_disable(void) |
void |
258 |
|
corefile_disable(void) |
259 |
{ |
{ |
260 |
struct rlimit rl; |
struct rlimit rl; |
261 |
|
|
262 |
getrlimit(RLIMIT_CORE, &rl); |
getrlimit(RLIMIT_CORE, &rl); |
263 |
|
|
264 |
rl.rlim_cur = rl.rlim_max = 0; |
rl.rlim_cur = rl.rlim_max = 0; |
265 |
setrlimit(RLIMIT_CORE, &rl); |
setrlimit(RLIMIT_CORE, &rl); |
266 |
} |
} |