RHEL-93944 RFE: Add Allow list for FoomaticRIPCommandLine PPD values [rhel-10]
Resolves: RHEL-93944
This commit is contained in:
parent
30151e07d7
commit
7679ea82cd
1440
0001-Introduce-foomatic-hash-and-reject-unauthorized-valu.patch
Normal file
1440
0001-Introduce-foomatic-hash-and-reject-unauthorized-valu.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@ Summary: OpenPrinting CUPS filters for CUPS 2.X
|
||||
Name: cups-filters
|
||||
Epoch: 1
|
||||
Version: 2.0.0
|
||||
Release: 10%{?dist}
|
||||
Release: 11%{?dist}
|
||||
|
||||
# the CUPS exception text is the same as LLVM exception, so using that name with
|
||||
# agreement from legal team
|
||||
@ -31,6 +31,15 @@ Source2: lftocrlf
|
||||
|
||||
|
||||
# Patches
|
||||
# introducing foomatic-hash, but without rejecting values in foomatic-rip
|
||||
# https://github.com/OpenPrinting/cups-filters/pull/648
|
||||
Patch001: 0001-Introduce-foomatic-hash-and-reject-unauthorized-valu.patch
|
||||
# make sure errors from foomatic-rip are propagated
|
||||
# https://github.com/OpenPrinting/cups-filters/pull/649
|
||||
Patch002: foomatic-ripdie-error.patch
|
||||
# rejecting the unknown values in foomatic-rip
|
||||
# https://github.com/OpenPrinting/cups-filters/pull/648
|
||||
Patch003: foomaticrip-reject-unknown-values.patch
|
||||
|
||||
|
||||
# driverless backend/driver was moved into a separate package to
|
||||
@ -63,6 +72,8 @@ BuildRequires: pkgconfig(libcupsfilters) >= 2.0b3
|
||||
BuildRequires: pkgconfig(libppd) >= 2.0b3
|
||||
# Make sure we get postscriptdriver tags.
|
||||
BuildRequires: python3-cups
|
||||
# for systemd unit for upgrade
|
||||
BuildRequires: systemd-rpm-macros
|
||||
|
||||
%if %{with braille}
|
||||
Recommends: braille-printer-app
|
||||
@ -132,6 +143,68 @@ queues.
|
||||
install -p -m 0755 %{SOURCE2} %{buildroot}%{_cups_serverbin}/filter/lftocrlf
|
||||
install -p -m 0644 %{SOURCE1} %{buildroot}%{_datadir}/ppd/cupsfilters/lftocrlf.ppd
|
||||
|
||||
# for post upgrade script to allow already existing printers
|
||||
mkdir -p %{buildroot}%{_libexecdir}/%{name}
|
||||
|
||||
# the script which does the deed - goes PPD file by PPD file if there are any
|
||||
# problematic PPD options, scans the values into file in /var/tmp for review, while
|
||||
# hashed values are saved in a file in directory where foomatic-rip reads it.
|
||||
#
|
||||
# hashes.new is for marking this script already run once, so it won't be run again.
|
||||
# It is needed to prevent allowing newly installed printers after another upgrade.
|
||||
# This is handled by systemd unit.
|
||||
cat > %{buildroot}%{_libexecdir}/%{name}/posttrans.sh << EOF
|
||||
#!/usr/bin/bash
|
||||
|
||||
if \$(grep -q -R 'FoomaticRIPCommandLine\|FoomaticRipOptionSetting' %{_sysconfdir}/cups/ppd)
|
||||
then
|
||||
tmpfile=\$(mktemp -p /var/tmp foomatic-scan.XXXXXXXX)
|
||||
|
||||
for ppd in %{_sysconfdir}/cups/ppd/*.ppd
|
||||
do
|
||||
foomatic-hash --ppd \$ppd \$tmpfile %{_sysconfdir}/foomatic/hashes.d/hashes.upgrade || :
|
||||
done
|
||||
|
||||
if test -f %{_sysconfdir}/foomatic/hashes.d/hashes.upgrade
|
||||
then
|
||||
echo "Foomatic-rip values which can inject code found - review findings in \$tmpfile. Read release notes for instructions." || :
|
||||
fi
|
||||
else
|
||||
touch %{_sysconfdir}/foomatic/hashes.d/hashes.new
|
||||
fi
|
||||
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
mkdir -p %{buildroot}%{_unitdir}
|
||||
|
||||
# Upgrade service which will be run only when the specified directory is empty
|
||||
# - the service will be run only once, on the first upgrade introducing the change.
|
||||
cat > %{buildroot}%{_unitdir}/foomaticrip-upgrade.service << EOF
|
||||
[Unit]
|
||||
Description=Allowing already installed printers for foomatic-rip
|
||||
ConditionPathIsDirectory=%{_sysconfdir}/foomatic/hashes.d
|
||||
ConditionDirectoryNotEmpty=!%{_sysconfdir}/foomatic/hashes.d
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=bash -c %{_libexecdir}/%{name}/posttrans.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
mkdir -p %{buildroot}%{_unitdir}/cups.service.d
|
||||
|
||||
# We have to make sure the upgrade service is run before starting cupsd, so the allowed
|
||||
# hashes are in place already and there is no printing disruption.
|
||||
cat > %{buildroot}%{_unitdir}/cups.service.d/10-foomaticrip-upgrade.conf << EOF
|
||||
[Unit]
|
||||
After=foomaticrip-upgrade.service
|
||||
Wants=foomaticrip-upgrade.service
|
||||
EOF
|
||||
|
||||
|
||||
# LSB3.2 requires /usr/bin/foomatic-rip,
|
||||
# create it temporarily as a relative symlink
|
||||
# we may use symlink to universal filter, but LSB is about guaranteed compatibility set
|
||||
@ -166,11 +239,29 @@ if [ $1 -gt 1 ]
|
||||
then
|
||||
rm -f /var/cache/cups/ppds.dat || :
|
||||
fi
|
||||
%systemd_post foomaticrip-upgrade.service
|
||||
|
||||
|
||||
%preun
|
||||
%systemd_preun foomaticrip-upgrade.service
|
||||
|
||||
|
||||
%postun
|
||||
%systemd_postun foomaticrip-upgrade.service
|
||||
|
||||
|
||||
%posttrans
|
||||
%systemd_posttrans_with_reload foomaticrip-upgrade.service
|
||||
if [ $1 -gt 1 ]
|
||||
then
|
||||
systemctl start foomaticrip-upgrade.service || :
|
||||
fi
|
||||
|
||||
|
||||
%files
|
||||
%license COPYING LICENSE NOTICE
|
||||
%doc AUTHORS ABOUT-NLS CHANGES.md CONTRIBUTING.md DEVELOPING.md README.md
|
||||
%{_bindir}/foomatic-hash
|
||||
%{_bindir}/foomatic-rip
|
||||
%attr(0744,root,root) %{_cups_serverbin}/backend/beh
|
||||
# all backends needs to be run only as root because of kerberos
|
||||
@ -208,6 +299,8 @@ fi
|
||||
%{_datadir}/cups/mime/cupsfilters.convs
|
||||
%{_datadir}/cups/mime/cupsfilters-universal-postscript.convs
|
||||
%{_datadir}/cups/mime/cupsfilters-universal.convs
|
||||
%dir %{_datadir}/foomatic
|
||||
%dir %{_datadir}/foomatic/hashes.d
|
||||
%{_datadir}/ppd/cupsfilters
|
||||
%if %{with cups_ppdc}
|
||||
# escp.h and pcl.h are required during runtime, because
|
||||
@ -220,7 +313,15 @@ fi
|
||||
%{_datadir}/ppdc/escp.h
|
||||
%{_datadir}/ppdc/pcl.h
|
||||
%endif
|
||||
%dir %{_libexecdir}/%{name}
|
||||
%attr(0744,root,root) %{_libexecdir}/%{name}/posttrans.sh
|
||||
%{_mandir}/man1/foomatic-hash.1.gz
|
||||
%{_mandir}/man1/foomatic-rip.1.gz
|
||||
%config(noreplace) %{_sysconfdir}/foomatic
|
||||
%ghost %attr(0644,root,root) %{_sysconfdir}/foomatic/hashes.d/hashes.new
|
||||
%dir %{_unitdir}/cups.service.d
|
||||
%{_unitdir}/cups.service.d/10-foomaticrip-upgrade.conf
|
||||
%{_unitdir}/foomaticrip-upgrade.service
|
||||
|
||||
%files driverless
|
||||
%license COPYING LICENSE NOTICE
|
||||
@ -234,6 +335,9 @@ fi
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Sep 30 2025 Zdenek Dohnal <zdohnal@redhat.com> - 1:2.0.0-11
|
||||
- RHEL-93944 RFE: Add Allow list for FoomaticRIPCommandLine PPD values [rhel-10]
|
||||
|
||||
* Wed Jul 23 2025 Zdenek Dohnal <zdohnal@redhat.com> - 1:2.0.0-10
|
||||
- RHEL-83060 lpinfo -m doesn't show textonly driver
|
||||
|
||||
|
||||
13
foomatic-ripdie-error.patch
Normal file
13
foomatic-ripdie-error.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/filter/foomatic-rip/util.c b/filter/foomatic-rip/util.c
|
||||
index 508bc09..ad79fbf 100644
|
||||
--- a/filter/foomatic-rip/util.c
|
||||
+++ b/filter/foomatic-rip/util.c
|
||||
@@ -76,7 +76,7 @@ rip_die(int status,
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
- _log("Process is dying with \"");
|
||||
+ _log("ERROR: Process is dying with \"");
|
||||
va_start(ap, msg);
|
||||
_logv(msg, ap);
|
||||
va_end(ap);
|
||||
188
foomaticrip-reject-unknown-values.patch
Normal file
188
foomaticrip-reject-unknown-values.patch
Normal file
@ -0,0 +1,188 @@
|
||||
From 41c5f2f6139e4d3693c2483ee4281202a80ae451 Mon Sep 17 00:00:00 2001
|
||||
From: zdohnal <zdohnal@redhat.com>
|
||||
Date: Tue, 22 Jul 2025 15:12:19 +0200
|
||||
Subject: [PATCH] Introduce foomatic-hash and reject unauthorized values in
|
||||
foomatic-rip (#648)
|
||||
|
||||
The change provides a way for users to have control over what values are
|
||||
allowed for the foomatic-rip-related PPD keywords FoomaticRIPCommandLine,
|
||||
FoomaticRIPCommandLinePDF, and FoomaticRIPOptionSetting. Since the
|
||||
values can be later used when constructing a shell command, the filter
|
||||
foomatic-rip was a target of several exploits (caused by issues at
|
||||
different places in CUPS or in different projects of the printing stack) to
|
||||
do arbitrary code execution when the filter is used.
|
||||
|
||||
By default the filter is run by user lp, so the issue is mitigated, but
|
||||
this PR gives admin complete control over what can be run in
|
||||
foomatic-rip and reject anything injected into system via different
|
||||
ways.
|
||||
|
||||
First, the new tool - foomatic-hash - can be called on a PPD file or
|
||||
directory with drivers/PPDs, with scan output and file with hexadecimal
|
||||
representation of hashed values. Once the scan output is reviewed by
|
||||
admin, admin can decide to put the resulting hashes into
|
||||
/etc/foomatic/hashes.d and allow them for the filter.
|
||||
---
|
||||
Makefile.am | 44 ++-
|
||||
README.md | 23 ++
|
||||
configure.ac | 2 +-
|
||||
filter/foomatic-rip/foomatic-hash.1 | 66 ++++
|
||||
filter/foomatic-rip/foomatic-hash.c | 549 ++++++++++++++++++++++++++
|
||||
filter/foomatic-rip/foomatic-rip.1.in | 16 +
|
||||
filter/foomatic-rip/foomaticrip.c | 75 ----
|
||||
filter/foomatic-rip/foomaticrip.h | 40 --
|
||||
filter/foomatic-rip/options.c | 67 ++++
|
||||
filter/foomatic-rip/process.c | 9 +
|
||||
filter/foomatic-rip/process.h | 3 +
|
||||
filter/foomatic-rip/util.c | 341 +++++++++++++++-
|
||||
filter/foomatic-rip/util.h | 67 ++++
|
||||
13 files changed, 1178 insertions(+), 124 deletions(-)
|
||||
create mode 100644 filter/foomatic-rip/foomatic-hash.1
|
||||
create mode 100644 filter/foomatic-rip/foomatic-hash.c
|
||||
|
||||
diff --git a/filter/foomatic-rip/foomatic-rip.1.in b/filter/foomatic-rip/foomatic-rip.1.in
|
||||
index 9685a95f5..3dff5215f 100644
|
||||
--- a/filter/foomatic-rip/foomatic-rip.1.in
|
||||
+++ b/filter/foomatic-rip/foomatic-rip.1.in
|
||||
@@ -193,6 +193,15 @@ friends. Several PPD files use shell constructs that require a more
|
||||
modern shell like \fBbash\fR, \fBzsh\fR, or \fBksh\fR.
|
||||
|
||||
|
||||
+.SH PPD OPTION VALUE RESTRICTIONS AND EXCEPTIONS
|
||||
+
|
||||
+The values of PPD options \fBFoomaticRIPCommandLine\fR, \fBFoomaticRIPCommandLinePDF\fR and \fBFoomaticRIPOptionSetting\fR
|
||||
+are rejected in the default configuration because of security implications. Users can use the tool \fBfoomatic-hash(1)\fR, which provides
|
||||
+values of affected PPD options from found drivers and hashes of those values in hexadecimal format. User is expected to review the found values,
|
||||
+and if there is nothing suspicious in the output, copy the file with hashes into into the directory \fB@sysconfdir@/foomatic/hashes.d\fR
|
||||
+to allow the exceptions for found values.
|
||||
+
|
||||
+
|
||||
.SH FILES
|
||||
.PD 0
|
||||
.TP 0
|
||||
@@ -209,6 +218,13 @@ The PPD files of the currently defined printers
|
||||
|
||||
Configuration file for foomatic-rip
|
||||
|
||||
+.TP 0
|
||||
+@sysconfdir@/foomatic/hashes.d
|
||||
+.TP 0
|
||||
+@datadir@/foomatic/hashes.d
|
||||
+
|
||||
+Directories with hashes of allowed values
|
||||
+
|
||||
.PD 0
|
||||
|
||||
.\".SH SEE ALSO
|
||||
diff --git a/filter/foomatic-rip/options.c b/filter/foomatic-rip/options.c
|
||||
index bad833bc1..032fe9ec3 100644
|
||||
--- a/filter/foomatic-rip/options.c
|
||||
+++ b/filter/foomatic-rip/options.c
|
||||
@@ -102,6 +102,42 @@ get_icc_profile_for_qualifier(const char **qualifier)
|
||||
}
|
||||
|
||||
|
||||
+//
|
||||
+// 'is_allowed_value' - Check if the option value is allowed.
|
||||
+//
|
||||
+
|
||||
+int // O - Boolean value - true 1 / false 0
|
||||
+is_allowed_value(cups_array_t *ar, // I - Array of already known hashes from system
|
||||
+ char *value, // I - Scanned value from PPD file
|
||||
+ size_t value_len) // I - Value length
|
||||
+{
|
||||
+ char hash_string[65]; // Help array to store hexadecimal hashed string
|
||||
+
|
||||
+ //
|
||||
+ // Empty string is allowed...
|
||||
+ //
|
||||
+
|
||||
+ if (!value_len)
|
||||
+ return (1);
|
||||
+
|
||||
+ //
|
||||
+ // Hash the value and get hexadecimal string for it...
|
||||
+ //
|
||||
+
|
||||
+ if (hash_data((unsigned char*)value, value_len, hash_string, sizeof(hash_string)))
|
||||
+ return (0);
|
||||
+
|
||||
+ //
|
||||
+ // Check if the found hexadecimal hashed string is in the array -> allowed on the system...
|
||||
+ //
|
||||
+
|
||||
+ if (cupsArrayFind(ar, hash_string))
|
||||
+ return (1);
|
||||
+
|
||||
+ return (0);
|
||||
+}
|
||||
+
|
||||
+
|
||||
// a selector is a general tri-dotted specification.
|
||||
// The 2nd and 3rd elements of the qualifier are optionally modified by
|
||||
// cupsICCQualifier2 and cupsICCQualifier3:
|
||||
@@ -1866,12 +1902,19 @@ read_ppd_file(const char *filename)
|
||||
option_t *opt, *current_opt = NULL;
|
||||
param_t *param;
|
||||
icc_mapping_entry_t *entry;
|
||||
+ cups_array_t *known_hashes = NULL;
|
||||
|
||||
fh = fopen(filename, "r");
|
||||
if (!fh)
|
||||
rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Unable to open PPD file %s\n", filename);
|
||||
_log("Parsing PPD file ...\n");
|
||||
|
||||
+ if (load_system_hashes(&known_hashes))
|
||||
+ {
|
||||
+ fclose(fh);
|
||||
+ rip_die(EXIT_PRNERR_NORETRY, "Not enough memory for array allocation\n.");
|
||||
+ }
|
||||
+
|
||||
dstrassure(value, 256);
|
||||
|
||||
qualifier_data = list_create();
|
||||
@@ -1955,10 +1998,26 @@ read_ppd_file(const char *filename)
|
||||
}
|
||||
else if (strcmp(key, "FoomaticRIPCommandLine") == 0)
|
||||
{
|
||||
+ if (!is_allowed_value(known_hashes, value->data, strlen(value->data)))
|
||||
+ {
|
||||
+ cupsArrayDelete(known_hashes);
|
||||
+ fclose(fh);
|
||||
+
|
||||
+ rip_die(EXIT_PRNERR_NOTALLOWED, "ERROR: The value of the key %s is not among the allowed values - see foomatic-rip man page for more instructions.\n", key);
|
||||
+ }
|
||||
+
|
||||
unhtmlify(cmd, 4096, value->data);
|
||||
}
|
||||
else if (strcmp(key, "FoomaticRIPCommandLinePDF") == 0)
|
||||
{
|
||||
+ if (!is_allowed_value(known_hashes, value->data, strlen(value->data)))
|
||||
+ {
|
||||
+ cupsArrayDelete(known_hashes);
|
||||
+ fclose(fh);
|
||||
+
|
||||
+ rip_die(EXIT_PRNERR_NOTALLOWED, "ERROR: The value of the key %s is not among the allowed values - see foomatic-rip man page for more instructions.\n", key);
|
||||
+ }
|
||||
+
|
||||
unhtmlify(cmd_pdf, 4096, value->data);
|
||||
}
|
||||
else if (!strcmp(key, "cupsFilter"))
|
||||
@@ -2097,6 +2156,14 @@ read_ppd_file(const char *filename)
|
||||
}
|
||||
else if (!strcmp(key, "FoomaticRIPOptionSetting"))
|
||||
{
|
||||
+ if (!is_allowed_value(known_hashes, value->data, strlen(value->data)))
|
||||
+ {
|
||||
+ cupsArrayDelete(known_hashes);
|
||||
+ fclose(fh);
|
||||
+
|
||||
+ rip_die(EXIT_PRNERR_NOTALLOWED, "ERROR: The value of the key %s is not among the allowed values - see foomatic-rip man page for more instructions.\n", key);
|
||||
+ }
|
||||
+
|
||||
// "*FoomaticRIPOptionSetting <option>[=<choice>]: <code>
|
||||
// For boolean options <choice> is not given
|
||||
option_set_choice(assure_option(name),
|
||||
--
|
||||
2.50.1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user