added stack control to PER

git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@1022 59561ff5-6e30-0410-9f3c-9617f08c8826
This commit is contained in:
vlm 2005-12-07 05:46:03 +00:00
parent 68a24641e4
commit 4d2ca1270e
16 changed files with 180 additions and 91 deletions

View File

@ -19,6 +19,7 @@
#include <errno.h> /* for errno */
#include <asn_application.h>
#include <asn_internal.h> /* for _ASN_DEFAULT_STACK_MAX */
extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */
#ifdef ASN_PDU_COLLECTION /* Generated by asn1c: -pdu=... */
@ -51,11 +52,17 @@ static enum output_format {
OUT_NULL /* -onull: No pretty-printing */
} oform; /* -o<format> */
#define DEBUG(fmt, args...) do { \
if(!opt_debug) break; \
fprintf(stderr, fmt, ##args); \
fprintf(stderr, "\n"); \
} while(0)
/* Debug output function */
static inline void
DEBUG(const char *fmt, ...) {
va_list ap;
if(!opt_debug) return;
fprintf(stderr, "AD: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
int
main(int ac, char **av) {
@ -131,9 +138,9 @@ main(int ac, char **av) {
break;
case 's':
opt_stack = atoi(optarg);
if(opt_stack <= 0) {
if(opt_stack < 0) {
fprintf(stderr,
"-s %s: Value greater than 0 expected\n",
"-s %s: Non-negative value expected\n",
optarg);
exit(EX_UNAVAILABLE);
}
@ -164,8 +171,8 @@ main(int ac, char **av) {
" -c Check ASN.1 constraints after decoding\n"
" -d Enable debugging (-dd is even better)\n"
" -n <num> Process files <num> times\n"
" -s <size> Set the stack usage limit\n"
, (long)suggested_bufsize);
" -s <size> Set the stack usage limit (default is %d)\n"
, (long)suggested_bufsize, _ASN_DEFAULT_STACK_MAX);
exit(EX_USAGE);
}
@ -250,11 +257,12 @@ static int write_out(const void *buffer, size_t size, void *key) {
return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1;
}
static char *buffer;
static size_t buf_offset; /* Offset from the start */
static char *buffer;
static size_t buf_len; /* Length of meaningful contents */
static size_t buf_size; /* Allocated memory */
static off_t buf_shifted; /* Number of bytes ever shifted */
static size_t buf_size; /* Allocated memory */
static size_t buf_offset; /* Offset from the start */
static off_t buf_shifted; /* Number of bytes ever shifted */
static int buf_nreallocs; /* Number of reallocations */
#define bufptr (buffer + buf_offset)
#define bufend (buffer + buf_offset + buf_len)
@ -262,13 +270,13 @@ static off_t buf_shifted; /* Number of bytes ever shifted */
/*
* Ensure that the buffer contains at least this amount of free space.
*/
static void buf_extend(size_t bySize) {
static void buf_extend(const void *data2add, size_t bySize) {
DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
(long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
if(buf_size >= (buf_offset + buf_len + bySize)) {
return; /* Nothing to do */
/* Nothing to do */
} else if(bySize <= buf_offset) {
DEBUG("\tContents shifted by %ld", (long)buf_offset);
@ -278,17 +286,22 @@ static void buf_extend(size_t bySize) {
buf_offset = 0;
} else {
size_t newsize = (buf_size << 2) + bySize;
void *p = realloc(buffer, newsize);
if(p) {
buffer = (char *)p;
buf_size = newsize;
DEBUG("\tBuffer reallocated to %ld", (long)newsize);
} else {
void *p = malloc(newsize);
if(!p) {
perror("realloc()");
exit(EX_OSERR);
}
memcpy(p, buffer, buf_len);
free(buffer);
buffer = (char *)p;
buf_size = newsize;
buf_offset = 0;
DEBUG("\tBuffer reallocated to %ld, %d time",
(long)newsize, ++buf_nreallocs);
}
memcpy(buffer + buf_offset + buf_len, data2add, bySize);
buf_len += bySize;
}
static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
@ -310,7 +323,7 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
DEBUG("Processing file %s", fname);
fp = fopen(fname, "r");
} else {
DEBUG("Processing standard input");
DEBUG("Processing %s", "standard input");
fname = "stdin";
fp = stdin;
}
@ -330,8 +343,10 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
fbuf_size = suggested_bufsize;
}
buf_nreallocs = 0;
buf_shifted = 0;
buf_offset = 0;
buf_size = 0;
buf_len = 0;
/* Pretend immediate EOF */
@ -339,19 +354,15 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
rval.consumed = 0;
while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
asn_per_data_t pd;
char *i_bptr;
size_t i_size;
/*
* Copy the data over, or use the original buffer.
*/
if(buf_len) {
if(buf_size) {
/* Append the new data into the intermediate buffer */
buf_extend(rd);
memcpy(bufend, fbuf, rd);
buf_len += rd;
buf_extend(fbuf, rd);
i_bptr = bufptr;
i_size = buf_len;
} else {
@ -369,36 +380,35 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
(void **)&structure, i_bptr, i_size);
break;
case INP_PER:
pd.buffer = (uint8_t *)i_bptr;
pd.nboff = 0;
pd.nbits = i_size * 8;
rval = pduType->uper_decoder(opt_codec_ctx, pduType, 0,
(void **)&structure, &pd);
rval = uper_decode(opt_codec_ctx, pduType,
(void **)&structure, i_bptr, i_size);
break;
}
DEBUG("decode(%ld) consumed %ld, code %d",
(long)buf_len, (long)rval.consumed, rval.code);
DEBUG("decode(%ld) consumed %ld (%ld), code %d",
(long)buf_len, (long)rval.consumed, (long)i_size,
rval.code);
if(buf_len == 0) {
if(buf_size == 0) {
/*
* Switch the remainder into the intermediate buffer.
*/
if(rval.code != RC_FAIL && rval.consumed < rd) {
buf_extend(rd - rval.consumed);
memcpy(bufend,
fbuf + rval.consumed,
rd - rval.consumed);
buf_len = rd - rval.consumed;
buf_extend(fbuf + rval.consumed,
rd - rval.consumed);
rval.consumed = 0;
}
}
switch(rval.code) {
case RC_OK:
DEBUG("RC_OK, finishing up");
DEBUG("RC_OK, finishing up with %ld",
(long)rval.consumed);
if(fp != stdin) fclose(fp);
return structure;
case RC_WMORE:
DEBUG("RC_WMORE, continuing...");
DEBUG("RC_WMORE, continuing %ld with %ld..%ld..%ld",
(long)rval.consumed, (long)buf_offset,
(long)buf_len, (long)buf_size);
/*
* Adjust position inside the source buffer.
*/

View File

@ -13,11 +13,13 @@ extern "C" {
struct asn_TYPE_descriptor_s; /* Forward declaration */
/*
* This structure defines a context that may be passed to every ASN.1 encoder
* or decoder function.
* This structure defines a set of parameters that may be passed
* to every ASN.1 encoder or decoder function.
* WARNING: if max_stack_size member is set, and you are calling the
* function pointers of the asn_TYPE_descriptor_t directly,
* this structure must be ALLOCATED ON THE STACK!
* function pointers of the asn_TYPE_descriptor_t directly,
* this structure must be ALLOCATED ON THE STACK!
* If you can't always satisfy this requirement, use ber_decode(),
* xer_decode() and uper_decode() functions instead.
*/
typedef struct asn_codec_ctx_s {
/*

View File

@ -82,6 +82,28 @@ static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; }
if(cb(" ", 4, app_key) < 0) return -1; \
} while(0)
/*
* Check stack against overflow, if limit is set.
*/
#define _ASN_DEFAULT_STACK_MAX (30000)
static inline int
_ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) {
if(ctx && ctx->max_stack_size) {
/* ctx MUST be allocated on the stack */
ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx);
if(usedstack > 0) usedstack = -usedstack; /* grows up! */
/* double negative required to avoid int wrap-around */
if(usedstack < -(ptrdiff_t)ctx->max_stack_size) {
ASN_DEBUG("Stack limit %ld reached",
(long)ctx->max_stack_size);
return -1;
}
}
return 0;
}
#ifdef __cplusplus
}
#endif

View File

@ -33,11 +33,18 @@ ber_decode(asn_codec_ctx_t *opt_codec_ctx,
asn_codec_ctx_t s_codec_ctx;
/*
* Satisfy the requirement that the codec context
* Stack checker requires that the codec context
* must be allocated on the stack.
*/
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
if(opt_codec_ctx) {
if(opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
opt_codec_ctx = &s_codec_ctx;
}
} else {
/* If context is not given, be security-conscious anyway */
memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
opt_codec_ctx = &s_codec_ctx;
}
@ -73,17 +80,8 @@ ber_check_tags(asn_codec_ctx_t *opt_codec_ctx,
/*
* Make sure we didn't exceed the maximum stack size.
*/
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
ptrdiff_t usedstack = ((char *)opt_codec_ctx - (char *)&size);
/* double negative is required to avoid int wrap-around */
if(usedstack > 0) usedstack = -usedstack;
ASN_DEBUG("Current stack size %ld", -(long)usedstack);
if(usedstack < -(ptrdiff_t)opt_codec_ctx->max_stack_size) {
ASN_DEBUG("Stack limit %ld reached",
(long)opt_codec_ctx->max_stack_size);
RETURN(RC_FAIL);
}
}
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
RETURN(RC_FAIL);
/*
* So what does all this implicit skip stuff mean?

View File

@ -46,8 +46,8 @@ typedef asn_dec_rval_t (ber_type_decoder_f)(
* head->last_tag_form is non-zero.
*/
asn_dec_rval_t ber_check_tags(
struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */
struct asn_TYPE_descriptor_s *type_dsc,
struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */
struct asn_TYPE_descriptor_s *type_descriptor,
asn_struct_ctx_t *opt_ctx, /* saved decoding context */
const void *ptr, size_t size,
int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */

View File

@ -84,17 +84,8 @@ ber_skip_length(asn_codec_ctx_t *opt_codec_ctx,
/*
* Make sure we didn't exceed the maximum stack size.
*/
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
ptrdiff_t usedstack = ((char *)opt_codec_ctx - (char *)&size);
/* double negative is required to avoid int wrap-around */
if(usedstack > 0) usedstack = -usedstack;
ASN_DEBUG("Current stack size %ld", -(long)usedstack);
if(usedstack < -(ptrdiff_t)opt_codec_ctx->max_stack_size) {
ASN_DEBUG("Stack limit %ld reached",
(long)opt_codec_ctx->max_stack_size);
return -1;
}
}
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
return -1;
/*
* Determine the size of L in TLV.

View File

@ -31,7 +31,6 @@ ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size,
* RETURN VALUES:
* Standard {-1,0,>0} convention.
*/
struct asn_codec_ctx_s; /* Forward declaration */
ssize_t ber_skip_length(
struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */
int _is_constructed, const void *bufptr, size_t size);

View File

@ -827,6 +827,9 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
void *st = *sptr;
int value;
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
_ASN_DECODE_FAILED;
/*
* Create the target structure if it is not present already.
*/

View File

@ -703,7 +703,8 @@ SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
}
tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d", tcv, ctx->phase);
ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]",
tcv, ctx->phase, xml_tag);
/* Skip the extensions section */
if(ctx->phase == 3) {
@ -829,7 +830,13 @@ SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
break;
}
ASN_DEBUG("Unexpected XML tag in SEQUENCE");
ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]",
size>0?((const char *)buf_ptr)[0]:'.',
size>1?((const char *)buf_ptr)[1]:'.',
size>2?((const char *)buf_ptr)[2]:'.',
size>3?((const char *)buf_ptr)[3]:'.',
size>4?((const char *)buf_ptr)[4]:'.',
size>5?((const char *)buf_ptr)[5]:'.');
break;
}
@ -1028,6 +1035,9 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
(void)constraints;
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
_ASN_DECODE_FAILED;
if(!st) {
st = *sptr = CALLOC(1, specs->struct_size);
if(!st) _ASN_DECODE_FAILED;

View File

@ -864,6 +864,9 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
int repeat = 0;
ssize_t nelems;
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
_ASN_DECODE_FAILED;
/*
* Create the target structure if it is not present already.
*/

View File

@ -1,2 +1,38 @@
#include <asn_application.h>
#include <asn_internal.h>
#include <per_decoder.h>
asn_dec_rval_t
uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) {
asn_codec_ctx_t s_codec_ctx;
asn_per_data_t pd;
/*
* Stack checker requires that the codec context
* must be allocated on the stack.
*/
if(opt_codec_ctx) {
if(opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
opt_codec_ctx = &s_codec_ctx;
}
} else {
/* If context is not given, be security-conscious anyway */
memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
opt_codec_ctx = &s_codec_ctx;
}
/* Fill in the position indicator */
pd.buffer = (const uint8_t *)buffer;
pd.nboff = 0;
pd.nbits = 8 * size; /* 8 is CHAR_BIT from <limits.h> */
/*
* Invoke type-specific decoder.
*/
if(!td->uper_decoder)
_ASN_DECODE_FAILED; /* PER is not compiled in */
return td->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd);
}

View File

@ -12,6 +12,18 @@
extern "C" {
#endif
struct asn_TYPE_descriptor_s; /* Forward declaration */
/*
* Unaligned PER decoder of any ASN.1 type. May be invoked by the application.
*/
asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx,
struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */
void **struct_ptr, /* Pointer to a target structure's pointer */
const void *buffer, /* Data to be decoded */
size_t size /* Size of data buffer */
);
/*
* Pre-computed PER constraints.
@ -23,7 +35,6 @@ extern "C" {
APC_EXTENSIBLE = 0x4 /* May have extension */
};
typedef struct asn_per_constraint_s {
enum asn_per_constraint_flags flags;
int range_bits; /* Full number of bits in the range */
int effective_bits; /* Effective bits */
@ -35,9 +46,6 @@ typedef struct asn_per_constraints_s {
asn_per_constraint_t size;
} asn_per_constraints_t;
struct asn_TYPE_descriptor_s; /* Forward declaration */
/*
* Type of the type-specific PER decoder function.
*/

View File

@ -12,7 +12,7 @@ int32_t
per_get_few_bits(asn_per_data_t *pd, int nbits) {
size_t off; /* Next after last bit offset */
uint32_t accum;
uint8_t *buf;
const uint8_t *buf;
if(nbits < 0 || pd->nboff + nbits > pd->nbits)
return -1;

View File

@ -15,9 +15,9 @@ extern "C" {
* This structure describes a position inside a PER bit stream.
*/
typedef struct asn_per_data_s {
uint8_t *buffer; /* Pointer to the octet stream */
size_t nboff; /* Bit offset to the meaningful bit */
size_t nbits; /* Number of bits in the stream */
const uint8_t *buffer; /* Pointer to the octet stream */
size_t nboff; /* Bit offset to the meaningful bit */
size_t nbits; /* Number of bits in the stream */
} asn_per_data_t;
/*

View File

@ -16,11 +16,18 @@ xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
asn_codec_ctx_t s_codec_ctx;
/*
* Satisfy the requirement that the codec context
* Stack checker requires that the codec context
* must be allocated on the stack.
*/
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
if(opt_codec_ctx) {
if(opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
opt_codec_ctx = &s_codec_ctx;
}
} else {
/* If context is not given, be security-conscious anyway */
memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
opt_codec_ctx = &s_codec_ctx;
}

View File

@ -14,13 +14,13 @@ extern "C" {
struct asn_TYPE_descriptor_s; /* Forward declaration */
/*
* The XER decoder of any type. May be invoked by the application.
* The XER decoder of any ASN.1 type. May be invoked by the application.
*/
asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx,
struct asn_TYPE_descriptor_s *type_descriptor,
void **struct_ptr, /* Pointer to a target structure's pointer */
const void *buffer, /* Data to be decoded */
size_t size /* Size of that buffer */
size_t size /* Size of data buffer */
);
/*