Menu

#385 Segfault in remote mode when LOADing HTTPS/ICY stream on ARM (Raspberry Pi)

1.33.x
open
nobody
None
5
2 days ago
3 days ago
No

Description:

mpg123 crashes with a segfault when using LOAD with an HTTPS webradio URL in remote mode (-R) on ARM (Raspberry Pi). The crash occurs in generic_sendstr() when attempting to print the ICY-NAME metadata. The issue reproduces on both 1.32.10 and 1.33.4.

Environment:

Platform: Raspberry Pi (armhf, arm-linux-gnueabihf)
OS: Raspbian Buster (Debian 10)
mpg123 versions tested: 1.32.10 and 1.33.4 (compiled from source)
GDB: Raspbian 8.2.1-2
Configure flags: ./configure --with-audio=alsa --enable-static --disable-shared
Binary is fully statically linked against libmpg123 (confirmed via ldd)

Steps to reproduce:

# Terminal 1
mpg123 -R --fifo /tmp/mpg123-fifo.cmd

# Terminal 2
echo "LOAD https://jazzradio.ice.infomaniak.ch/jazzradio-high" > /tmp/mpg123-fifo.cmd

Observed behavior:
mpg123 outputs @I jazzradio-high then immediately segfaults.
Backtrace (1.33.4):

gdb --args /usr/local/bin/mpg123 -R --fifo /tmp/mpg123-fifo.cmd 
    Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
@R MPG123 (ThOr) v11
[Detaching after fork from child process 23855]
[Detaching after fork from child process 23856]
@I jazzradio-high

Program received signal SIGSEGV, Segmentation fault.
0x76fbc24c in strlen () from /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so
(gdb) bt full
#0  0x76fbc24c in strlen () from /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so
No symbol table info available.
#1  0x000200a0 in utf8outstr (dest_=dest_@entry=0x7efff13c, source=0xb <error: Cannot access memory at address 0xb>, source@entry=0xbec68 "", to_terminal=to_terminal@entry=1)
    at src/local.c:290
        dest = 0x0
        width = 0
        source_fill = <optimized out>
#2  0x00020db4 in outstr (dest=0x7efff13c, dest@entry=0x7efff124, str=str@entry=0xbec68 "", is_utf8=is_utf8@entry=1, is_term=1) at src/local.c:449
        ret = 0
        usrc = <optimized out>
#3  0x00017fec in generic_sendstr (is_utf8=is_utf8@entry=1, fmt=fmt@entry=0x8d688 "I ICY-NAME: %s", str=0xb <error: Cannot access memory at address 0xb>) at src/control_generic.c:81
        ap = {__ap = 0x7efff14c}
        outbuf = 0x0
#4  0x00018638 in generic_load (state=1, arg=<optimized out>, fr=<optimized out>) at src/control_generic.c:333
No locals.
#5  generic_load (fr=<optimized out>, arg=<optimized out>, state=1) at src/control_generic.c:311
No locals.
#6  0x00019ca8 in control_generic (fr=0x1) at src/control_generic.c:929
        toksave = 0x7efff293 ""
        len = 0
        comstr = <optimized out>
        cmd = 0x7efff258 "LOAD"
        arg = 0x7efff25d "https://jazzradio.ice.infomaniak.ch/jazzradio-high"
        counter = <optimized out>
        next_comstr = 0x7efff294 ""
        tv = {tv_sec = 0, tv_usec = 0}
        fds = {__fds_bits = {8, 0 <repeats 31 times>}}
        n = <optimized out>
        alive = <optimized out>
        silent = <optimized out>
        __func__ = "control_generic"
        buf = "LOAD\000https://jazzradio.ice.infomaniak.ch/jazzradio-high\000mp3", '\000' <repeats 149 times>...
        last_len = 0
#7  0x000139c4 in main (sys_argc=<optimized out>, sys_argv=<optimized out>) at src/mpg123.c:1309
        ret = <optimized out>
        result = 0
        end_of_files = 0 '\000'
        parr = 8421440
        fname = <optimized out>
        libpar = 10
        mp = <optimized out>
        pl_utf8 = 0
        start_time = {tv_sec = 1000, tv_usec = 1996476672}
        __func__ = "main"
        stderr_width = 2130705400
        stdin_width = <optimized out>
        term_ctrl_default = 1
(gdb)

Analysis:

The crash happens at src/control_generic.c:333:

if(filept->htd.icy_name.fill) generic_sendstr(1, "I ICY-NAME: %s", filept->htd.icy_name.p);

The guard icy_name.fill passes (non-zero), but icy_name.p is 0xb — a corrupted pointer, not NULL and not a valid address. This suggests the mpg_string struct is getting corrupted upstream, likely during the HTTPS network helper fork/handoff (two "Detaching after fork from child process" messages are visible before the crash).

The issue may be ARM-specific. I have not yet tested whether HTTP (non-TLS) streams also crash.

Discussion

  • Thomas Orgis

    Thomas Orgis - 3 days ago

    I cannot reproduce on AMD64. Is this specific to remote control mode or does plain

    mpg123 https://jazzradio.ice.infomaniak.ch/jazzradio-high
    

    also crash? It also prints the ICY info for me … though it is not very informative:

     src/mpg123 https://jazzradio.ice.infomaniak.ch/jazzradio-high
    High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3
        version 1.33.5-dev; written and copyright by Michael Hipp and others
        free software (LGPL) without any warranty but with best wishes
    
    Directory: https://jazzradio.ice.infomaniak.ch/
    
    Terminal control enabled, press 'h' for listing of keys and functions.
    
    Playing MPEG stream 1 of 1: jazzradio-high ...
    ICY-NAME: JAZZ RADIO NATIONALE
    ICY-URL: https://jazzradio.ice.infomaniak.ch/jazzradio-high.mp3
    
    MPEG 1.0 L III cbr192 44100 j-s
    
    ICY-META: StreamTitle='';
    
     
  • Thomas Orgis

    Thomas Orgis - 3 days ago

    Next step would be to check if a stream capture (--streamdump file) that is then opened with correct --icy-interval from disk also crashes. This isolates things from the actual HTTP process. Of course, the history of the corrupted string struct would be good

     
  • abdelaziz sbaai

    abdelaziz sbaai - 2 days ago

    Environment

    - Platform: armv7l (Raspberry Pi, Raspbian Buster/Debian 10)

    1. The problem only occurs in remote mode; plain mode works fine

    Plain mode plays the stream without issue:

    mpg123 https://jazzradio.ice.infomaniak.ch/jazzradio-high
    

    Remote mode crashes:

    # Terminal 1
    mpg123 -R --fifo /tmp/mpg123-fifo.cmd
    
    # Terminal 2
    echo "LOAD https://jazzradio.ice.infomaniak.ch/jazzradio-high" > /tmp/mpg123-fifo.cmd
    

    Output before crash:

    @I jazzradio-high
    Segmentation fault.
    

    2. Stream capture replayed with correct --icy-interval from disk does NOT crash

    Captured the raw stream using curl (since mpg123 crashes in remote mode before completing a dump):

    mpg123 --streamdump /tmp/mpg123-streamdump https://streaming.nrjaudio.fm/oumvmk8fnozc?origine=fluxurlradio
    

    Confirmed the ICY metadata interval:

    $ curl -sL -H "Icy-MetaData: 1" -D /tmp/icy-headers.txt \
      "https://jazzradio.ice.infomaniak.ch/jazzradio-high"
    $ grep -i icy-metaint /tmp/icy-headers.txt
    

    Result: icy-metaint: 16000

    Replayed in remote mode:

    gdb --args /usr/local/bin/mpg123 -R --fifo /tmp/mpg123-fifo.cmd --icy-interval 16000
    (gdb) run
    
    # From another terminal
    echo "LOAD /tmp/mpg123-streamdump" > /tmp/mpg123-fifo.cmd
    

    This played back successfully with no crash.


    3. History of the corrupted string struct

    Set a watchpoint on filept->htd.icy_name.p and a breakpoint on generic_load:

    gdb --args /usr/local/bin/mpg123 -R --fifo /tmp/mpg123-fifo.cmd
    (gdb) break generic_load
    (gdb) run
    

    Sent the LOAD command from another terminal. On first breakpoint hit (entry to generic_load), filept is still NULL as expected. Continued, and after the two fork detaches the watchpoint triggered:

    (gdb) break generic_load
    Breakpoint 1 at 0x18458: generic_load. (2 locations)
    (gdb) run
    Starting program: /usr/local/bin/mpg123 -R --fifo /tmp/mpg123-fifo.cmd
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
    @R MPG123 (ThOr) v11
    
    Breakpoint 1, generic_load (fr=0xbec68, arg=0x7efff27d "https://jazzradio.ice.infomaniak.ch/jazzradio-high", state=1) at src/control_generic.c:313
    313             sendstat_disabled = FALSE;
    (gdb) bt full
    #0  generic_load (fr=0xbec68, arg=0x7efff27d "https://jazzradio.ice.infomaniak.ch/jazzradio-high", state=1) at src/control_generic.c:313
    No locals.
    #1  0x00019ca8 in control_generic (fr=0x1) at src/control_generic.c:929
            toksave = 0x7efff2af ""
            len = 0
            comstr = <optimized out>
            cmd = 0x7efff278 "LOAD"
            arg = 0x7efff27d "https://jazzradio.ice.infomaniak.ch/jazzradio-high"
            counter = <optimized out>
            next_comstr = 0x7efff2b0 ""
            tv = {tv_sec = 0, tv_usec = 0}
            fds = {__fds_bits = {8, 0 <repeats 31 times>}}
            n = <optimized out>
            alive = <optimized out>
            silent = <optimized out>
            __func__ = "control_generic"
            buf = "LOAD\000https://jazzradio.ice.infomaniak.ch/jazzradio-high", '\000' <repeats 153 times>...
            last_len = 0
    #2  0x000139c4 in main (sys_argc=<optimized out>, sys_argv=<optimized out>) at src/mpg123.c:1309
            ret = <optimized out>
            result = 0
            end_of_files = 0 '\000'
            parr = 8421440
            fname = <optimized out>
            libpar = 10
            mp = <optimized out>
            pl_utf8 = 0
            start_time = {tv_sec = 1000, tv_usec = 1996476672}
            __func__ = "main"
            stderr_width = 2130705432
            stdin_width = <optimized out>
            term_ctrl_default = 1
    (gdb) print *filept
    Cannot access memory at address 0x0
    (gdb) print filept->htd
    Cannot access memory at address 0x10c
    (gdb) continue
    Continuing.
    [Detaching after fork from child process 16736]
    [Detaching after fork from child process 16737]
    
    Breakpoint 1, generic_load (state=1, arg=0x7efff27d "https://jazzradio.ice.infomaniak.ch/jazzradio-high", fr=0xbec68) at src/control_generic.c:326
    326             mpg123_seek(fr, 0, SEEK_SET); /* This finds ID3v2 at beginning. */
    (gdb) bt full
    #0  generic_load (state=1, arg=0x7efff27d "https://jazzradio.ice.infomaniak.ch/jazzradio-high", fr=0xbec68) at src/control_generic.c:326
    No locals.
    #1  generic_load (fr=0xbec68, arg=0x7efff27d "https://jazzradio.ice.infomaniak.ch/jazzradio-high", state=1) at src/control_generic.c:311
    No locals.
    #2  0x00019ca8 in control_generic (fr=0x1) at src/control_generic.c:929
            toksave = 0x7efff2af ""
            len = 0
            comstr = <optimized out>
            cmd = 0x7efff278 "LOAD"
            arg = 0x7efff27d "https://jazzradio.ice.infomaniak.ch/jazzradio-high"
            counter = <optimized out>
            next_comstr = 0x7efff2b0 ""
            tv = {tv_sec = 0, tv_usec = 0}
            fds = {__fds_bits = {8, 0 <repeats 31 times>}}
            n = <optimized out>
            alive = <optimized out>
            silent = <optimized out>
            __func__ = "control_generic"
            buf = "LOAD\000https://jazzradio.ice.infomaniak.ch/jazzradio-high", '\000' <repeats 153 times>...
            last_len = 0
    #3  0x000139c4 in main (sys_argc=<optimized out>, sys_argv=<optimized out>) at src/mpg123.c:1309
            ret = <optimized out>
            result = 0
            end_of_files = 0 '\000'
            parr = 8421440
            fname = <optimized out>
            libpar = 10
            mp = <optimized out>
            pl_utf8 = 0
            start_time = {tv_sec = 1000, tv_usec = 1996476672}
            __func__ = "main"
            stderr_width = 2130705432
            stdin_width = <optimized out>
            term_ctrl_default = 1
    (gdb) print *filept
    $1 = {
      buf = "\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type, Icy-MetaData\r\nAccess-Control-Allow-Methods: GET, OPTIONS, SOURCE, PUT, HEAD, STATS\r\nicy-"..., bufp = 0xd34f1 "\377\373\262d\017\210\026\021f\315Gi\340\002Z\244\312\f\354\024", fill = 39, fd = -1, htd = {content_type = {p = 0x0, size = 819024,
          fill = 11}, icy_name = {p = 0xb <error: Cannot access memory at address 0xb>, size = 866256, fill = 21}, icy_url = {p = 0x15 <error: Cannot access memory at address 0x15>,
          size = 867776, fill = 55}, icy_interval = 55, proxyhost = {p = 0x0, size = 16000, fill = 0}, proxyport = {p = 0x0, size = 0, fill = 0}, proxystate = PROXY_UNKNOWN}, nh = 0x0}
    (gdb) print filept->htd
    $2 = {content_type = {p = 0x0, size = 819024, fill = 11}, icy_name = {p = 0xb <error: Cannot access memory at address 0xb>, size = 866256, fill = 21}, icy_url = {
        p = 0x15 <error: Cannot access memory at address 0x15>, size = 867776, fill = 55}, icy_interval = 55, proxyhost = {p = 0x0, size = 16000, fill = 0}, proxyport = {p = 0x0, size = 0,
        fill = 0}, proxystate = PROXY_UNKNOWN}
    (gdb)
    
     

Log in to post a comment.

MongoDB Logo MongoDB