zeromq / libzmq

ZeroMQ core engine in C++, implements ZMTP/3.1
https://www.zeromq.org
Mozilla Public License 2.0
9.75k stars 2.36k forks source link

libzmq/ffmpeg: "Address family not supported by protocol (src/ip_resolver.cpp:542) / Aborted" from mpd.service "RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK" #4737

Open iconoclasthero opened 2 months ago

iconoclasthero commented 2 months ago

tl;dr: libzmq errors out when RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX is in the mpd systemd unit file when mpd, running as a system service, calls ffmpeg ... zmq:tcp://127.0.0.1:5555 directly (i.e., in the systemd environment). How to get around this while retaining security in the systemd unit?

Issue description

I was able to get ffmpeg's libzmq implementation to work on the cli either using cat /tmp/mpd.fifo | ffmpeg ... -i - ... zmq:tcp://127.0.0.1:5555 pipe as stdin or just using the named pipe as direct input ffmepg ... -i /tmp/mpd.fifo ... zmq:tcp://127.0.0.1:5555 but it kept erroring out when called directly by mpd's pipe output, e.g.,

audio_output {
    name            "ffmpeg zmq"
    enabled         "no"
    type            "pipe"
    format          "48000:16:2"
    command         "ffmpeg -hide_banner -f s16le -ar 48000 -ac 2 -i - -f mpegts -acodec libopus -b:a 128k zmq:tcp://127.0.0.1:5555 >> /var/log/mpd/ffmpeg.log 2>&1"
}

results in ffmpeg reporting,"Address family not supported by protocol (src/ip_resolver.cpp:542) / Aborted" and mpd just saying it was a broken pipe.

Upon a good bit of investigation and helpful suggestions from #ffmpeg, #bash, and #systemd the offending line in systemd unit file mpd.service was: RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

What is the best way to let libzmq have whatever access it needs without significantly sacrificing security (which is described in the mpd.service unit file as one of the "# more paranoid security settings")?

replacing the RestrictAddressFamlies=... with

IPAddressAllow=localhost
IPAddressDeny=any

does solve the problem so if that's the best solution then this can be closed and left for anyone else looking to solve this problem.

Environment

$ ldd $(which ffmpeg) | grep zmq; pkg-config --modversion libzmq
    libzmq.so.5 => /usr/local/lib/libzmq.so.5 (0x000073830ca6c000)
4.3.6

so when ffmpeg was compiled (after its libzmq was patched) with --enable=libzmq it presumably used the 4.3.6 that pkgconfig displayed. (If it's super duper relevant I'm sure I could recompile ffmpeg again to test.)

Minimal test code / Steps to reproduce the issue

  1. See above...
  2. run mpd as system service using the default systemd unit file included with mpd source.
  3. create an mpd pipe output shown above with the ffmpeg command: command "ffmpeg -hide_banner -f s16le -ar 48000 -ac 2 -i - -f mpegts -acodec libopus -b:a 128k zmq:tcp://127.0.0.1:5555 >> /var/log/mpd/ffmpeg.log 2>&1"
  4. enable the pipe output to ffmpeg/zmq
  5. hear no sound
  6. look at the logs

What's the actual result? (include assertion message & call stack if applicable)

mpd can't use the output, it results in ffmpeg reporting,"Address family not supported by protocol (src/ip_resolver.cpp:542) / Aborted" and mpd just saying it was a broken pipe.

I put an strace in front of ffmpeg in the mpd pipe command in mpd.conf:

$ for i in /var/lib/mpd/ffmpegstrace.log.*; do cat "$i"; hr; done
⋮
read(3, "?\376\v\374\226\375d\373\256\375y\373s\3753\373\17\375\302\372\340\374\205\372I\375\347\372a\375\37\373"..., 36864) = 4096
read(3, "h\3731\372-\373\356\371\302\373\201\372\350\373\214\372\247\373=\372\375\373\242\372\307\373e\372\332\373\212\372"..., 32768) = 8192
read(3, "\203\371\22\371\0\371R\370$\3716\370\260\371{\370\264\372a\371\316\373t\372\320\373]\372\300\372;\371"..., 65536) = 4096
read(3, "f\375\306\376\310\375\312\376Q\376\2\377\3\377L\377o\377@\377\f\377o\376\267\376\250\375]\376\325\374"..., 61440) = 4096
read(3, "w\0Z\377\7\0\355\376\277\377\276\376\254\377\260\376v\377n\376\336\376\303\375s\3769\375\221\376D\375"..., 57344) = 4096
read(3, "u\2#\4\307\2\322\4\362\2J\5\340\2\205\5_\2B\5B\2W\5_\2\256\5\360\1`\5"..., 53248) = 4096
read(3, "\245\374\t\371\220\374\6\371\225\374\30\371v\375\3\372\255\376O\373\317\376\225\373;\376\37\3739\376P\373"..., 49152) = 4096
read(3, "\251\376\"\3752\377D\375O\377\32\375\373\376k\374\374\376\"\374\323\376\317\373\353\376\267\373\235\3777\374"..., 45056) = 4096
read(3, "\237\375H\377k\375\372\376&\375\235\376\24\375\206\376\262\374\23\376\307\373\17\375\241\373\323\374\236\373\263\374"..., 40960) = 4096
read(3, "\246\3\350\3\352\2\31\3@\2v\2\374\1\16\2\271\1\241\1q\1<\1\202\1\16\1\f\1`\0"..., 36864) = 4096
read(3, "\345\4\270\7\230\4\245\7U\4\254\0073\4\314\7\r\4\303\7\363\3\332\7\372\3\360\7\251\3\256\7"..., 32768) = 4096
read(3, "g\6\272\2\263\6-\3\372\6\251\3\307\6\272\3[\6\255\3K\6\354\3w\6\207\4\7\7~\5"..., 65536) = 4096
read(3, "\321\377I\1\252\0\261\1\273\1[\2\266\2\356\2S\0037\3<\3\362\2\263\2B\2\331\1R\1"..., 61440) = 4096
read(3, "\6\365\277\370x\365\372\370\355\365W\371I\366\301\371\261\3667\3726\367\335\372\223\367\\\3732\370\360\373"..., 57344) = 4096
read(3, "\336\372v\1\327\372L\1\355\3727\0014\373/\1/\373\323\0\335\372.\0\312\372\302\3774\373\322\377"..., 53248) = 4096
read(3, "\343\3706\1\242\370\26\1o\370\7\1T\370\365\0\213\370\7\1\311\370#\1\t\371A\1b\371~\1"..., 49152) = 8192
read(3, "\227\361\374\362u\361T\363e\361\237\363!\361\277\363\334\360\356\363\344\360c\364\243\360\216\364G\360\233\364"..., 40960) = 4096
read(3, "\330\377\34\376\203\377!\376\335\376\323\375$\376\201\375\236\375B\375\2\375\367\374\224\374\330\374{\374\343\374"..., 36864) = 4096
brk(0x5a490936a000)                     = 0x5a490936a000
read(3, ">\21<\f\355\20\2\f\7\21,\f\16\21N\f-\21\244\fV\21\346\fV\21\r\r^\21D\r"..., 32768) = 4096
read(3, "\367\5\333\2\241\6c\3\7\7\310\3\220\7L\4\243\7j\4x\7Y\4\207\7`\4\\\79\4"..., 65536) = 4096
read(3, "\301\367\256\363[\367%\363\23\367\315\362\31\367\302\362S\367\345\362\245\3679\363\20\370\231\363J\370\310\363"..., 61440) = 4096
read(3, "\255\377P\0K\377\273\3777\377m\377\24\377\n\3771\377\343\376`\377\311\376*\377M\3768\377\23\376"..., 57344) = 4096
read(3, "@\377\216\372\16\377\221\372\0\377\244\372\17\377\314\372u\377[\373\264\377\237\373\256\377\261\373\225\377\307\373"..., 53248) = 4096
read(3, "%\367<\366\20\367.\366-\367@\366~\367\223\366\202\367\223\366e\367b\366M\367D\366\26\367\2\366"..., 49152) = 4096
read(3, "\230\2\265\0\343\2\n\1g\3\232\1x\3\274\1i\3\267\1H\3\247\1J\3\324\1\253\3N\2"..., 45056) = 4096
read(3, "\244\r\355\f\374\6\220\6\332\4\230\4x\vq\n`\v\371\10\342\n\257\10\341\7\221\7\337\5\367\4"..., 40960) = 4096
read(3, "k\372B\375=\374\240\377\372\375c\2;\1\275\4\376\3\222\6\223\0\210\4\226\375\3\2\367\3730\377"..., 36864) = 4096
read(3, "\204\374q\375\243\373\257\374\266\374\357\374\t\375K\375\256\3732\374\352\3738\374?\375\235\375\7\376p\376"..., 32768) = 4096
read(3, "\215\4Q\5\214\4i\5A\4\21\5\226\3\204\4\335\2\f\4\205\2\314\3\221\3\v\5D\4\25\6"..., 65536) = 4096
read(3, ")\372v\370\374\371\30\370q\372o\370\344\372\344\370\352\372\331\370\205\373q\371,\374%\372\r\375\t\373"..., 61440) = 4096
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
ioctl(2, TCGETS, 0x7ffd2e003870)        = -1 ENOTTY (Inappropriate ioctl for device)
write(2, "[aist#0:0/pcm_s16le @ 0x5a490935"..., 38) = 38
write(2, "Guessed Channel Layout: stereo\n", 31) = 31
write(2, "Input #0, s16le, from 'fd:':\n", 29) = 29
write(2, "  Duration: ", 12)            = 12
write(2, "N/A", 3)                      = 3
write(2, ", bitrate: ", 11)             = 11
write(2, "1536 kb/s", 9)                = 9
write(2, "\n", 1)                       = 1
write(2, "  Stream #0", 11)             = 11
write(2, ":0", 2)                       = 2
write(2, ": Audio: pcm_s16le, 48000 Hz, st"..., 52) = 52
write(2, "\n", 1)                       = 1
eventfd2(0, EFD_CLOEXEC)                = 4
fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
fcntl(4, F_GETFL)                       = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
getpid()                                = 360340
getpid()                                = 360340
eventfd2(0, EFD_CLOEXEC)                = 5
fcntl(5, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
fcntl(5, F_GETFL)                       = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
getpid()                                = 360340
epoll_create1(EPOLL_CLOEXEC)            = 6
epoll_ctl(6, EPOLL_CTL_ADD, 5, {events=0, data={u32=154481152, u64=99269733593600}}) = 0
epoll_ctl(6, EPOLL_CTL_MOD, 5, {events=EPOLLIN, data={u32=154481152, u64=99269733593600}}) = 0
getpid()                                = 360340
rt_sigaction(SIGRT_1, {sa_handler=0x77902289e830, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_RESTART|SA_SIGINFO, sa_restorer=0x779022845250}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
mmap(NULL, 8392704, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x779021000000
mprotect(0x779021001000, 8388608, PROT_READ|PROT_WRITE) = 0
rt_sigprocmask(SIG_BLOCK, ~[], [], 8)   = 0
clone3({flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, child_tid=0x779021800990, parent_tid=0x779021800990, exit_signal=0, stack=0x779021000000, stack_size=0x7ffc80, tls=0x7790218006c0}, 88) = -1 ENOSYS (Function not implemented)
clone(child_stack=0x7790217ffc70, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid=[360346], tls=0x7790218006c0, child_tidptr=0x779021800990) = 360346
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
eventfd2(0, EFD_CLOEXEC)                = 7
fcntl(7, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(7, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
fcntl(7, F_GETFL)                       = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl(7, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
getpid()                                = 360340
epoll_create1(EPOLL_CLOEXEC)            = 8
epoll_ctl(8, EPOLL_CTL_ADD, 7, {events=0, data={u32=154491008, u64=99269733603456}}) = 0
epoll_ctl(8, EPOLL_CTL_MOD, 7, {events=EPOLLIN, data={u32=154491008, u64=99269733603456}}) = 0
mmap(NULL, 8392704, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x779020600000
mprotect(0x779020601000, 8388608, PROT_READ|PROT_WRITE) = 0
rt_sigprocmask(SIG_BLOCK, ~[], [], 8)   = 0
clone(child_stack=0x779020dffc70, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid=[360347], tls=0x779020e006c0, child_tidptr=0x779020e00990) = 360347
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
eventfd2(0, EFD_CLOEXEC)                = 9
fcntl(9, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(9, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
fcntl(9, F_GETFL)                       = 0x802 (flags O_RDWR|O_NONBLOCK)
fcntl(9, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
getpid()                                = 360340
getpid()                                = 360340
poll([{fd=9, events=POLLIN}], 1, 0)     = 0 (Timeout)
socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE) = -1 EAFNOSUPPORT (Address family not supported by protocol)
write(2, "Address family not supported by "..., 67) = 67
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
gettid()                                = 360340
getpid()                                = 360340
tgkill(360340, 360340, SIGABRT)         = 0
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=360340, si_uid=113} ---
+++ killed by SIGABRT +++
######################################################################################################################
rseq(0x779021800fe0, 0x20, 0, 0x53053053) = 0
set_robust_list(0x7790218009a0, 24)     = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], NULL, 8) = 0
sched_getparam(360346, [0])             = 0
sched_getscheduler(360346)              = 0 (SCHED_OTHER)
sched_setscheduler(360346, SCHED_OTHER, [0]) = 0
prctl(PR_SET_NAME, "ZMQbg/Reaper")      = 0
epoll_wait(6,  <unfinished ...>)        = ?
+++ killed by SIGABRT +++
######################################################################################################################
rseq(0x779020e00fe0, 0x20, 0, 0x53053053) = 0
set_robust_list(0x779020e009a0, 24)     = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], NULL, 8) = 0
sched_getparam(360347, [0])             = 0
sched_getscheduler(360347)              = 0 (SCHED_OTHER)
sched_setscheduler(360347, SCHED_OTHER, [0]) = 0
prctl(PR_SET_NAME, "ZMQbg/IO/0")        = 0
epoll_wait(8,  <unfinished ...>)        = ?
+++ killed by SIGABRT +++
#####################################################################################################################

What's the expected result?

I just want ffmpeg to stream music from one machine to the other and I want mpd to be able to use an unnamed pipe so ffmpeg can be called directly from mpd like I've been doing with rtsp instead of some workaround:

audio_output {
     name            "pipe to ffmpeg - suffix"
     enabled         "no"
     type            "pipe"
     format          "48000:16:2"
     command         "ffmpeg -loglevel error -hide_banner -y -f s16le -ar 48000 -ac 2 -vn -i - -c libopus -b:a 64k -f rtsp
rtsp://localhost:8554/mpd/mpd.opus"
}
iconoclasthero commented 2 months ago

I think one of the following is true: