229 lines
5.8 KiB

// Licensed under BSD-MIT: See LICENSE.
#ifndef CCAN_PTR_VALID_H
#define CCAN_PTR_VALID_H
#include "config.h"
#include <stdbool.h>
#include <stdlib.h>
/**
* ptr_valid_read - can I safely read from a pointer?
* @p: the proposed pointer.
*
* This function verifies that the pointer @p is safe to dereference for
* reading. It is very slow, particularly if the answer is "no".
*
* Sets errno to EFAULT on failure.
*
* See Also:
* ptr_valid_batch_read()
*/
#define ptr_valid_read(p) \
ptr_valid_r((p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
/**
* ptr_valid_write - can I safely write to a pointer?
* @p: the proposed pointer.
*
* This function verifies that the pointer @p is safe to dereference
* for writing (and reading). It is very slow, particularly if the
* answer is "no".
*
* Sets errno to EFAULT on failure.
*
* See Also:
* ptr_valid_batch_write()
*/
#define ptr_valid_write(p) \
ptr_valid_w((p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
/**
* ptr_valid_string - can I safely read a string?
* @p: the proposed string.
*
* This function verifies that the pointer @p is safe to dereference
* up to a nul character. It is very slow, particularly if the answer
* is "no".
*
* Sets errno to EFAULT on failure.
*
* See Also:
* ptr_valid_batch_string()
*/
bool ptr_valid_string(const char *p);
/**
* ptr_valid - generic pointer check function
* @p: the proposed pointer.
* @align: the alignment requirements of the pointer.
* @size: the size of the region @p should point to
* @write: true if @p should be writable as well as readable.
*
* This function verifies that the pointer @p is safe to dereference.
* It is very slow, particularly if the answer is "no".
*
* Sets errno to EFAULT on failure.
*
* See Also:
* ptr_valid_batch()
*/
bool ptr_valid(const void *p, size_t align, size_t size, bool write);
/**
* struct ptr_valid_batch - pointer to store state for batch ptr ops
*
* Treat as private.
*/
struct ptr_valid_batch {
unsigned int num_maps;
struct ptr_valid_map *maps;
int child_pid;
int to_child, from_child;
void *last;
bool last_ok;
};
/**
* ptr_valid_batch_start - prepare for a batch of ptr_valid checks.
* @batch: an uninitialized ptr_valid_batch structure.
*
* This initializes @batch; this same @batch pointer can be reused
* until the memory map changes (eg. via mmap(), munmap() or even
* malloc() and free()).
*
* This is useful to check many pointers, because otherwise it can be
* extremely slow.
*
* Example:
* struct linked {
* struct linked *next;
* const char *str;
* };
*
* static bool check_linked_carefully(struct linked *head)
* {
* struct ptr_valid_batch batch;
* struct linked *old = head;
* bool half = true;
*
* // If this fails, we can't check. Assume OK.
* if (!ptr_valid_batch_start(&batch))
* return true;
*
* while (head) {
* if (!ptr_valid_batch_read(&batch, head))
* goto fail;
* if (!ptr_valid_batch_string(&batch, head->str))
* goto fail;
* // Loop detection; move old at half speed of head.
* if (half)
* old = old->next;
* half = !half;
* if (head == old) {
* errno = ELOOP;
* goto fail;
* }
* }
* ptr_valid_batch_end(&batch);
* return true;
*
* fail:
* ptr_valid_batch_end(&batch);
* return false;
* }
*
* See Also:
* ptr_valid_batch_stop()
*/
bool ptr_valid_batch_start(struct ptr_valid_batch *batch);
/**
* ptr_valid_batch_read - can I safely read from a pointer?
* @batch: the batch initialized by ptr_valid_batch_start().
* @p: the proposed pointer.
*
* Batched version of ptr_valid_read().
*/
#define ptr_valid_batch_read(batch, p) \
ptr_valid_batch_r((batch), \
(p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
/**
* ptr_valid_batch_write - can I safely write to a pointer?
* @batch: the batch initialized by ptr_valid_batch_start().
* @p: the proposed pointer.
*
* Batched version of ptr_valid_write().
*/
#define ptr_valid_batch_write(batch, p) \
ptr_valid_batch_w((batch), \
(p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p)))
/**
* ptr_valid_batch_string - can I safely read a string?
* @batch: the batch initialized by ptr_valid_batch_start().
* @p: the proposed string.
*
* Batched version of ptr_valid_string().
*/
bool ptr_valid_batch_string(struct ptr_valid_batch *batch, const char *p);
/**
* ptr_valid_batch - generic batched pointer check function
* @batch: the batch initialized by ptr_valid_batch_start().
* @p: the proposed pointer.
* @align: the alignment requirements of the pointer.
* @size: the size of the region @p should point to
* @write: true if @p should be writable as well as readable.
*
* Batched version of ptr_valid().
*/
bool ptr_valid_batch(struct ptr_valid_batch *batch,
const void *p, size_t alignment, size_t size, bool write);
/**
* ptr_valid_batch_end - end a batch of ptr_valid checks.
* @batch: a ptr_valid_batch structure.
*
* This is used after all checks are complete.
*
* See Also:
* ptr_valid_batch_start()
*/
void ptr_valid_batch_end(struct ptr_valid_batch *batch);
/* These wrappers get constness correct. */
static inline bool ptr_valid_r(const void *p, size_t align, size_t size)
{
return ptr_valid(p, align, size, false);
}
static inline bool ptr_valid_w(void *p, size_t align, size_t size)
{
return ptr_valid(p, align, size, true);
}
static inline bool ptr_valid_batch_r(struct ptr_valid_batch *batch,
const void *p, size_t align, size_t size)
{
return ptr_valid_batch(batch, p, align, size, false);
}
static inline bool ptr_valid_batch_w(struct ptr_valid_batch *batch,
void *p, size_t align, size_t size)
{
return ptr_valid_batch(batch, p, align, size, true);
}
struct ptr_valid_map {
const char *start, *end;
bool is_write;
};
#if HAVE_ALIGNOF
#define PTR_VALID_ALIGNOF(var) __alignof__(var)
#else
/* Can't check this... */
#define PTR_VALID_ALIGNOF(var) 1
#endif
#endif /* CCAN_PTR_VALID_H */