1 /*
2  * Copyright (C) 2009-2012 Free Software Foundation, Inc.
3  *
4  * Author: Jonathan Bastien-Filiatrault
5  *
6  * This file is part of GNUTLS.
7  *
8  * The GNUTLS library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>
20  *
21  */
22 
23 #ifndef GNUTLS_LIB_MBUFFERS_H
24 #define GNUTLS_LIB_MBUFFERS_H
25 
26 #include "gnutls_int.h"
27 #include "errors.h"
28 #include <assert.h>
29 
30 void _mbuffer_head_init(mbuffer_head_st * buf);
31 void _mbuffer_head_clear(mbuffer_head_st * buf);
32 void _mbuffer_enqueue(mbuffer_head_st * buf, mbuffer_st * bufel);
33 mbuffer_st *_mbuffer_dequeue(mbuffer_head_st * buf, mbuffer_st * bufel);
34 int _mbuffer_head_remove_bytes(mbuffer_head_st * buf, size_t bytes);
35 mbuffer_st *_mbuffer_alloc(size_t maximum_size);
36 int _mbuffer_linearize(mbuffer_head_st * buf);
37 
38 mbuffer_st *_mbuffer_head_get_first(mbuffer_head_st * buf,
39 				    gnutls_datum_t * msg);
40 mbuffer_st *_mbuffer_head_get_next(mbuffer_st * cur, gnutls_datum_t * msg);
41 
42 void _mbuffer_head_push_first(mbuffer_head_st * buf, mbuffer_st * bufel);
43 
44 mbuffer_st *_mbuffer_head_pop_first(mbuffer_head_st * buf);
45 
46 /* This is dangerous since it will replace bufel with a new
47  * one.
48  */
49 int _mbuffer_append_data(mbuffer_st * bufel, void *newdata,
50 			 size_t newdata_size);
51 
52 
53 /* For "user" use. One can have buffer data and header.
54  */
55 
_mbuffer_get_uhead_ptr(mbuffer_st * bufel)56 inline static void *_mbuffer_get_uhead_ptr(mbuffer_st * bufel)
57 {
58 	return bufel->msg.data + bufel->mark;
59 }
60 
_mbuffer_get_udata_ptr(mbuffer_st * bufel)61 inline static void *_mbuffer_get_udata_ptr(mbuffer_st * bufel)
62 {
63 	return bufel->msg.data + bufel->uhead_mark + bufel->mark;
64 }
65 
_mbuffer_set_udata_size(mbuffer_st * bufel,size_t size)66 inline static void _mbuffer_set_udata_size(mbuffer_st * bufel, size_t size)
67 {
68 	bufel->msg.size = size + bufel->uhead_mark + bufel->mark;
69 }
70 
71 inline static void
_mbuffer_set_udata(mbuffer_st * bufel,void * data,size_t data_size)72 _mbuffer_set_udata(mbuffer_st * bufel, void *data, size_t data_size)
73 {
74 	memcpy(_mbuffer_get_udata_ptr(bufel), data,
75 	       data_size);
76 	_mbuffer_set_udata_size(bufel, data_size);
77 }
78 
_mbuffer_get_udata_size(mbuffer_st * bufel)79 inline static size_t _mbuffer_get_udata_size(mbuffer_st * bufel)
80 {
81 	return bufel->msg.size - bufel->uhead_mark - bufel->mark;
82 }
83 
84 /* discards size bytes from the begging of the buffer */
85 inline static void
_mbuffer_consume(mbuffer_head_st * buf,mbuffer_st * bufel,size_t size)86 _mbuffer_consume(mbuffer_head_st * buf, mbuffer_st * bufel, size_t size)
87 {
88 	bufel->uhead_mark = 0;
89 	if (bufel->mark + size < bufel->msg.size)
90 		bufel->mark += size;
91 	else
92 		bufel->mark = bufel->msg.size;
93 
94 	buf->byte_length -= size;
95 }
96 
_mbuffer_get_uhead_size(mbuffer_st * bufel)97 inline static size_t _mbuffer_get_uhead_size(mbuffer_st * bufel)
98 {
99 	return bufel->uhead_mark;
100 }
101 
_mbuffer_set_uhead_size(mbuffer_st * bufel,size_t size)102 inline static void _mbuffer_set_uhead_size(mbuffer_st * bufel, size_t size)
103 {
104 	bufel->uhead_mark = size;
105 }
106 
_mbuffer_init(mbuffer_st * bufel,size_t max)107 inline static void _mbuffer_init(mbuffer_st *bufel, size_t max)
108 {
109 	memset(bufel, 0, sizeof(*bufel));
110 	bufel->maximum_size = max;
111 
112 	/* payload points after the mbuffer_st structure */
113 	bufel->msg.data = (uint8_t *) bufel + sizeof(mbuffer_st);
114 }
115 
116 /* Helper functions to utilize a gnutls_buffer_st in order
117  * to generate a gnutls_mbuffer_st, without multiple allocations.
118  */
_gnutls_buffer_init_mbuffer(gnutls_buffer_st * buf,size_t header_size)119 inline static int _gnutls_buffer_init_mbuffer(gnutls_buffer_st * buf, size_t header_size)
120 {
121 	int ret;
122 	mbuffer_st *bufel;
123 
124 	_gnutls_buffer_init(buf);
125 
126 	ret = _gnutls_buffer_resize(buf, sizeof(mbuffer_st)+header_size);
127 	if (ret < 0)
128 		return gnutls_assert_val(ret);
129 
130 	/* we store the uhead size on the uninitialized bufel, only to read
131 	 * it back on _gnutls_buffer_to_mbuffer(). */
132 	bufel = (void*)buf->data;
133 	_mbuffer_set_uhead_size(bufel, header_size);
134 
135 	buf->length = sizeof(mbuffer_st)+header_size;
136 
137 	return 0;
138 }
139 
140 #define _gnutls_buffer_init_handshake_mbuffer(b) _gnutls_buffer_init_mbuffer(b, HANDSHAKE_HEADER_SIZE(session))
141 
142 
143 /* Cannot fail */
_gnutls_buffer_to_mbuffer(gnutls_buffer_st * buf)144 inline static mbuffer_st *_gnutls_buffer_to_mbuffer(gnutls_buffer_st * buf)
145 {
146 	mbuffer_st *bufel;
147 	unsigned header_size;
148 
149 	bufel = (void*)buf->data;
150 
151 	header_size = _mbuffer_get_uhead_size(bufel);
152 	assert(buf->length >= sizeof(mbuffer_st)+header_size);
153 
154 	_mbuffer_init(bufel, buf->length - sizeof(mbuffer_st));
155 
156 	_mbuffer_set_udata_size(bufel, buf->length - sizeof(mbuffer_st));
157 	_mbuffer_set_uhead_size(bufel, header_size);
158 
159 	_gnutls_buffer_init(buf); /* avoid double frees */
160 
161 	return bufel;
162 }
163 
_gnutls_handshake_alloc(gnutls_session_t session,size_t maximum)164 inline static mbuffer_st *_gnutls_handshake_alloc(gnutls_session_t session,
165 						  size_t maximum)
166 {
167 	mbuffer_st *bufel =
168 	    _mbuffer_alloc(HANDSHAKE_HEADER_SIZE(session) + maximum);
169 
170 	if (!bufel)
171 		return NULL;
172 
173 	_mbuffer_set_uhead_size(bufel, HANDSHAKE_HEADER_SIZE(session));
174 	_mbuffer_set_udata_size(bufel, maximum);
175 
176 	return bufel;
177 }
178 
179 /* Free a segment, if the pointer is not NULL
180  *
181  * We take a ** to detect and fix double free bugs (the dangling
182  * pointer case). It also makes sure the pointer has a known value
183  * after freeing.
184  */
_mbuffer_xfree(mbuffer_st ** bufel)185 inline static void _mbuffer_xfree(mbuffer_st ** bufel)
186 {
187 	if (*bufel)
188 		gnutls_free(*bufel);
189 
190 	*bufel = NULL;
191 }
192 
193 #ifdef ENABLE_ALIGN16
194 mbuffer_st *_mbuffer_alloc_align16(size_t maximum_size, unsigned align_pos);
195 int _mbuffer_linearize_align16(mbuffer_head_st * buf, unsigned align_pos);
196 #else
197 # define _mbuffer_alloc_align16(x,y) _mbuffer_alloc(x)
198 # define _mbuffer_linearize_align16(x,y) _mbuffer_linearize(x)
199 #endif
200 
201 #endif /* GNUTLS_LIB_MBUFFERS_H */
202