Jump to page: 1 24  
Page
Thread overview
std.file functions and embedded NUL characters [CWE-158]
Jul 31
kdevel
Jul 31
Doigt
Jul 31
Doigt
Jul 31
Doigt
Jul 31
monkyyy
Jul 31
Doigt
Jul 31
kdevel
Jul 31
Doigt
Jul 31
monkyyy
Jul 31
monkyyy
6 days ago
Kagamin
Jul 31
kdevel
Jul 31
kdevel
6 days ago
Sönke Ludwig
Jul 31
monkyyy
Aug 01
0xEAB
Aug 01
monkyyy
Aug 01
monkyyy
Aug 01
kdevel
Aug 03
kdevel
5 days ago
kdevel
Jul 31
Doigt
July 31
Some python code:

   #!/usr/bin/python

   def myfun (filename):
      open (filename, 'w')

   myfun ("a\0c")

which when executed behaves in an exemplary manner:

   Traceback (most recent call last):
     File "./test.py", line 6, in <module>
       myfun ("a\0c")
     File "./test.py", line 4, in myfun
       open (filename, 'w')
   TypeError: file() argument 1 must be encoded string without null
   bytes, not str

Other languages like D, perl or even Ada seem to let the embedded NUL
character silently truncate the filename. This poses a considerable
risk when the input to std.file functions is not controlled by the
program author [1]. E.g.

   rmdirRecurse ("/\0/home/user/subdir");

[1] https://cwe.mitre.org/data/definitions/158.html
July 31
On Thursday, 31 July 2025 at 20:45:14 UTC, kdevel wrote:
> Some python code:
>
>    #!/usr/bin/python
>
>    def myfun (filename):
>       open (filename, 'w')
>
>    myfun ("a\0c")
>
> which when executed behaves in an exemplary manner:
>
>    Traceback (most recent call last):
>      File "./test.py", line 6, in <module>
>        myfun ("a\0c")
>      File "./test.py", line 4, in myfun
>        open (filename, 'w')
>    TypeError: file() argument 1 must be encoded string without null
>    bytes, not str
>
> Other languages like D, perl or even Ada seem to let the embedded NUL
> character silently truncate the filename. This poses a considerable
> risk when the input to std.file functions is not controlled by the
> program author [1]. E.g.
>
>    rmdirRecurse ("/\0/home/user/subdir");
>
> [1] https://cwe.mitre.org/data/definitions/158.html

Do you actually have a source or an example program that D actually does anything with the null terminator or are you talking out of your ass? D doesn't care about the null terminator and doesn't do anything with it.

Try this code on run.dlang.io and report back with your apology:
import std.stdio;
void main()
{
    writeln("Hello\0World\0!");
}
July 31
On Thu, Jul 31, 2025 at 09:25:44PM +0000, Doigt via Digitalmars-d wrote:
> On Thursday, 31 July 2025 at 20:45:14 UTC, kdevel wrote:
[...]
> > Other languages like D, perl or even Ada seem to let the embedded NUL character silently truncate the filename. This poses a considerable risk when the input to std.file functions is not controlled by the program author [1]. E.g.
> > 
> >    rmdirRecurse ("/\0/home/user/subdir");
> > 
> > [1] https://cwe.mitre.org/data/definitions/158.html
> 
> Do you actually have a source or an example program that D actually does anything with the null terminator or are you talking out of your ass? D doesn't care about the null terminator and doesn't do anything with it.

This tone is uncalled for.  OP is specifically pointing the issue with passing NUL-containing strings to underlying OS calls.  For example:

```
void main() {
	auto fp = File("/tmp/x\0reallynow", "w");
	// What's the filename of the created file?
}
```


T

-- 
Last night, I dreamed about my pet rabbits all lined up like in a parade, and hopping backwards. Then I woke up and realized that it was my receding hare line!
July 31
On Thursday, 31 July 2025 at 21:25:44 UTC, Doigt wrote:
> On Thursday, 31 July 2025 at 20:45:14 UTC, kdevel wrote:
>> Some python code:
>>
>>    #!/usr/bin/python
>>
>>    def myfun (filename):
>>       open (filename, 'w')
>>
>>    myfun ("a\0c")
>>
>> which when executed behaves in an exemplary manner:
>>
>>    Traceback (most recent call last):
>>      File "./test.py", line 6, in <module>
>>        myfun ("a\0c")
>>      File "./test.py", line 4, in myfun
>>        open (filename, 'w')
>>    TypeError: file() argument 1 must be encoded string without null
>>    bytes, not str
>>
>> Other languages like D, perl or even Ada seem to let the embedded NUL
>> character silently truncate the filename. This poses a considerable
>> risk when the input to std.file functions is not controlled by the
>> program author [1]. E.g.
>>
>>    rmdirRecurse ("/\0/home/user/subdir");
>>
>> [1] https://cwe.mitre.org/data/definitions/158.html
>
> Do you actually have a source or an example program that D actually does anything with the null terminator or are you talking out of your ass? D doesn't care about the null terminator and doesn't do anything with it.
>
> Try this code on run.dlang.io and report back with your apology:
> import std.stdio;
> void main()
> {
>     writeln("Hello\0World\0!");
> }

D does nothing with the NULL terminator, but I think the argument here is that for many file operations, the filename string eventually gets converted to a C string before it is passed to an API (C stdlib? syscall?) where the null terminator is significant.

It is best NOT to be rude and nasty, but if you are, you should at least understand the technical argument
August 01
This is quite a good example of why for PhobosV3 I want us to go through a FilePath abstraction, rather than accepting random strings for file names.

This is indeed a security vulnerability, but it isn't on D's side.
All system API's take in a null terminated string, when it should've been pointer + length.

If someone has a problem with this currently, you can call ``isValidPath`` in ``std.path``, which will check for the null character.

https://dlang.org/phobos/std_path.html#isValidPath
July 31
On Thursday, 31 July 2025 at 21:25:44 UTC, Doigt wrote:
> [...]
> Do you actually have a source or an example program that D actually does anything with the null terminator

I did not argue that D "does" something "with the null terminator".
D like perl or Ada ignores the potential occurrence of NUL in the
string data when calling the underlying C functions for file system
operations.

   import std;

   void main ()
   {
      File ("abc", "w");
      std.file.rename ("abc", "ab\0c");
   }

Instead of throwing as the python code does this D program leaves
a file named "ab" in the filesystem.
July 31
On Thursday, 31 July 2025 at 21:47:24 UTC, Richard (Rikki) Andrew Cattermole wrote:
> This is quite a good example of why for PhobosV3 I want us to go through a FilePath abstraction, rather than accepting random strings for file names.

whats wrong with just changing toStringz? I dont understand the threat profile imagined by the infinitely wise cve org; but you could make toStringz:

a) shorten it to the first null char
b) replace null with something
c) (bad idea but youll love it) assert when detecting extra null
July 31
On Thursday, 31 July 2025 at 20:45:14 UTC, kdevel wrote:
> Some python code:
>
>    #!/usr/bin/python
>
>    def myfun (filename):
>       open (filename, 'w')
>
>    myfun ("a\0c")
>
> which when executed behaves in an exemplary manner:
>
>    Traceback (most recent call last):
>      File "./test.py", line 6, in <module>
>        myfun ("a\0c")
>      File "./test.py", line 4, in myfun
>        open (filename, 'w')
>    TypeError: file() argument 1 must be encoded string without null
>    bytes, not str
>
> Other languages like D, perl or even Ada seem to let the embedded NUL
> character silently truncate the filename. This poses a considerable
> risk when the input to std.file functions is not controlled by the
> program author [1]. E.g.
>
>    rmdirRecurse ("/\0/home/user/subdir");
>
> [1] https://cwe.mitre.org/data/definitions/158.html

https://github.com/dlang/phobos/blob/205256abb1f86faf986f8c789cb733ca4137246e/std/string.d#L368

are you sure? Im not entirely sure if this will always trigger but theres asserts here
July 31
On Thursday, 31 July 2025 at 21:47:24 UTC, Richard (Rikki) Andrew Cattermole wrote:
> This is indeed a security vulnerability, but it isn't on D's side.
> All system API's take in a null terminated string, when it should've been pointer + length.

The cause of the problem is the silent truncation when the conversion
from D-string to C-const char * takes place. This is not a problem of
the API which is in the case of POSIX is totally simple (compared to
all the VMS/Windows APIs).

There must be a reason why C++ uses const char* in its filesystem functions [1].

> If someone has a problem with this currently, you can call ``isValidPath`` in ``std.path``, which will check for the null character.

Unfortunately isValidPath also flags perfectly legal filenames
as invalid, e.g. such containing invalid UTF-8 sequences.

[1] https://en.cppreference.com/w/cpp/header/iostream.html
July 31
On Thursday, 31 July 2025 at 22:38:41 UTC, kdevel wrote:
> Unfortunately isValidPath also flags perfectly legal filenames
> as invalid, e.g. such containing invalid UTF-8 sequences.

I stand corrected. This is probably not true:

ivp.d:
```
   import std;

   void main (string [] args)
   {
      auto input = "a\xfc";
      writeln (input, ": ", isValidPath (input));
   }
```

$ ./ivp [latin9 mode console]
aü: true

« First   ‹ Prev
1 2 3 4