Interesting article posted in the ACM TechNews feed about “popular” languages and common coding errors. Fortran was not mentioned - in this case not being popular might be for the best.
Fortran: Security by Obscurity.
But now I’m trying to imagine what could a cyberattack on a Fortran application look like. I don’t think many Fortran apps work with user data. I imagine injecting numerical errors into the opponents weather prediction system, subtle enough to not crash the simulation, but large enough to cause a very different forecast a day ahead.
Does anyone know of some real Fortran vulnerabilities being exploited in the past?
Interesting observation, though I don’t think the main focus of the article was cyber security, but rather common programming mistakes. Possibly relevant for the evolution of Fortran in that we should be cautious about copying a feature design from a different language if that feature commonly causes problems there.
I was particularly amused by the paragraph that says [errors found in C++ codes are decreasing mainly] “because C++ is becoming less prevalent.”
Les Hatton has studied errors in C, C++, and Fortran 77 scientific software – some papers are here. His collaborator Tim Hopkins co-authored Numerical Computing With Modern Fortran (2013). One hopes that Fortran 90+ features such as modules have reduced the frequency of defects.
When I read only the title and not the article, I get what I deserve…
You’re right in pointing out to @milancurcic the “security flaw” mentioned in this report are actually program and coding vulnerabilities as shown in this “heat map” in the underlying report behind the article:
However, @milancurcic is correct when it comes to Fortran that it escapes scrutiny due to obscurity.
Readers should pay close attention to the items on the C++ list: error handling
, numeric errors
, code quality
, race condition
, buffer overflow
, etc. And note Fortran codes are especially vulnerable to all the issues associated with C++ (and other compiled languages also on the list) but often in worse ways. Consider race condition
: imagine how the “implied” SAVE attribute with object initialization in type declaration statements that can hurt thread-safety unbeknownst to a programmer.
In fact, almost any funding authority - whether in industry or outside e.g., large governmental research or international agencies, etc. - will not consider Fortran for any NEW medium to large application using modern Fortran today or in the near future, especially if avoidance of code vulnerabilities is paramount to the effort and if 2 or more developers are needed, let alone for efforts requiring tens or hundreds or thousands of developers.
And something all the Fortran standard-bearers should keep in mind: the vulnerabilities in Fortran also have to do with the standard deferring a lot of aspects to the processors, cue all the things which are left as “processor-dependent” in the language standard. These all come at their own cost also, mostly hidden but often via extreme fragmentation
.
Just one case in point: the discussions and difficulties around better and clearer handling of finalization of finalizable objects in Fortran c.f. [J3] [EXTERNAL] Re: Clarification on F18/017.
Fortran is lucky the adoption of object-oriented (OO) paradigm in its codes is still in its infancy and so many codes and developer approaches are still following the procedural style of legacy FORTRAN. However, an OO foundation is a great enabler of collaborative development and also other paradigms including parallel programming (c.f. Numrich book on COARRAYs) and as such, it is paramount to modern codes. But now, should it be adopted more often, the issues around finalization will be at the fore among other issues with OO in Fortran (see below for an example). And Fortran will be found particularly vulnerable per the very same yardsticks mentioned in the article in the original post here.
And my view is decidedly this: Fortran should not shy away from the key features - say OO - just because others or Fortran itself faced vulnerabilities. Same with generic programming, exception handling, etc., features that got deferred again with Fortran 202X.
Rather, Fortran should strive to do better by focusing not just on performance but also programmer productivity and program protection.
An example of this is my proposal to be able to derive an inextensible type in Fortran: https://j3-fortran.org/doc/year/19/19-186.txt. That is, having an ability to “seal” a class (a ka derived type) to prevent it from being extended (subclassed). Fortran currently marks every derived type as extensible, leaving the door wide open for deep hierarchies in libraries, and across libraries, possibly even an infinite chain of hierarchies. This is an aspect that leads to significant vulnerabilities in programs. Pretty much every programming language including Python recently has realized the dangers with this and offer options such as “FINAL” or “SEALED” to library developers. This is something that can immediately prove valuable in the context of Fortran stdlib
effort, especially for the time when the volunteers realize developing a standard library for Fortran in Fortran-only can prove rather limiting and just like how certain useful intrinsics like ABS and MAX (variable argument lists) spring forth via some “magic”, valuable facilities will necessitate other solution approaches beyond Fortran-only which will then make prudent the “protecting” of stdlib solutions, say in terms of the way C++ does with STL and marks them as off-limits for subclassing, etc.
It is a rather simple matter which will not take too much effort to include in the standard. Yet it’s going to take an inordinate amount of effort to get it added, unfortunately. But this just shows how vulnerabilities come about in Fortran and which are yet hidden on account of the very small domain of Fortran users compared to other languages.
About security, see also What about security issues in Fortran?
In the thread which @vmagnin linked, Steve mentions an ISO document demonstrating several Fortran vulnerabilities. Some scenarios are quite interesting like
use iso_c_binding ! potentially exploitable
use, intrinsic :: iso_c_binding ! safer
The idea here is that one might inadvertently use a non-intrinsic iso_c_binding
containing malicious code.
Thanks @billlong for sharing the article.
Maybe the Use iso_c_binding is not much of a real risk but I just did a global search on the application I am working on and found 142 occurrences with “intrinsic” and 5 without. I prefer to add as many safety guards as possible to my code so fixed
I have found in my new Metcalf’s that we can even write:
use, intrinsic :: iso_c_binding, only: c_int
I have updated some of my projects with such commands:
$ find . -iname *.f90 -exec sed -i 's/use iso_c_binding/use, intrinsic :: iso_c_binding/' '{}' \;
Here, find
will recursively search all the .f90
files in a project and apply the following sed
command to replace the string use iso_c_binding
by use, intrinsic :: iso_c_binding
. The option -i
means --in-place
: the file is modified instead of begin written on the standard output. And '{}'
will be replaced by the path of each Fortran file.
We have assumed that all was written in lowercase, but you can also use the \|
operator (an escaped |) to search variants. The parenthesis around each expression are also escaped:
$ find . -iname *.f90 -exec sed -i 's/\(use iso_fortran_env\)\|\(use ISO_FORTRAN_ENV\)/use, intrinsic :: iso_fortran_env/' '{}' \;
I have tested on some projects.
Of course, you should first make a test on a copy of your project, as all files will me modified without asking confirmation.
Note: there is three other intrinsic modules, the IEEE modules.
The Mariner/Mercury bug in FORTRAN code:
There is a useful lesson to be learned from the failure of one of the earliest planetary probes launched by NASA. The cause of the failure was eventually traced to a statement in its control software similar to this:
DO 15 I = 1.100
when what should have been written was:
DO 15 I = 1,100
but somehow a dot had replaced the comma. Because Fortran ignores spaces, this was seen by the compiler as:
DO15I = 1.100
which is a perfectly valid assignment to a variable called DO15I and not at all what was intended.Fortran77 permits an additional comma to be inserted after the label in a DO statement, so it could now be written as:
DO 15,I = 1,100
which has the great advantage that it is no longer as vulnerable to a single-point failure.There are many hazards of this sort in Fortran, but the risk of falling victim to them can be minimised by adopting the programming practices of more experienced users.
(source)
Wikipedia says:
In other accounts, the bug consisted of:
- A period typed in place of a comma, causing a FORTRAN DO loop statement to be misinterpreted (although there is no evidence that FORTRAN was used in the mission), of the form “DO 5 K=1. 3” interpreted as assignment “DO5K = 1.3”. There are anecdotal reports that there was, in fact, such a bug in a NASA orbit computation program at about this time, but it was a program for Project Mercury, not Mariner, and the claim was that the bug was noticed and fixed before any serious consequences resulted.
- A missing comma.
- An extraneous semicolon.
Note that this issue with spaces is a feature of the fixed-source form for statements in Fortran. In the current Fortran standard this is considered obsolescent. (So is using a statement number as part of a DO statement, although omitting the statement label does not “solve” this problem as does the use of free-source form. .)