TL;DR it's TERMINFO related or when ~/.terminfo exists and no TERM file
exists therein. Also trying to read "none" (or maybe also "none.db" when
the TERMINFO thing happens) from the current working directory might not
be a good idea, if an attacker can put naughty things into either of
those files and a sh or ksh or whatever is run in a suitable directory?

On 2024-04-08 15:30:11 +0000, Jeremy Mates wrote:
>  79510 ksh      NAMI  "none.db"
>  79510 ksh      RET   open -1 errno 2 No such file or directory
>  79510 ksh      CALL  mprotect(0x4e89f6c1000,0x1000,0x3<PROT_READ|PROT_WRITE>)
>  79510 ksh      RET   mprotect 0
>  79510 ksh      CALL  mprotect(0x4e89f6c1000,0x1000,0x1<PROT_READ>)
>  79510 ksh      RET   mprotect 0
>  79510 ksh      CALL  open(0x744b97b1eed0,0x10000<O_RDONLY|O_CLOEXEC>)
>  79510 ksh      NAMI  "none"
>  79510 ksh      RET   open -1 errno 2 No such file or directory
>  79510 ksh      CALL  sendsyslog(0x744b97b1c140,35,0<>)
>  79510 ksh      GIO   fd -1 wrote 35 bytes
>        "<10>ksh: vfprintf %s NULL in "%.*s""

There are two instances of "none" in the ncurses code; setting TERMPATH
to "yyyy" and recompiling results in hits for "yyyy.db" in my custom
(and very incomplete) ~/.terminfo directory where to tigger this error
~/.terminfo/r/rxvt-unicode-256color does not exist, but that file does
exist in /usr/share/terminfo (and also /usr/local/share/terminfo but
that looks to be last in the list and is not consulted).

     62759 rogue    CALL  fcntl(1,F_ISATTY)
     62759 rogue    RET   fcntl 1
    ... (various kbind calls removed)
     62759 rogue    CALL  issetugid()
     62759 rogue    RET   issetugid 0
    ...
     62759 rogue    CALL  issetugid()
     62759 rogue    RET   issetugid 0
    ...
     62759 rogue    CALL  stat(0xbd1b58b8700,0xbd1b5893c00)
     62759 rogue    NAMI  "/home/jmates/.terminfo"
     62759 rogue    STRU  struct stat { dev=1035, ino=9504797, mode=drwx------ 
, nlink=5, uid=1000<"jmates">, gid=1000<"jmates">, rdev=37949602, 
atime=1664240431<"Sep 27 01:00:31 2022">.902138053, mtime=1713140694<"Apr 15 
00:24:54 2024">.605888358, ctime=1713140694<"Apr 15 00:24:54 2024">.605888358, 
size=512, blocks=8, blksize=32768, flags=0x0, gen=0x0 }
     62759 rogue    RET   stat 0
     62759 rogue    CALL  stat(0xbd1b58b8717,0xbd1b5893c80)
     62759 rogue    NAMI  "/usr/share/terminfo"
     62759 rogue    STRU  struct stat { dev=1029, ino=77975, mode=drwxr-xr-x , 
nlink=44, uid=0<"root">, gid=0<"wheel">, rdev=347089, atime=1710969405<"Mar 20 
21:16:45 2024">, mtime=1710969405<"Mar 20 21:16:45 2024">, 
ctime=1712330397<"Apr  5 15:19:57 2024">.280403075, size=1024, blocks=4, 
blksize=16384, flags=0x0, gen=0x0 }
     62759 rogue    RET   stat 0
     62759 rogue    CALL  stat(0xbd1b58b872b,0xbd1b5893d00)
     62759 rogue    NAMI  "/usr/local/share/terminfo"
     62759 rogue    STRU  struct stat { dev=1031, ino=1398, mode=drwxr-xr-x , 
nlink=4, uid=0<"root">, gid=0<"wheel">, rdev=27828, atime=1664242579<"Sep 27 
01:36:19 2022">.894146606, mtime=1699341912<"Nov  7 07:25:12 2023">.868578098, 
ctime=1699341912<"Nov  7 07:25:12 2023">.868578098, size=512, blocks=4, 
blksize=16384, flags=0x0, gen=0x0 }
     62759 rogue    RET   stat 0
     62759 rogue    CALL  stat(0xbd1b58b8759,0xbd1b5893d80)
     62759 rogue    NAMI  "yyyy"
     62759 rogue    RET   stat -1 errno 2 No such file or directory
    ...
     62759 rogue    CALL  stat(0xbd1b58b8700,0x798526d4f508)
     62759 rogue    NAMI  "/home/jmates/.terminfo"
     62759 rogue    STRU  struct stat { dev=1035, ino=9504797, mode=drwx------ 
, nlink=5, uid=1000<"jmates">, gid=1000<"jmates">, rdev=37949602, 
atime=1664240431<"Sep 27 01:00:31 2022">.902138053, mtime=1713140694<"Apr 15 
00:24:54 2024">.605888358, ctime=1713140694<"Apr 15 00:24:54 2024">.605888358, 
size=512, blocks=8, blksize=32768, flags=0x0, gen=0x0 }
     62759 rogue    RET   stat 0
    ...
     62759 rogue    CALL  access(0x798526d57640,0x4<R_OK>)
     62759 rogue    NAMI  "/home/jmates/.terminfo/r/rxvt-unicode-256color"
     62759 rogue    RET   access -1 errno 2 No such file or directory
    ...
     62759 rogue    CALL  issetugid()
     62759 rogue    RET   issetugid 0
     62759 rogue    CALL  issetugid()
     62759 rogue    RET   issetugid 0
    ...
     62759 rogue    CALL  issetugid()
     62759 rogue    RET   issetugid 0
    ...
     62759 rogue    CALL  open(0x798526d4b960,0x10000<O_RDONLY|O_CLOEXEC>)
     62759 rogue    NAMI  "yyyy.db"
     62759 rogue    RET   open -1 errno 2 No such file or directory
     62759 rogue    CALL  
mprotect(0xbd21fb19000,0x1000,0x3<PROT_READ|PROT_WRITE>)
     62759 rogue    RET   mprotect 0
     62759 rogue    CALL  mprotect(0xbd21fb19000,0x1000,0x1<PROT_READ>)
     62759 rogue    RET   mprotect 0
     62759 rogue    CALL  open(0x798526d4f230,0x10000<O_RDONLY|O_CLOEXEC>)
     62759 rogue    NAMI  "yyyy"
     62759 rogue    RET   open -1 errno 2 No such file or directory
    ...
     62759 rogue    CALL  sendsyslog(0x798526d4c4a0,37,0<>)
     62759 rogue    GIO   fd -1 wrote 37 bytes
           "<10>rogue: vfprintf %s NULL in "%.*s""
     62759 rogue    RET   sendsyslog 0
     62759 rogue    CALL  stat(0xbd1b58b8717,0x798526d4f508)
     62759 rogue    NAMI  "/usr/share/terminfo"
     62759 rogue    STRU  struct stat { dev=1029, ino=77975, mode=drwxr-xr-x , 
nlink=44, uid=0<"root">, gid=0<"wheel">, rdev=347089, atime=1710969405<"Mar 20 
21:16:45 2024">, mtime=1710969405<"Mar 20 21:16:45 2024">, 
ctime=1712330397<"Apr  5 15:19:57 2024">.280403075, size=1024, blocks=4, 
blksize=16384, flags=0x0, gen=0x0 }
     62759 rogue    RET   stat 0
     62759 rogue    CALL  access(0x798526d57640,0x4<R_OK>)
     62759 rogue    NAMI  "/usr/share/terminfo/r/rxvt-unicode-256color"
     62759 rogue    RET   access 0
     62759 rogue    CALL  kbind(0x798526d47488,24,0x815fa3cb78805dae)
     62759 rogue    RET   kbind 0
     62759 rogue    CALL  open(0x798526d57640,0<O_RDONLY>)
     62759 rogue    NAMI  "/usr/share/terminfo/r/rxvt-unicode-256color"
     62759 rogue    RET   open 4
     62759 rogue    CALL  kbind(0x798526d47488,24,0x815fa3cb78805dae)
     62759 rogue    RET   kbind 0
     62759 rogue    CALL  fstat(4,0x798526d47400)
     62759 rogue    STRU  struct stat { dev=1029, ino=104522, mode=-r--r--r-- , 
nlink=1, uid=0<"root">, gid=7<"bin">, rdev=435250, atime=1710969405<"Mar 20 
21:16:45 2024">, mtime=1710969405<"Mar 20 21:16:45 2024">, 
ctime=1712330396<"Apr  5 15:19:56 2024">.780400236, size=2234, blocks=8, 
blksize=16384, flags=0x0, gen=0x0 }
     62759 rogue    RET   fstat 0
     62759 rogue    CALL  
mmap(0,0x4000,0x3<PROT_READ|PROT_WRITE>,0x1002<MAP_PRIVATE|MAP_ANON>,-1,0)
     62759 rogue    RET   mmap 12996211314688/0xbd1ea8f1000
     62759 rogue    CALL  read(4,0xbd1ea8f1000,0x4000)
     62759 rogue    GIO   fd 4 read 2234 bytes
           "\^Z\^AN\0\^]\0\^_\0p\^A$\^Erxvt-unicode-256color|rxvt-unicode 
terminal\
    ...

ksh is a bad test for this due to the static compile, so I used a rogue
process. Also lots of things don't like it when you break libcurses, but
there is ed. So /usr/src/lib/libcurses/ncurses_def.h had

        #ifndef TERMINFO
        #define TERMINFO "xxxx"
        #endif

        #ifndef TERMPATH
        #define TERMPATH "yyyy"
        #endif

and there were no "xxxx" in the kdump, which points maybe to TERMPATH
being the problem, or the problem happens after something involving
TERMPATH. Neither TERMPATH nor TERMINFO are set in the environment.
There is no ~/.termcap but there is a /etc/termcap. There are a few
vfprintf calls in the curses code but I put abort() in front of them and
nothing blew up so it's probably from elsewhere.

If I touch ~/yyyy ~/yyyy.db and open urxvt in that directory, the ktrace
finds "yyyy" but then wanders off to the usual " NULL in " thing.

         96611 rogue    NAMI  "yyyy"
         96611 rogue    RET   open 4
         96611 rogue    CALL  fstat(4,0x7525cedf8070)
         96611 rogue    STRU  struct stat { dev=1035, ino=9505870, 
mode=-rw-r--r-- , nlink=1, uid=1000<"jmates">, gid=1000<"jmates">, rdev=0, 
atime=1713143512<"Apr 15 01:11:52 2024">.995956221, mtime=1713143512<"Apr 15 
01:11:52 2024">.995956221, ctime=1713143512<"Apr 15 01:11:52 2024">.995956221, 
size=0, blocks=0, blksize=32768, flags=0x0, gen=0x0 }
         96611 rogue    RET   fstat 0
         96611 rogue    CALL  
mmap(0,0x8000,0x3<PROT_READ|PROT_WRITE>,0x1002<MAP_PRIVATE|MAP_ANON>,-1,0)
         96611 rogue    RET   mmap 6666624118784/0x61031c33000
         96611 rogue    CALL  read(4,0x61031c33000,0x8000)
         96611 rogue    RET   read 0
         96611 rogue    CALL  close(4)
         96611 rogue    RET   close 0
         96611 rogue    CALL  kbind(0x7525cedfbd38,24,0x1c572990c7c01030)
         96611 rogue    RET   kbind 0
         96611 rogue    CALL  sendsyslog(0x7525cedf8d00,37,0<>)
         96611 rogue    GIO   fd -1 wrote 37 bytes
                   "<10>rogue: vfprintf %s NULL in "%.*s""

Maybe ncurses by default (maybe) trying to read random "none" or
"none.db" files out of the current working directory isn't a good thing?
(No idea what code happens if an attacker does get those files into a
suitable directory.)

If I move aside the ~/.terminfo directory, a kdump shows only a check
for a "none" file (which did not exist), and not the a prior check for a
"none.db" file. With TERMINFO=/var/empty set a "none.db" file is looked
for, in addition to "none". Fiddling with TERMPATH and TERMCAP does not
appear to influence anything.

No idea where the vfprintf is being gotten to, but it seems to be
TERMINFO and hashed database related; it crops up when TERMINFO is
set, or if there's a ~/.terminfo directory that lacks the necessary
$TERM file.

Reply via email to