Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mpd for openSUSE:Factory checked in at 2026-06-22 17:33:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mpd (Old) and /work/SRC/openSUSE:Factory/.mpd.new.1956 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mpd" Mon Jun 22 17:33:07 2026 rev:63 rq:1360819 version:0.24.12 Changes: -------- --- /work/SRC/openSUSE:Factory/mpd/mpd.changes 2026-05-08 16:43:48.801284402 +0200 +++ /work/SRC/openSUSE:Factory/.mpd.new.1956/mpd.changes 2026-06-22 17:33:35.510474810 +0200 @@ -1,0 +2,11 @@ +Sun Jun 21 10:08:04 UTC 2026 - Илья Индиго <[email protected]> + +- Updated to 0.24.12 + * https://raw.githubusercontent.com/MusicPlayerDaemon/MPD/v0.24.10/NEWS + * protocol: fixed path traversal bug and allow empty URI + * playlist: do not allow newlines in song URIs + * decoder + * pcm: fixed stack buffer overflow + * sidplay: added fall back to SIDLiteBuilder if ReSIDfpBuilder is unavailable + +------------------------------------------------------------------- Old: ---- mpd-0.24.10.tar.xz mpd-0.24.10.tar.xz.sig New: ---- mpd-0.24.12.tar.xz mpd-0.24.12.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mpd.spec ++++++ --- /var/tmp/diff_new_pack.pPL5dJ/_old 2026-06-22 17:33:36.554511408 +0200 +++ /var/tmp/diff_new_pack.pPL5dJ/_new 2026-06-22 17:33:36.558511548 +0200 @@ -18,7 +18,7 @@ %define ver 0.24 Name: mpd -Version: %{ver}.10 +Version: %{ver}.12 Release: 0 Summary: Music Player Daemon License: GPL-2.0-or-later ++++++ mpd-0.24.10.tar.xz -> mpd-0.24.12.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/NEWS new/mpd-0.24.12/NEWS --- old/mpd-0.24.10/NEWS 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/NEWS 2026-05-15 07:46:52.000000000 +0200 @@ -1,3 +1,17 @@ +ver 0.24.12 (2026/05/15) +* protocol + - allow empty URI in "lsinfo", "add" etc. (0.24.11 regression) + +ver 0.24.11 (2026/05/15) +* protocol + - fix path traversal bug +* playlist: do not allow newlines in song URIs +* input + - curl: require version 7.85.0 +* decoder + - pcm: fix stack buffer overflow + - sidplay: fall back to SIDLiteBuilder if ReSIDfpBuilder is unavailable + ver 0.24.10 (2026/05/06) * input - cache: fix deadlock bug diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/meson.build new/mpd-0.24.12/meson.build --- old/mpd-0.24.10/meson.build 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/meson.build 2026-05-15 07:46:52.000000000 +0200 @@ -1,7 +1,7 @@ project( 'mpd', ['c', 'cpp'], - version: '0.24.10', + version: '0.24.12', meson_version: '>= 1.0', default_options: [ 'c_std=c11', @@ -481,6 +481,7 @@ endif subdir('src/util') +subdir('src/protocol') subdir('src/cmdline') subdir('src/time') subdir('src/lib/icu') @@ -658,6 +659,7 @@ more_deps, chromaprint_dep, fmt_dep, + protocol_dep, ], link_args: link_args, build_by_default: not get_option('fuzzer'), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/LocateUri.cxx new/mpd-0.24.12/src/LocateUri.cxx --- old/mpd-0.24.10/src/LocateUri.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/LocateUri.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -8,7 +8,9 @@ #include "ls.hxx" #include "storage/Registry.hxx" #include "util/ASCII.hxx" +#include "util/StringCompare.hxx" #include "util/UriExtract.hxx" +#include "util/UriUtil.hxx" #ifdef ENABLE_DATABASE #include "storage/StorageInterface.hxx" @@ -86,11 +88,11 @@ LocatedUri LocateUri(UriPluginKind kind, - const char *uri, const IClient *client + const char *uri, const IClient *client, #ifdef ENABLE_DATABASE - , const Storage *storage + const Storage *storage, #endif - ) + bool allow_empty) { /* skip the obsolete "file://" prefix */ const char *path_utf8 = StringAfterPrefixCaseASCII(uri, "file://"); @@ -115,6 +117,12 @@ , storage #endif ); - else + else if (allow_empty && StringIsEmpty(uri)) return LocatedUri(LocatedUri::Type::RELATIVE, uri); + else { + if (!uri_safe_local(uri)) + throw std::invalid_argument{"Bad relative path"}; + + return LocatedUri(LocatedUri::Type::RELATIVE, uri); + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/LocateUri.hxx new/mpd-0.24.12/src/LocateUri.hxx --- old/mpd-0.24.10/src/LocateUri.hxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/LocateUri.hxx 2026-05-15 07:46:52.000000000 +0200 @@ -71,13 +71,14 @@ * @param storage a #Storage instance which may be used to convert * absolute URIs to relative ones, using Storage::MapToRelativeUTF8(); * that feature is disabled if this parameter is nullptr + * @param allow_empty is an empty URI allowed in this context? */ LocatedUri LocateUri(UriPluginKind kind, - const char *uri, const IClient *client + const char *uri, const IClient *client, #ifdef ENABLE_DATABASE - , const Storage *storage + const Storage *storage, #endif - ); + bool allow_empty=false); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/PlaylistFile.cxx new/mpd-0.24.12/src/PlaylistFile.cxx --- old/mpd-0.24.10/src/PlaylistFile.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/PlaylistFile.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -11,6 +11,7 @@ #include "SongLoader.hxx" #include "Mapper.hxx" #include "protocol/RangeArg.hxx" +#include "protocol/Verify.hxx" #include "io/FileLineReader.hxx" #include "io/FileOutputStream.hxx" #include "io/BufferedOutputStream.hxx" @@ -70,8 +71,7 @@ #ifdef _WIN32 std::strchr(name_utf8, '\\') == nullptr && #endif - std::strchr(name_utf8, '\n') == nullptr && - std::strchr(name_utf8, '\r') == nullptr; + VerifyStringUTF8(name_utf8); } static const AllocatedPath & diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/SongUpdate.cxx new/mpd-0.24.12/src/SongUpdate.cxx --- old/mpd-0.24.10/src/SongUpdate.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/SongUpdate.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -10,6 +10,7 @@ #include "input/InputStream.hxx" #include "input/WaitReady.hxx" #include "decoder/DecoderList.hxx" +#include "protocol/Verify.hxx" #include "fs/AllocatedPath.hxx" #include "fs/FileInfo.hxx" #include "thread/Mutex.hxx" @@ -41,7 +42,7 @@ const StorageFileInfo &info, Directory &parent) { assert(!uri_has_scheme(path_utf8)); - assert(path_utf8.find('\n') == path_utf8.npos); + assert(VerifyRelativePathUTF8(path_utf8)); auto song = std::make_unique<Song>(path_utf8, parent); if (!song->UpdateFile(storage, info)) @@ -96,7 +97,7 @@ Directory &parent) noexcept { assert(!uri_has_scheme(name_utf8)); - assert(name_utf8.find('\n') == name_utf8.npos); + assert(VerifyRelativePathUTF8(name_utf8)); auto song = std::make_unique<Song>(name_utf8, parent); if (!song->UpdateFileInArchive(archive)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/archive/plugins/Iso9660ArchivePlugin.cxx new/mpd-0.24.12/src/archive/plugins/Iso9660ArchivePlugin.cxx --- old/mpd-0.24.10/src/archive/plugins/Iso9660ArchivePlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/archive/plugins/Iso9660ArchivePlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -11,11 +11,11 @@ #include "../ArchiveVisitor.hxx" #include "input/InputStream.hxx" #include "fs/Path.hxx" +#include "protocol/Verify.hxx" #include "lib/fmt/PathFormatter.hxx" #include "lib/fmt/RuntimeError.hxx" #include "thread/ScopeUnlock.hxx" #include "util/StringCompare.hxx" -#include "util/UTF8.hxx" #include <cdio/iso9660.h> @@ -83,14 +83,12 @@ auto *statbuf = (iso9660_stat_t *) _cdio_list_node_data(entnode); const char *filename = statbuf->filename; - if (StringIsEmpty(filename) || - PathTraitsUTF8::IsSpecialFilename(filename)) + if (PathTraitsUTF8::IsSpecialFilename(filename)) /* skip empty names (libcdio bug?) */ /* skip special names like "." and ".." */ continue; - if (!ValidateUTF8(filename)) - /* ignore file names which are not valid UTF-8 */ + if (!VerifyRelativePathUTF8(filename)) continue; size_t filename_length = strlen(filename); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/archive/plugins/ZzipArchivePlugin.cxx new/mpd-0.24.12/src/archive/plugins/ZzipArchivePlugin.cxx --- old/mpd-0.24.10/src/archive/plugins/ZzipArchivePlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/archive/plugins/ZzipArchivePlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -14,9 +14,9 @@ #include "lib/fmt/RuntimeError.hxx" #include "fs/NarrowPath.hxx" #include "fs/Path.hxx" +#include "protocol/Verify.hxx" #include "lib/fmt/SystemError.hxx" #include "thread/ScopeUnlock.hxx" -#include "util/UTF8.hxx" #include <zzip/zzip.h> @@ -70,7 +70,7 @@ ZZIP_DIRENT dirent; while (zzip_dir_read(dir->dir, &dirent)) //add only files - if (dirent.st_size > 0 && ValidateUTF8(dirent.d_name)) + if (dirent.st_size > 0 && VerifyRelativePathUTF8(dirent.d_name)) visitor.VisitArchiveEntry(dirent.d_name); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/archive/plugins/meson.build new/mpd-0.24.12/src/archive/plugins/meson.build --- old/mpd-0.24.10/src/archive/plugins/meson.build 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/archive/plugins/meson.build 2026-05-15 07:46:52.000000000 +0200 @@ -35,6 +35,7 @@ libbz2_dep, libiso9660_dep, libzzip_dep, + protocol_dep, ], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/command/FileCommands.cxx new/mpd-0.24.12/src/command/FileCommands.cxx --- old/mpd-0.24.10/src/command/FileCommands.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/command/FileCommands.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -5,6 +5,7 @@ #include "FileCommands.hxx" #include "Request.hxx" #include "protocol/Ack.hxx" +#include "protocol/Verify.hxx" #include "client/Client.hxx" #include "client/Response.hxx" #include "util/CharUtil.hxx" @@ -41,13 +42,6 @@ return PathTraitsFS::IsSpecialFilename(name_fs); } -[[gnu::pure]] -static bool -skip_path(Path name_fs) noexcept -{ - return name_fs.HasNewline(); -} - CommandResult handle_listfiles_local(Response &r, Path path_fs) { @@ -55,7 +49,7 @@ while (reader.ReadEntry()) { const Path name_fs = reader.GetEntry(); - if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs)) + if (SkipNameFS(name_fs.c_str()) || !VerifySeenFilename(name_fs)) continue; std::string name_utf8 = name_fs.ToUTF8(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/command/OtherCommands.cxx new/mpd-0.24.12/src/command/OtherCommands.cxx --- old/mpd-0.24.10/src/command/OtherCommands.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/command/OtherCommands.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -83,11 +83,11 @@ /* default is root directory */ const auto uri = args.GetOptional(0, ""); - const auto located_uri = LocateUri(UriPluginKind::STORAGE, uri, &client + const auto located_uri = LocateUri(UriPluginKind::STORAGE, uri, &client, #ifdef ENABLE_DATABASE - , nullptr + nullptr, #endif - ); + true); switch (located_uri.type) { case LocatedUri::Type::ABSOLUTE: @@ -203,11 +203,11 @@ compatibility, work around this here */ uri = ""; - const auto located_uri = LocateUri(UriPluginKind::INPUT, uri, &client + const auto located_uri = LocateUri(UriPluginKind::INPUT, uri, &client, #ifdef ENABLE_DATABASE - , nullptr + nullptr, #endif - ); + true); switch (located_uri.type) { case LocatedUri::Type::ABSOLUTE: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/command/QueueCommands.cxx new/mpd-0.24.12/src/command/QueueCommands.cxx --- old/mpd-0.24.10/src/command/QueueCommands.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/command/QueueCommands.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -70,11 +70,11 @@ : old_size; const auto located_uri = LocateUri(UriPluginKind::INPUT, uri, - &client + &client, #ifdef ENABLE_DATABASE - , nullptr + nullptr, #endif - ); + true); switch (located_uri.type) { case LocatedUri::Type::ABSOLUTE: AddUri(client, located_uri); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/command/StorageCommands.cxx new/mpd-0.24.12/src/command/StorageCommands.cxx --- old/mpd-0.24.10/src/command/StorageCommands.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/command/StorageCommands.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -17,24 +17,18 @@ #include "db/update/Service.hxx" #include "TimePrint.hxx" #include "protocol/IdleFlags.hxx" +#include "protocol/Verify.hxx" #include <fmt/format.h> #include <memory> -[[gnu::pure]] -static bool -skip_path(const char *name_utf8) noexcept -{ - return std::strchr(name_utf8, '\n') != nullptr; -} - static void handle_listfiles_storage(Response &r, StorageDirectoryReader &reader) { const char *name_utf8; while ((name_utf8 = reader.Read()) != nullptr) { - if (skip_path(name_utf8)) + if (!VerifySeenFilenameUTF8(name_utf8)) continue; StorageFileInfo info; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/db/update/Archive.cxx new/mpd-0.24.12/src/db/update/Archive.cxx --- old/mpd-0.24.10/src/db/update/Archive.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/db/update/Archive.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -7,6 +7,7 @@ #include "db/plugins/simple/Directory.hxx" #include "db/plugins/simple/Song.hxx" #include "storage/StorageInterface.hxx" +#include "protocol/Verify.hxx" #include "lib/fmt/PathFormatter.hxx" #include "fs/AllocatedPath.hxx" #include "storage/FileInfo.hxx" @@ -35,22 +36,13 @@ return directory.FindSong(name); } -[[gnu::pure]] -static bool -IsAcceptableFilename(std::string_view name) noexcept -{ - return !name.empty() && - /* newlines cannot be represented in MPD's protocol */ - name.find('\n') == name.npos; -} - void UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory, std::string_view name) noexcept { const auto [child_name, rest] = Split(name, '/'); if (rest.data() != nullptr) { - if (!IsAcceptableFilename(child_name)) + if (!VerifyRelativePathUTF8(child_name)) return; //add dir is not there already @@ -60,7 +52,7 @@ //create directories first UpdateArchiveTree(archive, *subdir, rest); } else { - if (!IsAcceptableFilename(name)) + if (!VerifyRelativePathUTF8(name)) return; //add file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/db/update/Walk.cxx new/mpd-0.24.12/src/db/update/Walk.cxx --- old/mpd-0.24.10/src/db/update/Walk.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/db/update/Walk.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -11,6 +11,7 @@ #include "db/plugins/simple/Song.hxx" #include "storage/StorageInterface.hxx" #include "ExcludeList.hxx" +#include "protocol/Verify.hxx" #include "fs/AllocatedPath.hxx" #include "fs/Traits.hxx" #include "fs/FileSystem.hxx" @@ -225,14 +226,6 @@ LogError(std::current_exception()); } -/* we don't look at files with newlines in their name */ -[[gnu::pure]] -static bool -skip_path(const char *name_utf8) noexcept -{ - return std::strchr(name_utf8, '\n') != nullptr; -} - [[gnu::pure]] bool UpdateWalk::SkipSymlink(const Directory *directory, @@ -359,7 +352,7 @@ const char *name_utf8; while (!cancel && (name_utf8 = reader->Read()) != nullptr) { - if (skip_path(name_utf8)) + if (!VerifySeenFilenameUTF8(name_utf8)) continue; { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/decoder/plugins/PcmDecoderPlugin.cxx new/mpd-0.24.12/src/decoder/plugins/PcmDecoderPlugin.cxx --- old/mpd-0.24.10/src/decoder/plugins/PcmDecoderPlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/decoder/plugins/PcmDecoderPlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -11,6 +11,7 @@ #include "util/ByteOrder.hxx" #include "util/Domain.hxx" #include "util/ByteReverse.hxx" +#include "util/DivideRoundUp.hxx" #include "util/StaticFifoBuffer.hxx" #include "util/CNumberParser.hxx" #include "util/MimeType.hxx" @@ -161,7 +162,7 @@ /* a buffer for pcm_unpack_24be() large enough to hold the results for a full source buffer */ - int32_t unpack_buffer[buffer.GetCapacity() / 3]; + int32_t unpack_buffer[DivideRoundUp(buffer.GetCapacity(), std::size_t{3})]; DecoderCommand cmd; do { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/decoder/plugins/SidplayDecoderPlugin.cxx new/mpd-0.24.12/src/decoder/plugins/SidplayDecoderPlugin.cxx --- old/mpd-0.24.10/src/decoder/plugins/SidplayDecoderPlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/decoder/plugins/SidplayDecoderPlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -27,9 +27,14 @@ #include <sidplayfp/SidConfig.h> #include <sidplayfp/SidTune.h> #include <sidplayfp/SidTuneInfo.h> -#include <sidplayfp/builders/residfp.h> #include <sidplayfp/SidDatabase.h> +#ifdef HAVE_RESID_BUILDER +#include <sidplayfp/builders/residfp.h> +#else +#include <sidplayfp/builders/sidlite.h> +#endif + #include <fmt/format.h> #include <array> @@ -233,7 +238,11 @@ /* initialize the builder */ +#ifdef HAVE_RESID_BUILDER ReSIDfpBuilder builder("ReSID"); +#else + SIDLiteBuilder builder{"SIDLite"}; +#endif #if LIBSIDPLAYFP_VERSION_MAJ < 3 if (!builder.getStatus()) { FmtWarning(sidplay_domain, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/decoder/plugins/meson.build new/mpd-0.24.12/src/decoder/plugins/meson.build --- old/mpd-0.24.10/src/decoder/plugins/meson.build 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/decoder/plugins/meson.build 2026-05-15 07:46:52.000000000 +0200 @@ -165,6 +165,7 @@ decoder_features.set('ENABLE_SIDPLAY', libsidplay_dep.found()) if libsidplay_dep.found() decoder_plugins_sources += 'SidplayDecoderPlugin.cxx' + decoder_features.set('HAVE_RESID_BUILDER', c_compiler.has_header('sidplayfp/builders/residfp.h', dependencies: libsidplay_dep)) endif decoder_plugins = static_library( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/input/plugins/CurlInputPlugin.cxx new/mpd-0.24.12/src/input/plugins/CurlInputPlugin.cxx --- old/mpd-0.24.10/src/input/plugins/CurlInputPlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/input/plugins/CurlInputPlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -628,10 +628,6 @@ static InputStreamPtr input_curl_open(std::string_view url, Mutex &mutex) { - if (!StringStartsWithIgnoreCase(url, "http://"sv) && - !StringStartsWithIgnoreCase(url, "https://"sv)) - return nullptr; - return CurlInputStream::Open(url, {}, mutex); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/lib/curl/Version.cxx new/mpd-0.24.12/src/lib/curl/Version.cxx --- old/mpd-0.24.10/src/lib/curl/Version.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/lib/curl/Version.cxx 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -// author: Max Kellermann <[email protected]> - -#include "Version.hxx" - -#include <curl/curl.h> - -bool -IsCurlOlderThan(unsigned version_num) noexcept -{ - const auto *const info = curl_version_info(CURLVERSION_FIRST); - return info == nullptr || info->version_num < version_num; -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/lib/curl/Version.hxx new/mpd-0.24.12/src/lib/curl/Version.hxx --- old/mpd-0.24.10/src/lib/curl/Version.hxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/lib/curl/Version.hxx 1970-01-01 01:00:00.000000000 +0100 @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -// author: Max Kellermann <[email protected]> - -#ifndef CURL_VERSION_HXX -#define CURL_VERSION_HXX - -[[gnu::const]] -bool -IsCurlOlderThan(unsigned version_num) noexcept; - -#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/lib/curl/meson.build new/mpd-0.24.12/src/lib/curl/meson.build --- old/mpd-0.24.10/src/lib/curl/meson.build 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/lib/curl/meson.build 2026-05-15 07:46:52.000000000 +0200 @@ -1,4 +1,4 @@ -curl_dep = dependency('libcurl', version: '>= 7.55', required: get_option('curl')) +curl_dep = dependency('libcurl', version: '>= 7.85', required: get_option('curl')) conf.set('ENABLE_CURL', curl_dep.found()) if not curl_dep.found() subdir_done() @@ -14,7 +14,6 @@ curl = static_library( 'curl', 'Delegate.cxx', - 'Version.cxx', 'Init.cxx', 'Global.cxx', 'Request.cxx', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/pcm/Dsd2Pcm.cxx new/mpd-0.24.12/src/pcm/Dsd2Pcm.cxx --- old/mpd-0.24.10/src/pcm/Dsd2Pcm.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/pcm/Dsd2Pcm.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -34,6 +34,7 @@ #include "Traits.hxx" #include "util/BitReverse.hxx" #include "util/Compiler.h" +#include "util/DivideRoundUp.hxx" #include "util/GenerateArray.hxx" #include <cassert> @@ -45,7 +46,7 @@ static constexpr size_t HTAPS = 48; /** number of "8 MACs" lookup tables */ -static constexpr size_t CTABLES = (HTAPS + 7) / 8; +static constexpr size_t CTABLES = DivideRoundUp(HTAPS, size_t{8}); static_assert(Dsd2Pcm::FIFOSIZE * 8 >= HTAPS * 2, "FIFOSIZE too small"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/pcm/FallbackResampler.cxx new/mpd-0.24.12/src/pcm/FallbackResampler.cxx --- old/mpd-0.24.10/src/pcm/FallbackResampler.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/pcm/FallbackResampler.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -2,6 +2,7 @@ // Copyright The Music Player Daemon Project #include "FallbackResampler.hxx" +#include "util/DivideRoundUp.hxx" #include "util/SpanCast.hxx" #include <cassert> @@ -55,8 +56,7 @@ { unsigned dest_pos = 0; unsigned src_frames = src.size() / channels; - unsigned dest_frames = - (src_frames * dest_rate + src_rate - 1) / src_rate; + const unsigned dest_frames = DivideRoundUp(src_frames * dest_rate, src_rate); unsigned dest_samples = dest_frames * channels; size_t dest_size = dest_samples * sizeof(T); T *dest_buffer = (T *)buffer.Get(dest_size); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/playlist/plugins/AsxPlaylistPlugin.cxx new/mpd-0.24.12/src/playlist/plugins/AsxPlaylistPlugin.cxx --- old/mpd-0.24.10/src/playlist/plugins/AsxPlaylistPlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/playlist/plugins/AsxPlaylistPlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -4,6 +4,7 @@ #include "AsxPlaylistPlugin.hxx" #include "../PlaylistPlugin.hxx" #include "../MemorySongEnumerator.hxx" +#include "protocol/Verify.hxx" #include "tag/Builder.hxx" #include "tag/Table.hxx" #include "util/ASCII.hxx" @@ -99,7 +100,7 @@ case AsxParser::ENTRY: if (StringEqualsCaseASCII(element_name, "entry")) { - if (!parser->location.empty()) + if (VerifyUriUTF8(parser->location)) parser->songs.emplace_front(std::move(parser->location), parser->tag_builder.Commit()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/playlist/plugins/PlsPlaylistPlugin.cxx new/mpd-0.24.12/src/playlist/plugins/PlsPlaylistPlugin.cxx --- old/mpd-0.24.10/src/playlist/plugins/PlsPlaylistPlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/playlist/plugins/PlsPlaylistPlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -8,6 +8,7 @@ #include "input/InputStream.hxx" #include "song/DetachedSong.hxx" #include "tag/Builder.hxx" +#include "protocol/Verify.hxx" #include "util/ASCII.hxx" #include "util/NumberParser.hxx" #include "util/StringCompare.hxx" @@ -113,7 +114,8 @@ auto i = songs.before_begin(); for (const auto &entry : entries) { - const char *uri = entry.file.c_str(); + if (!VerifyUriUTF8(entry.file)) + continue; TagBuilder tag; if (!entry.title.empty()) @@ -122,7 +124,7 @@ if (entry.length > 0) tag.SetDuration(SignedSongTime::FromS(entry.length)); - i = songs.emplace_after(i, uri, tag.Commit()); + i = songs.emplace_after(i, std::move(entry.file), tag.Commit()); } return true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/playlist/plugins/RssPlaylistPlugin.cxx new/mpd-0.24.12/src/playlist/plugins/RssPlaylistPlugin.cxx --- old/mpd-0.24.10/src/playlist/plugins/RssPlaylistPlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/playlist/plugins/RssPlaylistPlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -5,6 +5,7 @@ #include "../PlaylistPlugin.hxx" #include "../MemorySongEnumerator.hxx" #include "tag/Builder.hxx" +#include "protocol/Verify.hxx" #include "util/ASCII.hxx" #include "lib/expat/ExpatParser.hxx" @@ -85,7 +86,7 @@ case RssParser::ITEM: if (StringEqualsCaseASCII(element_name, "item")) { - if (!parser->location.empty()) + if (VerifyUriUTF8(parser->location)) parser->songs.emplace_front(std::move(parser->location), parser->tag_builder.Commit()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/playlist/plugins/XspfPlaylistPlugin.cxx new/mpd-0.24.12/src/playlist/plugins/XspfPlaylistPlugin.cxx --- old/mpd-0.24.10/src/playlist/plugins/XspfPlaylistPlugin.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/playlist/plugins/XspfPlaylistPlugin.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -4,6 +4,7 @@ #include "XspfPlaylistPlugin.hxx" #include "../PlaylistPlugin.hxx" #include "../MemorySongEnumerator.hxx" +#include "protocol/Verify.hxx" #include "song/DetachedSong.hxx" #include "input/InputStream.hxx" #include "tag/Builder.hxx" @@ -129,7 +130,7 @@ case XspfParser::TRACK: if (strcmp(element_name, "track") == 0) { - if (!parser->location.empty()) + if (VerifyUriUTF8(parser->location)) parser->songs.emplace_front(std::move(parser->location), parser->tag_builder.Commit()); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/playlist/plugins/meson.build new/mpd-0.24.12/src/playlist/plugins/meson.build --- old/mpd-0.24.10/src/playlist/plugins/meson.build 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/playlist/plugins/meson.build 2026-05-15 07:46:52.000000000 +0200 @@ -10,6 +10,7 @@ flac_dep, input_basic_dep, config_dep, + protocol_dep, ] playlist_features.set('ENABLE_CUE', get_option('cue')) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/protocol/Verify.cxx new/mpd-0.24.12/src/protocol/Verify.cxx --- old/mpd-0.24.10/src/protocol/Verify.cxx 1970-01-01 01:00:00.000000000 +0100 +++ new/mpd-0.24.12/src/protocol/Verify.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright The Music Player Daemon Project + +#include "Verify.hxx" +#include "fs/Path.hxx" +#include "util/UTF8.hxx" + +#include <cstring> // for std::strchr() + +/** + * Is this a valid string for transmitting it as a value over the MPD + * text protocol? + */ +bool +VerifyStringUTF8(const char *s) noexcept +{ + /* newlines cannot be represented in MPD's protocol */ + return std::strchr(s, '\n') == nullptr && + /* the MPD protocol is UTF-8 only */ + ValidateUTF8(s); +} + +bool +VerifyStringUTF8(std::string_view s) noexcept +{ + /* newlines cannot be represented in MPD's protocol */ + return s.find('\n') == s.npos && + /* null bytes are forbidden, too */ + s.find('\0') == s.npos && + /* the MPD protocol is UTF-8 only */ + ValidateUTF8(s); +} + +bool +VerifySeenFilename(Path filename_fs) noexcept +{ + return !filename_fs.HasNewline(); +} + +bool +VerifyPathUTF8(std::string_view path_utf8) noexcept +{ + return !path_utf8.empty() && VerifyStringUTF8(path_utf8); +} + +bool +VerifyRelativePathUTF8(std::string_view path_utf8) noexcept +{ + // TODO check whether it's a relative path + return VerifyPathUTF8(path_utf8); +} + +bool +VerifyUriUTF8(std::string_view uri_utf8) noexcept +{ + return !uri_utf8.empty() && VerifyStringUTF8(uri_utf8); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/protocol/Verify.hxx new/mpd-0.24.12/src/protocol/Verify.hxx --- old/mpd-0.24.10/src/protocol/Verify.hxx 1970-01-01 01:00:00.000000000 +0100 +++ new/mpd-0.24.12/src/protocol/Verify.hxx 2026-05-15 07:46:52.000000000 +0200 @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright The Music Player Daemon Project + +#pragma once + +#include <string_view> + +class Path; + +/** + * Is this a valid string for transmitting it as a value over the MPD + * text protocol? + */ +[[gnu::pure]] +bool +VerifyStringUTF8(const char *s) noexcept; + +[[gnu::pure]] +bool +VerifyStringUTF8(std::string_view s) noexcept; + +/** + * Is this a valid filename (for transmitting it as a value over the + * MPD text protocol)? + * + * Note: this function is designed to be used to verify actual file + * names (that were actually seen); for example, it does not check for + * path separators which would be invalid in a bare file name. + */ +[[gnu::pure]] +static inline +bool +VerifySeenFilenameUTF8(const char *filename_utf8) noexcept +{ + return VerifyStringUTF8(filename_utf8); +} + +[[gnu::pure]] +bool +VerifySeenFilename(Path filename_fs) noexcept; + +/** + * Is this a valid path (for transmitting it as a value over the MPD + * text protocol)? + */ +[[gnu::pure]] +bool +VerifyPathUTF8(std::string_view path_utf8) noexcept; + +/** + * Is this a valid relative path (for transmitting it as a value over + * the MPD text protocol)? + */ +[[gnu::pure]] +bool +VerifyRelativePathUTF8(std::string_view path_utf8) noexcept; + +/** + * Is this a valid URI string (for transmitting it as a value over + * the MPD text protocol)? + * + * In the MPD protocol, URIs can be actual URIs or absolute/relative + * file paths. This function allows all of these. + */ +[[gnu::pure]] +bool +VerifyUriUTF8(std::string_view uri_utf8) noexcept; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/protocol/meson.build new/mpd-0.24.12/src/protocol/meson.build --- old/mpd-0.24.10/src/protocol/meson.build 1970-01-01 01:00:00.000000000 +0100 +++ new/mpd-0.24.12/src/protocol/meson.build 2026-05-15 07:46:52.000000000 +0200 @@ -0,0 +1,12 @@ +protocol = static_library( + 'protocol', + 'Verify.cxx', + include_directories: inc, + dependencies: [ + util_dep, + ], +) + +protocol_dep = declare_dependency( + link_with: protocol, +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/tag/Rva2.cxx new/mpd-0.24.12/src/tag/Rva2.cxx --- old/mpd-0.24.10/src/tag/Rva2.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/tag/Rva2.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -3,6 +3,7 @@ #include "Rva2.hxx" #include "ReplayGainInfo.hxx" +#include "util/DivideRoundUp.hxx" #include <id3tag.h> @@ -31,7 +32,7 @@ static inline id3_length_t rva2_peak_bytes(const Rva2Data &data) { - return (data.peak_bits + 7) / 8; + return DivideRoundUp(unsigned{data.peak_bits}, 8U); } static inline int diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/util/DivideRoundUp.hxx new/mpd-0.24.12/src/util/DivideRoundUp.hxx --- old/mpd-0.24.10/src/util/DivideRoundUp.hxx 1970-01-01 01:00:00.000000000 +0100 +++ new/mpd-0.24.12/src/util/DivideRoundUp.hxx 2026-05-15 07:46:52.000000000 +0200 @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: BSD-2-Clause +// Copyright CM4all GmbH +// author: Max Kellermann <[email protected]> + +#pragma once + +#include <concepts> // for std::unsigned_integral + +template<std::unsigned_integral T> +static constexpr T +DivideRoundUp(T a, T b) noexcept +{ + return (a + b - 1) / b; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/util/UTF8.cxx new/mpd-0.24.12/src/util/UTF8.cxx --- old/mpd-0.24.10/src/util/UTF8.cxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/util/UTF8.cxx 2026-05-15 07:46:52.000000000 +0200 @@ -141,6 +141,55 @@ return true; } +bool +ValidateUTF8(std::string_view s) noexcept +{ + for (auto i = s.begin(), end = s.end(); i != end; ++i) { + uint8_t ch = *i; + if (IsASCII(ch)) + continue; + + if (IsContinuation(ch)) + /* continuation without a prefix */ + return false; + + if (IsLeading1(ch)) { + /* 1 continuation */ + if (++i == end || !IsContinuation(*i)) + return false; + } else if (IsLeading2(ch)) { + /* 2 continuations */ + if (++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i)) + return false; + } else if (IsLeading3(ch)) { + /* 3 continuations */ + if (++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i)) + return false; + } else if (IsLeading4(ch)) { + /* 4 continuations */ + if (++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i)) + return false; + } else if (IsLeading5(ch)) { + /* 5 continuations */ + if (++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i) || + ++i == end || !IsContinuation(*i)) + return false; + } else + return false; + } + + return true; +} + std::size_t SequenceLengthUTF8(char ch) noexcept { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/util/UTF8.hxx new/mpd-0.24.12/src/util/UTF8.hxx --- old/mpd-0.24.10/src/util/UTF8.hxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/util/UTF8.hxx 2026-05-15 07:46:52.000000000 +0200 @@ -1,10 +1,10 @@ // SPDX-License-Identifier: BSD-2-Clause // author: Max Kellermann <[email protected]> -#ifndef UTF8_HXX -#define UTF8_HXX +#pragma once #include <cstddef> +#include <string_view> /** * Is this a valid UTF-8 string? @@ -13,6 +13,10 @@ bool ValidateUTF8(const char *p) noexcept; +[[gnu::pure]] +bool +ValidateUTF8(std::string_view s) noexcept; + /** * @return the number of the sequence beginning with the given * character, or 0 if the character is not a valid start byte @@ -57,5 +61,3 @@ [[gnu::pure]] [[gnu::nonnull]] std::size_t LengthUTF8(const char *p) noexcept; - -#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/src/util/UriUtil.hxx new/mpd-0.24.12/src/util/UriUtil.hxx --- old/mpd-0.24.10/src/util/UriUtil.hxx 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/src/util/UriUtil.hxx 2026-05-15 07:46:52.000000000 +0200 @@ -12,7 +12,6 @@ * - non-empty * - does not begin or end with a slash * - no double slashes - * - no path component begins with a dot */ [[gnu::pure]] bool diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mpd-0.24.10/subprojects/sqlite3.wrap new/mpd-0.24.12/subprojects/sqlite3.wrap --- old/mpd-0.24.10/subprojects/sqlite3.wrap 2026-05-06 22:00:04.000000000 +0200 +++ new/mpd-0.24.12/subprojects/sqlite3.wrap 2026-05-15 07:46:52.000000000 +0200 @@ -1,14 +1,14 @@ [wrap-file] -directory = sqlite-amalgamation-3530000 -source_url = https://www.sqlite.org/2026/sqlite-amalgamation-3530000.zip -source_filename = sqlite-amalgamation-3530000.zip -source_hash = bf3733d7c71b3ab0f6fd8a9ea0052ad87fa037d94333e14ce09878ba3492c3b0 -source_fallback_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.53.0-1/get_source/sqlite-amalgamation-3530000.zip -patch_filename = sqlite3_3.53.0-1_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.53.0-1/get_patch -patch_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sqlite3_3.53.0-1/sqlite3_3.53.0-1_patch.zip -patch_hash = 370e827f3e25567c0990eeadba831aef389ea37d44e32dac063f2b82371e8455 -wrapdb_version = 3.53.0-1 +directory = sqlite-amalgamation-3530100 +source_url = https://www.sqlite.org/2026/sqlite-amalgamation-3530100.zip +source_filename = sqlite-amalgamation-3530100.zip +source_hash = 36ad6e7f38540a3b21a2ac36340833f0a9e426bc1c752751c3ba669466827eae +source_fallback_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.53.1-1/get_source/sqlite-amalgamation-3530100.zip +patch_filename = sqlite3_3.53.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.53.1-1/get_patch +patch_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sqlite3_3.53.1-1/sqlite3_3.53.1-1_patch.zip +patch_hash = d1a5758285f8a0659317f0f84e9c9c8c839fe7c1d19448ac62d95ecefd5ba3a5 +wrapdb_version = 3.53.1-1 [provide] dependency_names = sqlite3
