Browse Source
ccan/autodata, ccan/breakpoint, ccan/crypto/hmac_sha256, ccan/crypto/hkdf_sha256, ccan/fdpass and ccan/io/fdpass. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
8 years ago
83 changed files with 2883 additions and 354 deletions
@ -1,3 +1,3 @@ |
|||||
CCAN imported from http://ccodearchive.net. |
CCAN imported from http://ccodearchive.net. |
||||
|
|
||||
CCAN version: init-2302-g6b74669 |
CCAN version: init-2338-g97ac583 |
||||
|
@ -0,0 +1 @@ |
|||||
|
../../licenses/BSD-MIT |
@ -0,0 +1,111 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* autodata - stash pointers in your binary for automatic registration |
||||
|
* |
||||
|
* This code allows declarations in your source which you can gather |
||||
|
* together at runtime to form tables. This is often used in place of |
||||
|
* having a central registration function or table. |
||||
|
* |
||||
|
* Note that this technique does not work in general for shared libaries, |
||||
|
* only for code compiled into a binary. |
||||
|
* |
||||
|
* License: BSD-MIT |
||||
|
* |
||||
|
* Example: |
||||
|
* // Distributed commandline option registration (note: ccan/opt is better!) |
||||
|
* #include <ccan/autodata/autodata.h> |
||||
|
* #include <stdio.h> |
||||
|
* #include <unistd.h> |
||||
|
* #include <stdbool.h> |
||||
|
* #include <err.h> |
||||
|
* |
||||
|
* static bool verbose = false; |
||||
|
* |
||||
|
* // This would normally be in a header, so any C file can use it. |
||||
|
* struct option { |
||||
|
* char c; |
||||
|
* bool takes_arg; |
||||
|
* bool (*cb)(char *optarg); |
||||
|
* }; |
||||
|
* AUTODATA_TYPE(options, struct option); |
||||
|
* #define REGISTER_OPTION(optstruct) \ |
||||
|
* AUTODATA(options, (optstruct)) |
||||
|
* |
||||
|
* // Now a few examples (could be anywhere in source) |
||||
|
* static bool verbose_cb(char *unused) |
||||
|
* { |
||||
|
* verbose = true; |
||||
|
* return true; |
||||
|
* } |
||||
|
* static struct option dash_v = { 'v', false, verbose_cb }; |
||||
|
* REGISTER_OPTION(&dash_v); |
||||
|
* |
||||
|
* static bool chdir_cb(char *dir) |
||||
|
* { |
||||
|
* if (verbose) |
||||
|
* printf("chdir to %s. ", dir); |
||||
|
* if (chdir(dir) != 0) |
||||
|
* return false; |
||||
|
* return true; |
||||
|
* } |
||||
|
* static struct option dash_C = { 'C', true, chdir_cb }; |
||||
|
* REGISTER_OPTION(&dash_C); |
||||
|
* |
||||
|
* int main(int argc, char *argv[]) |
||||
|
* { |
||||
|
* struct option **opts; |
||||
|
* size_t i, num; |
||||
|
* int o; |
||||
|
* char *optstring, *p; |
||||
|
* |
||||
|
* // Gather together all the registered options. |
||||
|
* opts = autodata_get(options, &num); |
||||
|
* |
||||
|
* // Make pretty string for getopt(). |
||||
|
* p = optstring = malloc(num * 2 + 1); |
||||
|
* for (i = 0; i < num; i++) { |
||||
|
* *(p++) = opts[i]->c; |
||||
|
* if (opts[i]->takes_arg) |
||||
|
* *(p++) = ':'; |
||||
|
* } |
||||
|
* *p = '\0'; |
||||
|
* |
||||
|
* while ((o = getopt(argc, argv, optstring)) != -1) { |
||||
|
* if (o == '?') |
||||
|
* exit(1); |
||||
|
* // Call callback in matching option. |
||||
|
* for (i = 0; i < num; i++) { |
||||
|
* if (opts[i]->c == o) { |
||||
|
* if (!opts[i]->cb(optarg)) |
||||
|
* err(1, "parsing -%c", o); |
||||
|
* break; |
||||
|
* } |
||||
|
* } |
||||
|
* } |
||||
|
* // free up gathered option table. |
||||
|
* autodata_free(opts); |
||||
|
* |
||||
|
* if (verbose) |
||||
|
* printf("verbose mode on\n"); |
||||
|
* return 0; |
||||
|
* } |
||||
|
* // Given "-v" outputs "verbose mode on\n" |
||||
|
* // Given "-v -C /" outputs "chdir to /. verbose mode on\n" |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
printf("ccan/compiler\n"); |
||||
|
printf("ccan/ptr_valid\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,80 @@ |
|||||
|
// Licensed under BSD-MIT: See LICENSE.
|
||||
|
#include "autodata.h" |
||||
|
#include <stdint.h> |
||||
|
#include <unistd.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#if HAVE_SECTION_START_STOP |
||||
|
void *autodata_get_section(void *start, void *stop, size_t *nump) |
||||
|
{ |
||||
|
*nump = (void **)(stop) - (void **)(start); |
||||
|
return start; |
||||
|
} |
||||
|
|
||||
|
void autodata_free(void *table UNNEEDED) |
||||
|
{ |
||||
|
} |
||||
|
#else |
||||
|
#include <ccan/ptr_valid/ptr_valid.h> |
||||
|
|
||||
|
void *autodata_make_table(const void *example, const char *name, size_t *nump) |
||||
|
{ |
||||
|
const char *start, *end, *tag; |
||||
|
struct ptr_valid_batch batch; |
||||
|
const void *const magic = (void *)AUTODATA_MAGIC; |
||||
|
void **table = NULL; |
||||
|
char first_magic; |
||||
|
|
||||
|
if (!ptr_valid_batch_start(&batch)) |
||||
|
return NULL; |
||||
|
|
||||
|
/* Get range to search. */ |
||||
|
for (start = (char *)((intptr_t)example & ~(getpagesize() - 1)); |
||||
|
ptr_valid_batch(&batch, start-getpagesize(), 1, sizeof(void *), |
||||
|
false); |
||||
|
start -= getpagesize()); |
||||
|
|
||||
|
for (end = (char *)((intptr_t)example & ~(getpagesize() - 1)); |
||||
|
ptr_valid_batch(&batch, end, 1, sizeof(void *), false); |
||||
|
end += getpagesize()); |
||||
|
|
||||
|
*nump = 0; |
||||
|
first_magic = *(char *)&magic; |
||||
|
for (tag = memchr(start, first_magic, end - start); |
||||
|
tag; |
||||
|
tag = memchr(tag+1, first_magic, end - (tag + 1))) { |
||||
|
void *adata[4]; |
||||
|
|
||||
|
/* We can read 4 void *'s here? */ |
||||
|
if (tag + sizeof(adata) > end) |
||||
|
continue; |
||||
|
|
||||
|
memcpy(adata, tag, sizeof(adata)); |
||||
|
|
||||
|
/* False match? */ |
||||
|
if (adata[0] != (void *)AUTODATA_MAGIC || adata[1] != tag) |
||||
|
continue; |
||||
|
|
||||
|
/* OK, check name. */ |
||||
|
if (!ptr_valid_batch_string(&batch, adata[3]) |
||||
|
|| strcmp(name, adata[3]) != 0) |
||||
|
continue; |
||||
|
|
||||
|
if (!ptr_valid_batch_read(&batch, (char *)adata[2])) |
||||
|
continue; |
||||
|
|
||||
|
table = realloc(table, sizeof(void *) * (*nump + 1)); |
||||
|
if (!table) |
||||
|
break; |
||||
|
table[*nump] = adata[2]; |
||||
|
(*nump)++; |
||||
|
} |
||||
|
ptr_valid_batch_end(&batch); |
||||
|
return table; |
||||
|
} |
||||
|
|
||||
|
void autodata_free(void *table) |
||||
|
{ |
||||
|
free(table); |
||||
|
} |
||||
|
#endif |
@ -0,0 +1,109 @@ |
|||||
|
// Licensed under BSD-MIT: See LICENSE.
|
||||
|
#ifndef CCAN_AUTODATA_H |
||||
|
#define CCAN_AUTODATA_H |
||||
|
#include "config.h" |
||||
|
#include <ccan/compiler/compiler.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#if HAVE_SECTION_START_STOP |
||||
|
|
||||
|
/**
|
||||
|
* AUTODATA_TYPE - declare the type for a given autodata name. |
||||
|
* @name: the name for this set of autodata |
||||
|
* @type: the type this autodata points to |
||||
|
* |
||||
|
* This macro is usually placed in a header: it must preceed any |
||||
|
* autodata functions in the file. |
||||
|
* |
||||
|
* Example: |
||||
|
* #include <ccan/autodata/autodata.h> |
||||
|
* |
||||
|
* // My set of char pointers.
|
||||
|
* AUTODATA_TYPE(names, char); |
||||
|
*/ |
||||
|
#define AUTODATA_TYPE(name, type) \ |
||||
|
typedef type autodata_##name##_; \ |
||||
|
extern type *__start_xautodata_##name[], *__stop_xautodata_##name[] |
||||
|
|
||||
|
/**
|
||||
|
* AUTODATA - add a pointer to this autodata set |
||||
|
* @name: the name of the set of autodata |
||||
|
* @ptr: the compile-time-known pointer |
||||
|
* |
||||
|
* This embeds @ptr into the binary, with the tag corresponding to |
||||
|
* @name (which must look like a valid identifier, no punctuation!). |
||||
|
* The type of @ptr must match that given by AUTODATA_TYPE. It is |
||||
|
* usually a file-level declaration. |
||||
|
* |
||||
|
* Example: |
||||
|
* // Put two char pointers into the names AUTODATA set.
|
||||
|
* AUTODATA(names, "Arabella"); |
||||
|
* AUTODATA(names, "Alex"); |
||||
|
*/ |
||||
|
#define AUTODATA(name, ptr) \ |
||||
|
static const autodata_##name##_ *NEEDED \ |
||||
|
__attribute__((section("xautodata_" #name))) \ |
||||
|
AUTODATA_VAR_(name, __LINE__) = (ptr); |
||||
|
|
||||
|
/**
|
||||
|
* autodata_get - get an autodata set |
||||
|
* @name: the name of the set of autodata |
||||
|
* @nump: the number of items in the set. |
||||
|
* |
||||
|
* This extract the embedded pointers matching @name. It may fail |
||||
|
* if malloc() fails, or if there is no AUTODATA at all. |
||||
|
* |
||||
|
* The return will be a pointer to an array of @type pointers (from |
||||
|
* AUTODATA_TYPE). |
||||
|
* |
||||
|
* Example: |
||||
|
* static void print_embedded_names(void) |
||||
|
* { |
||||
|
* unsigned int i; |
||||
|
* size_t num; |
||||
|
* char **n = autodata_get(names, &num); |
||||
|
* |
||||
|
* for (i = 0; i < num; i++) |
||||
|
* printf("%s\n", n[i]); |
||||
|
* } |
||||
|
*/ |
||||
|
#define autodata_get(name, nump) \ |
||||
|
((autodata_##name##_ **) \ |
||||
|
autodata_get_section(__start_xautodata_##name, \ |
||||
|
__stop_xautodata_##name, (nump))) |
||||
|
#endif /* HAVE_SECTION_START_STOP */ |
||||
|
|
||||
|
/**
|
||||
|
* autodata_free - free the table returned by autodata_get() |
||||
|
* @p: the table. |
||||
|
*/ |
||||
|
void autodata_free(void *p); |
||||
|
|
||||
|
/* Internal functions. */ |
||||
|
#define AUTODATA_VAR__(name, line) autodata_##name##_##line |
||||
|
#define AUTODATA_VAR_(name, line) AUTODATA_VAR__(name, line) |
||||
|
|
||||
|
#if HAVE_SECTION_START_STOP |
||||
|
void *autodata_get_section(void *start, void *stop, size_t *nump); |
||||
|
#else |
||||
|
#define AUTODATA_TYPE(name, type) \ |
||||
|
typedef type autodata_##name##_; \ |
||||
|
static const void *autodata_##name##_ex = &autodata_##name##_ex |
||||
|
|
||||
|
#define AUTODATA_MAGIC ((long)0xFEEDA10DA7AF00D5ULL) |
||||
|
#define AUTODATA(name, ptr) \ |
||||
|
static const autodata_##name##_ *NEEDED \ |
||||
|
AUTODATA_VAR_(name, __LINE__)[4] = \ |
||||
|
{ (void *)AUTODATA_MAGIC, \ |
||||
|
(void *)&AUTODATA_VAR_(name, __LINE__), \ |
||||
|
(ptr), \ |
||||
|
(void *)#name } |
||||
|
|
||||
|
#define autodata_get(name, nump) \ |
||||
|
((autodata_##name##_ **) \ |
||||
|
autodata_make_table(&autodata_##name##_ex, #name, (nump))) |
||||
|
|
||||
|
void *autodata_make_table(const void *example, const char *name, size_t *nump); |
||||
|
#endif |
||||
|
|
||||
|
#endif /* CCAN_AUTODATA_H */ |
@ -0,0 +1,6 @@ |
|||||
|
/* Check that linking together works. */ |
||||
|
#include <ccan/autodata/autodata.h> |
||||
|
|
||||
|
AUTODATA_TYPE(autostrings, char); |
||||
|
|
||||
|
AUTODATA(autostrings, "helper"); |
@ -0,0 +1,71 @@ |
|||||
|
#include <ccan/autodata/autodata.h> |
||||
|
/* Include the C files directly. */ |
||||
|
#include <ccan/autodata/autodata.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
AUTODATA_TYPE(autostrings, char); |
||||
|
|
||||
|
AUTODATA(autostrings, "genuine"); |
||||
|
|
||||
|
#if !HAVE_SECTION_START_STOP |
||||
|
/* These are all fake, to test the various failure paths. */ |
||||
|
/* Hopefully fake_alpha or fake_omega will test run-past-end. */ |
||||
|
static const void *NEEDED fake_alpha[] = { (void *)AUTODATA_MAGIC }; |
||||
|
|
||||
|
/* Wrong magic in the middle. */ |
||||
|
static const void *NEEDED fake1[] = { (void *)(AUTODATA_MAGIC ^ 0x10000), |
||||
|
(void *)&fake1, |
||||
|
"fake1", |
||||
|
(void *)"autostrings" }; |
||||
|
|
||||
|
/* Wrong self pointer. */ |
||||
|
static const void *NEEDED fake2[] = { (void *)AUTODATA_MAGIC, |
||||
|
(void *)&fake1, |
||||
|
"fake2", |
||||
|
(void *)"autostrings" }; |
||||
|
|
||||
|
/* Wrong name. */ |
||||
|
static const void *NEEDED fake3[] = { (void *)AUTODATA_MAGIC, |
||||
|
(void *)&fake3, |
||||
|
"fake3", |
||||
|
(void *)"autostrings2" }; |
||||
|
|
||||
|
/* Invalid self-pointer. */ |
||||
|
static const void *NEEDED fake4[] = { (void *)AUTODATA_MAGIC, |
||||
|
(void *)1UL, |
||||
|
"fake4", |
||||
|
(void *)"autostrings" }; |
||||
|
|
||||
|
/* Invalid name pointer */ |
||||
|
static const void *NEEDED fake5[] = { (void *)AUTODATA_MAGIC, |
||||
|
(void *)&fake5, |
||||
|
"fake5", |
||||
|
(void *)1UL }; |
||||
|
|
||||
|
/* Invalid contents pointer */ |
||||
|
static const void *NEEDED fake6[] = { (void *)AUTODATA_MAGIC, |
||||
|
(void *)&fake6, |
||||
|
(char *)1UL, |
||||
|
(void *)"autostrings" }; |
||||
|
|
||||
|
static const void *NEEDED fake_omega[] = { (void *)AUTODATA_MAGIC }; |
||||
|
#endif |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
char **table; |
||||
|
size_t num; |
||||
|
|
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(2); |
||||
|
|
||||
|
table = autodata_get(autostrings, &num); |
||||
|
ok1(num == 2); |
||||
|
ok1((!strcmp(table[0], "genuine") && !strcmp(table[1], "helper")) |
||||
|
|| (!strcmp(table[1], "genuine") && !strcmp(table[0], "helper"))); |
||||
|
|
||||
|
autodata_free(table); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
#include <ccan/autodata/autodata.h> |
||||
|
/* Include the C files directly. */ |
||||
|
#include <ccan/autodata/autodata.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
AUTODATA_TYPE(autostrings, char); |
||||
|
|
||||
|
AUTODATA(autostrings, "hello"); |
||||
|
AUTODATA(autostrings, "world"); |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
char **table; |
||||
|
size_t num; |
||||
|
int i, hello = -1, world = -1, helper = -1; |
||||
|
|
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(4); |
||||
|
|
||||
|
table = autodata_get(autostrings, &num); |
||||
|
ok1(num == 3); |
||||
|
|
||||
|
for (i = 0; i < num; i++) { |
||||
|
if (strcmp(table[i], "hello") == 0) |
||||
|
hello = i; |
||||
|
else if (strcmp(table[i], "world") == 0) |
||||
|
world = i; |
||||
|
else if (strcmp(table[i], "helper") == 0) |
||||
|
helper = i; |
||||
|
else |
||||
|
fail("Unknown entry %s", table[i]); |
||||
|
} |
||||
|
ok1(hello != -1); |
||||
|
ok1(world != -1); |
||||
|
ok1(helper != -1); |
||||
|
|
||||
|
autodata_free(table); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
../../licenses/CC0 |
@ -0,0 +1,34 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* breakpoint - break if the program is run under gdb. |
||||
|
* |
||||
|
* This code allows you to insert breakpoints within a program. These will |
||||
|
* do nothing unless your program is run under GDB. |
||||
|
* |
||||
|
* License: CC0 (Public domain) |
||||
|
* |
||||
|
* Example: |
||||
|
* #include <ccan/breakpoint/breakpoint.h> |
||||
|
* |
||||
|
* int main(void) |
||||
|
* { |
||||
|
* breakpoint(); |
||||
|
* return 0; |
||||
|
* } |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
printf("ccan/compiler\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
/* CC0 (Public domain) - see LICENSE file for details
|
||||
|
* |
||||
|
* Idea for implementation thanks to stackoverflow.com: |
||||
|
* http://stackoverflow.com/questions/3596781/detect-if-gdb-is-running
|
||||
|
*/ |
||||
|
#include <ccan/breakpoint/breakpoint.h> |
||||
|
|
||||
|
bool breakpoint_initialized; |
||||
|
bool breakpoint_under_debug; |
||||
|
|
||||
|
/* This doesn't get called if we're under GDB. */ |
||||
|
static void trap(int signum) |
||||
|
{ |
||||
|
breakpoint_initialized = true; |
||||
|
} |
||||
|
|
||||
|
void breakpoint_init(void) |
||||
|
{ |
||||
|
struct sigaction old, new; |
||||
|
|
||||
|
new.sa_handler = trap; |
||||
|
new.sa_flags = 0; |
||||
|
sigemptyset(&new.sa_mask); |
||||
|
sigaction(SIGTRAP, &new, &old); |
||||
|
kill(getpid(), SIGTRAP); |
||||
|
sigaction(SIGTRAP, &old, NULL); |
||||
|
|
||||
|
if (!breakpoint_initialized) { |
||||
|
breakpoint_initialized = true; |
||||
|
breakpoint_under_debug = true; |
||||
|
} |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
/* CC0 (Public domain) - see LICENSE file for details */ |
||||
|
#ifndef CCAN_BREAKPOINT_H |
||||
|
#define CCAN_BREAKPOINT_H |
||||
|
#include <ccan/compiler/compiler.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <unistd.h> |
||||
|
#include <signal.h> |
||||
|
#include <stdbool.h> |
||||
|
|
||||
|
void breakpoint_init(void) COLD; |
||||
|
extern bool breakpoint_initialized; |
||||
|
extern bool breakpoint_under_debug; |
||||
|
|
||||
|
/**
|
||||
|
* breakpoint - stop if running under the debugger. |
||||
|
*/ |
||||
|
static inline void breakpoint(void) |
||||
|
{ |
||||
|
if (!breakpoint_initialized) |
||||
|
breakpoint_init(); |
||||
|
if (breakpoint_under_debug) |
||||
|
kill(getpid(), SIGTRAP); |
||||
|
} |
||||
|
#endif /* CCAN_BREAKPOINT_H */ |
@ -0,0 +1,17 @@ |
|||||
|
#include <ccan/breakpoint/breakpoint.h> |
||||
|
#include <ccan/breakpoint/breakpoint.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(2); |
||||
|
|
||||
|
breakpoint(); |
||||
|
|
||||
|
ok1(breakpoint_initialized); |
||||
|
ok1(!breakpoint_under_debug); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
../../../licenses/BSD-MIT |
@ -0,0 +1,30 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* crypto/hkdf_sha256 - RFC5869 Hardened Key Derivation Functions using SHA256 |
||||
|
* |
||||
|
* This code implements the hkdf described in RFC5869. |
||||
|
* |
||||
|
* License: BSD-MIT |
||||
|
* Maintainer: Rusty Russell <rusty@rustcorp.com.au> |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
printf("ccan/crypto/hmac_sha256\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
if (strcmp(argv[1], "testdepends") == 0) { |
||||
|
printf("ccan/str/hex\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
/* MIT (BSD) license - see LICENSE file for details */ |
||||
|
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h> |
||||
|
#include <ccan/crypto/hmac_sha256/hmac_sha256.h> |
||||
|
#include <assert.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
void hkdf_sha256(void *okm, size_t okm_size, |
||||
|
const void *s, size_t ssize, |
||||
|
const void *k, size_t ksize, |
||||
|
const void *info, size_t isize) |
||||
|
{ |
||||
|
struct hmac_sha256 prk, t; |
||||
|
struct hmac_sha256_ctx ctx; |
||||
|
unsigned char c; |
||||
|
|
||||
|
assert(okm_size < 255 * sizeof(t)); |
||||
|
|
||||
|
/* RFC 5869:
|
||||
|
* |
||||
|
* 2.2. Step 1: Extract |
||||
|
* |
||||
|
* HKDF-Extract(salt, IKM) -> PRK |
||||
|
* |
||||
|
* Options: |
||||
|
* Hash a hash function; HashLen denotes the length of the |
||||
|
* hash function output in octets |
||||
|
* |
||||
|
* Inputs: |
||||
|
* salt optional salt value (a non-secret random value); |
||||
|
* if not provided, it is set to a string of HashLen zeros. |
||||
|
* IKM input keying material |
||||
|
* |
||||
|
* Output: |
||||
|
* PRK a pseudorandom key (of HashLen octets) |
||||
|
* |
||||
|
* The output PRK is calculated as follows: |
||||
|
* |
||||
|
* PRK = HMAC-Hash(salt, IKM) |
||||
|
*/ |
||||
|
hmac_sha256(&prk, s, ssize, k, ksize); |
||||
|
|
||||
|
/*
|
||||
|
* 2.3. Step 2: Expand |
||||
|
* |
||||
|
* HKDF-Expand(PRK, info, L) -> OKM |
||||
|
* |
||||
|
* Options: |
||||
|
* Hash a hash function; HashLen denotes the length of the |
||||
|
* hash function output in octets |
||||
|
* |
||||
|
* Inputs: |
||||
|
* PRK a pseudorandom key of at least HashLen octets |
||||
|
* (usually, the output from the extract step) |
||||
|
* info optional context and application specific information |
||||
|
* (can be a zero-length string) |
||||
|
* L length of output keying material in octets |
||||
|
* (<= 255*HashLen) |
||||
|
* |
||||
|
* Output: |
||||
|
* OKM output keying material (of L octets) |
||||
|
* |
||||
|
* The output OKM is calculated as follows: |
||||
|
* |
||||
|
* N = ceil(L/HashLen) |
||||
|
* T = T(1) | T(2) | T(3) | ... | T(N) |
||||
|
* OKM = first L octets of T |
||||
|
* |
||||
|
* where: |
||||
|
* T(0) = empty string (zero length) |
||||
|
* T(1) = HMAC-Hash(PRK, T(0) | info | 0x01) |
||||
|
* T(2) = HMAC-Hash(PRK, T(1) | info | 0x02) |
||||
|
* T(3) = HMAC-Hash(PRK, T(2) | info | 0x03) |
||||
|
* ... |
||||
|
* |
||||
|
* (where the constant concatenated to the end of each T(n) is a |
||||
|
* single octet.) |
||||
|
*/ |
||||
|
c = 1; |
||||
|
hmac_sha256_init(&ctx, &prk, sizeof(prk)); |
||||
|
hmac_sha256_update(&ctx, info, isize); |
||||
|
hmac_sha256_update(&ctx, &c, 1); |
||||
|
hmac_sha256_done(&ctx, &t); |
||||
|
|
||||
|
while (okm_size > sizeof(t)) { |
||||
|
memcpy(okm, &t, sizeof(t)); |
||||
|
okm = (char *)okm + sizeof(t); |
||||
|
okm_size -= sizeof(t); |
||||
|
|
||||
|
c++; |
||||
|
hmac_sha256_init(&ctx, &prk, sizeof(prk)); |
||||
|
hmac_sha256_update(&ctx, &t, sizeof(t)); |
||||
|
hmac_sha256_update(&ctx, info, isize); |
||||
|
hmac_sha256_update(&ctx, &c, 1); |
||||
|
hmac_sha256_done(&ctx, &t); |
||||
|
} |
||||
|
memcpy(okm, &t, okm_size); |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
#ifndef CCAN_CRYPTO_HKDF_SHA256_H |
||||
|
#define CCAN_CRYPTO_HKDF_SHA256_H |
||||
|
/* BSD-MIT - see LICENSE file for details */ |
||||
|
#include "config.h" |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
/**
|
||||
|
* hkdf_sha256 - generate a derived key |
||||
|
* @okm: where to output the key |
||||
|
* @okm_size: the number of bytes pointed to by @okm (must be less than 255*32) |
||||
|
* @s: salt |
||||
|
* @ssize: the number of bytes pointed to by @s |
||||
|
* @k: pointer to input key |
||||
|
* @ksize: the number of bytes pointed to by @k |
||||
|
* @info: pointer to info |
||||
|
* @isize: the number of bytes pointed to by @info |
||||
|
*/ |
||||
|
void hkdf_sha256(void *okm, size_t okm_size, |
||||
|
const void *s, size_t ssize, |
||||
|
const void *k, size_t ksize, |
||||
|
const void *info, size_t isize); |
||||
|
#endif /* CCAN_CRYPTO_HKDF_SHA256_H */ |
@ -0,0 +1,101 @@ |
|||||
|
/* From RFC5869 Appendix A
|
||||
|
* |
||||
|
* https://tools.ietf.org/html/rfc5869
|
||||
|
*/ |
||||
|
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
#include <ccan/str/hex/hex.h> |
||||
|
#include <string.h> |
||||
|
#include <assert.h> |
||||
|
|
||||
|
struct test { |
||||
|
const char *ikm, *salt, *info, *okm; |
||||
|
}; |
||||
|
|
||||
|
static struct test tests[] = { { |
||||
|
/* Test Case 1
|
||||
|
Basic test case with SHA-256 |
||||
|
*/ |
||||
|
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", /* (22 octets) */ |
||||
|
"000102030405060708090a0b0c", /* (13 octets) */ |
||||
|
"f0f1f2f3f4f5f6f7f8f9", /* (10 octets) */ |
||||
|
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", /* (42 octets) */ |
||||
|
}, |
||||
|
{ |
||||
|
/* Test Case 2
|
||||
|
* |
||||
|
* Test with SHA-256 and longer inputs/outputs */ |
||||
|
"000102030405060708090a0b0c0d0e0f" |
||||
|
"101112131415161718191a1b1c1d1e1f" |
||||
|
"202122232425262728292a2b2c2d2e2f" |
||||
|
"303132333435363738393a3b3c3d3e3f" |
||||
|
"404142434445464748494a4b4c4d4e4f", /* (80 octets) */ |
||||
|
"606162636465666768696a6b6c6d6e6f" |
||||
|
"707172737475767778797a7b7c7d7e7f" |
||||
|
"808182838485868788898a8b8c8d8e8f" |
||||
|
"909192939495969798999a9b9c9d9e9f" |
||||
|
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", /* (80 octets )*/ |
||||
|
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" |
||||
|
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" |
||||
|
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" |
||||
|
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef" |
||||
|
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", /* (80 octets) */ |
||||
|
"b11e398dc80327a1c8e7f78c596a4934" |
||||
|
"4f012eda2d4efad8a050cc4c19afa97c" |
||||
|
"59045a99cac7827271cb41c65e590e09" |
||||
|
"da3275600c2f09b8367793a9aca3db71" |
||||
|
"cc30c58179ec3e87c14c01d5c1f3434f" |
||||
|
"1d87" /* (82 octets) */ |
||||
|
}, |
||||
|
{ |
||||
|
/* Test Case 3
|
||||
|
* |
||||
|
* Test with SHA-256 and zero-length salt/info |
||||
|
*/ |
||||
|
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", /* (22 octets) */ |
||||
|
"", /* (0 octets) */ |
||||
|
"", /* (0 octets) */ |
||||
|
"8da4e775a563c18f715f802a063c5a31" |
||||
|
"b8a11f5c5ee1879ec3454e5f3c738d2d" |
||||
|
"9d201395faa4b61a96c8" /* (42 octets) */ |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
static void *fromhex(const char *str, size_t *len) |
||||
|
{ |
||||
|
void *p; |
||||
|
|
||||
|
*len = hex_data_size(strlen(str)); |
||||
|
p = malloc(*len); |
||||
|
if (!hex_decode(str, strlen(str), p, *len)) |
||||
|
abort(); |
||||
|
return p; |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
size_t i; |
||||
|
|
||||
|
plan_tests(sizeof(tests) / sizeof(tests[0])); |
||||
|
|
||||
|
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { |
||||
|
size_t ksize, ssize, isize, okmsize; |
||||
|
void *k, *s, *info, *expect, *okm; |
||||
|
|
||||
|
k = fromhex(tests[i].ikm, &ksize); |
||||
|
s = fromhex(tests[i].salt, &ssize); |
||||
|
info = fromhex(tests[i].info, &isize); |
||||
|
expect = fromhex(tests[i].okm, &okmsize); |
||||
|
okm = malloc(okmsize); |
||||
|
hkdf_sha256(okm, okmsize, s, ssize, k, ksize, info, isize); |
||||
|
ok1(memcmp(okm, expect, okmsize) == 0); |
||||
|
|
||||
|
free(k); |
||||
|
free(s); |
||||
|
free(info); |
||||
|
free(expect); |
||||
|
free(okm); |
||||
|
} |
||||
|
|
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
../../../licenses/BSD-MIT |
@ -0,0 +1,52 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* crypto/hmac_sha256 - RFC2104 HMAC using SHA256. |
||||
|
* |
||||
|
* This code implements RFC2104, which is a fairly standard HMAC. |
||||
|
* |
||||
|
* License: BSD-MIT |
||||
|
* Maintainer: Rusty Russell <rusty@rustcorp.com.au> |
||||
|
* |
||||
|
* Example: |
||||
|
* #include <ccan/crypto/hmac_sha256/hmac_sha256.h> |
||||
|
* #include <err.h> |
||||
|
* #include <stdio.h> |
||||
|
* #include <string.h> |
||||
|
* |
||||
|
* // Simple demonstration: idential strings will have the same hash, but |
||||
|
* // two different strings will not. |
||||
|
* int main(int argc, char *argv[]) |
||||
|
* { |
||||
|
* struct hmac_sha256 hash1, hash2; |
||||
|
* |
||||
|
* if (argc != 3) |
||||
|
* errx(1, "Usage: %s <string1> <string2>", argv[0]); |
||||
|
* |
||||
|
* hmac_sha256(&hash1, "key", 3, argv[1], strlen(argv[1])); |
||||
|
* hmac_sha256(&hash2, "key", 3, argv[2], strlen(argv[2])); |
||||
|
* printf("Hash is %s\n", memcmp(&hash1, &hash2, sizeof(hash1)) |
||||
|
* ? "different" : "same"); |
||||
|
* return 0; |
||||
|
* } |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
printf("ccan/crypto/sha256\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
if (strcmp(argv[1], "testdepends") == 0) { |
||||
|
printf("ccan/str/hex\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,160 @@ |
|||||
|
/* MIT (BSD) license - see LICENSE file for details */ |
||||
|
#include <ccan/crypto/hmac_sha256/hmac_sha256.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#define IPAD 0x3636363636363636ULL |
||||
|
#define OPAD 0x5C5C5C5C5C5C5C5CULL |
||||
|
|
||||
|
#define BLOCK_U64S (HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)) |
||||
|
|
||||
|
static inline void xor_block(uint64_t block[BLOCK_U64S], uint64_t pad) |
||||
|
{ |
||||
|
size_t i; |
||||
|
|
||||
|
for (i = 0; i < BLOCK_U64S; i++) |
||||
|
block[i] ^= pad; |
||||
|
} |
||||
|
|
||||
|
void hmac_sha256_init(struct hmac_sha256_ctx *ctx, |
||||
|
const void *k, size_t ksize) |
||||
|
{ |
||||
|
struct sha256 hashed_key; |
||||
|
/* We use k_opad as k_ipad temporarily. */ |
||||
|
uint64_t *k_ipad = ctx->k_opad; |
||||
|
|
||||
|
/* (keys longer than B bytes are first hashed using H) */ |
||||
|
if (ksize > HMAC_SHA256_BLOCKSIZE) { |
||||
|
sha256(&hashed_key, k, ksize); |
||||
|
k = &hashed_key; |
||||
|
ksize = sizeof(hashed_key); |
||||
|
} |
||||
|
|
||||
|
/* From RFC2104:
|
||||
|
* |
||||
|
* (1) append zeros to the end of K to create a B byte string |
||||
|
* (e.g., if K is of length 20 bytes and B=64, then K will be |
||||
|
* appended with 44 zero bytes 0x00) |
||||
|
*/ |
||||
|
memcpy(k_ipad, k, ksize); |
||||
|
memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize); |
||||
|
|
||||
|
/*
|
||||
|
* (2) XOR (bitwise exclusive-OR) the B byte string computed |
||||
|
* in step (1) with ipad |
||||
|
*/ |
||||
|
xor_block(k_ipad, IPAD); |
||||
|
|
||||
|
/*
|
||||
|
* We start (4) here, appending text later: |
||||
|
* |
||||
|
* (3) append the stream of data 'text' to the B byte string resulting |
||||
|
* from step (2) |
||||
|
* (4) apply H to the stream generated in step (3) |
||||
|
*/ |
||||
|
sha256_init(&ctx->sha); |
||||
|
sha256_update(&ctx->sha, k_ipad, HMAC_SHA256_BLOCKSIZE); |
||||
|
|
||||
|
/*
|
||||
|
* (5) XOR (bitwise exclusive-OR) the B byte string computed in |
||||
|
* step (1) with opad |
||||
|
*/ |
||||
|
xor_block(ctx->k_opad, IPAD^OPAD); |
||||
|
} |
||||
|
|
||||
|
void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size) |
||||
|
{ |
||||
|
/* This is the appending-text part of this:
|
||||
|
* |
||||
|
* (3) append the stream of data 'text' to the B byte string resulting |
||||
|
* from step (2) |
||||
|
* (4) apply H to the stream generated in step (3) |
||||
|
*/ |
||||
|
sha256_update(&ctx->sha, p, size); |
||||
|
} |
||||
|
|
||||
|
void hmac_sha256_done(struct hmac_sha256_ctx *ctx, |
||||
|
struct hmac_sha256 *hmac) |
||||
|
{ |
||||
|
/* (4) apply H to the stream generated in step (3) */ |
||||
|
sha256_done(&ctx->sha, &hmac->sha); |
||||
|
|
||||
|
/*
|
||||
|
* (6) append the H result from step (4) to the B byte string |
||||
|
* resulting from step (5) |
||||
|
* (7) apply H to the stream generated in step (6) and output |
||||
|
* the result |
||||
|
*/ |
||||
|
sha256_init(&ctx->sha); |
||||
|
sha256_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad)); |
||||
|
sha256_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha)); |
||||
|
sha256_done(&ctx->sha, &hmac->sha); |
||||
|
} |
||||
|
|
||||
|
#if 1 |
||||
|
void hmac_sha256(struct hmac_sha256 *hmac, |
||||
|
const void *k, size_t ksize, |
||||
|
const void *d, size_t dsize) |
||||
|
{ |
||||
|
struct hmac_sha256_ctx ctx; |
||||
|
|
||||
|
hmac_sha256_init(&ctx, k, ksize); |
||||
|
hmac_sha256_update(&ctx, d, dsize); |
||||
|
hmac_sha256_done(&ctx, hmac); |
||||
|
} |
||||
|
#else |
||||
|
/* Direct mapping from MD5 example in RFC2104 */ |
||||
|
void hmac_sha256(struct hmac_sha256 *hmac, |
||||
|
const void *key, size_t key_len, |
||||
|
const void *text, size_t text_len) |
||||
|
{ |
||||
|
struct sha256_ctx context; |
||||
|
unsigned char k_ipad[65]; /* inner padding -
|
||||
|
* key XORd with ipad |
||||
|
*/ |
||||
|
unsigned char k_opad[65]; /* outer padding -
|
||||
|
* key XORd with opad |
||||
|
*//* start out by storing key in pads */ |
||||
|
unsigned char tk[32]; |
||||
|
int i; |
||||
|
|
||||
|
/* if key is longer than 64 bytes reset it to key=MD5(key) */ |
||||
|
if (key_len > 64) { |
||||
|
|
||||
|
struct sha256_ctx tctx; |
||||
|
|
||||
|
sha256_init(&tctx); |
||||
|
sha256_update(&tctx, key, key_len); |
||||
|
sha256_done(&tctx, tk); |
||||
|
|
||||
|
key = tk; |
||||
|
key_len = 32; |
||||
|
} |
||||
|
bzero( k_ipad, sizeof k_ipad); |
||||
|
bzero( k_opad, sizeof k_opad); |
||||
|
bcopy( key, k_ipad, key_len); |
||||
|
bcopy( key, k_opad, key_len); |
||||
|
|
||||
|
/* XOR key with ipad and opad values */ |
||||
|
for (i=0; i<64; i++) { |
||||
|
k_ipad[i] ^= 0x36; |
||||
|
k_opad[i] ^= 0x5c; |
||||
|
} |
||||
|
/*
|
||||
|
* perform inner MD5 |
||||
|
*/ |
||||
|
sha256_init(&context); /* init context for 1st
|
||||
|
* pass */ |
||||
|
sha256_update(&context, k_ipad, 64); /* start with inner pad */ |
||||
|
sha256_update(&context, text, text_len); /* then text of datagram */ |
||||
|
sha256_done(&context, &hmac->sha); /* finish up 1st pass */ |
||||
|
/*
|
||||
|
* perform outer MD5 |
||||
|
*/ |
||||
|
sha256_init(&context); /* init context for 2nd
|
||||
|
* pass */ |
||||
|
sha256_update(&context, k_opad, 64); /* start with outer pad */ |
||||
|
sha256_update(&context, &hmac->sha, 32); /* then results of 1st
|
||||
|
* hash */ |
||||
|
sha256_done(&context, &hmac->sha); /* finish up 2nd pass */ |
||||
|
} |
||||
|
#endif |
@ -0,0 +1,86 @@ |
|||||
|
#ifndef CCAN_CRYPTO_HMAC_SHA256_H |
||||
|
#define CCAN_CRYPTO_HMAC_SHA256_H |
||||
|
/* BSD-MIT - see LICENSE file for details */ |
||||
|
#include "config.h" |
||||
|
#include <stdint.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <ccan/crypto/sha256/sha256.h> |
||||
|
|
||||
|
/* Number of bytes per block. */ |
||||
|
#define HMAC_SHA256_BLOCKSIZE 64 |
||||
|
|
||||
|
/**
|
||||
|
* struct hmac_sha256 - structure representing a completed HMAC. |
||||
|
*/ |
||||
|
struct hmac_sha256 { |
||||
|
struct sha256 sha; |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* hmac_sha256 - return hmac of an object with a key. |
||||
|
* @hmac: the hmac to fill in |
||||
|
* @k: pointer to the key, |
||||
|
* @ksize: the number of bytes pointed to by @k |
||||
|
* @d: pointer to memory, |
||||
|
* @dsize: the number of bytes pointed to by @d |
||||
|
*/ |
||||
|
void hmac_sha256(struct hmac_sha256 *hmac, |
||||
|
const void *k, size_t ksize, |
||||
|
const void *d, size_t dsize); |
||||
|
|
||||
|
/**
|
||||
|
* struct hmac_sha256_ctx - structure to store running context for hmac_sha256 |
||||
|
*/ |
||||
|
struct hmac_sha256_ctx { |
||||
|
struct sha256_ctx sha; |
||||
|
uint64_t k_opad[HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)]; |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* hmac_sha256_init - initialize an HMAC_SHA256 context. |
||||
|
* @ctx: the hmac_sha256_ctx to initialize |
||||
|
* @k: pointer to the key, |
||||
|
* @ksize: the number of bytes pointed to by @k |
||||
|
* |
||||
|
* This must be called before hmac_sha256_update or hmac_sha256_done. |
||||
|
* |
||||
|
* If it was already initialized, this forgets anything which was |
||||
|
* hashed before. |
||||
|
* |
||||
|
* Example: |
||||
|
* static void hmac_all(const char *key, |
||||
|
* const char **arr, struct hmac_sha256 *hash) |
||||
|
* { |
||||
|
* size_t i; |
||||
|
* struct hmac_sha256_ctx ctx; |
||||
|
* |
||||
|
* hmac_sha256_init(&ctx, key, strlen(key)); |
||||
|
* for (i = 0; arr[i]; i++) |
||||
|
* hmac_sha256_update(&ctx, arr[i], strlen(arr[i])); |
||||
|
* hmac_sha256_done(&ctx, hash); |
||||
|
* } |
||||
|
*/ |
||||
|
void hmac_sha256_init(struct hmac_sha256_ctx *ctx, |
||||
|
const void *k, size_t ksize); |
||||
|
|
||||
|
/**
|
||||
|
* hmac_sha256_update - include some memory in the hash. |
||||
|
* @ctx: the hmac_sha256_ctx to use |
||||
|
* @p: pointer to memory, |
||||
|
* @size: the number of bytes pointed to by @p |
||||
|
* |
||||
|
* You can call this multiple times to hash more data, before calling |
||||
|
* hmac_sha256_done(). |
||||
|
*/ |
||||
|
void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size); |
||||
|
|
||||
|
/**
|
||||
|
* hmac_sha256_done - finish HMAC_SHA256 and return the hash |
||||
|
* @ctx: the hmac_sha256_ctx to complete |
||||
|
* @res: the hash to return. |
||||
|
* |
||||
|
* Note that @ctx is *destroyed* by this, and must be reinitialized. |
||||
|
* To avoid that, pass a copy instead. |
||||
|
*/ |
||||
|
void hmac_sha256_done(struct hmac_sha256_ctx *hmac_sha256, struct hmac_sha256 *res); |
||||
|
#endif /* CCAN_CRYPTO_HMAC_SHA256_H */ |
@ -0,0 +1,159 @@ |
|||||
|
/* From RFC4231 "Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256,
|
||||
|
* HMAC-SHA-384, and HMAC-SHA-512" |
||||
|
* |
||||
|
* https://tools.ietf.org/html/rfc4231
|
||||
|
*/ |
||||
|
#include <ccan/crypto/hmac_sha256/hmac_sha256.h> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
#include <ccan/str/hex/hex.h> |
||||
|
#include <string.h> |
||||
|
#include <assert.h> |
||||
|
|
||||
|
struct test { |
||||
|
const char *key, *data, *hmac; |
||||
|
}; |
||||
|
|
||||
|
static struct test tests[] = { { |
||||
|
/* Test Case 1 */ |
||||
|
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", /* (20 bytes) */ |
||||
|
"4869205468657265", /* ("Hi There") */ |
||||
|
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" |
||||
|
}, |
||||
|
/* Test Case 2:
|
||||
|
Test with a key shorter than the length of the HMAC output. */ |
||||
|
{ |
||||
|
"4a656665", /* ("Jefe") */ |
||||
|
/* ("what do ya want for nothing?") */ |
||||
|
"7768617420646f2079612077616e7420666f72206e6f7468696e673f", |
||||
|
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" |
||||
|
}, |
||||
|
{ |
||||
|
/* Test Case 3
|
||||
|
|
||||
|
Test with a combined length of key and data that is larger than 64 |
||||
|
bytes (= block-size of SHA-224 and SHA-256). |
||||
|
*/ |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", /* (20 bytes) */ |
||||
|
"dddddddddddddddddddddddddddddddd" |
||||
|
"dddddddddddddddddddddddddddddddd" |
||||
|
"dddddddddddddddddddddddddddddddd" |
||||
|
"dddd", /* (50 bytes) */ |
||||
|
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe" |
||||
|
}, |
||||
|
{ |
||||
|
/* Test Case 4
|
||||
|
|
||||
|
Test with a combined length of key and data that is larger than 64 |
||||
|
bytes (= block-size of SHA-224 and SHA-256). |
||||
|
*/ |
||||
|
"0102030405060708090a0b0c0d0e0f10111213141516171819", /* (25 bytes) */ |
||||
|
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" |
||||
|
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" |
||||
|
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" |
||||
|
"cdcd", /* (50 bytes) */ |
||||
|
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b" |
||||
|
}, |
||||
|
#if 0 |
||||
|
{ |
||||
|
/* Test Case 5
|
||||
|
|
||||
|
Test with a truncation of output to 128 bits. |
||||
|
*/ |
||||
|
"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", /* (20 bytes) */ |
||||
|
"546573742057697468205472756e636174696f6e", /* ("Test With Truncation") */ |
||||
|
"a3b6167473100ee06e0c796c2955552b" |
||||
|
}, |
||||
|
#endif |
||||
|
{ |
||||
|
/* Test Case 6
|
||||
|
|
||||
|
Test with a key larger than 128 bytes (= block-size of SHA-384 and |
||||
|
SHA-512). |
||||
|
*/ |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaa", /* (131 bytes) */ |
||||
|
"54657374205573696e67204c61726765" /* ("Test Using Large") */ |
||||
|
"72205468616e20426c6f636b2d53697a" /* ("r Than Block-Siz") */ |
||||
|
"65204b6579202d2048617368204b6579" /* ("e Key - Hash Key") */ |
||||
|
"204669727374", /* (" First") */ |
||||
|
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54" |
||||
|
}, |
||||
|
{ |
||||
|
/* Test Case 7
|
||||
|
|
||||
|
Test with a key and data that is larger than 128 bytes (= block-size |
||||
|
of SHA-384 and SHA-512). */ |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
||||
|
"aaaaaa", /* (131 bytes) */ |
||||
|
"54686973206973206120746573742075" /* ("This is a test u") */ |
||||
|
"73696e672061206c6172676572207468" /* ("sing a larger th") */ |
||||
|
"616e20626c6f636b2d73697a65206b65" /* ("an block-size ke") */ |
||||
|
"7920616e642061206c61726765722074" /* ("y and a larger t") */ |
||||
|
"68616e20626c6f636b2d73697a652064" /* ("han block-size d") */ |
||||
|
"6174612e20546865206b6579206e6565" /* ("ata. The key nee") */ |
||||
|
"647320746f2062652068617368656420" /* ("ds to be hashed ") */ |
||||
|
"6265666f7265206265696e6720757365" /* ("before being use") */ |
||||
|
"642062792074686520484d414320616c" /* ("d by the HMAC al") */ |
||||
|
"676f726974686d2e", /* ("gorithm.") */ |
||||
|
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
static void *fromhex(const char *str, size_t *len) |
||||
|
{ |
||||
|
void *p; |
||||
|
|
||||
|
*len = hex_data_size(strlen(str)); |
||||
|
p = malloc(*len); |
||||
|
if (!hex_decode(str, strlen(str), p, *len)) |
||||
|
abort(); |
||||
|
return p; |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
size_t i; |
||||
|
struct hmac_sha256 hmac; |
||||
|
|
||||
|
plan_tests(sizeof(tests) / sizeof(tests[0]) * 2); |
||||
|
|
||||
|
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { |
||||
|
size_t ksize, dsize, hmacsize; |
||||
|
void *k, *d, *expect; |
||||
|
struct hmac_sha256_ctx ctx; |
||||
|
|
||||
|
k = fromhex(tests[i].key, &ksize); |
||||
|
d = fromhex(tests[i].data, &dsize); |
||||
|
expect = fromhex(tests[i].hmac, &hmacsize); |
||||
|
assert(hmacsize == sizeof(hmac)); |
||||
|
hmac_sha256(&hmac, k, ksize, d, dsize); |
||||
|
ok1(memcmp(&hmac, expect, hmacsize) == 0); |
||||
|
|
||||
|
/* Now test partial API. */ |
||||
|
hmac_sha256_init(&ctx, k, ksize); |
||||
|
hmac_sha256_update(&ctx, d, dsize / 2); |
||||
|
hmac_sha256_update(&ctx, (char *)d + dsize/2, dsize - dsize/2); |
||||
|
hmac_sha256_done(&ctx, &hmac); |
||||
|
ok1(memcmp(&hmac, expect, hmacsize) == 0); |
||||
|
|
||||
|
free(k); |
||||
|
free(d); |
||||
|
free(expect); |
||||
|
} |
||||
|
|
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
#! /usr/bin/make
|
||||
|
|
||||
|
CCANDIR=../../../.. |
||||
|
CFLAGS=-Wall -Werror -O3 -I$(CCANDIR) -DSHACHAIN_BITS=48 |
||||
|
#CFLAGS=-Wall -Werror -g3 -I$(CCANDIR) -DSHACHAIN_BITS=48
|
||||
|
|
||||
|
# 48 bit index for shachain. This is what lightning uses.
|
||||
|
CCAN_OBJS:=ccan-str.o ccan-err.o ccan-hex.o ccan-shachain.o ccan-sha256.o ccan-rbuf.o |
||||
|
|
||||
|
all: shachain48 |
||||
|
|
||||
|
shachain48: shachain48.o $(CCAN_OBJS) |
||||
|
|
||||
|
shachain48.o: $(CCANDIR)/ccan/crypto/shachain/shachain.h \ |
||||
|
$(CCANDIR)/ccan/str/hex/hex.h \
|
||||
|
$(CCANDIR)/ccan/str/str.h \
|
||||
|
$(CCANDIR)/ccan/err/err.h \
|
||||
|
$(CCANDIR)/ccan/rbuf/rbuf.h |
||||
|
|
||||
|
shachain48.o $(CCAN_OBJS): $(CCANDIR)/config.h |
||||
|
|
||||
|
$(CCANDIR)/config.h: |
||||
|
$(MAKE) -C $(CCANDIR) config.h |
||||
|
|
||||
|
clean: |
||||
|
rm -f shachain *.o |
||||
|
|
||||
|
ccan-err.o: $(CCANDIR)/ccan/err/err.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-hex.o: $(CCANDIR)/ccan/str/hex/hex.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-str.o: $(CCANDIR)/ccan/str/str.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-shachain.o: $(CCANDIR)/ccan/crypto/shachain/shachain.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-sha256.o: $(CCANDIR)/ccan/crypto/sha256/sha256.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
||||
|
ccan-rbuf.o: $(CCANDIR)/ccan/rbuf/rbuf.c |
||||
|
$(CC) $(CFLAGS) -c -o $@ $< |
@ -0,0 +1,58 @@ |
|||||
|
#include <ccan/crypto/shachain/shachain.h> |
||||
|
#include <ccan/str/hex/hex.h> |
||||
|
#include <ccan/str/str.h> |
||||
|
#include <ccan/err/err.h> |
||||
|
#include <ccan/rbuf/rbuf.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
if (argc == 2 && streq(argv[1], "--store")) { |
||||
|
struct shachain s; |
||||
|
struct rbuf rbuf; |
||||
|
size_t size = rbuf_good_size(STDIN_FILENO); |
||||
|
char *p; |
||||
|
|
||||
|
shachain_init(&s); |
||||
|
rbuf_init(&rbuf, STDIN_FILENO, malloc(size), size); |
||||
|
|
||||
|
while ((p = rbuf_read_str(&rbuf, '\n', realloc)) != NULL) { |
||||
|
struct sha256 hash; |
||||
|
unsigned long long idx; |
||||
|
|
||||
|
if (strstarts(p, "0x")) |
||||
|
p += 2; |
||||
|
if (!hex_decode(p, 64, &hash, sizeof(hash))) |
||||
|
errx(2, "%.*s is not 64 chars of hex", 64, p); |
||||
|
p += 64; |
||||
|
p += strspn(p, " \t"); |
||||
|
idx = strtoull(p, NULL, 0); |
||||
|
if (shachain_add_hash(&s, idx, &hash)) |
||||
|
printf("OK\n"); |
||||
|
else |
||||
|
printf("ERROR\n"); |
||||
|
} |
||||
|
} else if (argc == 3) { |
||||
|
struct sha256 seed, hash; |
||||
|
const char *p; |
||||
|
unsigned long long idx; |
||||
|
char hex[65]; |
||||
|
|
||||
|
if (strstarts(argv[1], "0x")) |
||||
|
p = argv[1] + 2; |
||||
|
else |
||||
|
p = argv[1]; |
||||
|
idx = strtoull(argv[2], NULL, 0); |
||||
|
|
||||
|
if (!hex_decode(p, 64, &seed, sizeof(seed))) |
||||
|
errx(2, "%s is not 64 chars of hex", p); |
||||
|
|
||||
|
shachain_from_seed(&seed, idx, &hash); |
||||
|
hex_encode(&hash, sizeof(hash), hex, sizeof(hex)); |
||||
|
printf("0x%s\n", hex); |
||||
|
} else |
||||
|
errx(1, "Usage: shachain --store OR shachain <seed> <index>"); |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
../../licenses/CC0 |
@ -0,0 +1,65 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* fdpass - routines to pass a file descriptor over a socket. |
||||
|
* |
||||
|
* This code handles all the hairy details of fd passing. |
||||
|
* |
||||
|
* License: CC0 (Public domain) |
||||
|
* Maintainer: Rusty Russell <rusty@rustcorp.com.au> |
||||
|
* |
||||
|
* Example: |
||||
|
* // Outputs hello! |
||||
|
* #include <ccan/fdpass/fdpass.h> |
||||
|
* #include <sys/socket.h> |
||||
|
* #include <sys/un.h> |
||||
|
* #include <stdio.h> |
||||
|
* #include <stdlib.h> |
||||
|
* #include <unistd.h> |
||||
|
* |
||||
|
* static void child(int sockfd) |
||||
|
* { |
||||
|
* char buffer[6]; |
||||
|
* int newfd = fdpass_recv(sockfd); |
||||
|
* read(newfd, buffer, sizeof(buffer)); |
||||
|
* printf("%.*s\n", (int)sizeof(buffer), buffer); |
||||
|
* exit(0); |
||||
|
* } |
||||
|
* |
||||
|
* static void parent(int sockfd) |
||||
|
* { |
||||
|
* int pfds[2]; |
||||
|
* |
||||
|
* pipe(pfds); |
||||
|
* fdpass_send(sockfd, pfds[0]); |
||||
|
* close(pfds[0]); |
||||
|
* write(pfds[1], "hello!", 6); |
||||
|
* exit(0); |
||||
|
* } |
||||
|
* |
||||
|
* int main(void) |
||||
|
* { |
||||
|
* int sv[2]; |
||||
|
* |
||||
|
* socketpair(AF_UNIX, SOCK_STREAM, 0, sv); |
||||
|
* if (fork() == 0) |
||||
|
* child(sv[0]); |
||||
|
* else |
||||
|
* parent(sv[1]); |
||||
|
* } |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) |
||||
|
return 0; |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
|
@ -0,0 +1,83 @@ |
|||||
|
/* CC0 license (public domain) - see LICENSE file for details */ |
||||
|
#include <ccan/fdpass/fdpass.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <errno.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
bool fdpass_send(int sockout, int fd) |
||||
|
{ |
||||
|
/* From the cmsg(3) manpage: */ |
||||
|
struct msghdr msg = { 0 }; |
||||
|
struct cmsghdr *cmsg; |
||||
|
struct iovec iov; |
||||
|
char c = 0; |
||||
|
union { /* Ancillary data buffer, wrapped in a union
|
||||
|
in order to ensure it is suitably aligned */ |
||||
|
char buf[CMSG_SPACE(sizeof(fd))]; |
||||
|
struct cmsghdr align; |
||||
|
} u; |
||||
|
|
||||
|
msg.msg_control = u.buf; |
||||
|
msg.msg_controllen = sizeof(u.buf); |
||||
|
memset(&u, 0, sizeof(u)); |
||||
|
cmsg = CMSG_FIRSTHDR(&msg); |
||||
|
cmsg->cmsg_level = SOL_SOCKET; |
||||
|
cmsg->cmsg_type = SCM_RIGHTS; |
||||
|
cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); |
||||
|
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); |
||||
|
|
||||
|
msg.msg_name = NULL; |
||||
|
msg.msg_namelen = 0; |
||||
|
msg.msg_iov = &iov; |
||||
|
msg.msg_iovlen = 1; |
||||
|
msg.msg_flags = 0; |
||||
|
|
||||
|
/* Keith Packard reports that 0-length sends don't work, so we
|
||||
|
* always send 1 byte. */ |
||||
|
iov.iov_base = &c; |
||||
|
iov.iov_len = 1; |
||||
|
|
||||
|
return sendmsg(sockout, &msg, 0) == 1; |
||||
|
} |
||||
|
|
||||
|
int fdpass_recv(int sockin) |
||||
|
{ |
||||
|
/* From the cmsg(3) manpage: */ |
||||
|
struct msghdr msg = { 0 }; |
||||
|
struct cmsghdr *cmsg; |
||||
|
struct iovec iov; |
||||
|
int fd; |
||||
|
char c; |
||||
|
union { /* Ancillary data buffer, wrapped in a union
|
||||
|
in order to ensure it is suitably aligned */ |
||||
|
char buf[CMSG_SPACE(sizeof(fd))]; |
||||
|
struct cmsghdr align; |
||||
|
} u; |
||||
|
|
||||
|
msg.msg_control = u.buf; |
||||
|
msg.msg_controllen = sizeof(u.buf); |
||||
|
|
||||
|
msg.msg_name = NULL; |
||||
|
msg.msg_namelen = 0; |
||||
|
msg.msg_iov = &iov; |
||||
|
msg.msg_iovlen = 1; |
||||
|
msg.msg_flags = 0; |
||||
|
|
||||
|
iov.iov_base = &c; |
||||
|
iov.iov_len = 1; |
||||
|
|
||||
|
if (recvmsg(sockin, &msg, 0) < 0) |
||||
|
return -1; |
||||
|
|
||||
|
cmsg = CMSG_FIRSTHDR(&msg); |
||||
|
if (!cmsg |
||||
|
|| cmsg->cmsg_len != CMSG_LEN(sizeof(fd)) |
||||
|
|| cmsg->cmsg_level != SOL_SOCKET |
||||
|
|| cmsg->cmsg_type != SCM_RIGHTS) { |
||||
|
errno = -EINVAL; |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); |
||||
|
return fd; |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
/* CC0 license (public domain) - see LICENSE file for details */ |
||||
|
#ifndef CCAN_FDPASS_H |
||||
|
#define CCAN_FDPASS_H |
||||
|
|
||||
|
#include <stdbool.h> |
||||
|
|
||||
|
/**
|
||||
|
* fdpass_send - send a file descriptor across a socket |
||||
|
* @sockout: socket to write to |
||||
|
* @fd: file descriptor to pass |
||||
|
* |
||||
|
* On failure, sets errno and returns false. |
||||
|
*/ |
||||
|
bool fdpass_send(int sockout, int fd); |
||||
|
|
||||
|
/**
|
||||
|
* fdpass_recv - receive a file descriptor from a socket |
||||
|
* @sockin: socket to read from |
||||
|
* |
||||
|
* On failure, returns -1 and sets errno. Otherwise returns fd. |
||||
|
*/ |
||||
|
int fdpass_recv(int sockin); |
||||
|
#endif /* CCAN_FDPASS_H */ |
@ -0,0 +1,88 @@ |
|||||
|
#include <ccan/fdpass/fdpass.h> |
||||
|
/* Include the C files directly. */ |
||||
|
#include <ccan/fdpass/fdpass.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <sys/un.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <unistd.h> |
||||
|
#include <assert.h> |
||||
|
|
||||
|
static void child(int sockfd) |
||||
|
{ |
||||
|
char c; |
||||
|
int newfd = fdpass_recv(sockfd); |
||||
|
assert(newfd >= 0); |
||||
|
assert(read(newfd, &c, 1) == 1); |
||||
|
assert(c == 0x77); |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
static void child_nofd(int sockfd) |
||||
|
{ |
||||
|
assert(fdpass_recv(sockfd) == -1); |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
static void parent(int sockfd) |
||||
|
{ |
||||
|
int pfds[2]; |
||||
|
|
||||
|
ok1(pipe(pfds) == 0); |
||||
|
ok1(fdpass_send(sockfd, pfds[0])); |
||||
|
ok1(close(pfds[0]) == 0); |
||||
|
ok1(write(pfds[1], "\x77", 1) == 1); |
||||
|
ok1(close(pfds[1]) == 0); |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
int sv[2]; |
||||
|
int pid, wstatus; |
||||
|
|
||||
|
plan_tests(17); |
||||
|
ok1(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); |
||||
|
|
||||
|
pid = fork(); |
||||
|
if (pid == 0) { |
||||
|
close(sv[1]); |
||||
|
child(sv[0]); |
||||
|
} |
||||
|
|
||||
|
parent(sv[1]); |
||||
|
ok1(waitpid(pid, &wstatus, 0) == pid); |
||||
|
ok1(WIFEXITED(wstatus)); |
||||
|
ok1(WEXITSTATUS(wstatus) == 0); |
||||
|
|
||||
|
pid = fork(); |
||||
|
if (pid == 0) { |
||||
|
close(sv[1]); |
||||
|
child_nofd(sv[0]); |
||||
|
} |
||||
|
/* Don't write an fd. */ |
||||
|
ok1(write(sv[1], "1", 1) == 1); |
||||
|
ok1(waitpid(pid, &wstatus, 0) == pid); |
||||
|
ok1(WIFEXITED(wstatus)); |
||||
|
ok1(WEXITSTATUS(wstatus) == 0); |
||||
|
|
||||
|
pid = fork(); |
||||
|
if (pid == 0) { |
||||
|
close(sv[1]); |
||||
|
child_nofd(sv[0]); |
||||
|
} |
||||
|
/* Don't write anything. */ |
||||
|
close(sv[1]); |
||||
|
ok1(waitpid(pid, &wstatus, 0) == pid); |
||||
|
ok1(WIFEXITED(wstatus)); |
||||
|
ok1(WEXITSTATUS(wstatus) == 0); |
||||
|
|
||||
|
close(sv[0]); |
||||
|
/* Test fdpass_recv from invalid fd. */ |
||||
|
ok1(fdpass_recv(sv[0]) == -1 && errno == EBADF); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
../../../licenses/LGPL-2.1 |
@ -0,0 +1,95 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* io/fdpass - IO helper for passing file descriptors across local sockets |
||||
|
* |
||||
|
* This code adds the ability to pass file descriptors to ccan/io. |
||||
|
* |
||||
|
* License: LGPL (v2.1 or any later version) |
||||
|
* Author: Rusty Russell <rusty@rustcorp.com.au> |
||||
|
* |
||||
|
* Example: |
||||
|
* // Given "hello" outputs hello |
||||
|
* #include <ccan/io/fdpass/fdpass.h> |
||||
|
* #include <sys/types.h> |
||||
|
* #include <sys/socket.h> |
||||
|
* #include <sys/un.h> |
||||
|
* #include <stdio.h> |
||||
|
* #include <stdlib.h> |
||||
|
* #include <unistd.h> |
||||
|
* |
||||
|
* // Child reads stdin into the buffer, prints it out. |
||||
|
* struct buf { |
||||
|
* size_t used; |
||||
|
* char c[100]; |
||||
|
* }; |
||||
|
* static struct io_plan *read_more(struct io_conn *conn, struct buf *buf) |
||||
|
* { |
||||
|
* printf("%.*s", (int)buf->used, buf->c); |
||||
|
* return io_read_partial(conn, buf->c, sizeof(buf->c), &buf->used, |
||||
|
* read_more, buf); |
||||
|
* } |
||||
|
* |
||||
|
* // Child has received fd, start reading loop. |
||||
|
* static struct io_plan *got_infd(struct io_conn *conn, int *infd) |
||||
|
* { |
||||
|
* struct buf *buf = calloc(1, sizeof(*buf)); |
||||
|
* |
||||
|
* io_new_conn(NULL, *infd, read_more, buf); |
||||
|
* return io_close(conn); |
||||
|
* } |
||||
|
* // Child is receiving the fd to read into. |
||||
|
* static struct io_plan *recv_infd(struct io_conn *conn, int *infd) |
||||
|
* { |
||||
|
* return io_recv_fd(conn, infd, got_infd, infd); |
||||
|
* } |
||||
|
* |
||||
|
* // Gets passed fd (stdin), which it reads from. |
||||
|
* static void child(int sockfd) |
||||
|
* { |
||||
|
* int infd; |
||||
|
* |
||||
|
* io_new_conn(NULL, sockfd, recv_infd, &infd); |
||||
|
* io_loop(NULL, NULL); |
||||
|
* exit(0); |
||||
|
* } |
||||
|
* |
||||
|
* static struct io_plan *send_stdin(struct io_conn *conn, void *unused) |
||||
|
* { |
||||
|
* return io_send_fd(conn, STDIN_FILENO, io_close_cb, NULL); |
||||
|
* } |
||||
|
* |
||||
|
* static void parent(int sockfd) |
||||
|
* { |
||||
|
* io_new_conn(NULL, sockfd, send_stdin, NULL); |
||||
|
* io_loop(NULL, NULL); |
||||
|
* exit(0); |
||||
|
* } |
||||
|
* |
||||
|
* int main(void) |
||||
|
* { |
||||
|
* int sv[2]; |
||||
|
* |
||||
|
* socketpair(AF_UNIX, SOCK_STREAM, 0, sv); |
||||
|
* if (fork() == 0) |
||||
|
* child(sv[0]); |
||||
|
* else |
||||
|
* parent(sv[1]); |
||||
|
* } |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
printf("ccan/fdpass\n"); |
||||
|
printf("ccan/io\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
/* GNU LGPL version 2 (or later) - see LICENSE file for details */ |
||||
|
#include <ccan/io/fdpass/fdpass.h> |
||||
|
#include <ccan/fdpass/fdpass.h> |
||||
|
#include <ccan/io/io_plan.h> |
||||
|
#include <errno.h> |
||||
|
|
||||
|
static int do_fd_send(int fd, struct io_plan_arg *arg) |
||||
|
{ |
||||
|
if (!fdpass_send(fd, arg->u1.s)) { |
||||
|
/* In case ccan/io ever gets smart with non-blocking. */ |
||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) |
||||
|
return 0; |
||||
|
return -1; |
||||
|
} |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
struct io_plan *io_send_fd_(struct io_conn *conn, |
||||
|
int fd, |
||||
|
struct io_plan *(*next)(struct io_conn *, void *), |
||||
|
void *next_arg) |
||||
|
{ |
||||
|
struct io_plan_arg *arg = io_plan_arg(conn, IO_OUT); |
||||
|
|
||||
|
arg->u1.s = fd; |
||||
|
|
||||
|
return io_set_plan(conn, IO_OUT, do_fd_send, next, next_arg); |
||||
|
} |
||||
|
|
||||
|
static int do_fd_recv(int fd, struct io_plan_arg *arg) |
||||
|
{ |
||||
|
int fdin = fdpass_recv(fd); |
||||
|
|
||||
|
if (fdin < 0) { |
||||
|
/* In case ccan/io ever gets smart with non-blocking. */ |
||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) |
||||
|
return 0; |
||||
|
return -1; |
||||
|
} |
||||
|
*(int *)arg->u1.vp = fdin; |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
struct io_plan *io_recv_fd_(struct io_conn *conn, |
||||
|
int *fd, |
||||
|
struct io_plan *(*next)(struct io_conn *, void *), |
||||
|
void *next_arg) |
||||
|
{ |
||||
|
struct io_plan_arg *arg = io_plan_arg(conn, IO_IN); |
||||
|
|
||||
|
arg->u1.vp = fd; |
||||
|
|
||||
|
return io_set_plan(conn, IO_IN, do_fd_recv, next, next_arg); |
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
/* GNU LGPL version 2 (or later) - see LICENSE file for details */ |
||||
|
#ifndef CCAN_IO_FDPASS_H |
||||
|
#define CCAN_IO_FDPASS_H |
||||
|
#include <ccan/io/io.h> |
||||
|
|
||||
|
/**
|
||||
|
* io_send_fd - output plan to send a file descriptor |
||||
|
* @conn: the connection that plan is for. |
||||
|
* @fd: the file descriptor to pass. |
||||
|
* @next: function to call output is done. |
||||
|
* @arg: @next argument |
||||
|
* |
||||
|
* This updates the output plan, to write out a file descriptor. This |
||||
|
* usually only works over an AF_LOCAL (ie. Unix domain) socket. Once |
||||
|
* that's sent, the @next function will be called: on an error, the |
||||
|
* finish function is called instead. |
||||
|
* |
||||
|
* Note that the I/O may actually be done immediately, and the other end |
||||
|
* of the socket must use io_recv_fd: if it does a normal read, the file |
||||
|
* descriptor will be lost. |
||||
|
* |
||||
|
* Example: |
||||
|
* static struct io_plan *fd_to_conn(struct io_conn *conn, int fd) |
||||
|
* { |
||||
|
* // Write fd, then close.
|
||||
|
* return io_send_fd(conn, fd, io_close_cb, NULL); |
||||
|
* } |
||||
|
*/ |
||||
|
#define io_send_fd(conn, fd, next, arg) \ |
||||
|
io_send_fd_((conn), (fd), \ |
||||
|
typesafe_cb_preargs(struct io_plan *, void *, \ |
||||
|
(next), (arg), struct io_conn *), \ |
||||
|
(arg)) |
||||
|
struct io_plan *io_send_fd_(struct io_conn *conn, |
||||
|
int fd, |
||||
|
struct io_plan *(*next)(struct io_conn *, void *), |
||||
|
void *arg); |
||||
|
|
||||
|
/**
|
||||
|
* io_recv_fd - input plan to receive a file descriptor |
||||
|
* @conn: the connection that plan is for. |
||||
|
* @fd: a pointer to where to place to file descriptor |
||||
|
* @next: function to call once input is done. |
||||
|
* @arg: @next argument |
||||
|
* |
||||
|
* This creates a plan to receive a file descriptor, as sent by |
||||
|
* io_send_fd. Once it's all read, the @next function will be called: |
||||
|
* on an error, the finish function is called instead. |
||||
|
* |
||||
|
* Note that the I/O may actually be done immediately. |
||||
|
* |
||||
|
* Example: |
||||
|
* static struct io_plan *read_from_conn(struct io_conn *conn, int *fdp) |
||||
|
* { |
||||
|
* // Read message, then close.
|
||||
|
* return io_recv_fd(conn, fdp, io_close_cb, NULL); |
||||
|
* } |
||||
|
*/ |
||||
|
#define io_recv_fd(conn, fd, next, arg) \ |
||||
|
io_recv_fd_((conn), (fd), \ |
||||
|
typesafe_cb_preargs(struct io_plan *, void *, \ |
||||
|
(next), (arg), struct io_conn *), \ |
||||
|
(arg)) |
||||
|
struct io_plan *io_recv_fd_(struct io_conn *conn, |
||||
|
int *fd, |
||||
|
struct io_plan *(*next)(struct io_conn *, void *), |
||||
|
void *arg); |
||||
|
#endif /* CCAN_IO_FDPASS_H */ |
@ -0,0 +1,51 @@ |
|||||
|
#include <ccan/io/fdpass/fdpass.h> |
||||
|
/* Include the C files directly. */ |
||||
|
#include <ccan/io/fdpass/fdpass.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
|
||||
|
static struct io_plan *try_reading(struct io_conn *conn, int *fd) |
||||
|
{ |
||||
|
char buf[6]; |
||||
|
ok1(read(*fd, buf, sizeof(buf)) == sizeof(buf)); |
||||
|
ok1(memcmp(buf, "hello!", sizeof(buf)) == 0); |
||||
|
return io_close(conn); |
||||
|
} |
||||
|
|
||||
|
static struct io_plan *get_fd(struct io_conn *conn, void *unused) |
||||
|
{ |
||||
|
int *fd = tal(conn, int); |
||||
|
return io_recv_fd(conn, fd, try_reading, fd); |
||||
|
} |
||||
|
|
||||
|
static struct io_plan *try_writing(struct io_conn *conn, int *pfd) |
||||
|
{ |
||||
|
close(pfd[0]); |
||||
|
ok1(write(pfd[1], "hello!", 6) == 6); |
||||
|
return io_close(conn); |
||||
|
} |
||||
|
|
||||
|
static struct io_plan *send_fd(struct io_conn *conn, int *pfd) |
||||
|
{ |
||||
|
return io_send_fd(conn, pfd[0], try_writing, pfd); |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
int sv[2]; |
||||
|
int pfd[2]; |
||||
|
|
||||
|
plan_tests(5); |
||||
|
ok1(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); |
||||
|
ok1(pipe(pfd) == 0); |
||||
|
|
||||
|
/* Pass read end of pipe to ourselves, test. */ |
||||
|
io_new_conn(NULL, sv[0], get_fd, NULL); |
||||
|
io_new_conn(NULL, sv[1], send_fd, pfd); |
||||
|
|
||||
|
io_loop(NULL, NULL); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-01-start-finish.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-02-read.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-03-readpartial.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-04-writepartial.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-05-write.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-07-break.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-09-connect.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-12-bidir.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-14-duplex-both-read.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-16-duplex-test.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-17-homemade-io.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-18-errno.c" |
|
@ -1,2 +0,0 @@ |
|||||
#define DEBUG_CONN |
|
||||
#include "run-19-always.c" |
|
@ -0,0 +1 @@ |
|||||
|
../../licenses/BSD-MIT |
@ -0,0 +1,29 @@ |
|||||
|
#include "config.h" |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
/** |
||||
|
* ptr_valid - test whether a pointer is safe to dereference. |
||||
|
* |
||||
|
* This little helper tells you if an address is mapped; it doesn't tell you |
||||
|
* if it's read-only (or execute only). |
||||
|
* |
||||
|
* License: BSD-MIT |
||||
|
* |
||||
|
* Ccanlint: |
||||
|
* // Our child actually crashes, but that's OK! |
||||
|
* tests_pass_valgrind test/run.c:--child-silent-after-fork=yes |
||||
|
*/ |
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
/* Expect exactly one argument */ |
||||
|
if (argc != 2) |
||||
|
return 1; |
||||
|
|
||||
|
if (strcmp(argv[1], "depends") == 0) { |
||||
|
printf("ccan/noerr\n"); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
return 1; |
||||
|
} |
@ -0,0 +1,344 @@ |
|||||
|
// Licensed under BSD-MIT: See LICENSE.
|
||||
|
#include "ptr_valid.h" |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <sys/stat.h> |
||||
|
#include <fcntl.h> |
||||
|
#include <ccan/noerr/noerr.h> |
||||
|
#include <unistd.h> |
||||
|
#include <errno.h> |
||||
|
#include <assert.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#if HAVE_PROC_SELF_MAPS |
||||
|
static char *grab(const char *filename) |
||||
|
{ |
||||
|
int ret, fd; |
||||
|
size_t max = 16384, s = 0; |
||||
|
char *buffer; |
||||
|
|
||||
|
fd = open(filename, O_RDONLY); |
||||
|
if (fd < 0) |
||||
|
return NULL; |
||||
|
|
||||
|
buffer = malloc(max+1); |
||||
|
if (!buffer) |
||||
|
goto close; |
||||
|
|
||||
|
while ((ret = read(fd, buffer + s, max - s)) > 0) { |
||||
|
s += ret; |
||||
|
if (s == max) { |
||||
|
buffer = realloc(buffer, max*2+1); |
||||
|
if (!buffer) |
||||
|
goto close; |
||||
|
max *= 2; |
||||
|
} |
||||
|
} |
||||
|
if (ret < 0) |
||||
|
goto free; |
||||
|
|
||||
|
close(fd); |
||||
|
buffer[s] = '\0'; |
||||
|
return buffer; |
||||
|
|
||||
|
free: |
||||
|
free(buffer); |
||||
|
close: |
||||
|
close_noerr(fd); |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
static char *skip_line(char *p) |
||||
|
{ |
||||
|
char *nl = strchr(p, '\n'); |
||||
|
if (!nl) |
||||
|
return NULL; |
||||
|
return nl + 1; |
||||
|
} |
||||
|
|
||||
|
static struct ptr_valid_map *add_map(struct ptr_valid_map *map, |
||||
|
unsigned int *num, |
||||
|
unsigned int *max, |
||||
|
unsigned long start, unsigned long end, bool is_write) |
||||
|
{ |
||||
|
if (*num == *max) { |
||||
|
*max *= 2; |
||||
|
map = realloc(map, sizeof(*map) * *max); |
||||
|
if (!map) |
||||
|
return NULL; |
||||
|
} |
||||
|
map[*num].start = (void *)start; |
||||
|
map[*num].end = (void *)end; |
||||
|
map[*num].is_write = is_write; |
||||
|
(*num)++; |
||||
|
return map; |
||||
|
} |
||||
|
|
||||
|
static struct ptr_valid_map *get_proc_maps(unsigned int *num) |
||||
|
{ |
||||
|
char *buf, *p; |
||||
|
struct ptr_valid_map *map; |
||||
|
unsigned int max = 16; |
||||
|
|
||||
|
buf = grab("/proc/self/maps"); |
||||
|
if (!buf) { |
||||
|
*num = 0; |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
map = malloc(sizeof(*map) * max); |
||||
|
if (!map) |
||||
|
goto free_buf; |
||||
|
|
||||
|
*num = 0; |
||||
|
for (p = buf; p && *p; p = skip_line(p)) { |
||||
|
unsigned long start, end; |
||||
|
char *endp; |
||||
|
|
||||
|
/* Expect '<start-in-hex>-<end-in-hex> rw... */ |
||||
|
start = strtoul(p, &endp, 16); |
||||
|
if (*endp != '-') |
||||
|
goto malformed; |
||||
|
end = strtoul(endp+1, &endp, 16); |
||||
|
if (*endp != ' ') |
||||
|
goto malformed; |
||||
|
|
||||
|
endp++; |
||||
|
if (endp[0] != 'r' && endp[0] != '-') |
||||
|
goto malformed; |
||||
|
if (endp[1] != 'w' && endp[1] != '-') |
||||
|
goto malformed; |
||||
|
|
||||
|
/* We only add readable mappings. */ |
||||
|
if (endp[0] == 'r') { |
||||
|
map = add_map(map, num, &max, start, end, |
||||
|
endp[1] == 'w'); |
||||
|
if (!map) |
||||
|
goto free_buf; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
free(buf); |
||||
|
return map; |
||||
|
|
||||
|
|
||||
|
malformed: |
||||
|
free(map); |
||||
|
free_buf: |
||||
|
free(buf); |
||||
|
*num = 0; |
||||
|
return NULL; |
||||
|
} |
||||
|
#else |
||||
|
static struct ptr_valid_map *get_proc_maps(unsigned int *num) |
||||
|
{ |
||||
|
*num = 0; |
||||
|
return NULL; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
static bool check_with_maps(struct ptr_valid_batch *batch, |
||||
|
const char *p, size_t size, bool is_write) |
||||
|
{ |
||||
|
unsigned int i; |
||||
|
|
||||
|
for (i = 0; i < batch->num_maps; i++) { |
||||
|
if (p >= batch->maps[i].start && p < batch->maps[i].end) { |
||||
|
/* Overlap into other maps? Recurse with remainder. */ |
||||
|
if (p + size > batch->maps[i].end) { |
||||
|
size_t len = p + size - batch->maps[i].end; |
||||
|
if (!check_with_maps(batch, batch->maps[i].end, |
||||
|
len, is_write)) |
||||
|
return false; |
||||
|
} |
||||
|
return !is_write || batch->maps[i].is_write; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
static void finish_child(struct ptr_valid_batch *batch) |
||||
|
{ |
||||
|
close(batch->to_child); |
||||
|
close(batch->from_child); |
||||
|
waitpid(batch->child_pid, NULL, 0); |
||||
|
batch->child_pid = 0; |
||||
|
} |
||||
|
|
||||
|
static bool child_alive(struct ptr_valid_batch *batch) |
||||
|
{ |
||||
|
return batch->child_pid != 0; |
||||
|
} |
||||
|
|
||||
|
static void run_child(int infd, int outfd) |
||||
|
{ |
||||
|
volatile char *p; |
||||
|
|
||||
|
/* This is how we expect to exit. */ |
||||
|
while (read(infd, &p, sizeof(p)) == sizeof(p)) { |
||||
|
size_t i, size; |
||||
|
bool is_write; |
||||
|
char ret = 0; |
||||
|
|
||||
|
/* This is weird. */ |
||||
|
if (read(infd, &size, sizeof(size)) != sizeof(size)) |
||||
|
exit(1); |
||||
|
if (read(infd, &is_write, sizeof(is_write)) != sizeof(is_write)) |
||||
|
exit(2); |
||||
|
|
||||
|
for (i = 0; i < size; i++) { |
||||
|
ret = p[i]; |
||||
|
if (is_write) |
||||
|
p[i] = ret; |
||||
|
} |
||||
|
|
||||
|
/* If we're still here, the answer is "yes". */ |
||||
|
if (write(outfd, &ret, 1) != 1) |
||||
|
exit(3); |
||||
|
} |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
static bool create_child(struct ptr_valid_batch *batch) |
||||
|
{ |
||||
|
int outpipe[2], inpipe[2]; |
||||
|
|
||||
|
if (pipe(outpipe) != 0) |
||||
|
return false; |
||||
|
if (pipe(inpipe) != 0) |
||||
|
goto close_outpipe; |
||||
|
|
||||
|
fflush(stdout); |
||||
|
batch->child_pid = fork(); |
||||
|
if (batch->child_pid == 0) { |
||||
|
close(outpipe[1]); |
||||
|
close(inpipe[0]); |
||||
|
run_child(outpipe[0], inpipe[1]); |
||||
|
} |
||||
|
|
||||
|
if (batch->child_pid == -1) |
||||
|
goto cleanup_pid; |
||||
|
|
||||
|
close(outpipe[0]); |
||||
|
close(inpipe[1]); |
||||
|
|
||||
|
batch->to_child = outpipe[1]; |
||||
|
batch->from_child = inpipe[0]; |
||||
|
return true; |
||||
|
|
||||
|
cleanup_pid: |
||||
|
batch->child_pid = 0; |
||||
|
close_noerr(inpipe[0]); |
||||
|
close_noerr(inpipe[1]); |
||||
|
close_outpipe: |
||||
|
close_noerr(outpipe[0]); |
||||
|
close_noerr(outpipe[1]); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
static bool check_with_child(struct ptr_valid_batch *batch, |
||||
|
const void *p, size_t size, bool is_write) |
||||
|
{ |
||||
|
char ret; |
||||
|
|
||||
|
if (!child_alive(batch)) { |
||||
|
if (!create_child(batch)) |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (write(batch->to_child, &p, sizeof(p)) |
||||
|
+ write(batch->to_child, &size, sizeof(size)) |
||||
|
+ write(batch->to_child, &is_write, sizeof(is_write)) |
||||
|
!= sizeof(p) + sizeof(size) + sizeof(is_write)) { |
||||
|
finish_child(batch); |
||||
|
errno = EFAULT; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (read(batch->from_child, &ret, sizeof(ret)) != sizeof(ret)) { |
||||
|
finish_child(batch); |
||||
|
errno = EFAULT; |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/* msync seems most well-defined test, but page could be mapped with
|
||||
|
* no permissions, and can't distiguish readonly from writable. */ |
||||
|
bool ptr_valid_batch(struct ptr_valid_batch *batch, |
||||
|
const void *p, size_t alignment, size_t size, bool write) |
||||
|
{ |
||||
|
char *start, *end; |
||||
|
bool ret; |
||||
|
|
||||
|
if ((intptr_t)p & (alignment - 1)) |
||||
|
return false; |
||||
|
|
||||
|
start = (void *)((intptr_t)p & ~(getpagesize() - 1)); |
||||
|
end = (void *)(((intptr_t)p + size - 1) & ~(getpagesize() - 1)); |
||||
|
|
||||
|
/* We cache single page hits. */ |
||||
|
if (start == end) { |
||||
|
if (batch->last && batch->last == start) |
||||
|
return batch->last_ok; |
||||
|
} |
||||
|
|
||||
|
if (batch->num_maps) |
||||
|
ret = check_with_maps(batch, p, size, write); |
||||
|
else |
||||
|
ret = check_with_child(batch, p, size, write); |
||||
|
|
||||
|
if (start == end) { |
||||
|
batch->last = start; |
||||
|
batch->last_ok = ret; |
||||
|
} |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool ptr_valid_batch_string(struct ptr_valid_batch *batch, const char *p) |
||||
|
{ |
||||
|
while (ptr_valid_batch(batch, p, 1, 1, false)) { |
||||
|
if (*p == '\0') |
||||
|
return true; |
||||
|
p++; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool ptr_valid(const void *p, size_t alignment, size_t size, bool write) |
||||
|
{ |
||||
|
bool ret; |
||||
|
struct ptr_valid_batch batch; |
||||
|
if (!ptr_valid_batch_start(&batch)) |
||||
|
return false; |
||||
|
ret = ptr_valid_batch(&batch, p, alignment, size, write); |
||||
|
ptr_valid_batch_end(&batch); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool ptr_valid_string(const char *p) |
||||
|
{ |
||||
|
bool ret; |
||||
|
struct ptr_valid_batch batch; |
||||
|
if (!ptr_valid_batch_start(&batch)) |
||||
|
return false; |
||||
|
ret = ptr_valid_batch_string(&batch, p); |
||||
|
ptr_valid_batch_end(&batch); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool ptr_valid_batch_start(struct ptr_valid_batch *batch) |
||||
|
{ |
||||
|
batch->child_pid = 0; |
||||
|
batch->maps = get_proc_maps(&batch->num_maps); |
||||
|
batch->last = NULL; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
void ptr_valid_batch_end(struct ptr_valid_batch *batch) |
||||
|
{ |
||||
|
if (child_alive(batch)) |
||||
|
finish_child(batch); |
||||
|
free(batch->maps); |
||||
|
} |
@ -0,0 +1,229 @@ |
|||||
|
// 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 */ |
@ -0,0 +1,56 @@ |
|||||
|
#include <ccan/ptr_valid/ptr_valid.h> |
||||
|
/* Include the C files directly. */ |
||||
|
#include <ccan/ptr_valid/ptr_valid.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
#include <sys/mman.h> |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
char *page; |
||||
|
struct ptr_valid_batch *batch = malloc(sizeof *batch); |
||||
|
|
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(14); |
||||
|
|
||||
|
page = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, |
||||
|
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
||||
|
strcpy(page, "hello"); |
||||
|
ok1(ptr_valid_read(page)); |
||||
|
ok1(ptr_valid_write(page)); |
||||
|
ok1(ptr_valid_string(page)); |
||||
|
|
||||
|
ok1(ptr_valid_batch_start(batch)); |
||||
|
ok1(ptr_valid_batch_string(batch, page)); |
||||
|
ptr_valid_batch_end(batch); |
||||
|
|
||||
|
/* Check invalid case. */ |
||||
|
munmap(page, getpagesize()); |
||||
|
ok1(!ptr_valid_string(page)); |
||||
|
|
||||
|
ok1(ptr_valid_batch_start(batch)); |
||||
|
ok1(!ptr_valid_batch_string(batch, page)); |
||||
|
ptr_valid_batch_end(batch); |
||||
|
|
||||
|
/* Check for overrun. */ |
||||
|
page = mmap(NULL, getpagesize()*2, PROT_READ|PROT_WRITE, |
||||
|
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
||||
|
munmap(page + getpagesize(), getpagesize()); |
||||
|
|
||||
|
memset(page, 'a', getpagesize()); |
||||
|
ok1(!ptr_valid_string(page)); |
||||
|
ok1(ptr_valid_batch_start(batch)); |
||||
|
ok1(!ptr_valid_batch_string(batch, page)); |
||||
|
ptr_valid_batch_end(batch); |
||||
|
|
||||
|
page[getpagesize()-1] = '\0'; |
||||
|
ok1(ptr_valid_string(page)); |
||||
|
|
||||
|
ok1(ptr_valid_batch_start(batch)); |
||||
|
ok1(ptr_valid_batch_string(batch, page)); |
||||
|
ptr_valid_batch_end(batch); |
||||
|
munmap(page, getpagesize()); |
||||
|
|
||||
|
free(batch); |
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1,90 @@ |
|||||
|
#include <ccan/ptr_valid/ptr_valid.h> |
||||
|
/* Include the C files directly. */ |
||||
|
#include <ccan/ptr_valid/ptr_valid.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
#include <sys/mman.h> |
||||
|
|
||||
|
static bool check_batch(char *p, unsigned int num, bool expect) |
||||
|
{ |
||||
|
struct ptr_valid_batch batch; |
||||
|
unsigned int i; |
||||
|
|
||||
|
if (!ptr_valid_batch_start(&batch)) |
||||
|
return false; |
||||
|
for (i = 0; i < num; i++) { |
||||
|
if (ptr_valid_batch(&batch, p + i, 1, 1, false) != expect) |
||||
|
return false; |
||||
|
if (ptr_valid_batch(&batch, p + i, 1, 1, true) != expect) |
||||
|
return false; |
||||
|
} |
||||
|
ptr_valid_batch_end(&batch); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
char *page; |
||||
|
|
||||
|
/* This is how many tests you plan to run */ |
||||
|
plan_tests(30); |
||||
|
|
||||
|
page = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, |
||||
|
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
||||
|
ok1(ptr_valid_read(page)); |
||||
|
ok1(ptr_valid_write(page)); |
||||
|
ok1(ptr_valid(page, 1, getpagesize(), false)); |
||||
|
ok1(ptr_valid(page, 1, getpagesize(), true)); |
||||
|
|
||||
|
/* Test alignment constraints. */ |
||||
|
ok1(ptr_valid(page, getpagesize(), getpagesize(), false)); |
||||
|
ok1(ptr_valid(page, getpagesize(), getpagesize(), true)); |
||||
|
ok1(!ptr_valid(page+1, getpagesize(), 1, false)); |
||||
|
ok1(!ptr_valid(page+1, getpagesize(), 1, true)); |
||||
|
|
||||
|
/* Test batch. */ |
||||
|
ok1(check_batch(page, getpagesize(), true)); |
||||
|
|
||||
|
/* Unmap, all should fail. */ |
||||
|
munmap(page, getpagesize()); |
||||
|
ok1(!ptr_valid_read(page)); |
||||
|
ok1(!ptr_valid_write(page)); |
||||
|
ok1(!ptr_valid(page, 1, getpagesize(), false)); |
||||
|
ok1(!ptr_valid(page, 1, getpagesize(), true)); |
||||
|
|
||||
|
/* Test alignment constraints. */ |
||||
|
ok1(!ptr_valid(page, getpagesize(), getpagesize(), false)); |
||||
|
ok1(!ptr_valid(page, getpagesize(), getpagesize(), true)); |
||||
|
ok1(!ptr_valid(page+1, getpagesize(), 1, false)); |
||||
|
ok1(!ptr_valid(page, getpagesize(), 1, true)); |
||||
|
|
||||
|
/* Test batch (slow, since each fails, so reduce count). */ |
||||
|
ok1(check_batch(page, 4, false)); |
||||
|
|
||||
|
/* Check read-only */ |
||||
|
page = mmap(NULL, getpagesize(), PROT_READ, |
||||
|
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
||||
|
ok1(ptr_valid_read(page)); |
||||
|
ok1(!ptr_valid_write(page)); |
||||
|
ok1(ptr_valid(page, 1, getpagesize(), false)); |
||||
|
ok1(!ptr_valid(page, 1, getpagesize(), true)); |
||||
|
|
||||
|
/* Test alignment constraints. */ |
||||
|
ok1(ptr_valid(page, getpagesize(), getpagesize(), false)); |
||||
|
ok1(!ptr_valid(page, getpagesize(), getpagesize(), true)); |
||||
|
ok1(!ptr_valid(page+1, getpagesize(), 1, false)); |
||||
|
ok1(!ptr_valid(page+1, getpagesize(), 1, true)); |
||||
|
munmap(page, getpagesize()); |
||||
|
|
||||
|
/* Check for overrun. */ |
||||
|
page = mmap(NULL, getpagesize()*2, PROT_READ|PROT_WRITE, |
||||
|
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
||||
|
munmap(page + getpagesize(), getpagesize()); |
||||
|
|
||||
|
ok1(ptr_valid(page, 1, getpagesize(), false)); |
||||
|
ok1(ptr_valid(page, 1, getpagesize(), true)); |
||||
|
ok1(!ptr_valid(page, 1, getpagesize()+1, false)); |
||||
|
ok1(!ptr_valid(page, 1, getpagesize()+1, true)); |
||||
|
|
||||
|
/* This exits depending on whether all tests passed */ |
||||
|
return exit_status(); |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
#include <ccan/tal/tal.h> |
||||
|
#include <ccan/tal/tal.c> |
||||
|
#include <ccan/tap/tap.h> |
||||
|
|
||||
|
static void destroy_inc(char *p UNNEEDED, int *destroy_count) |
||||
|
{ |
||||
|
(*destroy_count)++; |
||||
|
} |
||||
|
|
||||
|
static void destroy_dec(char *p UNNEEDED, int *destroy_count) |
||||
|
{ |
||||
|
(*destroy_count)--; |
||||
|
} |
||||
|
|
||||
|
int main(void) |
||||
|
{ |
||||
|
char *p; |
||||
|
int destroy_count1 = 0, destroy_count2 = 0; |
||||
|
|
||||
|
plan_tests(10); |
||||
|
|
||||
|
p = tal(NULL, char); |
||||
|
/* Del must match both fn and arg. */ |
||||
|
ok1(tal_add_destructor2(p, destroy_inc, &destroy_count1)); |
||||
|
ok1(!tal_del_destructor2(p, destroy_inc, &destroy_count2)); |
||||
|
ok1(!tal_del_destructor2(p, destroy_dec, &destroy_count1)); |
||||
|
ok1(tal_del_destructor2(p, destroy_inc, &destroy_count1)); |
||||
|
ok1(!tal_del_destructor2(p, destroy_inc, &destroy_count1)); |
||||
|
|
||||
|
ok1(tal_add_destructor2(p, destroy_inc, &destroy_count1)); |
||||
|
ok1(tal_add_destructor2(p, destroy_dec, &destroy_count2)); |
||||
|
ok1(tal_free(p) == NULL); |
||||
|
ok1(destroy_count1 == 1); |
||||
|
ok1(destroy_count2 == -1); |
||||
|
|
||||
|
tal_cleanup(); |
||||
|
return exit_status(); |
||||
|
} |
Loading…
Reference in new issue