Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UsefulBuf examples code #136

Merged
merged 3 commits into from
Apr 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o sr

TEST_OBJ=test/UsefulBuf_Tests.o test/qcbor_encode_tests.o \
test/qcbor_decode_tests.o test/run_tests.o \
test/float_tests.o test/half_to_double_from_rfc7049.o example.o
test/float_tests.o test/half_to_double_from_rfc7049.o example.o ub-example.o

.PHONY: all so install uninstall clean

Expand Down Expand Up @@ -58,6 +58,7 @@ src/iee754.o: src/ieee754.h
src/qcbor_err_to_str.o: inc/qcbor/qcbor_common.h

example.o: $(PUBLIC_INTERFACE)
ub-example.o: $(PUBLIC_INTERFACE)

test/run_tests.o: test/UsefulBuf_Tests.h test/float_tests.h test/run_tests.h test/qcbor_encode_tests.h test/qcbor_decode_tests.h inc/qcbor/qcbor_private.h
test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor/UsefulBuf.h
Expand Down
10 changes: 8 additions & 2 deletions QCBOR.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
E776E091214AE07500E67947 /* qcbor_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08E214AE07500E67947 /* qcbor_decode.c */; };
E776E097214AE0C700E67947 /* cmd_line_main.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E096214AE0C700E67947 /* cmd_line_main.c */; };
E7864766252CE63100A0C11B /* qcbor_err_to_str.c in Sources */ = {isa = PBXBuildFile; fileRef = E7864765252CE63100A0C11B /* qcbor_err_to_str.c */; };
E7C960B92800A09E00FB537C /* ub-example.c in Sources */ = {isa = PBXBuildFile; fileRef = E7C960B82800A09E00FB537C /* ub-example.c */; };
E7FDBF04256C969D007138A8 /* qcbor_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08C214AE07400E67947 /* qcbor_encode.c */; };
E7FDBF05256C969D007138A8 /* ieee754.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B57582161CA690080D658 /* ieee754.c */; };
E7FDBF06256C969D007138A8 /* qcbor_err_to_str.c in Sources */ = {isa = PBXBuildFile; fileRef = E7864765252CE63100A0C11B /* qcbor_err_to_str.c */; };
Expand Down Expand Up @@ -170,13 +171,15 @@
E776E08D214AE07500E67947 /* UsefulBuf.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = UsefulBuf.c; path = src/UsefulBuf.c; sourceTree = "<group>"; tabWidth = 3; };
E776E08E214AE07500E67947 /* qcbor_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_decode.c; path = src/qcbor_decode.c; sourceTree = "<group>"; tabWidth = 3; };
E776E094214AE09700E67947 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/UsefulBuf.h; sourceTree = "<group>"; tabWidth = 3; };
E776E096214AE0C700E67947 /* cmd_line_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cmd_line_main.c; sourceTree = "<group>"; };
E776E096214AE0C700E67947 /* cmd_line_main.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; path = cmd_line_main.c; sourceTree = "<group>"; tabWidth = 3; };
E776E161214EE19C00E67947 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
E7864765252CE63100A0C11B /* qcbor_err_to_str.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_err_to_str.c; path = src/qcbor_err_to_str.c; sourceTree = "<group>"; };
E78C91DE240C90C100F4CECE /* qcbor_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_decode.h; path = inc/qcbor/qcbor_decode.h; sourceTree = "<group>"; tabWidth = 3; };
E78C91DF240C90C100F4CECE /* qcbor_common.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_common.h; path = inc/qcbor/qcbor_common.h; sourceTree = "<group>"; tabWidth = 3; };
E78C91E0240C90C100F4CECE /* qcbor_private.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_private.h; path = inc/qcbor/qcbor_private.h; sourceTree = "<group>"; tabWidth = 3; };
E78C91E1240C90C100F4CECE /* qcbor_encode.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = qcbor_encode.h; path = inc/qcbor/qcbor_encode.h; sourceTree = "<group>"; tabWidth = 3; };
E7C960B72800A09E00FB537C /* ub-example.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ub-example.h"; sourceTree = "<group>"; };
E7C960B82800A09E00FB537C /* ub-example.c */ = {isa = PBXFileReference; indentWidth = 3; lastKnownFileType = sourcecode.c.c; path = "ub-example.c"; sourceTree = "<group>"; tabWidth = 3; };
E7FDBF16256C969D007138A8 /* QCBOR_Disable_Indef */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Indef; sourceTree = BUILT_PRODUCTS_DIR; };
E7FDBF2C257A6C1F007138A8 /* QCBOR_Disable_Indef_array */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Indef_array; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -230,8 +233,10 @@
E743D0E024AC51470017899F /* example */ = {
isa = PBXGroup;
children = (
E743D0E124AC516D0017899F /* example.c */,
E743D0F224AC54600017899F /* example.h */,
E743D0E124AC516D0017899F /* example.c */,
E7C960B72800A09E00FB537C /* ub-example.h */,
E7C960B82800A09E00FB537C /* ub-example.c */,
);
name = example;
sourceTree = "<group>";
Expand Down Expand Up @@ -525,6 +530,7 @@
E776E090214AE07500E67947 /* UsefulBuf.c in Sources */,
0FA9BEBA216DC7AD00BA646B /* qcbor_encode_tests.c in Sources */,
E776E097214AE0C700E67947 /* cmd_line_main.c in Sources */,
E7C960B92800A09E00FB537C /* ub-example.c in Sources */,
E743D0F324AD08020017899F /* example.c in Sources */,
0FA9BEBD216DE31700BA646B /* UsefulBuf_Tests.c in Sources */,
);
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ few days.

When the fix has been created, it will be privately verified with the party that reported it.
Only after the fix has been verified and the reporter has had a chance to integrate the fix,
will be be made available as a public commit in GitHub.
will it be made available as a public commit in GitHub.

If the reporter doesn't respond or can't integrate the fix, it will be made public after 30 days.

2 changes: 2 additions & 0 deletions cmd_line_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <stdio.h>
#include "run_tests.h"
#include "example.h"
#include "ub-example.h"


/*
Expand All @@ -33,6 +34,7 @@ int main(int argc, const char * argv[])
(void)argc; // Avoid unused parameter error

RunQCborExample();
RunUsefulBufExample();


// This call prints out sizes of data structures to remind us
Expand Down
260 changes: 260 additions & 0 deletions ub-example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
/* =========================================================================
ub-example.c -- Example code for UsefulBuf

Copyright (c) 2022, Laurence Lundblade. All rights reserved.

SPDX-License-Identifier: BSD-3-Clause

See BSD-3-Clause license in README.md

Created on 4/8/22
========================================================================== */

#include "ub-example.h"

#include "UsefulBuf.h"


/*
* A considerable number of the security issues with C code come from
* mistakes made with pointers and lengths. UsefulBuf adopts a
* convention that a pointer and length *always* go together to help
* mitigate this. With UsefulBuf there are never pointers without
* lengths, so you always know how big a buffer or some binary data
* is.
*
* C99 allows passing structures so a structure is used. Compilers are
* smart these days so the object code produced is little different
* than passing two separate parameters. Passing structures also makes
* the interfaces prettier. Assignments of structures also can make
* code prettier.
*
* ALong with the UsefulBuf structure, there are a bunch of (tested!)
* functions to manipulate them so code using it may have no pointer
* manipulation at all.
*
* Constness is also a useful and desirous thing. See
* https://stackoverflow.com/questions/117293/use-of-const-for-function-parameters
* Keeping const distinct from non-const is helpful when reading the
* code and helps avoid some coding mistakes. In this example the
* buffers filled in with data are const and the ones that are
* to-be-filled in are not const.
*
* This contrived example copies data from input to output expanding
* bytes with the value 'x' to 'xx'.
*
* Input -- This is the pointer and length of the input, the bytes to
* copy. Note that UsefulBufC.ptr is a const void * indicating that
* input data won't be changed by this function. There is a "C" in
* "UsefulBufC "to indicate the value is const. The length here is
* the length of the valid input data. Note also that the parameter
* Input is const, so this is fully const and clearly an [in]
* parameter.
*
* OutputBuffer -- This is a pointer and length of the memory to be
* used to store the output. The correct length here is critical for
* code security. Note that UsefulBuf.ptr is void *, it is not const
* indicating data can be written to it. Note that the parameter
* itself *is* const indicating that the code below will not point
* this to some other buffer or change the length and clearly marking
* it as an [in] parameter.
*
* Output -- This is the interesting and unusual one. To stay
* consistent with always pairing a length and a pointer, this is
* returned as a UsefulBuC. Also, to stay consistent with valid data
* being const, it is a UsefulBufC, not a UsefulBuf. It is however, an
* [out] parameter so the parameter is a pointer to a UsefulBufC.
*
* In this case and most cases, the pointer in Output->ptr will be the
* same as OutputBuffer.ptr. This may seem redundant, but there are a
* few reasons for it. First, is the goal of always pairing a pointer
* and a length. Second is being more strict and correct with
* constness. Third is the code hygiene and clarity of having
* variables for to-be-filled buffers be distinct from those
* containing valid data. Fourth, there are no [in,out] parameters,
* only [in] parameters and [out] parameters (the to-be-filled-in
* buffer is considered an [in] parameter).
*
* Note that the compiler will be smart and should generate pretty
* much the same code as for a traditional interface. On x86 with
* gcc-11 and no stack guards, the UB code is 81 bytes and the
* traditional code is 77 bytes.
*
* Finally, this supports computing of the length of the would-be
* output without actually doing any outputting. Pass {NULL, SIZE_MAX}
* for the OutputBuffer and the length will be returned in Output.
*/
int
ExpandxUB(const UsefulBufC Input,
const UsefulBuf OutputBuffer,
UsefulBufC *Output)
{
size_t nInputPosition;
size_t nOutputPosition;

nOutputPosition = 0;

/* Loop over all the bytes in Input */
for(nInputPosition = 0; nInputPosition < Input.len; nInputPosition++) {
const uint8_t nInputByte = ((uint8_t*)Input.ptr)[nInputPosition];

/* Copy every byte */
if(OutputBuffer.ptr != NULL) {
((uint8_t *)OutputBuffer.ptr)[nOutputPosition] = nInputByte;
}
nOutputPosition++;
if(nOutputPosition >= OutputBuffer.len) {
return -1;
}

/* Double output 'x' because that is what this contrived example does */
if(nInputByte== 'x') {
if(OutputBuffer.ptr != NULL) {
((uint8_t *)OutputBuffer.ptr)[nOutputPosition] = 'x';
}
nOutputPosition++;
if(nOutputPosition >= OutputBuffer.len) {
return -1;
}
}
}

*Output = (UsefulBufC){OutputBuffer.ptr, nOutputPosition};

return 0; /* success */
}


/* This is the more tradional way to implement this. */
int
ExpandxTraditional(const uint8_t *pInputPointer,
const size_t uInputLength,
uint8_t *pOutputBuffer,
const size_t uOutputBufferLength,
size_t *puOutputLength)
{
size_t nInputPosition;
size_t nOutputPosition;

nOutputPosition = 0;

/* Loop over all the bytes in Input */
for(nInputPosition = 0; nInputPosition < uInputLength; nInputPosition++) {
const uint8_t nInputByte = ((uint8_t*)pInputPointer)[nInputPosition];

/* Copy every byte */
if(pOutputBuffer != NULL) {
((uint8_t *)pOutputBuffer)[nOutputPosition] = nInputByte;
}
nOutputPosition++;
if(nOutputPosition >= uOutputBufferLength) {
return -1;
}

/* Double output 'x' because that is what this contrived example does */
if(nInputByte== 'x') {
if(pOutputBuffer != NULL) {
((uint8_t *)pOutputBuffer)[nOutputPosition] = 'x';
}
nOutputPosition++;
if(nOutputPosition >= uOutputBufferLength) {
return -1;
}
}
}

*puOutputLength = nOutputPosition;

return 0; /* success */
}


/*
* Here's an example of going from a traditional interface
* interface to a UsefulBuf interface.
*/
int
ExpandxTraditionalAdaptor(const uint8_t *pInputPointer,
size_t uInputLength,
uint8_t *pOutputBuffer,
size_t uOutputBufferLength,
size_t *puOutputLength)
{
UsefulBufC Input;
UsefulBuf OutputBuffer;
UsefulBufC Output;
int nReturn;

Input = (UsefulBufC){pInputPointer, uInputLength};
OutputBuffer = (UsefulBuf){pOutputBuffer, uOutputBufferLength};

nReturn = ExpandxUB(Input, OutputBuffer, &Output);

*puOutputLength = Output.len;

return nReturn;
}


/* Here's an example for going from a UsefulBuf interface
to a traditional interface. */
int
ExpandxUBAdaptor(const UsefulBufC Input,
const UsefulBuf OutputBuffer,
UsefulBufC *Output)
{
Output->ptr = OutputBuffer.ptr;

return ExpandxTraditional(Input.ptr, Input.len,
OutputBuffer.ptr, OutputBuffer.len,
&(Output->len));
}



#define INPUT "xyz123xyz"

int32_t RunUsefulBufExample()
{
/* ------------ UsefulBuf examples ------------- */
UsefulBufC Input = UsefulBuf_FROM_SZ_LITERAL(INPUT);

/* This macros makes a 20 byte buffer on the stack. It also makes
* a UsefulBuf on the stack. It sets up the UsefulBuf to point to
* the 20 byte buffer and sets it's length to 20 bytes. This
* is the empty, to-be-filled in memory for the output. It is not
* const. */
MakeUsefulBufOnStack(OutBuf, sizeof(INPUT) * 2);

/* This is were the pointer and the length of the completed output
* will be placed. Output.ptr is a pointer to const bytes. */
UsefulBufC Output;

ExpandxUB(Input, OutBuf, &Output);

ExpandxUBAdaptor(Input, OutBuf, &Output);



/* ------ Get Size example -------- */
ExpandxUB(Input, (UsefulBuf){NULL, SIZE_MAX}, &Output);

/* Size is in Output.len */



/* ---------- Traditional examples (for comparison) --------- */
uint8_t puBuffer[sizeof(INPUT) * 2];
size_t uOutputSize;

ExpandxTraditional((const uint8_t *)INPUT, sizeof(INPUT),
puBuffer, sizeof(puBuffer),
&uOutputSize);


ExpandxTraditionalAdaptor((const uint8_t *)INPUT, sizeof(INPUT),
puBuffer, sizeof(puBuffer),
&uOutputSize);

return 0;
}
19 changes: 19 additions & 0 deletions ub-example.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* =========================================================================
ub-example.h -- Example code for UsefulBuf

Copyright (c) 2022, Laurence Lundblade. All rights reserved.

SPDX-License-Identifier: BSD-3-Clause

See BSD-3-Clause license in README.md

Created on 4/8/22
========================================================================== */
#ifndef ub_example_h
#define ub_example_h

#include <stdint.h>

int32_t RunUsefulBufExample(void);

#endif /* ub_example_h */