@@ -146,6 +146,119 @@ int main()
146146 */
147147 }
148148
149+ /*
150+ * Verify that our memcpy implementation successfully copies capabilities
151+ * even when it is given a region that is not capability-aligned.
152+ */
153+ message (" Checking memcpy behaviors" );
154+ {
155+ static constexpr size_t ncaps = 16 ;
156+
157+ int * icaps[ncaps];
158+
159+ for (size_t i = 0 ; i < ncaps; i++)
160+ {
161+ icaps[i] = (int *)&icaps[i];
162+ SNMALLOC_CHECK (__builtin_cheri_tag_get (icaps[i]));
163+ }
164+
165+ int * ocaps[ncaps];
166+
167+ /*
168+ * While it may seem trivial, check the both-aligned case, both for one
169+ * and for many capabilities.
170+ */
171+ bzero (ocaps, sizeof (ocaps));
172+ snmalloc::memcpy<false >(ocaps, icaps, sizeof (void *));
173+ SNMALLOC_CHECK (__builtin_cheri_tag_get (ocaps[0 ]));
174+ SNMALLOC_CHECK (__builtin_cheri_equal_exact (icaps[0 ], ocaps[0 ]));
175+
176+ bzero (ocaps, sizeof (ocaps));
177+ snmalloc::memcpy<false >(ocaps, icaps, sizeof (icaps));
178+ for (size_t i = 0 ; i < ncaps; i++)
179+ {
180+ SNMALLOC_CHECK (__builtin_cheri_tag_get (ocaps[i]));
181+ SNMALLOC_CHECK (__builtin_cheri_equal_exact (icaps[i], ocaps[i]));
182+ }
183+
184+ /*
185+ * When both input and output are equally misaligned, we should preserve
186+ * caps that aren't sheared by the copy. The size of this copy is also
187+ * "unnatural", which should guarantee that any memcpy implementation that
188+ * tries the overlapping-misaligned-sizeof(long)-at-the-end dance corrupts
189+ * the penultimate capability by overwriting it with (identical) data.
190+ *
191+ * Probe a misaligned copy of bytes followed by a zero or more pointers
192+ * followed by bytes.
193+ */
194+ for (size_t pre = 1 ; pre < sizeof (int *); pre ++)
195+ {
196+ for (size_t post = 0 ; post < sizeof (int *); post ++)
197+ {
198+ for (size_t ptrs = 0 ; ptrs < ncaps - 2 ; ptrs++)
199+ {
200+ bzero (ocaps, sizeof (ocaps));
201+
202+ snmalloc::memcpy<false >(
203+ pointer_offset (ocaps, pre ),
204+ pointer_offset (icaps, pre ),
205+ (ptrs + 1 ) * sizeof (int *) - pre + post );
206+
207+ /* prefix */
208+ SNMALLOC_CHECK (
209+ memcmp (
210+ pointer_offset (icaps, pre ),
211+ pointer_offset (ocaps, pre ),
212+ sizeof (int *) - pre ) == 0 );
213+ /* pointer */
214+ for (size_t p = 0 ; p < ptrs; p++)
215+ {
216+ SNMALLOC_CHECK (__builtin_cheri_tag_get (ocaps[1 + p]));
217+ SNMALLOC_CHECK (
218+ __builtin_cheri_equal_exact (icaps[1 + p], ocaps[1 + p]));
219+ }
220+ /* suffix */
221+ SNMALLOC_CHECK (memcmp (&icaps[1 + ptrs], &ocaps[1 + ptrs], post ) == 0 );
222+ }
223+ }
224+ }
225+
226+ /*
227+ * If the alignments are different, then the bytes should get copied but
228+ * the tags should be cleared.
229+ */
230+ for (size_t sa = 0 ; sa < sizeof (int *); sa++)
231+ {
232+ for (size_t da = 0 ; da < sizeof (int *); da++)
233+ {
234+ static constexpr size_t n = 4 ;
235+
236+ if (sa == da)
237+ {
238+ continue ;
239+ }
240+
241+ bzero (ocaps, n * sizeof (int *));
242+
243+ snmalloc::memcpy<false >(
244+ pointer_offset (ocaps, da),
245+ pointer_offset (icaps, sa),
246+ n * sizeof (int *) - da - sa);
247+
248+ for (size_t i = 0 ; i < n; i++)
249+ {
250+ SNMALLOC_CHECK (__builtin_cheri_tag_get (ocaps[i]) == 0 );
251+ }
252+
253+ SNMALLOC_CHECK (
254+ memcmp (
255+ pointer_offset (icaps, sa),
256+ pointer_offset (ocaps, da),
257+ n * sizeof (int *) - da - sa) == 0 );
258+ }
259+ }
260+ }
261+
149262 message (" CHERI checks OK" );
150263 return 0 ;
151264}
0 commit comments