xref: /haiku/headers/private/kernel/util/iovec_support.h (revision 65cdc13e7d31ea987d9d6e9bf7f6373aab5eecf2)
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 
12*65cdc13eSAugustin Cavalier typedef struct generic_io_vec {
13*65cdc13eSAugustin Cavalier 	generic_addr_t	base;
14*65cdc13eSAugustin Cavalier 	generic_size_t	length;
15*65cdc13eSAugustin Cavalier } generic_io_vec;
16*65cdc13eSAugustin Cavalier 
17*65cdc13eSAugustin Cavalier 
18*65cdc13eSAugustin Cavalier #ifdef IS_USER_ADDRESS
1900f1e7c5SAugustin Cavalier static inline status_t
2000f1e7c5SAugustin Cavalier get_iovecs_from_user(const iovec* userVecs, size_t vecCount, iovec*& vecs,
2100f1e7c5SAugustin Cavalier 	bool permitNull = false)
2200f1e7c5SAugustin Cavalier {
2300f1e7c5SAugustin Cavalier 	// prevent integer overflow
24013719cfSJérôme Duval 	if (vecCount > IOV_MAX || vecCount == 0)
2500f1e7c5SAugustin Cavalier 		return B_BAD_VALUE;
2600f1e7c5SAugustin Cavalier 
2700f1e7c5SAugustin Cavalier 	if (!IS_USER_ADDRESS(userVecs))
2800f1e7c5SAugustin Cavalier 		return B_BAD_ADDRESS;
2900f1e7c5SAugustin Cavalier 
3000f1e7c5SAugustin Cavalier 	vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
3100f1e7c5SAugustin Cavalier 	if (vecs == NULL)
3200f1e7c5SAugustin Cavalier 		return B_NO_MEMORY;
3300f1e7c5SAugustin Cavalier 
34013719cfSJérôme Duval 	if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) != B_OK) {
35013719cfSJérôme Duval 		free(vecs);
3600f1e7c5SAugustin Cavalier 		return B_BAD_ADDRESS;
37013719cfSJérôme Duval 	}
3800f1e7c5SAugustin Cavalier 
39013719cfSJérôme Duval 	size_t total = 0;
4000f1e7c5SAugustin Cavalier 	for (size_t i = 0; i < vecCount; i++) {
4100f1e7c5SAugustin Cavalier 		if (permitNull && vecs[i].iov_base == NULL)
4200f1e7c5SAugustin Cavalier 			continue;
43013719cfSJérôme Duval 		if (!is_user_address_range(vecs[i].iov_base, vecs[i].iov_len)) {
44013719cfSJérôme Duval 			free(vecs);
4500f1e7c5SAugustin Cavalier 			return B_BAD_ADDRESS;
4600f1e7c5SAugustin Cavalier 		}
47013719cfSJérôme Duval 		if (vecs[i].iov_len > SSIZE_MAX || total > (SSIZE_MAX - vecs[i].iov_len)) {
48013719cfSJérôme Duval 			free(vecs);
49013719cfSJérôme Duval 			return B_BAD_VALUE;
50013719cfSJérôme Duval 		}
51013719cfSJérôme Duval 		total += vecs[i].iov_len;
52013719cfSJérôme Duval 	}
5300f1e7c5SAugustin Cavalier 
5400f1e7c5SAugustin Cavalier 	return B_OK;
5500f1e7c5SAugustin Cavalier }
56*65cdc13eSAugustin Cavalier #endif
5700f1e7c5SAugustin Cavalier 
5800f1e7c5SAugustin Cavalier 
5900f1e7c5SAugustin Cavalier #endif	// _UTIL_IOVEC_SUPPORT_H
60