xref: /haiku/headers/private/kernel/util/iovec_support.h (revision 013719cfc63815693a376fd0ca202b94d06124bc)
100f1e7c5SAugustin Cavalier /*
200f1e7c5SAugustin Cavalier  * Copyright 2022, Haiku, Inc. All rights reserved.
300f1e7c5SAugustin Cavalier  * Distributed under the terms of the MIT license.
400f1e7c5SAugustin Cavalier  */
500f1e7c5SAugustin Cavalier #ifndef _UTIL_IOVEC_SUPPORT_H
600f1e7c5SAugustin Cavalier #define _UTIL_IOVEC_SUPPORT_H
700f1e7c5SAugustin Cavalier 
800f1e7c5SAugustin Cavalier 
900f1e7c5SAugustin Cavalier #include <KernelExport.h>
1000f1e7c5SAugustin Cavalier 
1100f1e7c5SAugustin Cavalier 
1200f1e7c5SAugustin Cavalier static inline status_t
1300f1e7c5SAugustin Cavalier get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec*& vecs,
1400f1e7c5SAugustin Cavalier 	bool permitNull = false)
1500f1e7c5SAugustin Cavalier {
1600f1e7c5SAugustin Cavalier 	// prevent integer overflow
17*013719cfSJérôme Duval 	if (vecCount > IOV_MAX || vecCount == 0)
1800f1e7c5SAugustin Cavalier 		return B_BAD_VALUE;
1900f1e7c5SAugustin Cavalier 
2000f1e7c5SAugustin Cavalier 	if (!IS_USER_ADDRESS(userVecs))
2100f1e7c5SAugustin Cavalier 		return B_BAD_ADDRESS;
2200f1e7c5SAugustin Cavalier 
2300f1e7c5SAugustin Cavalier 	vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
2400f1e7c5SAugustin Cavalier 	if (vecs == NULL)
2500f1e7c5SAugustin Cavalier 		return B_NO_MEMORY;
2600f1e7c5SAugustin Cavalier 
27*013719cfSJérôme Duval 	if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK) {
28*013719cfSJérôme Duval 		free(vecs);
2900f1e7c5SAugustin Cavalier 		return B_BAD_ADDRESS;
30*013719cfSJérôme Duval 	}
3100f1e7c5SAugustin Cavalier 
32*013719cfSJérôme Duval 	size_t total = 0;
3300f1e7c5SAugustin Cavalier 	for (size_t i = 0; i < vecCount; i++) {
3400f1e7c5SAugustin Cavalier 		if (permitNull && vecs[i].iov_base == NULL)
3500f1e7c5SAugustin Cavalier 			continue;
36*013719cfSJérôme Duval 		if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) {
37*013719cfSJérôme Duval 			free(vecs);
3800f1e7c5SAugustin Cavalier 			return B_BAD_ADDRESS;
3900f1e7c5SAugustin Cavalier 		}
40*013719cfSJérôme Duval 		if (vecs[i].iov_len > SSIZE_MAX || total > (SSIZE_MAX - vecs[i].iov_len)) {
41*013719cfSJérôme Duval 			free(vecs);
42*013719cfSJérôme Duval 			return B_BAD_VALUE;
43*013719cfSJérôme Duval 		}
44*013719cfSJérôme Duval 		total += vecs[i].iov_len;
45*013719cfSJérôme Duval 	}
4600f1e7c5SAugustin Cavalier 
4700f1e7c5SAugustin Cavalier 	return B_OK;
4800f1e7c5SAugustin Cavalier }
4900f1e7c5SAugustin Cavalier 
5000f1e7c5SAugustin Cavalier 
5100f1e7c5SAugustin Cavalier #endif	// _UTIL_IOVEC_SUPPORT_H
52