Arithmetic pitfalls and dragons

Killing dragons spawned by arithmetic-related security pitfalls Date: 02/12/2016

The Black & Scholes

In the last week, which followed my attempt to earn money with financial trading, I glanced through the Black & Scholes model. This study resulted in the creation of OptionsCat, an open-source tool to work with European options. I faced many Arithmetic-related security pitfalls when writing this tool, which motivated me to study it and write a blog post.

Motivation

One motivation for writing custom software in C language for calculating the Black-Scholes model for stock options is that C is a highly efficient and powerful programming language. It is often used for performance-critical applications, such as financial modelling and other numerical computing tasks because it allows you to write code that is fast, compact, and portable.

Another motivation for using C is that it is widely supported and used in the financial industry. Many financial institutions and trading firms use C for their software development, so using C can make it easier for you to integrate your software with existing systems and workflows.

Finally, using C for your custom software can also be a challenging and rewarding learning experience. It can help you improve your programming skills and knowledge of finance and mathematics, and it can be a fun and exciting way to explore new technologies and techniques.

Security point view

I always develop my implementations for the algorithms presented throughout the finance books. That's because the writers are often careless about security pitfalls. From this article's perspective, this is a problem or dragon that can be solved by adding a chapter about validation.

Programming languages that enable direct memory access and do not provide buffer boundary checks and arithmetic numeric checks are particularly vulnerable to integer overflow attacks. An integer overflow may occur when computing the memory size to allocate a buffer, often leading to a buffer overflow.

Integer overflow

The integer overflow occurs when the result of an operation on two integers exceeds the maximum or minimum value that the integer data type can represent. In C, C++, and Objective-C, the integer data types have fixed sizes and ranges of values, so if the result of an operation falls outside of this range, it will overflow and produce an incorrect result.

One potential risk of integer overflow is that it can lead to unpredictable and potentially dangerous behaviour in your program. For example, if an overflow occurs in a critical part of your code, such as a calculation that determines the size of a buffer, it can cause your program to crash or to behave erratically. This can result in lost data, productivity, and other negative consequences.

Another risk of integer overflow is that it can be a security vulnerability. If an attacker can cause an integer overflow in your program, they may be able to exploit it to gain access to sensitive information or to take control of your program. This can result in data breaches, unauthorized access, and other security incidents.

To avoid the risks of integer overflow, it is essential to carefully design and tests your code to ensure that it handles integer values correctly and avoids overflow. This can include using appropriate data types, checking for overflow before performing operations, and using other techniques to prevent or handle overflow situations.

Blexim quote

"Integer overflows cannot be detected after they have happened, so there is not way for an application to tell if a result it has calculated previously is in fact correct. This can get dangerous if the calculation has to do with the size of a buffer or how far into an array to index. Of course most integer overflows are not exploitable because memory is not being directly overwritten, but sometimes they can lead to other classes of bugs, frequently buffer overflows. As well as this, integer overflows can be difficult to spot, so even well audited code can spring surprises."

by blexim - Phrack Volume 0x0b, Issue 0x3c, Phile #0x0a of 0x10

Sometimes programmers talk to me about the use of the Big integer library. Like LibGMP to solve it, but when you work with big int need limit those numbers. Arithmetic operations with big int when a user sends an input with a considerable length can cause Denial of service. Libgmp is a library for arbitrary-precision arithmetic, which provides functions for performing mathematical operations on numbers with many digits. This can be useful for applications that require a high degree of precision, such as cryptography or scientific computing.

However, libgmp does not solve the problem of integer overflow. The integer overflow occurs when the result of an operation on two integers exceeds the maximum or minimum value that the integer data type can represent. This can happen regardless of the number of digits in the numbers involved, and it is a separate issue from the precision of the numbers.

To avoid the risks of integer overflow, you can use libgmp to perform arbitrary-precision arithmetic, which can help you avoid losing precision in your calculations. However, you will still need to carefully design and test your code to ensure that it handles integer values correctly and avoids overflow. This can include using appropriate data types, checking for overflow before performing operations, and using other techniques to prevent or handle overflow situations.

The use of Integers is not hard to find in the stock markets. But double is then expected and can bring us a problem if we don't control the length, for example:

#include < math.h>
#include < stdio.h> 

double mul_code(double x,double y) 
{
  double result=0;
   
  return result = x*y;
}

int main()
{
 double a=90000000000, b=20000000000000;

 printf("Result: %f\n", mul_code(a,b));
 return 0;
}

If you compile it and run it, it returns something like "1799999999999999916112.*(dirts...)". Anyone asks me, "why to return it ?", you don't validate the operation and have not passed the carrying limit. This causes undefined behaviour, overflow and soon. Here be dragons!!

Killing dragons in integers

There are lots of ways for us to solve that point. One is validating user input. This way, you can use automatons, regular expressions, and strnlen() to limit the number of lengths. Remember phrack; the correct way to test for integer overflow during multiplication is to test before the multiplication, test if the number is negative, and replace functions like atoi() to strtol().

Some operating systems have solutions at libraries to mitigate the problem. For example, OSX has os/overflow.h. With this header, you can do something like it:

/* os_mul3_overflow(a, b, c) -> (a * b * c) */
#define os_mul3_overflow(a, b, c, res) __os_warn_unused(__extension__({ \
	__typeof(*(res)) _tmp; \
	bool _s, _t; \
	_s = os_mul_overflow((a), (b), &_tmp); \
	_t = os_mul_overflow((c), _tmp, (res)); \
	_s | _t; \
}))

Another way to mitigate this way is from OpenBSD:

Other approaches that we can see is the using libraries and other ways to write safe code with integers, sometimes calling each function safe_add(), safe_sub(), safe_mul(), and safe_div() is very boring when having significant expressions. Thinking about it, I wrote a solution; look at my project Here!

Killing dragons in double

The Cert C book by Robert Seacord has an example of solving the problem at the double. The derivatives and futures have many operations with double. One way to detect possible bugs is using the function fetestexcept().

double call_gamma(const double S, const double K, const double r, const double v, const double T) 
{
  	double ret = norm_pdf(d_j(1, S, K, r, v, T))/(S*v*sqrt(T));

	int fpeRaised=0;

	fpeRaised=fetestexcept(FE_INVALID | FE_DIVBYZERO |FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT);

	  	if(fpeRaised!=32 && fpeRaised!=0)
		{
			DEBUG("error here!");
	   		perror("Log: \n");
			exit(0);
		}

  	fpeRaised=feclearexcept(FE_ALL_EXCEPT);

	return ret;
}

At inputs don't use atof() function. Replace with strtod(), other examples with the double look are the following code here.

References

Note: Gcc provides Built-in Functions to Perform Arithmetic with Overflow Checking.

Thank you for reading.

Cheers!

Last updated