Bug 1691347 - Work around a null argument bug in _platform_strstr in CUPS. r=dholbert

This is just a large conditional to check for the specific branches taken
that would result in the null string. The path in CUPS is as follows:

In cupsCopyDestInfo, CUPS_DEST_FLAG_DEVICE is set when the connection is not
null (same as CUPS_HTTP_DEFAULT), the print server is not the same as our
hostname and is not path-based (starts with a '/'), or the IPP port is
different than the global server IPP port.

c9da6f63b2/cups/dest-options.c (L718-L722)

In _cupsGetDestResource, CUPS fetches the IPP options "printer-uri-supported"
and "device-uri". Importantly, IPP options are returned as null when missing.

23c45db76a/cups/dest.c (L1138-L1141)

If the CUPS_DEST_FLAG_DEVICE is set or the "printer-uri-supported" option is
not set, CUPS checks for "._tcp" in the "device-uri" option without doing a
NULL-check first.

23c45db76a/cups/dest.c (L1144)

If we find that those branches will be taken, don't actually fetch the CUPS
data and instead just return an empty printer info.

Differential Revision: https://phabricator.services.mozilla.com/D128529
This commit is contained in:
Emily McDonough 2021-10-22 22:55:25 +00:00
Родитель d5dbd9115b
Коммит c286431b9a
3 изменённых файлов: 82 добавлений и 3 удалений

Просмотреть файл

@ -58,14 +58,19 @@ class nsCUPSShim {
X(Optional::No, cupsGetDests) \
X(Optional::No, cupsGetNamedDest) \
X(Optional::No, cupsGetOption) \
X(Optional::No, cupsServer) \
X(Optional::Yes, httpAddrPort) \
X(Optional::No, httpClose) \
X(Optional::No, httpGetHostname) \
X(Optional::Yes, httpGetAddress) \
X(Optional::No, ippAddString) \
X(Optional::No, ippAddStrings) \
X(Optional::No, ippDelete) \
X(Optional::No, ippFindAttribute) \
X(Optional::No, ippGetCount) \
X(Optional::No, ippGetString) \
X(Optional::No, ippNewRequest)
X(Optional::No, ippNewRequest) \
X(Optional::No, ippPort)
#ifdef CUPS_SHIM_RUNTIME_LINK
// Define a single field which holds a function pointer.

Просмотреть файл

@ -149,8 +149,7 @@ bool nsPrinterCUPS::SupportsColor() const {
bool nsPrinterCUPS::SupportsCollation() const {
// We can't depend on cupsGetIntegerOption existing.
const char* const value = mShim.cupsGetOption(
"printer-type", mPrinter->num_options, mPrinter->options);
const char* const value = FindCUPSOption("printer-type");
if (!value) {
return false;
}
@ -350,6 +349,77 @@ nsPrinterCUPS::PrinterInfoLock nsPrinterCUPS::TryEnsurePrinterInfo(
lock->mTriedInitWithConnection = true;
}
MOZ_ASSERT(mPrinter);
// httpGetAddress was only added in CUPS 2.0, and some systems still use
// CUPS 1.7.
if (aConnection && MOZ_LIKELY(mShim.httpGetAddress && mShim.httpAddrPort)) {
// This is a workaround for the CUPS Bug seen in bug 1691347.
// This is to avoid a null string being passed to strstr in CUPS. The path
// in CUPS that leads to this is as follows:
//
// In cupsCopyDestInfo, CUPS_DEST_FLAG_DEVICE is set when the connection is
// not null (same as CUPS_HTTP_DEFAULT), the print server is not the same
// as our hostname and is not path-based (starts with a '/'), or the IPP
// port is different than the global server IPP port.
//
// https://github.com/apple/cups/blob/c9da6f63b263faef5d50592fe8cf8056e0a58aa2/cups/dest-options.c#L718-L722
//
// In _cupsGetDestResource, CUPS fetches the IPP options "device-uri" and
// "printer-uri-supported". Note that IPP options are returned as null when
// missing.
//
// https://github.com/apple/cups/blob/23c45db76a8520fd6c3b1d9164dbe312f1ab1481/cups/dest.c#L1138-L1141
//
// If the CUPS_DEST_FLAG_DEVICE is set or the "printer-uri-supported"
// option is not set, CUPS checks for "._tcp" in the "device-uri" option
// without doing a NULL-check first.
//
// https://github.com/apple/cups/blob/23c45db76a8520fd6c3b1d9164dbe312f1ab1481/cups/dest.c#L1144
//
// If we find that those branches will be taken, don't actually fetch the
// CUPS data and instead just return an empty printer info.
const char* const serverNameBytes = mShim.cupsServer();
if (MOZ_LIKELY(serverNameBytes)) {
const nsDependentCString serverName{serverNameBytes};
// We only need enough characters to determine equality with serverName.
// + 2 because we need one byte for the null-character, and we also want
// to get more characters of the host name than the server name if
// possible. Otherwise, if the hostname starts with the same text as the
// entire server name, it would compare equal when it's not.
const size_t hostnameMemLength = serverName.Length() + 2;
auto hostnameMem = MakeUnique<char[]>(hostnameMemLength);
// We don't expect httpGetHostname to return null when a connection is
// passed, but it's better not to make assumptions.
const char* const hostnameBytes = mShim.httpGetHostname(
aConnection, hostnameMem.get(), hostnameMemLength);
if (MOZ_LIKELY(hostnameBytes)) {
const nsDependentCString hostname{hostnameBytes};
// Match the condional at
// https://github.com/apple/cups/blob/c9da6f63b263faef5d50592fe8cf8056e0a58aa2/cups/dest-options.c#L718
const bool portsDiffer =
mShim.httpAddrPort(mShim.httpGetAddress(aConnection)) !=
mShim.ippPort();
const bool cupsDestDeviceFlag =
(hostname != serverName && serverName[0] != '/') || portsDiffer;
// Match the conditional at
// https://github.com/apple/cups/blob/23c45db76a8520fd6c3b1d9164dbe312f1ab1481/cups/dest.c#L1144
// but if device-uri is null do not call into CUPS.
if ((cupsDestDeviceFlag || !FindCUPSOption("printer-uri-supported")) &&
!FindCUPSOption("device-uri")) {
return lock;
}
}
}
}
// All CUPS calls that take the printer info do null-checks internally, so we
// can fetch this info and only worry about the result of the later CUPS
// functions.

Просмотреть файл

@ -48,6 +48,10 @@ class nsPrinterCUPS final : public nsPrinterBase {
static void ForEachExtraMonochromeSetting(
mozilla::FunctionRef<void(const nsACString&, const nsACString&)>);
inline const char* FindCUPSOption(const char* name) const {
return mShim.cupsGetOption(name, mPrinter->num_options, mPrinter->options);
}
private:
struct CUPSPrinterInfo {
cups_dinfo_t* mPrinterInfo = nullptr;