public inbox for openembedded-core@lists.openembedded.org
 help / color / mirror / Atom feed
* [OE-core][kirkstone 0/7] Patch review
@ 2022-08-04 14:06 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2022-08-04 14:06 UTC (permalink / raw)
  To: openembedded-core

Please review this set of patches for kirkstone and have comments back
by end of day Sunday.

This should be the almost final set of patches for the 4.0.3 release -
there remains an intermittent linux-yocto reproducibility issue that
needs to get fixed.

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/4015

The following changes since commit 3564ce3d9b2030dd420362c66147bd327090915c:

  initscripts: run umountnfs as a KILL script (2022-07-28 05:32:25 -1000)

are available in the Git repository at:

  git://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  http://cgit.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Alex Kiernan (1):
  openssh: Add openssh-sftp-server to openssh RDEPENDS

Dmitry Baryshkov (1):
  linux-firwmare: restore WHENCE_CHKSUM variable

Khem Raj (1):
  libgcc: Fix standalone target builds with usrmerge distro feature

Martin Jansa (1):
  kernel.bbclass: pass LD also in savedefconfig

Mingli Yu (1):
  strace: set COMPATIBLE_HOST for riscv32

Shruthi Ravichandran (1):
  package_manager/ipk: do not pipe stderr to stdout

Sundeep KOKKONDA (1):
  binutils: stable 2.38 branch updates

 meta/classes/kernel.bbclass                   |  2 +-
 meta/lib/oe/package_manager/ipk/__init__.py   | 23 +++++++++++--------
 .../openssh/openssh_8.9p1.bb                  |  2 +-
 .../binutils/binutils-2.38.inc                |  2 +-
 meta/recipes-devtools/gcc/libgcc-common.inc   |  8 +++++--
 meta/recipes-devtools/strace/strace_5.16.bb   |  3 +++
 .../linux-firmware/linux-firmware_20220708.bb |  5 +++-
 7 files changed, 29 insertions(+), 16 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2023-04-15 15:26 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2023-04-15 15:26 UTC (permalink / raw)
  To: openembedded-core

Please review this set of patches for kirkstone and have comments back by
end of day Tuesday.

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/5185

The following changes since commit ff4b57ffff903a93b710284c7c7f916ddd74712f:

  uninative: Upgrade to 3.9 to include glibc 2.37 (2023-04-04 05:32:01 -1000)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  http://cgit.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Hitendra Prajapati (2):
  curl: CVE-2023-27533 TELNET option IAC injection
  curl: CVE-2023-27534 SFTP path resolving discrepancy

Joe Slater (1):
  go: fix CVE-2022-41724, 41725

Mark Hatle (1):
  openssl: Move microblaze to linux-latomic config

Pawan Badganchi (1):
  tiff: Add fix for CVE-2022-4645

Peter Marko (1):
  package.bbclass: correct check for /build in copydebugsources()

Yash Shinde (1):
  binutils : Fix CVE-2023-1579

 meta/classes/package.bbclass                  |    2 +-
 .../openssl/openssl_3.0.8.bb                  |    4 +-
 .../binutils/binutils-2.38.inc                |    4 +
 .../binutils/0021-CVE-2023-1579-1.patch       |  459 ++++
 .../binutils/0021-CVE-2023-1579-2.patch       | 2127 +++++++++++++++
 .../binutils/0021-CVE-2023-1579-3.patch       |  156 ++
 .../binutils/0021-CVE-2023-1579-4.patch       |   37 +
 meta/recipes-devtools/go/go-1.17.13.inc       |    5 +-
 .../go/go-1.19/add_godebug.patch              |   84 +
 .../go/go-1.19/cve-2022-41724.patch           | 2391 +++++++++++++++++
 .../go/go-1.19/cve-2022-41725.patch           |  652 +++++
 ...-of-TIFFTAG_INKNAMES-and-related-TIF.patch |    5 +-
 .../curl/curl/CVE-2023-27533.patch            |  208 ++
 .../curl/curl/CVE-2023-27534.patch            |  122 +
 meta/recipes-support/curl/curl_7.82.0.bb      |    2 +
 15 files changed, 6252 insertions(+), 6 deletions(-)
 create mode 100644 meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch
 create mode 100644 meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-2.patch
 create mode 100644 meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-3.patch
 create mode 100644 meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-4.patch
 create mode 100644 meta/recipes-devtools/go/go-1.19/add_godebug.patch
 create mode 100644 meta/recipes-devtools/go/go-1.19/cve-2022-41724.patch
 create mode 100644 meta/recipes-devtools/go/go-1.19/cve-2022-41725.patch
 create mode 100644 meta/recipes-support/curl/curl/CVE-2023-27533.patch
 create mode 100644 meta/recipes-support/curl/curl/CVE-2023-27534.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2023-10-30  2:20 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2023-10-30  2:20 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Tuesday, October 31

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/6115

The following changes since commit 7681436190354b5c5b6c3a82b3094badd81113de:

  vim: Upgrade 9.0.2009 -> 9.0.2048 (2023-10-20 06:38:00 -1000)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Archana Polampalli (2):
  curl: fix CVE-2023-38545
  curl: fix CVE-2023-38546

Fahad Arslan (2):
  linux-firmware: create separate package for cirrus and cnm firmwares
  linux-firmware: create separate packages

Niko Mauno (1):
  package_rpm: Allow compression mode override

Peter Marko (1):
  openssl: Upgrade 3.0.11 -> 3.0.12

Steve Sakoman (1):
  cve-exclusion_5.10.inc: update for 5.10.197

 meta/classes/package_rpm.bbclass              |   6 +-
 .../{openssl_3.0.11.bb => openssl_3.0.12.bb}  |   2 +-
 .../linux-firmware/linux-firmware_20230804.bb | 260 +++++++++++++++++-
 .../linux/cve-exclusion_5.10.inc              | 123 +++++++--
 .../curl/curl/CVE-2023-38545.patch            | 133 +++++++++
 .../curl/curl/CVE-2023-38546.patch            | 137 +++++++++
 meta/recipes-support/curl/curl_7.82.0.bb      |   2 +
 7 files changed, 633 insertions(+), 30 deletions(-)
 rename meta/recipes-connectivity/openssl/{openssl_3.0.11.bb => openssl_3.0.12.bb} (99%)
 create mode 100644 meta/recipes-support/curl/curl/CVE-2023-38545.patch
 create mode 100644 meta/recipes-support/curl/curl/CVE-2023-38546.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2023-11-08 22:52 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2023-11-08 22:52 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Friday, November 10

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/6158

The following changes since commit 0eb8e67aa6833df0cde29833568a70e65c21d7e5:

  build-appliance-image: Update to kirkstone head revision (2023-11-03 04:27:49 -1000)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Narpat Mali (1):
  python3-jinja2: Fixed ptest result output as per the standard

Ross Burton (3):
  cve-check: sort the package list in the JSON report
  cve-check: slightly more verbose warning when adding the same package
    twice
  cve-check: don't warn if a patch is remote

Sanjana (1):
  binutils: Fix CVE-2022-47010

Soumya Sambu (1):
  libwebp: Fix CVE-2023-4863

Vijay Anusuri (1):
  xserver-xorg: Fix for CVE-2023-5367 and CVE-2023-5380

 meta/classes/cve-check.bbclass                |   2 +
 meta/lib/oe/cve_check.py                      |  13 +--
 .../binutils/binutils-2.38.inc                |   1 +
 .../binutils/0032-CVE-2022-47010.patch        |  38 +++++++
 .../python/python3-jinja2/run-ptest           |   2 +-
 .../xserver-xorg/CVE-2023-5367.patch          |  84 +++++++++++++++
 .../xserver-xorg/CVE-2023-5380.patch          | 102 ++++++++++++++++++
 .../xorg-xserver/xserver-xorg_21.1.8.bb       |   2 +
 ...23-5129.patch => CVE-2023-4863-0001.patch} |  20 ++--
 .../webp/files/CVE-2023-4863-0002.patch       |  53 +++++++++
 meta/recipes-multimedia/webp/libwebp_1.2.4.bb |   3 +-
 11 files changed, 303 insertions(+), 17 deletions(-)
 create mode 100644 meta/recipes-devtools/binutils/binutils/0032-CVE-2022-47010.patch
 create mode 100644 meta/recipes-graphics/xorg-xserver/xserver-xorg/CVE-2023-5367.patch
 create mode 100644 meta/recipes-graphics/xorg-xserver/xserver-xorg/CVE-2023-5380.patch
 rename meta/recipes-multimedia/webp/files/{CVE-2023-5129.patch => CVE-2023-4863-0001.patch} (97%)
 create mode 100644 meta/recipes-multimedia/webp/files/CVE-2023-4863-0002.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2024-01-17 15:58 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-01-17 15:58 UTC (permalink / raw)
  To: openembedded-core

Please reviwe this set of changes for kirkstone and have comments back by
end of day Friday, January 19

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/6458

The following changes since commit 8e27f96c0befbbb5cf8a2f7076b7a1ffd79addb6:

  linux-firmware: upgrade 20230804 -> 20231030 (2024-01-09 05:50:24 -1000)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Hitendra Prajapati (1):
  systemd: fix CVE-2023-7008

Martin Jansa (1):
  pybootchartgui: fix 2 SyntaxWarnings

Peter Marko (2):
  sqlite3: backport patch for CVE-2023-7104
  zlib: ignore CVE-2023-6992

Poonam Jadhav (1):
  Revert "curl: Backport fix CVE-2023-32001"

Soumya Sambu (1):
  cpio: upgrade to 2.14

Vivek Kumbhar (1):
  openssl: Backport fix for CVE-2023-6129

 .../openssl/openssl/CVE-2023-6129.patch       | 113 ++++
 .../openssl/openssl_3.0.12.bb                 |   1 +
 .../systemd/systemd/CVE-2023-7008.patch       |  40 ++
 meta/recipes-core/systemd/systemd_250.5.bb    |   1 +
 meta/recipes-core/zlib/zlib_1.2.11.bb         |   3 +
 ...charset_alias-when-building-for-musl.patch |  30 -
 ...ove-superfluous-declaration-of-progr.patch |  28 -
 ...-calculation-of-CRC-in-copy-out-mode.patch |  58 --
 ...appending-to-archives-bigger-than-2G.patch | 312 ----------
 .../cpio/cpio-2.13/CVE-2021-38185.patch       | 581 ------------------
 .../cpio/{cpio_2.13.bb => cpio_2.14.bb}       |   9 +-
 ...e-needed-header-for-major-minor-macr.patch |  47 ++
 .../curl/curl/CVE-2023-32001.patch            |  39 --
 meta/recipes-support/curl/curl_7.82.0.bb      |   1 -
 .../sqlite/files/CVE-2023-7104.patch          |  44 ++
 meta/recipes-support/sqlite/sqlite3_3.38.5.bb |   1 +
 scripts/pybootchartgui/pybootchartgui/draw.py |   4 +-
 17 files changed, 254 insertions(+), 1058 deletions(-)
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2023-6129.patch
 create mode 100644 meta/recipes-core/systemd/systemd/CVE-2023-7008.patch
 delete mode 100644 meta/recipes-extended/cpio/cpio-2.13/0001-Unset-need_charset_alias-when-building-for-musl.patch
 delete mode 100644 meta/recipes-extended/cpio/cpio-2.13/0002-src-global.c-Remove-superfluous-declaration-of-progr.patch
 delete mode 100644 meta/recipes-extended/cpio/cpio-2.13/0003-Fix-calculation-of-CRC-in-copy-out-mode.patch
 delete mode 100644 meta/recipes-extended/cpio/cpio-2.13/0004-Fix-appending-to-archives-bigger-than-2G.patch
 delete mode 100644 meta/recipes-extended/cpio/cpio-2.13/CVE-2021-38185.patch
 rename meta/recipes-extended/cpio/{cpio_2.13.bb => cpio_2.14.bb} (74%)
 create mode 100644 meta/recipes-extended/cpio/files/0001-configure-Include-needed-header-for-major-minor-macr.patch
 delete mode 100644 meta/recipes-support/curl/curl/CVE-2023-32001.patch
 create mode 100644 meta/recipes-support/sqlite/files/CVE-2023-7104.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2024-02-06 15:45 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-02-06 15:45 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Thursday, February 8

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/6539

The following changes since commit 60d88989698968c13f8e641f0ba1a82fcf700fb7:

  image-live.bbclass: LIVE_ROOTFS_TYPE support compression (2024-01-30 07:10:42 -1000)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Deepthi Hemraj (4):
  binutils: internal gdb: Fix CVE-2023-39129
  binutils: internal gdb: Fix CVE-2023-39130
  gdb: Fix CVE-2023-39129
  gdb: Fix CVE-2023-39130

Peter Marko (3):
  curl: ignore CVE-2023-42915
  gcc-shared-source: ignore CVE-2023-4039
  openssl: Upgrade 3.0.12 -> 3.0.13

 .../openssl/openssl/CVE-2023-5678.patch       | 180 ----------
 .../openssl/openssl/CVE-2023-6129.patch       | 113 ------
 .../openssl/openssl/CVE-2023-6237.patch       | 127 -------
 .../{openssl_3.0.12.bb => openssl_3.0.13.bb}  |   6 +-
 .../binutils/binutils-2.38.inc                |   2 +
 .../binutils/0035-CVE-2023-39129.patch        |  50 +++
 .../binutils/0036-CVE-2023-39130.patch        | 326 ++++++++++++++++++
 .../gcc/gcc-shared-source.inc                 |   3 +
 meta/recipes-devtools/gdb/gdb.inc             |   2 +
 .../gdb/gdb/0012-CVE-2023-39129.patch         |  50 +++
 .../gdb/gdb/0013-CVE-2023-39130.patch         | 326 ++++++++++++++++++
 meta/recipes-support/curl/curl_7.82.0.bb      |   3 +
 12 files changed, 764 insertions(+), 424 deletions(-)
 delete mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2023-5678.patch
 delete mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2023-6129.patch
 delete mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2023-6237.patch
 rename meta/recipes-connectivity/openssl/{openssl_3.0.12.bb => openssl_3.0.13.bb} (97%)
 create mode 100644 meta/recipes-devtools/binutils/binutils/0035-CVE-2023-39129.patch
 create mode 100644 meta/recipes-devtools/binutils/binutils/0036-CVE-2023-39130.patch
 create mode 100644 meta/recipes-devtools/gdb/gdb/0012-CVE-2023-39129.patch
 create mode 100644 meta/recipes-devtools/gdb/gdb/0013-CVE-2023-39130.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2024-04-17 20:35 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-04-17 20:35 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Friday, April 19

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/6817

The following changes since commit f94c74cee8b2650dd3211a49dc7e88bf60d2e6a7:

  tcl: skip async and event tests in run-ptest (2024-04-16 05:00:24 -0700)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Harish Sadineni (1):
  rust: add CVE_CHECK_IGNORE for CVE-2024-24576

Meenali Gupta (1):
  libssh2: fix CVE-2023-48795

Poonam Jadhav (1):
  ppp: Add RSA-MD in LICENSE

Sana Kazi (1):
  systemd: Fix vlan qos mapping

Soumya Sambu (1):
  nghttp2: Fix CVE-2024-28182

Steve Sakoman (1):
  valgrind: skip intermittently failing ptest

Yogita Urade (1):
  ruby: fix CVE-2024-27281

 meta/recipes-connectivity/ppp/ppp_2.4.9.bb    |   2 +-
 .../systemd/fix-vlan-qos-mapping.patch        | 140 ++++++
 meta/recipes-core/systemd/systemd_250.5.bb    |   1 +
 .../ruby/ruby/CVE-2024-27281.patch            |  97 ++++
 meta/recipes-devtools/ruby/ruby_3.1.3.bb      |   1 +
 meta/recipes-devtools/rust/rust-source.inc    |   3 +
 .../valgrind/valgrind/remove-for-all          |   2 +
 .../libssh2/libssh2/CVE-2023-48795.patch      | 459 ++++++++++++++++++
 .../recipes-support/libssh2/libssh2_1.10.0.bb |   1 +
 .../nghttp2/nghttp2/CVE-2024-28182-0001.patch | 110 +++++
 .../nghttp2/nghttp2/CVE-2024-28182-0002.patch | 105 ++++
 .../recipes-support/nghttp2/nghttp2_1.47.0.bb |   2 +
 12 files changed, 922 insertions(+), 1 deletion(-)
 create mode 100644 meta/recipes-core/systemd/systemd/fix-vlan-qos-mapping.patch
 create mode 100644 meta/recipes-devtools/ruby/ruby/CVE-2024-27281.patch
 create mode 100644 meta/recipes-support/libssh2/libssh2/CVE-2023-48795.patch
 create mode 100644 meta/recipes-support/nghttp2/nghttp2/CVE-2024-28182-0001.patch
 create mode 100644 meta/recipes-support/nghttp2/nghttp2/CVE-2024-28182-0002.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2024-05-30 18:37 Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 1/7] ghostscript: fix CVE-2024-33870 Steve Sakoman
                   ` (6 more replies)
  0 siblings, 7 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:37 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirktsone and have comments back by
end of day Saturday, June 1

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/6984

The following changes since commit e0a1ed7aa1f2b12d985414db9a75d6e151ae8d21:

  initscripts: Add custom mount args for /var/lib (2024-05-22 05:07:30 -0700)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Archana Polampalli (5):
  ghostscript: fix CVE-2024-33870
  ghostscript: fix CVE-2024-33869
  ghostscript: fix CVE-2024-33871
  ghostscript: fix CVE-2024-29510
  ghostscript: fix CVE-2023-52722

Soumya Sambu (2):
  util-linux: Fix CVE-2024-28085
  git: Fix multiple CVEs

 meta/recipes-core/util-linux/util-linux.inc   |    5 +
 .../util-linux/CVE-2024-28085-0001.patch      |  202 +
 .../util-linux/CVE-2024-28085-0002.patch      |  172 +
 .../util-linux/CVE-2024-28085-0003.patch      |  223 +
 .../util-linux/CVE-2024-28085-0004.patch      |   36 +
 .../util-linux/CVE-2024-28085-0005.patch      |   34 +
 .../git/git/CVE-2024-32002-0001.patch         |   69 +
 .../git/git/CVE-2024-32002-0002.patch         |  213 +
 .../git/git/CVE-2024-32002-0003.patch         |  141 +
 .../git/git/CVE-2024-32002-0004.patch         |  150 +
 .../git/git/CVE-2024-32004-0001.patch         |   95 +
 .../git/git/CVE-2024-32004-0002.patch         |  187 +
 .../git/git/CVE-2024-32004-0003.patch         |  158 +
 .../git/git/CVE-2024-32020.patch              |  114 +
 .../git/git/CVE-2024-32021-0001.patch         |   89 +
 .../git/git/CVE-2024-32021-0002.patch         |   65 +
 .../git/git/CVE-2024-32465.patch              |  206 +
 meta/recipes-devtools/git/git_2.35.7.bb       |   11 +
 .../ghostscript/CVE-2023-52722.patch          |   43 +
 .../ghostscript/CVE-2024-29510.patch          |   84 +
 .../ghostscript/CVE-2024-33869-0001.patch     |   39 +
 .../ghostscript/CVE-2024-33869-0002.patch     |   52 +
 .../ghostscript/CVE-2024-33870.patch          |   92 +
 .../ghostscript/CVE-2024-33871-0001.patch     | 4863 +++++++++++++++++
 .../ghostscript/CVE-2024-33871-0002.patch     |   43 +
 .../ghostscript/ghostscript_9.55.0.bb         |    7 +
 26 files changed, 7393 insertions(+)
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32020.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32465.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2023-52722.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-29510.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0001.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0002.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33870.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0001.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0002.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 1/7] ghostscript: fix CVE-2024-33870
  2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
@ 2024-05-30 18:38 ` Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 2/7] ghostscript: fix CVE-2024-33869 Steve Sakoman
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:38 UTC (permalink / raw)
  To: openembedded-core

From: Archana Polampalli <archana.polampalli@windriver.com>

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
 .../ghostscript/CVE-2024-33870.patch          | 92 +++++++++++++++++++
 .../ghostscript/ghostscript_9.55.0.bb         |  1 +
 2 files changed, 93 insertions(+)
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33870.patch

diff --git a/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33870.patch b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33870.patch
new file mode 100644
index 0000000000..0d289b6d07
--- /dev/null
+++ b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33870.patch
@@ -0,0 +1,92 @@
+From 79aef19c685984dc3da2dc090450407d9fbcff80 Mon Sep 17 00:00:00 2001
+From: Ken Sharp <Ken.Sharp@artifex.com>
+Date: Tue, 26 Mar 2024 12:00:14 +0000
+Subject: [PATCH 1/5] Bug #707686
+
+See bug thread for details
+
+In addition to the noted bug; an error path (return from
+gp_file_name_reduce not successful) could elad to a memory leak as we
+did not free 'bufferfull'. Fix that too.
+
+This addresses CVE-2024-33870
+
+CVE: CVE-2024-33870
+
+Upstream-Status: Backport [https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=79aef19c685984dc]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ base/gpmisc.c | 33 ++++++++++++++++++++++++++++++---
+ 1 file changed, 30 insertions(+), 3 deletions(-)
+
+diff --git a/base/gpmisc.c b/base/gpmisc.c
+index f9a9230..3b6fffa 100644
+--- a/base/gpmisc.c
++++ b/base/gpmisc.c
+@@ -1042,7 +1042,7 @@ gp_validate_path_len(const gs_memory_t *mem,
+                      const uint         len,
+                      const char        *mode)
+ {
+-    char *buffer, *bufferfull;
++    char *buffer, *bufferfull = NULL;
+     uint rlen;
+     int code = 0;
+     const char *cdirstr = gp_file_name_current();
+@@ -1095,8 +1095,10 @@ gp_validate_path_len(const gs_memory_t *mem,
+             return gs_error_VMerror;
+
+         buffer = bufferfull + prefix_len;
+-        if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success)
+-            return gs_error_invalidfileaccess;
++	if (gp_file_name_reduce(path, (uint)len, buffer, &rlen) != gp_combine_success) {
++           code = gs_note_error(gs_error_invalidfileaccess);
++            goto exit;
++        }
+         buffer[rlen] = 0;
+     }
+     while (1) {
+@@ -1131,9 +1133,33 @@ gp_validate_path_len(const gs_memory_t *mem,
+             code = gs_note_error(gs_error_invalidfileaccess);
+         }
+         if (code < 0 && prefix_len > 0 && buffer > bufferfull) {
++            uint newlen = rlen + cdirstrl + dirsepstrl;
++            char *newbuffer;
++            int code;
++
+             buffer = bufferfull;
+             memcpy(buffer, cdirstr, cdirstrl);
+             memcpy(buffer + cdirstrl, dirsepstr, dirsepstrl);
++	    /* We've prepended a './' or similar for the current working directory. We need
++             * to execute file_name_reduce on that, to eliminate any '../' or similar from
++             * the (new) full path.
++             */
++            newbuffer = (char *)gs_alloc_bytes(mem->thread_safe_memory, newlen + 1, "gp_validate_path");
++            if (newbuffer == NULL) {
++                code = gs_note_error(gs_error_VMerror);
++                goto exit;
++            }
++
++            memcpy(newbuffer, buffer, rlen + cdirstrl + dirsepstrl);
++            newbuffer[newlen] = 0x00;
++
++            code = gp_file_name_reduce(newbuffer, (uint)newlen, buffer, &newlen);
++            gs_free_object(mem->thread_safe_memory, newbuffer, "gp_validate_path");
++            if (code != gp_combine_success) {
++                code = gs_note_error(gs_error_invalidfileaccess);
++                goto exit;
++            }
++
+             continue;
+         }
+         else if (code < 0 && cdirstrl > 0 && prefix_len == 0 && buffer == bufferfull) {
+@@ -1152,6 +1178,7 @@ gp_validate_path_len(const gs_memory_t *mem,
+                                            gs_path_control_flag_is_scratch_file);
+     }
+
++exit:
+     gs_free_object(mem->thread_safe_memory, bufferfull, "gp_validate_path");
+ #ifdef EACCES
+     if (code == gs_error_invalidfileaccess)
+--
+2.40.0
diff --git a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
index e99c740685..5fa4da0fb8 100644
--- a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
+++ b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
@@ -43,6 +43,7 @@ SRC_URI_BASE = "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/d
                 file://CVE-2023-38559.patch \
                 file://CVE-2023-43115.patch \
                 file://CVE-2023-46751.patch \
+                file://CVE-2024-33870.patch \
 "
 
 SRC_URI = "${SRC_URI_BASE} \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 2/7] ghostscript: fix CVE-2024-33869
  2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 1/7] ghostscript: fix CVE-2024-33870 Steve Sakoman
@ 2024-05-30 18:38 ` Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 3/7] ghostscript: fix CVE-2024-33871 Steve Sakoman
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:38 UTC (permalink / raw)
  To: openembedded-core

From: Archana Polampalli <archana.polampalli@windriver.com>

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
 .../ghostscript/CVE-2024-33869-0001.patch     | 39 ++++++++++++++
 .../ghostscript/CVE-2024-33869-0002.patch     | 52 +++++++++++++++++++
 .../ghostscript/ghostscript_9.55.0.bb         |  2 +
 3 files changed, 93 insertions(+)
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0001.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0002.patch

diff --git a/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0001.patch b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0001.patch
new file mode 100644
index 0000000000..2e60ae6048
--- /dev/null
+++ b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0001.patch
@@ -0,0 +1,39 @@
+From 5ae2e320d69a7d0973011796bd388cd5befa1a43 Mon Sep 17 00:00:00 2001
+From: Ken Sharp <Ken.Sharp@artifex.com>
+Date: Tue, 26 Mar 2024 12:02:57 +0000
+Subject: [PATCH 2/5] Bug #707691
+
+Part 1; when stripping a potential Current Working Dirctory specifier
+from a path, make certain it really is a CWD, and not simply large
+ebough to be a CWD.
+
+Reasons are in the bug thread, this is not (IMO) serious.
+
+This is part of the fix for CVE-2024-33869
+
+CVE: CVE-2024-33869
+
+Upstream-Status: Backport [https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=5ae2e320d69a7d0973]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ base/gpmisc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/base/gpmisc.c b/base/gpmisc.c
+index 3b6fffa..a0b58c8 100644
+--- a/base/gpmisc.c
++++ b/base/gpmisc.c
+@@ -1162,8 +1162,8 @@ gp_validate_path_len(const gs_memory_t *mem,
+
+             continue;
+         }
+-        else if (code < 0 && cdirstrl > 0 && prefix_len == 0 && buffer == bufferfull) {
+-            buffer = bufferfull + cdirstrl + dirsepstrl;
++        else if (code < 0 && cdirstrl > 0 && prefix_len == 0 && buffer == bufferfull
++            && memcmp(buffer, cdirstr, cdirstrl) && !memcmp(buffer + cdirstrl, dirsepstr, dirsepstrl)) {
+             continue;
+         }
+         break;
+--
+2.40.0
diff --git a/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0002.patch b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0002.patch
new file mode 100644
index 0000000000..5ba038a0e7
--- /dev/null
+++ b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33869-0002.patch
@@ -0,0 +1,52 @@
+From f5336e5b4154f515ac83bc5b9eba94302e6618d4 Mon Sep 17 00:00:00 2001
+From: Ken Sharp <Ken.Sharp@artifex.com>
+Date: Tue, 26 Mar 2024 12:07:18 +0000
+Subject: [PATCH 3/5] Bug 707691 part 2
+
+See bug thread for details
+
+This is the second part of the fix for CVE-2024-33869
+
+CVE: CVE-2024-33869
+
+Upstream-Status: Backport [https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=f5336e5b4154f515ac83]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ base/gpmisc.c | 21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+diff --git a/base/gpmisc.c b/base/gpmisc.c
+index a0b58c8..69bee47 100644
+--- a/base/gpmisc.c
++++ b/base/gpmisc.c
+@@ -1089,6 +1089,27 @@ gp_validate_path_len(const gs_memory_t *mem,
+         rlen = len;
+     }
+     else {
++        char *test = (char *)path, *test1;
++        uint tlen = len, slen;
++
++        /* Look for any pipe (%pipe% or '|' specifications between path separators
++         * Reject any path spec which has a %pipe% or '|' anywhere except at the start.
++         */
++        while (tlen > 0) {
++            if (test[0] == '|' || (tlen > 5 && memcmp(test, "%pipe", 5) == 0)) {
++                code = gs_note_error(gs_error_invalidfileaccess);
++                goto exit;
++            }
++            test1 = test;
++            slen = search_separator((const char **)&test, path + len, test1, 1);
++            if(slen == 0)
++                break;
++            test += slen;
++            tlen -= test - test1;
++            if (test >= path + len)
++                break;
++        }
++
+         rlen = len+1;
+         bufferfull = (char *)gs_alloc_bytes(mem->thread_safe_memory, rlen + prefix_len, "gp_validate_path");
+         if (bufferfull == NULL)
+--
+2.40.0
diff --git a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
index 5fa4da0fb8..083ee4b337 100644
--- a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
+++ b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
@@ -44,6 +44,8 @@ SRC_URI_BASE = "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/d
                 file://CVE-2023-43115.patch \
                 file://CVE-2023-46751.patch \
                 file://CVE-2024-33870.patch \
+                file://CVE-2024-33869-0001.patch \
+                file://CVE-2024-33869-0002.patch \
 "
 
 SRC_URI = "${SRC_URI_BASE} \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 3/7] ghostscript: fix CVE-2024-33871
  2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 1/7] ghostscript: fix CVE-2024-33870 Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 2/7] ghostscript: fix CVE-2024-33869 Steve Sakoman
@ 2024-05-30 18:38 ` Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 4/7] ghostscript: fix CVE-2024-29510 Steve Sakoman
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:38 UTC (permalink / raw)
  To: openembedded-core

From: Archana Polampalli <archana.polampalli@windriver.com>

Added dependent patch [1] for backporting this CVE

[1] https://github.com/ArtifexSoftware/ghostpdl/commit/8b47f269b83b172b22606806fe5ec272d974e797

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
 .../ghostscript/CVE-2024-33871-0001.patch     | 4863 +++++++++++++++++
 .../ghostscript/CVE-2024-33871-0002.patch     |   43 +
 .../ghostscript/ghostscript_9.55.0.bb         |    2 +
 3 files changed, 4908 insertions(+)
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0001.patch
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0002.patch

diff --git a/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0001.patch b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0001.patch
new file mode 100644
index 0000000000..008f588bff
--- /dev/null
+++ b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0001.patch
@@ -0,0 +1,4863 @@
+From 8b47f269b83b172b22606806fe5ec272d974e797 Mon Sep 17 00:00:00 2001
+From: Michael Vrhel <michael.vrhel@artifex.com>
+Date: Mon, 22 Nov 2021 12:13:10 -0800
+Subject: [PATCH 6/7] Removal of globals in opvp device
+
+Thanks to Robin for suggesting the structure form
+to get the globals at a common offset for the
+raster and vector forms of the device. That coupled
+with pushing the device through all the methods and
+doing initialization was the biggest effort.
+
+Thanks also to Chris for his help in providing
+understanding as to what this device was actually doing.
+
+This commit includes a test harness for the opvp
+device, which uses the device client API to write
+out the commands it receives to a text file for
+comparison.  To build the driver use  ./build_opv_harness.sh
+To use the driver use a command line like
+-sDEVICE=opvp -sDriver=libopv.so -o output.txt -f ./examples/tiger.eps
+The command lines are always dumped to the same
+file which is opvp_command_dump.txt.   Note that the
+harness itself has to rely upon globals due to our
+inability to change the client API.
+
+CVE: CVE-2024-33871
+
+Upstream-Status: Backport [https://github.com/ArtifexSoftware/ghostpdl/commit/8b47f269b83b172b22606]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ contrib/opvp/README.txt           |   18 +
+ contrib/opvp/build_opv_harness.sh |    4 +
+ contrib/opvp/gdevopvp.c           | 1879 +++++++++++++++++------------
+ contrib/opvp/opvp.h               |    9 +-
+ contrib/opvp/opvp_0_2_0.h         |    4 +-
+ contrib/opvp/opvpharness.c        |  947 +++++++++++++++
+ 6 files changed, 2070 insertions(+), 791 deletions(-)
+ create mode 100644 contrib/opvp/README.txt
+ create mode 100755 contrib/opvp/build_opv_harness.sh
+ create mode 100644 contrib/opvp/opvpharness.c
+
+diff --git a/contrib/opvp/README.txt b/contrib/opvp/README.txt
+new file mode 100644
+index 0000000..fd2250e
+--- /dev/null
++++ b/contrib/opvp/README.txt
+@@ -0,0 +1,18 @@
++In an effort to remove globals in devices
++that ship with Ghostscript, the opvp device was updated
++to place it's global values into the device structure.
++
++As part of that commit, a harness was added to enable
++testing of the opvp device client API to test for any
++issues. To build the harness use  ./build_opv_harness.sh
++This will create a debug version of the shared object
++libopv.so. The command line
++gs -sDEVICE=opvp -sDriver=./contrib/opvp/libopv.so -o output.txt -f ./examples/tiger.eps
++can then be used.
++
++This command should create a file called
++opvp_command_dump.txt that contains the calls and
++the parameters made to the client API. Note that the
++harness itself has to rely upon globals. To do otherwise
++would require a to change the client API, which we
++do not own.
+\ No newline at end of file
+diff --git a/contrib/opvp/build_opv_harness.sh b/contrib/opvp/build_opv_harness.sh
+new file mode 100755
+index 0000000..8d10f05
+--- /dev/null
++++ b/contrib/opvp/build_opv_harness.sh
+@@ -0,0 +1,4 @@
++#!/bin/bash
++
++gcc -Werror -Wall -c -fpic -g opvpharness.c
++gcc -shared -o libopv.so opvpharness.o
+\ No newline at end of file
+diff --git a/contrib/opvp/gdevopvp.c b/contrib/opvp/gdevopvp.c
+index 844b46c..64afbfe 100644
+--- a/contrib/opvp/gdevopvp.c
++++ b/contrib/opvp/gdevopvp.c
+@@ -115,14 +115,62 @@ typedef struct {
+
+ #define MAX_PATH_POINTS 1000
+
+-/* driver */
+-typedef struct  gx_device_opvp_s {
++/* To remove the existing globals from this device,
++   we place the current globals into a structure
++   and place them at the same offset location
++   for the opvp and oprp devices, allowing easy
++   access regardless of the device type. */
++
++typedef struct opXp_globals_s {
++    bool vector;
++    bool inkjet;
++    bool zoomAuto;
++    bool zooming;
++    bool beginPage;
++    float margins[4];
++    float zoom[2];
++    float shift[2];
++    opvp_int_t outputFD;
++    opvp_int_t nApiEntry;
++    opvp_dc_t printerContext;
++    opvp_cspace_t colorSpace;
++    opvp_cspace_t savedColorSpace;
++    char* vectorDriver;
++    char* printerModel;
++    void* handle;
++    opvp_brush_t* vectorFillColor;
++    opvp_int_t* ErrorNo;
++    opvp_api_procs_t* apiEntry;
++    OPVP_api_procs* apiEntry_0_2;
++    char* jobInfo;
++    char* docInfo;
++    opvp_dc_t(*OpenPrinter)(opvp_int_t, const opvp_char_t*,
++        const opvp_int_t[2], opvp_api_procs_t**);
++    int (*OpenPrinter_0_2)(int, char*, int*,
++        OPVP_api_procs**);
++    int (*GetLastError)(gx_device*);
++} opXp_globals;
++
++typedef struct base_opvp_s {
+     gx_device_vector_common;
++} base_opvp;
++
++typedef struct base_oprp_s {
++    gx_device_common;
++    gx_prn_device_common;
++} base_oprp;
++
++typedef struct gx_device_opvp_s {
++    gx_device_vector_common;
++    char padding[1 + (sizeof(base_oprp) > sizeof(base_opvp) ? sizeof(base_oprp) - sizeof(base_opvp) : 0)];
++    opXp_globals globals;
+ } gx_device_opvp;
+
+-typedef struct  gx_device_oprp_s {
++typedef struct gx_device_oprp_s {
+     gx_device_common;
+     gx_prn_device_common;
++    char padding[1 + (sizeof(base_opvp) > sizeof(base_oprp) ? sizeof(base_opvp) - sizeof(base_oprp) : 0)];
++    opXp_globals globals;
+ } gx_device_oprp;
+
+ /* point (internal) */
+@@ -135,15 +183,16 @@ typedef struct {
+
+ /* Utilities */
+ static  int opvp_startpage(gx_device *);
+-static  int opvp_endpage(void);
++static  int opvp_endpage(gx_device*);
+ static  char *opvp_alloc_string(char **, const char *);
+ static  char *opvp_cat_string(char **, const char *);
+ static  char *opvp_adjust_num_string(char *);
+-static  char **opvp_gen_dynamic_lib_name(void);
++static  char **opvp_gen_dynamic_lib_name(gx_device*);
+ static  char *opvp_to_utf8(char *);
+-#define opvp_check_in_page(pdev)        \
+-                ((beginPage) || (inkjet) ? 0 \
+-                    : (*vdev_proc(pdev, beginpage))((gx_device_vector*)pdev))
++#define opvp_check_in_page(opdev)        \
++                 ((((gx_device_opvp*)(opdev))->globals.beginPage) || \
++                  (((gx_device_opvp*)(opdev))->globals.inkjet) ? 0  \
++                    : (*vdev_proc(opdev, beginpage))((gx_device_vector*)opdev))
+ static  int opvp_get_papertable_index(gx_device *);
+ static  char *opvp_get_sizestring(float, float);
+ /* not used     static  const char *opvp_get_papersize_region(gx_device *);*/
+@@ -160,8 +209,8 @@ static  int opvp_draw_image(gx_device_opvp *, int,
+                             int, int, int, int, int, int, const byte *);
+
+ /* load/unload vector driver */
+-static  int opvp_load_vector_driver(void);
+-static  int opvp_unload_vector_driver(void);
++static  int opvp_load_vector_driver(gx_device*);
++static  int opvp_unload_vector_driver(gx_device*);
+ static  int prepare_open(gx_device *);
+
+ /* driver procs */
+@@ -177,10 +226,10 @@ static  int opvp_copy_mono(gx_device *, const byte *, int, int,
+                            gx_color_index, gx_color_index);
+ static  int opvp_copy_color(gx_device *, const byte *, int, int,
+                             gx_bitmap_id, int, int, int, int);
+-static  int _get_params(gs_param_list *);
++static  int _get_params(gx_device*, gs_param_list *);
+ static  int opvp_get_params(gx_device *, gs_param_list *);
+ static  int oprp_get_params(gx_device *, gs_param_list *);
+-static  int _put_params(gs_param_list *);
++static  int _put_params(gx_device*, gs_param_list *);
+ static  int opvp_put_params(gx_device *, gs_param_list *);
+ static  int oprp_put_params(gx_device *, gs_param_list *);
+ static  int opvp_fill_path(gx_device *, const gs_gstate *, gx_path *,
+@@ -295,6 +344,53 @@ gs_public_st_suffix_add0_final(
+     NULL, /* *jobInfo */\
+     NULL /* *docInfo */
+
++
++static int
++GetLastError_1_0(gx_device* dev)
++{
++    gx_device_opvp* pdev = (gx_device_opvp*)dev;
++
++    return *(pdev->globals.ErrorNo);
++}
++
++/* Initialize the globals */
++static void
++InitGlobals(gx_device* dev)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    opdev->globals.vector = true;
++    opdev->globals.inkjet = false;
++    opdev->globals.zoomAuto = false;
++    opdev->globals.zooming = false;
++    opdev->globals.beginPage = false;
++    opdev->globals.margins[0] = 0;
++    opdev->globals.margins[1] = 0;
++    opdev->globals.margins[2] = 0;
++    opdev->globals.margins[3] = 0;
++    opdev->globals.zoom[0] = 1;
++    opdev->globals.zoom[1] = 1;
++    opdev->globals.shift[0] = 0;
++    opdev->globals.shift[1] = 0;
++    opdev->globals.outputFD = -1;
++    opdev->globals.nApiEntry = 0;
++    opdev->globals.printerContext = -1;
++    opdev->globals.colorSpace = OPVP_CSPACE_STANDARDRGB;
++    opdev->globals.savedColorSpace = OPVP_CSPACE_STANDARDRGB;
++    opdev->globals.vectorDriver = NULL;
++    opdev->globals.printerModel = NULL;
++    opdev->globals.handle = NULL;
++    opdev->globals.vectorFillColor = NULL;
++    opdev->globals.ErrorNo = NULL;
++    opdev->globals.apiEntry = NULL;
++    opdev->globals.apiEntry_0_2 = NULL;
++    opdev->globals.jobInfo = NULL;
++    opdev->globals.docInfo = NULL;
++    opdev->globals.OpenPrinter = NULL;
++    opdev->globals.OpenPrinter_0_2 = NULL;
++    opdev->globals.GetLastError = GetLastError_1_0;
++}
++
+ /* device procs */
+ static void
+ opvp_initialize_device_procs(gx_device *dev)
+@@ -325,6 +421,9 @@ opvp_initialize_device_procs(gx_device *dev)
+      * by the system to the default. For compatibility we do the same. */
+     set_dev_proc(dev, encode_color, NULL);
+     set_dev_proc(dev, decode_color, NULL);
++
++    /* And the device globals */
++    InitGlobals(dev);
+ }
+
+ /* vector procs */
+@@ -394,6 +493,9 @@ oprp_initialize_device_procs(gx_device *dev)
+      * by the system to the default. For compatibility we do the same. */
+     set_dev_proc(dev, encode_color, NULL);
+     set_dev_proc(dev, decode_color, NULL);
++
++    /* And the device globals */
++    InitGlobals(dev);
+ }
+
+ const gx_device_oprp gs_oprp_device =
+@@ -412,43 +514,6 @@ const gx_device_oprp gs_oprp_device =
+     )
+ };
+
+-/* driver mode */
+-static bool vector = true;
+-static bool inkjet = false;
+-static char *vectorDriver = NULL;
+-static char *printerModel = NULL;
+-static void *handle = NULL;
+-static opvp_dc_t (*OpenPrinter)(opvp_int_t,const opvp_char_t*,
+-                                  const opvp_int_t[2],
+-                                  opvp_api_procs_t**) = NULL;
+-static int (*OpenPrinter_0_2)(int,char*,int*,
+-                                  OPVP_api_procs**) = NULL;
+-static opvp_int_t *ErrorNo = NULL;
+-static opvp_int_t outputFD = -1;
+-static opvp_int_t nApiEntry = 0;
+-static opvp_api_procs_t *apiEntry = NULL;
+-static OPVP_api_procs *apiEntry_0_2 = NULL;
+-static opvp_dc_t printerContext = -1;
+-static char *jobInfo = NULL;
+-static char *docInfo = NULL;
+-static opvp_cspace_t colorSpace = OPVP_CSPACE_STANDARDRGB;
+-static opvp_cspace_t savedColorSpace;
+-static opvp_brush_t *vectorFillColor = NULL;
+-static float margins[4] = {0, 0, 0, 0};
+-static float zoom[2] = {1, 1};
+-static float shift[2] = {0, 0};
+-static bool zoomAuto = false;
+-static bool zooming = false;
+-static bool beginPage = false;
+-
+-static int
+-GetLastError_1_0(void)
+-{
+-    return *ErrorNo;
+-}
+-
+-static int (*GetLastError)(void) = GetLastError_1_0;
+-
+ /* Wrapper functions that keep compatible with 0.2 */
+
+ /* color space mapping 0.2 to 1.0 */
+@@ -496,9 +561,11 @@ static int colorDepth_0_2[] = {
+
+ /* translate error code */
+ static int
+-GetLastError_0_2(void)
++GetLastError_0_2(gx_device* dev)
+ {
+-    switch(*ErrorNo) {
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
++    switch(*(opdev->globals.ErrorNo)) {
+     case OPVP_FATALERROR_0_2:
+         return OPVP_FATALERROR;
+         break;
+@@ -526,48 +593,51 @@ GetLastError_0_2(void)
+ }
+
+ static opvp_result_t
+-StartPageWrapper(opvp_dc_t printerContext, const opvp_char_t *pageInfo)
++StartPageWrapper(gx_device *dev, opvp_dc_t printerContext, const opvp_char_t *pageInfo)
+ {
+     int r;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+-    if ((r = apiEntry_0_2->StartPage(printerContext,
++    if ((r = opdev->globals.apiEntry_0_2->StartPage(printerContext,
+            /* discard const */(char *)pageInfo)) != OPVP_OK) {
+           /* error */
+         return r;
+     }
+     /* initialize ROP */
+-    if (apiEntry_0_2->SetROP != NULL) {
+-        apiEntry_0_2->SetROP(printerContext,
++    if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++        opdev->globals.apiEntry_0_2->SetROP(printerContext,
+           OPVP_0_2_ROP_P);
+     }
+     return OPVP_OK;
+ }
+
+ static opvp_result_t
+-InitGSWrapper(opvp_dc_t printerContext)
++InitGSWrapper(gx_device *dev, opvp_dc_t printerContext)
+ {
+     int r;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+-    if ((r = apiEntry_0_2->InitGS(printerContext)) != OPVP_OK) {
++    if ((r = opdev->globals.apiEntry_0_2->InitGS(printerContext)) != OPVP_OK) {
+           /* error */
+         return r;
+     }
+     /* initialize ROP */
+-    if (apiEntry_0_2->SetROP != NULL) {
+-        apiEntry_0_2->SetROP(printerContext,
++    if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++        opdev->globals.apiEntry_0_2->SetROP(printerContext,
+           OPVP_0_2_ROP_P);
+     }
+     return OPVP_OK;
+ }
+
+ static opvp_result_t
+-QueryColorSpaceWrapper( opvp_dc_t printerContext, opvp_int_t *pnum,
++QueryColorSpaceWrapper(gx_device *dev, opvp_dc_t printerContext, opvp_int_t *pnum,
+     opvp_cspace_t *pcspace)
+ {
+     int r;
+     int i;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+-    if ((r = apiEntry_0_2->QueryColorSpace(printerContext,
++    if ((r = opdev->globals.apiEntry_0_2->QueryColorSpace(printerContext,
+          (OPVP_ColorSpace *)pcspace,pnum)) != OPVP_OK) {
+         /* error */
+         return r;
+@@ -587,51 +657,54 @@ QueryColorSpaceWrapper( opvp_dc_t printerContext, opvp_int_t *pnum,
+ }
+
+ static opvp_result_t
+-SetColorSpaceWrapper(opvp_dc_t printerContext, opvp_cspace_t cspace)
++SetColorSpaceWrapper(gx_device *dev, opvp_dc_t printerContext, opvp_cspace_t cspace)
+ {
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
+     if (cspace == OPVP_CSPACE_DEVICEKRGB) {
+         /* 0.2 doesn't have OPVP_CSPACE_DEVICEKRGB */
+-        *ErrorNo = OPVP_NOTSUPPORTED_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_NOTSUPPORTED_0_2;
+         return -1;
+     }
+     if ((int)cspace
+          >= sizeof(cspace_1_0_to_0_2)/sizeof(OPVP_ColorSpace)) {
+         /* unknown color space */
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+-    return  apiEntry_0_2->SetColorSpace(printerContext,
++    return  opdev->globals.apiEntry_0_2->SetColorSpace(printerContext,
+       cspace_1_0_to_0_2[cspace]);
+ }
+
++/* Not used
+ static opvp_result_t
+-GetColorSpaceWrapper(opvp_dc_t printerContext, opvp_cspace_t *pcspace)
++GetColorSpaceWrapper(gx_device *dev, opvp_dc_t printerContext, opvp_cspace_t *pcspace)
+ {
+     int r;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+-    if ((r = apiEntry_0_2->GetColorSpace(printerContext,
++    if ((r = opdev->globals.apiEntry_0_2->GetColorSpace(printerContext,
+       (OPVP_ColorSpace *)pcspace)) != OPVP_OK) {
+-        /* error */
+         return r;
+     }
+     if (*pcspace
+          >= sizeof(cspace_0_2_to_1_0)/sizeof(opvp_cspace_t)) {
+-        /* unknown color space */
+-        /* set DEVICERGB instead */
+         *pcspace = OPVP_CSPACE_DEVICERGB;
+     } else {
+         *pcspace = cspace_0_2_to_1_0[*pcspace];
+     }
+     return r;
+ }
++*/
+
+ static opvp_result_t
+-SetStrokeColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
++SetStrokeColorWrapper(gx_device *dev, opvp_dc_t printerContext, const opvp_brush_t *brush)
+ {
+     OPVP_Brush brush_0_2;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     if (brush == NULL) {
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     if (brush->colorSpace == OPVP_CSPACE_DEVICEKRGB) {
+@@ -641,7 +714,7 @@ SetStrokeColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
+     if ((int)brush->colorSpace
+          >= sizeof(cspace_1_0_to_0_2)/sizeof(OPVP_ColorSpace)) {
+         /* unknown color space */
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     brush_0_2.colorSpace = cspace_1_0_to_0_2[brush->colorSpace];
+@@ -649,16 +722,17 @@ SetStrokeColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
+     brush_0_2.yorg = brush->yorg;
+     brush_0_2.pbrush = (OPVP_BrushData *)brush->pbrush;
+     memcpy(brush_0_2.color,brush->color,sizeof(brush_0_2.color));
+-    return apiEntry_0_2->SetStrokeColor(printerContext,&brush_0_2);
++    return opdev->globals.apiEntry_0_2->SetStrokeColor(printerContext, &brush_0_2);
+ }
+
+ static opvp_result_t
+-SetFillColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
++SetFillColorWrapper(gx_device *dev, opvp_dc_t printerContext, const opvp_brush_t *brush)
+ {
+     OPVP_Brush brush_0_2;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     if (brush == NULL) {
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     if (brush->colorSpace == OPVP_CSPACE_DEVICEKRGB) {
+@@ -668,7 +742,7 @@ SetFillColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
+     if ((int)brush->colorSpace
+          >= sizeof(cspace_1_0_to_0_2)/sizeof(OPVP_ColorSpace)) {
+         /* unknown color space */
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     brush_0_2.colorSpace = cspace_1_0_to_0_2[brush->colorSpace];
+@@ -676,27 +750,28 @@ SetFillColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
+     brush_0_2.yorg = brush->yorg;
+     brush_0_2.pbrush = (OPVP_BrushData *)brush->pbrush;
+     memcpy(brush_0_2.color,brush->color,sizeof(brush_0_2.color));
+-    return apiEntry_0_2->SetFillColor(printerContext,&brush_0_2);
++    return opdev->globals.apiEntry_0_2->SetFillColor(printerContext, &brush_0_2);
+ }
+
+ static opvp_result_t
+-SetBgColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
++SetBgColorWrapper(gx_device *dev, opvp_dc_t printerContext, const opvp_brush_t *brush)
+ {
+     OPVP_Brush brush_0_2;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     if (brush == NULL) {
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     if (brush->colorSpace == OPVP_CSPACE_DEVICEKRGB) {
+         /* 0.2 doesn't have OPVP_CSPACE_DEVICEKRGB */
+-        *ErrorNo = OPVP_NOTSUPPORTED_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_NOTSUPPORTED_0_2;
+         return -1;
+     }
+     if ((int)brush->colorSpace
+          >= sizeof(cspace_1_0_to_0_2)/sizeof(OPVP_ColorSpace)) {
+         /* unknown color space */
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     brush_0_2.colorSpace = cspace_1_0_to_0_2[brush->colorSpace];
+@@ -704,11 +779,12 @@ SetBgColorWrapper(opvp_dc_t printerContext, const opvp_brush_t *brush)
+     brush_0_2.yorg = brush->yorg;
+     brush_0_2.pbrush = (OPVP_BrushData *)brush->pbrush;
+     memcpy(brush_0_2.color,brush->color,sizeof(brush_0_2.color));
+-    return apiEntry_0_2->SetBgColor(printerContext,&brush_0_2);
++    return opdev->globals.apiEntry_0_2->SetBgColor(printerContext, &brush_0_2);
+ }
+
+ static opvp_result_t
+ DrawImageWrapper(
++    gx_device *dev,
+     opvp_dc_t printerContext,
+     opvp_int_t sourceWidth,
+     opvp_int_t sourceHeight,
+@@ -723,30 +799,31 @@ DrawImageWrapper(
+     OPVP_ImageFormat iformat_0_2;
+     OPVP_PaintMode paintmode_0_2 = OPVP_paintModeTransparent;
+     int depth;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     if (imageFormat == OPVP_IFORMAT_MASK) {
+-        if (apiEntry_0_2->GetPaintMode != NULL) {
+-            apiEntry_0_2->GetPaintMode(printerContext,
++        if (opdev->globals.apiEntry_0_2->GetPaintMode != NULL) {
++            opdev->globals.apiEntry_0_2->GetPaintMode(printerContext,
+               &paintmode_0_2);
+         }
+         if (paintmode_0_2 != OPVP_paintModeTransparent) {
+-            if (apiEntry_0_2->SetROP != NULL) {
+-                apiEntry_0_2->SetROP(printerContext,
++            if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++                opdev->globals.apiEntry_0_2->SetROP(printerContext,
+                     OPVP_0_2_ROP_S);
+             }
+         }
+         else {
+-            if (apiEntry_0_2->SetROP != NULL) {
+-                apiEntry_0_2->SetROP(printerContext,
++            if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++                opdev->globals.apiEntry_0_2->SetROP(printerContext,
+                     OPVP_0_2_ROP_OR);
+             }
+         }
+         depth = 1;
+     } else {
+-        if (apiEntry_0_2->SetROP != NULL) {
+-            apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_S);
++        if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++            opdev->globals.apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_S);
+         }
+-        depth = colorDepth_0_2[colorSpace];
++        depth = colorDepth_0_2[opdev->globals.colorSpace];
+     }
+
+     OPVP_I2FIX(0,rect.p0.x);
+@@ -755,17 +832,17 @@ DrawImageWrapper(
+     OPVP_I2FIX(destinationHeight,rect.p1.y);
+     if (imageFormat >= sizeof(iformat_1_0_to_0_2)/sizeof(OPVP_ImageFormat)) {
+         /* illegal image format */
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     iformat_0_2 = iformat_1_0_to_0_2[imageFormat];
+-    r = apiEntry_0_2->DrawImage(printerContext,sourceWidth,sourceHeight,
++    r = opdev->globals.apiEntry_0_2->DrawImage(printerContext,sourceWidth,sourceHeight,
+             depth,iformat_0_2,rect,
+             sourcePitch*sourceHeight,
+             /* remove const */ (void *)imagedata);
+
+-    if (apiEntry_0_2->SetROP != NULL) {
+-        apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_P);
++    if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++        opdev->globals.apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_P);
+     }
+
+     return r;
+@@ -773,6 +850,7 @@ DrawImageWrapper(
+
+ static opvp_result_t
+ StartDrawImageWrapper(
++    gx_device *dev,
+     opvp_dc_t printerContext,
+     opvp_int_t sourceWidth,
+     opvp_int_t sourceHeight,
+@@ -786,28 +864,29 @@ StartDrawImageWrapper(
+     OPVP_ImageFormat iformat_0_2;
+     OPVP_PaintMode paintmode_0_2 = OPVP_paintModeTransparent;
+     int depth;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     if (imageFormat == OPVP_IFORMAT_MASK) {
+-        if (apiEntry_0_2->GetPaintMode != NULL) {
+-            apiEntry_0_2->GetPaintMode(printerContext,
++        if (opdev->globals.apiEntry_0_2->GetPaintMode != NULL) {
++            opdev->globals.apiEntry_0_2->GetPaintMode(printerContext,
+               &paintmode_0_2);
+         }
+         if (paintmode_0_2 != OPVP_paintModeTransparent) {
+-            if (apiEntry_0_2->SetROP != NULL) {
+-                apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_S);
++            if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++                opdev->globals.apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_S);
+             }
+         }
+         else {
+-            if (apiEntry_0_2->SetROP != NULL) {
+-                apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_OR);
++            if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++                opdev->globals.apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_OR);
+             }
+         }
+         depth = 1;
+     } else {
+-        if (apiEntry_0_2->SetROP != NULL) {
+-            apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_S);
++        if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++            opdev->globals.apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_S);
+         }
+-        depth = colorDepth_0_2[colorSpace];
++        depth = colorDepth_0_2[opdev->globals.colorSpace];
+     }
+
+     OPVP_I2FIX(0,rect.p0.x);
+@@ -816,310 +895,518 @@ StartDrawImageWrapper(
+     OPVP_I2FIX(destinationHeight,rect.p1.y);
+     if (imageFormat >= sizeof(iformat_1_0_to_0_2)/sizeof(OPVP_ImageFormat)) {
+         /* illegal image format */
+-        *ErrorNo = OPVP_PARAMERROR_0_2;
++        *(opdev->globals.ErrorNo) = OPVP_PARAMERROR_0_2;
+         return -1;
+     }
+     iformat_0_2 = iformat_1_0_to_0_2[imageFormat];
+-    r = apiEntry_0_2->StartDrawImage(printerContext,
+-            sourceWidth,sourceHeight,
+-            depth,iformat_0_2,rect);
++    r = opdev->globals.apiEntry_0_2->StartDrawImage(printerContext,
++            sourceWidth, sourceHeight,
++            depth, iformat_0_2, rect);
+
+     return r;
+ }
+
+ static opvp_result_t
+-EndDrawImageWrapper(opvp_dc_t printerContext)
++EndDrawImageWrapper(gx_device *dev, opvp_dc_t printerContext)
+ {
+     int r;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+-    r = apiEntry_0_2->EndDrawImage(printerContext);
++    r = opdev->globals.apiEntry_0_2->EndDrawImage(printerContext);
+
+     /* make sure rop is pattern copy */
+-    if (apiEntry_0_2->SetROP != NULL) {
+-        apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_P);
++    if (opdev->globals.apiEntry_0_2->SetROP != NULL) {
++        opdev->globals.apiEntry_0_2->SetROP(printerContext,OPVP_0_2_ROP_P);
+     }
+
+     return r;
+ }
+
++/* Not used
+ static opvp_result_t
+ QueryDeviceCapabilityWrapper(
++    gx_device *dev,
+     opvp_dc_t printerContext,
+     opvp_queryinfoflags_t queryflag,
+     opvp_int_t *buflen,
+     opvp_char_t *infoBuf)
+ {
+-    return apiEntry_0_2->QueryDeviceCapability(printerContext,queryflag,
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
++    return opdev->globals.apiEntry_0_2->QueryDeviceCapability(printerContext,queryflag,
+       *buflen,(char *)infoBuf);
+ }
+
+ static opvp_result_t
+ QueryDeviceInfoWrapper(
++    gx_device *dev,
+     opvp_dc_t printerContext,
+     opvp_queryinfoflags_t queryflag,
+     opvp_int_t *buflen,
+     opvp_char_t *infoBuf)
+ {
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
+     if (queryflag & OPVP_QF_MEDIACOPY) {
+-        *ErrorNo = OPVP_NOTSUPPORTED;
++        *(opdev->globals.ErrorNo) = OPVP_NOTSUPPORTED;
+         return -1;
+     }
+     if (queryflag & OPVP_QF_PRINTREGION) {
+         queryflag &= ~OPVP_QF_PRINTREGION;
+         queryflag |= 0x0020000;
+     }
+-    return apiEntry_0_2->QueryDeviceInfo(printerContext,queryflag,
+-      *buflen,(char *)infoBuf);
++    return opdev->globals.apiEntry_0_2->QueryDeviceInfo(printerContext, queryflag,
++      *buflen, (char *)infoBuf);
+ }
++*/
+
+ static opvp_result_t
+-SetLineDashWrapper(opvp_dc_t printerContext, opvp_int_t num,
++SetLineDashWrapper(gx_device *dev, opvp_dc_t printerContext, opvp_int_t num,
+     const opvp_fix_t *pdash)
+ {
+-    return apiEntry_0_2->SetLineDash(printerContext,
+-      /* remove const */ (OPVP_Fix *)pdash,num);
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
++    return opdev->globals.apiEntry_0_2->SetLineDash(printerContext, num,
++      /* remove const */ (OPVP_Fix *)pdash);
+ }
+
++/* Not used
+ static opvp_result_t
+-GetLineDashWrapper(opvp_dc_t printerContext, opvp_int_t *pnum,
++GetLineDashWrapper(gx_device* dev, opvp_dc_t printerContext, opvp_int_t *pnum,
+     opvp_fix_t *pdash)
+ {
+-    return apiEntry_0_2->GetLineDash(printerContext,
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
++    return opdev->globals.apiEntry_0_2->GetLineDash(printerContext,
+       pdash,pnum);
+ }
++*/
+
+ static opvp_dc_t
+ OpenPrinterWrapper(
++    gx_device *dev,
+     opvp_int_t outputFD,
+     const opvp_char_t *printerModel,
+     const opvp_int_t apiVersion[2],
+     opvp_api_procs_t **apiProcs)
+ {
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
+     opvp_dc_t dc = -1;
+
+-    if (OpenPrinter != NULL) {
+-        dc = (*OpenPrinter)(outputFD,printerModel,apiVersion,apiProcs);
++    if (opdev->globals.OpenPrinter != NULL) {
++        dc = (*(opdev->globals.OpenPrinter))(outputFD, printerModel, apiVersion, apiProcs);
+     } else {
+         /* try version 0.2 */
+
+-        if (OpenPrinter_0_2 != NULL) {
++        if (opdev->globals.OpenPrinter_0_2 != NULL) {
+             static opvp_api_procs_t tEntry;
+-            int nApiEntry;
++            int nApiEntry;  /* Alias with prior global. Kept as is */
+
+-            dc = (*OpenPrinter_0_2)(outputFD,
++            dc = (*(opdev->globals.OpenPrinter_0_2))(outputFD,
+                     /* remove const */
+                     (char *)printerModel,
+-                    &nApiEntry,&apiEntry_0_2);
++                    &nApiEntry,
++                    &(opdev->globals.apiEntry_0_2));
+             /* setting functions */
+             tEntry.opvpClosePrinter
+-                    = apiEntry_0_2->ClosePrinter;
++                    = opdev->globals.apiEntry_0_2->ClosePrinter;
+             tEntry.opvpStartJob
+                     = (opvp_result_t (*)(opvp_int_t,
+                        const opvp_char_t*))
+-                       apiEntry_0_2->StartJob;
+-            tEntry.opvpEndJob = apiEntry_0_2->EndJob;
++                       opdev->globals.apiEntry_0_2->StartJob;
++            tEntry.opvpEndJob = opdev->globals.apiEntry_0_2->EndJob;
+             tEntry.opvpAbortJob = NULL;
+             tEntry.opvpStartDoc
+                     = (opvp_result_t (*)(opvp_dc_t,
+                        const opvp_char_t*))
+-                       apiEntry_0_2->StartDoc;
+-            tEntry.opvpEndDoc = apiEntry_0_2->EndDoc;
+-            if (apiEntry_0_2->StartPage != NULL) {
+-                tEntry.opvpStartPage = StartPageWrapper;
+-            } else {
+-                tEntry.opvpStartPage = NULL;
+-            }
+-            tEntry.opvpEndPage = apiEntry_0_2->EndPage;
+-
+-            if (apiEntry_0_2->QueryDeviceCapability != NULL) {
+-                tEntry.opvpQueryDeviceCapability
+-                  = QueryDeviceCapabilityWrapper;
+-            } else {
+-                tEntry.opvpQueryDeviceCapability = NULL;
+-            }
+-
+-            if (apiEntry_0_2->QueryDeviceInfo != NULL) {
+-                tEntry.opvpQueryDeviceInfo = QueryDeviceInfoWrapper;
+-            } else {
+-                tEntry.opvpQueryDeviceInfo = NULL;
+-            }
+-
+-            tEntry.opvpResetCTM = apiEntry_0_2->ResetCTM;
++                       opdev->globals.apiEntry_0_2->StartDoc;
++            tEntry.opvpEndDoc = opdev->globals.apiEntry_0_2->EndDoc;
++            tEntry.opvpStartPage = NULL;
++            tEntry.opvpEndPage = opdev->globals.apiEntry_0_2->EndPage;
++            tEntry.opvpQueryDeviceCapability = NULL;
++            tEntry.opvpQueryDeviceInfo = NULL;
++            tEntry.opvpResetCTM = opdev->globals.apiEntry_0_2->ResetCTM;
+             tEntry.opvpSetCTM = (opvp_result_t (*)(opvp_dc_t,
+                        const opvp_ctm_t*))
+-                       apiEntry_0_2->SetCTM;
++                       opdev->globals.apiEntry_0_2->SetCTM;
+             tEntry.opvpGetCTM = (opvp_result_t (*)(opvp_dc_t,opvp_ctm_t*))
+-                       apiEntry_0_2->GetCTM;
+-            if (apiEntry_0_2->InitGS != NULL) {
+-                tEntry.opvpInitGS = InitGSWrapper;
+-            } else {
+-                tEntry.opvpInitGS = NULL;
+-            }
+-            tEntry.opvpSaveGS = apiEntry_0_2->SaveGS;
+-            tEntry.opvpRestoreGS = apiEntry_0_2->RestoreGS;
+-            if (apiEntry_0_2->QueryColorSpace != NULL) {
+-                tEntry.opvpQueryColorSpace = QueryColorSpaceWrapper;
+-            } else {
+-                tEntry.opvpQueryColorSpace = NULL;
+-            }
+-            if (apiEntry_0_2->SetColorSpace != NULL) {
+-                tEntry.opvpSetColorSpace = SetColorSpaceWrapper;
+-            } else {
+-                tEntry.opvpSetColorSpace = NULL;
+-            }
+-            if (apiEntry_0_2->GetColorSpace != NULL) {
+-                tEntry.opvpGetColorSpace = GetColorSpaceWrapper;
+-            } else {
+-                tEntry.opvpGetColorSpace = NULL;
+-            }
++                opdev->globals.apiEntry_0_2->GetCTM;
++            tEntry.opvpInitGS = NULL;
++            tEntry.opvpSaveGS = opdev->globals.apiEntry_0_2->SaveGS;
++            tEntry.opvpRestoreGS = opdev->globals.apiEntry_0_2->RestoreGS;
++            tEntry.opvpQueryColorSpace = NULL;
++            tEntry.opvpSetColorSpace = NULL;
++            tEntry.opvpGetColorSpace = NULL;
++
+             tEntry.opvpSetFillMode
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_fillmode_t))
+-                       apiEntry_0_2->SetFillMode;
++                opdev->globals.apiEntry_0_2->SetFillMode;
+             tEntry.opvpGetFillMode
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_fillmode_t*))
+-                       apiEntry_0_2->GetFillMode;
+-            tEntry.opvpSetAlphaConstant = apiEntry_0_2->SetAlphaConstant;
+-            tEntry.opvpGetAlphaConstant = apiEntry_0_2->GetAlphaConstant;
+-            tEntry.opvpSetLineWidth = apiEntry_0_2->SetLineWidth;
+-            tEntry.opvpGetLineWidth = apiEntry_0_2->GetLineWidth;
+-            if (apiEntry_0_2->SetLineDash != NULL) {
+-                tEntry.opvpSetLineDash = SetLineDashWrapper;
+-            } else {
+-                tEntry.opvpSetLineDash = NULL;
+-            }
+-            if (apiEntry_0_2->GetLineDash != NULL) {
+-                tEntry.opvpGetLineDash = GetLineDashWrapper;
+-            } else {
+-                tEntry.opvpGetLineDash = NULL;
+-            }
++                opdev->globals.apiEntry_0_2->GetFillMode;
++            tEntry.opvpSetAlphaConstant = opdev->globals.apiEntry_0_2->SetAlphaConstant;
++            tEntry.opvpGetAlphaConstant = opdev->globals.apiEntry_0_2->GetAlphaConstant;
++            tEntry.opvpSetLineWidth = opdev->globals.apiEntry_0_2->SetLineWidth;
++            tEntry.opvpGetLineWidth = opdev->globals.apiEntry_0_2->GetLineWidth;
++            tEntry.opvpSetLineDash = NULL;
++            tEntry.opvpGetLineDash = NULL;
++
+             tEntry.opvpSetLineDashOffset
+-                    = apiEntry_0_2->SetLineDashOffset;
++                    = opdev->globals.apiEntry_0_2->SetLineDashOffset;
+             tEntry.opvpGetLineDashOffset
+-                    = apiEntry_0_2->GetLineDashOffset;
++                    = opdev->globals.apiEntry_0_2->GetLineDashOffset;
+             tEntry.opvpSetLineStyle
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_linestyle_t))
+-                       apiEntry_0_2->SetLineStyle;
++                opdev->globals.apiEntry_0_2->SetLineStyle;
+             tEntry.opvpGetLineStyle
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_linestyle_t*))
+-                       apiEntry_0_2->GetLineStyle;
++                opdev->globals.apiEntry_0_2->GetLineStyle;
+             tEntry.opvpSetLineCap
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_linecap_t))
+-                       apiEntry_0_2->SetLineCap;
++                opdev->globals.apiEntry_0_2->SetLineCap;
+             tEntry.opvpGetLineCap
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_linecap_t*))
+-                       apiEntry_0_2->GetLineCap;
++                opdev->globals.apiEntry_0_2->GetLineCap;
+             tEntry.opvpSetLineJoin
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_linejoin_t))
+-                       apiEntry_0_2->SetLineJoin;
++                opdev->globals.apiEntry_0_2->SetLineJoin;
+             tEntry.opvpGetLineJoin
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_linejoin_t*))
+-                       apiEntry_0_2->GetLineJoin;
+-            tEntry.opvpSetMiterLimit = apiEntry_0_2->SetMiterLimit;
+-            tEntry.opvpGetMiterLimit = apiEntry_0_2->GetMiterLimit;
++                opdev->globals.apiEntry_0_2->GetLineJoin;
++            tEntry.opvpSetMiterLimit = opdev->globals.apiEntry_0_2->SetMiterLimit;
++            tEntry.opvpGetMiterLimit = opdev->globals.apiEntry_0_2->GetMiterLimit;
+             tEntry.opvpSetPaintMode
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_paintmode_t))
+-                       apiEntry_0_2->SetPaintMode;
++                opdev->globals.apiEntry_0_2->SetPaintMode;
+             tEntry.opvpGetPaintMode
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_paintmode_t*))
+-                       apiEntry_0_2->GetPaintMode;
+-            if (apiEntry_0_2->SetStrokeColor != NULL) {
+-                tEntry.opvpSetStrokeColor = SetStrokeColorWrapper;
+-            } else {
+-                tEntry.opvpSetStrokeColor = NULL;
+-            }
+-            if (apiEntry_0_2->SetFillColor != NULL) {
+-                tEntry.opvpSetFillColor = SetFillColorWrapper;
+-            } else {
+-                tEntry.opvpSetFillColor = NULL;
+-            }
+-            if (apiEntry_0_2->SetBgColor != NULL) {
+-                tEntry.opvpSetBgColor = SetBgColorWrapper;
+-            } else {
+-                tEntry.opvpSetBgColor = NULL;
+-            }
+-            tEntry.opvpNewPath = apiEntry_0_2->NewPath;
+-            tEntry.opvpEndPath = apiEntry_0_2->EndPath;
+-            tEntry.opvpStrokePath = apiEntry_0_2->StrokePath;
+-            tEntry.opvpFillPath = apiEntry_0_2->FillPath;
+-            tEntry.opvpStrokeFillPath = apiEntry_0_2->StrokeFillPath;
++                opdev->globals.apiEntry_0_2->GetPaintMode;
++            tEntry.opvpSetStrokeColor = NULL;
++            tEntry.opvpSetFillColor = NULL;
++            tEntry.opvpSetBgColor = NULL;
++            tEntry.opvpNewPath = opdev->globals.apiEntry_0_2->NewPath;
++            tEntry.opvpEndPath = opdev->globals.apiEntry_0_2->EndPath;
++            tEntry.opvpStrokePath = opdev->globals.apiEntry_0_2->StrokePath;
++            tEntry.opvpFillPath = opdev->globals.apiEntry_0_2->FillPath;
++            tEntry.opvpStrokeFillPath = opdev->globals.apiEntry_0_2->StrokeFillPath;
+             tEntry.opvpSetClipPath
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_cliprule_t))
+-                       apiEntry_0_2->SetClipPath;
+-            tEntry.opvpResetClipPath = apiEntry_0_2->ResetClipPath;
+-            tEntry.opvpSetCurrentPoint = apiEntry_0_2->SetCurrentPoint;
++                opdev->globals.apiEntry_0_2->SetClipPath;
++            tEntry.opvpResetClipPath = opdev->globals.apiEntry_0_2->ResetClipPath;
++            tEntry.opvpSetCurrentPoint = opdev->globals.apiEntry_0_2->SetCurrentPoint;
+             tEntry.opvpLinePath
+                     = (opvp_result_t (*)(opvp_dc_t,
+                        opvp_pathmode_t,opvp_int_t,
+                        const opvp_point_t*))
+-                       apiEntry_0_2->LinePath;
++                opdev->globals.apiEntry_0_2->LinePath;
+             tEntry.opvpPolygonPath
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_int_t,
+                        const opvp_int_t*,
+                        const opvp_point_t*))
+-                       apiEntry_0_2->PolygonPath;
++                opdev->globals.apiEntry_0_2->PolygonPath;
+             tEntry.opvpRectanglePath
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_int_t,
+                        const opvp_rectangle_t*))
+-                       apiEntry_0_2->RectanglePath;
++                opdev->globals.apiEntry_0_2->RectanglePath;
+             tEntry.opvpRoundRectanglePath
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_int_t,
+                        const opvp_roundrectangle_t*))
+-                       apiEntry_0_2->RoundRectanglePath;
++                opdev->globals.apiEntry_0_2->RoundRectanglePath;
+             tEntry.opvpBezierPath
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_int_t,
+                        const opvp_point_t*))
+-                       apiEntry_0_2->BezierPath;
++                opdev->globals.apiEntry_0_2->BezierPath;
+             tEntry.opvpArcPath
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_arcmode_t,
+                        opvp_arcdir_t,opvp_fix_t,opvp_fix_t,opvp_fix_t,
+                        opvp_fix_t,opvp_fix_t,opvp_fix_t,opvp_fix_t,
+-                       opvp_fix_t))apiEntry_0_2->ArcPath;
+-            if (apiEntry_0_2->DrawImage != NULL) {
+-                tEntry.opvpDrawImage = DrawImageWrapper;
+-            } else {
+-                tEntry.opvpDrawImage = NULL;
+-            }
+-            if (apiEntry_0_2->StartDrawImage != NULL) {
+-                tEntry.opvpStartDrawImage = StartDrawImageWrapper;
+-            } else {
+-                tEntry.opvpStartDrawImage = NULL;
+-            }
++                       opvp_fix_t))opdev->globals.apiEntry_0_2->ArcPath;
++            tEntry.opvpDrawImage = NULL;
++            tEntry.opvpStartDrawImage = NULL;
+             tEntry.opvpTransferDrawImage =
+                (opvp_result_t (*)(opvp_dc_t,opvp_int_t,const void*))
+-               apiEntry_0_2->TransferDrawImage;
+-            if (apiEntry_0_2->EndDrawImage != NULL) {
+-                tEntry.opvpEndDrawImage = EndDrawImageWrapper;
+-            } else {
+-                tEntry.opvpEndDrawImage = NULL;
+-            }
+-            tEntry.opvpStartScanline = apiEntry_0_2->StartScanline;
++                opdev->globals.apiEntry_0_2->TransferDrawImage;
++            tEntry.opvpEndDrawImage = NULL;
++            tEntry.opvpStartScanline = opdev->globals.apiEntry_0_2->StartScanline;
+             tEntry.opvpScanline
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_int_t,
+                        const opvp_int_t*))
+-                       apiEntry_0_2->Scanline;
+-            tEntry.opvpEndScanline = apiEntry_0_2->EndScanline;
+-            tEntry.opvpStartRaster = apiEntry_0_2->StartRaster;
++                opdev->globals.apiEntry_0_2->Scanline;
++            tEntry.opvpEndScanline = opdev->globals.apiEntry_0_2->EndScanline;
++            tEntry.opvpStartRaster = opdev->globals.apiEntry_0_2->StartRaster;
+             tEntry.opvpTransferRasterData
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_int_t,
+                        const opvp_byte_t*))
+-                       apiEntry_0_2->TransferRasterData;
+-            tEntry.opvpSkipRaster = apiEntry_0_2->SkipRaster;
+-            tEntry.opvpEndRaster = apiEntry_0_2->EndRaster;
+-            tEntry.opvpStartStream = apiEntry_0_2->StartStream;
++                opdev->globals.apiEntry_0_2->TransferRasterData;
++            tEntry.opvpSkipRaster = opdev->globals.apiEntry_0_2->SkipRaster;
++            tEntry.opvpEndRaster = opdev->globals.apiEntry_0_2->EndRaster;
++            tEntry.opvpStartStream = opdev->globals.apiEntry_0_2->StartStream;
+             tEntry.opvpTransferStreamData
+                     = (opvp_result_t (*)(opvp_dc_t,opvp_int_t,
+                        const void *))
+-                       apiEntry_0_2->TransferStreamData;
+-            tEntry.opvpEndStream = apiEntry_0_2->EndStream;
++                opdev->globals.apiEntry_0_2->TransferStreamData;
++            tEntry.opvpEndStream = opdev->globals.apiEntry_0_2->EndStream;
+
+             *apiProcs = &tEntry;
+
+-            GetLastError = GetLastError_0_2;
++            opdev->globals.GetLastError = GetLastError_0_2;
+         }
+     }
+     return dc;
+ }
+
++/* Set of methods to separate the 0.2 and 1.0 calls AND deal with the prior use of globals */
++static opvp_result_t
++gsopvpStartPage(gx_device* dev, opvp_dc_t printerContext, const opvp_char_t* pageInfo)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->StartPage) {
++        return StartPageWrapper(dev, printerContext, pageInfo);
++    } else if (opdev->globals.apiEntry->opvpStartPage) {
++        return opdev->globals.apiEntry->opvpStartPage(printerContext, pageInfo);
++    } else
++        return OPVP_FATALERROR;
++}
++
++/* Not used
++static opvp_result_t
++gsopvpQueryDeviceCapability(
++    gx_device* dev,
++    opvp_dc_t printerContext,
++    opvp_queryinfoflags_t queryflag,
++    opvp_int_t* buflen,
++    opvp_char_t* infoBuf)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->QueryDeviceCapability) {
++        return QueryDeviceCapabilityWrapper(dev, printerContext, queryflag, buflen, infoBuf);
++    } else if (opdev->globals.apiEntry->opvpQueryDeviceCapability) {
++        return opdev->globals.apiEntry->opvpQueryDeviceCapability(printerContext, queryflag, buflen, infoBuf);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpQueryDeviceInfo(
++    gx_device* dev,
++    opvp_dc_t printerContext,
++    opvp_queryinfoflags_t queryflag,
++    opvp_int_t* buflen,
++    opvp_char_t* infoBuf)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->QueryDeviceCapability) {
++        return QueryDeviceInfoWrapper(dev, printerContext, queryflag, buflen, infoBuf);
++    } else if (opdev->globals.apiEntry->opvpQueryDeviceCapability) {
++        return opdev->globals.apiEntry->opvpQueryDeviceInfo(printerContext, queryflag, buflen, infoBuf);
++    } else
++        return OPVP_FATALERROR;
++}
++*/
++
++static opvp_result_t
++gsopvpInitGS(gx_device* dev, opvp_dc_t printerContext)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->InitGS) {
++        return InitGSWrapper(dev, printerContext);
++    } else if (opdev->globals.apiEntry->opvpInitGS) {
++        return opdev->globals.apiEntry->opvpInitGS(printerContext);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpQueryColorSpace(gx_device* dev, opvp_dc_t printerContext, opvp_int_t* pnum,
++    opvp_cspace_t* pcspace)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->QueryColorSpace) {
++        return QueryColorSpaceWrapper(dev, printerContext, pnum, pcspace);
++    } else if (opdev->globals.apiEntry->opvpQueryColorSpace) {
++        return opdev->globals.apiEntry->opvpQueryColorSpace(printerContext, pnum, pcspace);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpSetColorSpace(gx_device* dev, opvp_dc_t printerContext, opvp_cspace_t cspace)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->SetColorSpace) {
++        return SetColorSpaceWrapper(dev, printerContext, cspace);
++    } else if (opdev->globals.apiEntry->opvpQueryColorSpace) {
++        return opdev->globals.apiEntry->opvpSetColorSpace(printerContext, cspace);
++    } else
++        return OPVP_FATALERROR;
++}
++
++/* Not used
++static opvp_result_t
++gsopvpGetColorSpace(gx_device* dev, opvp_dc_t printerContext, opvp_cspace_t* pcspace)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->GetColorSpace) {
++        return GetColorSpaceWrapper(dev, printerContext, pcspace);
++    } else if (opdev->globals.apiEntry->opvpGetColorSpace) {
++        return opdev->globals.apiEntry->opvpGetColorSpace(printerContext, pcspace);
++    } else
++        return OPVP_FATALERROR;
++}
++*/
++
++static opvp_result_t
++gsopvpSetLineDash(gx_device* dev, opvp_dc_t printerContext, opvp_int_t num,
++    const opvp_fix_t* pdash)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->SetLineDash) {
++        return SetLineDashWrapper(dev, printerContext, num, pdash);
++    } else if (opdev->globals.apiEntry->opvpSetLineDash) {
++        return opdev->globals.apiEntry->opvpSetLineDash(printerContext, num, pdash);
++    } else
++        return OPVP_FATALERROR;
++}
++
++/* Not used
++static opvp_result_t
++gsopvpGetLineDash(gx_device* dev, opvp_dc_t printerContext, opvp_int_t* pnum,
++    opvp_fix_t* pdash)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->GetLineDash) {
++        return GetLineDashWrapper(dev, printerContext, pnum, pdash);
++    } else if (opdev->globals.apiEntry->opvpGetLineDash) {
++        return opdev->globals.apiEntry->opvpGetLineDash(printerContext, pnum, pdash);
++    } else
++        return OPVP_FATALERROR;
++}
++*/
++
++static opvp_result_t
++gsopvpSetStrokeColor(gx_device* dev, opvp_dc_t printerContext, const opvp_brush_t* brush)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->SetStrokeColor) {
++        return SetStrokeColorWrapper(dev, printerContext, brush);
++    } else if (opdev->globals.apiEntry->opvpSetStrokeColor) {
++        return opdev->globals.apiEntry->opvpSetStrokeColor(printerContext, brush);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpSetFillColor(gx_device* dev, opvp_dc_t printerContext, const opvp_brush_t* brush)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->SetFillColor) {
++        return SetFillColorWrapper(dev, printerContext, brush);
++    } else if (opdev->globals.apiEntry->opvpSetFillColor) {
++        return opdev->globals.apiEntry->opvpSetFillColor(printerContext, brush);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpSetBgColor(gx_device* dev, opvp_dc_t printerContext, const opvp_brush_t* brush)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->SetBgColor) {
++        return SetBgColorWrapper(dev, printerContext, brush);
++    } else if (opdev->globals.apiEntry->opvpSetBgColor) {
++        return opdev->globals.apiEntry->opvpSetBgColor(printerContext, brush);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpDrawImage(
++    gx_device* dev,
++    opvp_dc_t printerContext,
++    opvp_int_t sourceWidth,
++    opvp_int_t sourceHeight,
++    opvp_int_t sourcePitch,
++    opvp_imageformat_t imageFormat,
++    opvp_int_t destinationWidth,
++    opvp_int_t destinationHeight,
++    const void* imagedata)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->DrawImage) {
++        return DrawImageWrapper(dev, printerContext, sourceWidth, sourceHeight,
++            sourcePitch, imageFormat, destinationWidth, destinationHeight, imagedata);
++    } else if (opdev->globals.apiEntry->opvpDrawImage) {
++        return opdev->globals.apiEntry->opvpDrawImage(printerContext, sourceWidth, sourceHeight,
++            sourcePitch, imageFormat, destinationWidth, destinationHeight, imagedata);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpStartDrawImage(
++    gx_device* dev,
++    opvp_dc_t printerContext,
++    opvp_int_t sourceWidth,
++    opvp_int_t sourceHeight,
++    opvp_int_t sourcePitch,
++    opvp_imageformat_t imageFormat,
++    opvp_int_t destinationWidth,
++    opvp_int_t destinationHeight)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->StartDrawImage) {
++        return StartDrawImageWrapper(dev, printerContext, sourceWidth, sourceHeight,
++            sourcePitch, imageFormat, destinationWidth, destinationHeight);
++    } else if (opdev->globals.apiEntry->opvpStartDrawImage) {
++        return opdev->globals.apiEntry->opvpStartDrawImage(printerContext, sourceWidth, sourceHeight,
++            sourcePitch, imageFormat, destinationWidth, destinationHeight);
++    } else
++        return OPVP_FATALERROR;
++}
++
++static opvp_result_t
++gsopvpEndDrawImage(gx_device* dev, opvp_dc_t printerContext)
++{
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.apiEntry_0_2 != NULL &&
++        opdev->globals.apiEntry_0_2->EndDrawImage) {
++        return EndDrawImageWrapper(dev, printerContext);
++    } else if (opdev->globals.apiEntry->opvpEndDrawImage) {
++        return opdev->globals.apiEntry->opvpEndDrawImage(printerContext);
++    } else
++        return OPVP_FATALERROR;
++}
++
+ /* for image */
+ static  const
+ gx_image_enum_procs_t opvp_image_enum_procs =
+@@ -1167,27 +1454,28 @@ typedef struct bbox_image_enum_s {
+ /* initialize Graphic State */
+ /* No defaults in OPVP 1.0 */
+ static int
+-InitGS(void)
++InitGS(gx_device* dev)
+ {
+-    if (apiEntry->opvpInitGS != NULL) {
+-        if (apiEntry->opvpInitGS(printerContext) != OPVP_OK) {
+-            return -1;
+-        }
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
++    if (gsopvpInitGS(dev, opdev->globals.printerContext) != OPVP_OK) {
++        return -1;
+     }
+-    if (apiEntry->opvpSetColorSpace != NULL) {
+-        if (apiEntry->opvpSetColorSpace(printerContext,colorSpace)
+-           != OPVP_OK) {
++
++    if (opdev->globals.apiEntry->opvpSetColorSpace != NULL) {
++        if (opdev->globals.apiEntry->opvpSetColorSpace(opdev->globals.printerContext,
++            opdev->globals.colorSpace) != OPVP_OK){
+             return -1;
+         }
+     }
+-    if (apiEntry->opvpSetPaintMode != NULL) {
+-        if (apiEntry->opvpSetPaintMode(printerContext,
++    if (opdev->globals.apiEntry->opvpSetPaintMode != NULL) {
++        if (opdev->globals.apiEntry->opvpSetPaintMode(opdev->globals.printerContext,
+             OPVP_PAINTMODE_TRANSPARENT) != OPVP_OK) {
+             return -1;
+         }
+     }
+-    if (apiEntry->opvpSetAlphaConstant != NULL) {
+-        if (apiEntry->opvpSetAlphaConstant(printerContext,1.0)
++    if (opdev->globals.apiEntry->opvpSetAlphaConstant != NULL) {
++        if (opdev->globals.apiEntry->opvpSetAlphaConstant(opdev->globals.printerContext,1.0)
+            != OPVP_OK) {
+             return -1;
+         }
+@@ -1203,20 +1491,20 @@ opvp_startpage(gx_device *dev)
+     int ecode = 0;
+     opvp_result_t r = -1;
+     static char *page_info = NULL;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     /* page info */
+     page_info = opvp_alloc_string(&page_info, OPVP_INFO_PREFIX);
+     page_info = opvp_cat_string(&page_info, opvp_gen_page_info(dev));
+
+     /* call StartPage */
+-    if (printerContext != -1) {
+-        if (apiEntry->opvpStartPage)
+-            r = apiEntry->opvpStartPage(printerContext,
+-                       (opvp_char_t *)opvp_to_utf8(page_info));
++    if (opdev->globals.printerContext != -1) {
++        r = gsopvpStartPage(dev, opdev->globals.printerContext,
++                (opvp_char_t*)opvp_to_utf8(page_info));
+         if (r != OPVP_OK) {
+             ecode = -1;
+         } else {
+-            ecode = InitGS();
++            ecode = InitGS(dev);
+         }
+     }
+
+@@ -1224,15 +1512,16 @@ opvp_startpage(gx_device *dev)
+ }
+
+ static  int
+-opvp_endpage(void)
++opvp_endpage(gx_device* dev)
+ {
+     int ecode = 0;
+     opvp_result_t r = -1;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     /* call EndPage */
+-    if (printerContext != -1) {
+-        if (apiEntry->opvpEndPage)
+-            r = apiEntry->opvpEndPage(printerContext);
++    if (opdev->globals.printerContext != -1) {
++        if (opdev->globals.apiEntry->opvpEndPage)
++            r = opdev->globals.apiEntry->opvpEndPage(opdev->globals.printerContext);
+         if (r != OPVP_OK) {
+             ecode = -1;
+         }
+@@ -1304,32 +1593,33 @@ opvp_adjust_num_string(char *num_string)
+ }
+
+ static  char **
+-opvp_gen_dynamic_lib_name(void)
++opvp_gen_dynamic_lib_name(gx_device* dev)
+ {
+     static char *buff[5] = {NULL,NULL,NULL,NULL,NULL};
+     char tbuff[OPVP_BUFF_SIZE];
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+-    if (!vectorDriver) {
++    if (!(opdev->globals.vectorDriver)) {
+         return NULL;
+     }
+
+     memset((void*)tbuff, 0, OPVP_BUFF_SIZE);
+-    strncpy(tbuff, vectorDriver, OPVP_BUFF_SIZE - 1);
++    strncpy(tbuff, opdev->globals.vectorDriver, OPVP_BUFF_SIZE - 1);
+     opvp_alloc_string(&(buff[0]), tbuff);
+
+     memset((void*)tbuff, 0, OPVP_BUFF_SIZE);
+-    strncpy(tbuff, vectorDriver, OPVP_BUFF_SIZE - 4);
++    strncpy(tbuff, opdev->globals.vectorDriver, OPVP_BUFF_SIZE - 4);
+     strcat(tbuff, ".so");
+     opvp_alloc_string(&(buff[1]), tbuff);
+
+     memset((void*)tbuff, 0, OPVP_BUFF_SIZE);
+-    strncpy(tbuff, vectorDriver, OPVP_BUFF_SIZE - 5);
++    strncpy(tbuff, opdev->globals.vectorDriver, OPVP_BUFF_SIZE - 5);
+     strcat(tbuff, ".dll");
+     opvp_alloc_string(&(buff[2]), tbuff);
+
+     memset((void*)tbuff, 0, OPVP_BUFF_SIZE);
+     strcpy(tbuff, "lib");
+-    strncat(tbuff, vectorDriver, OPVP_BUFF_SIZE - 7);
++    strncat(tbuff, opdev->globals.vectorDriver, OPVP_BUFF_SIZE - 7);
+     strcat(tbuff, ".so");
+     opvp_alloc_string(&(buff[3]), tbuff);
+
+@@ -1387,7 +1677,7 @@ opvp_to_utf8(char *string)
+ }
+
+ static float
+-opvp_fabsf(float f)
++opvp_fabsf(gx_device* dev, float f)
+ {
+     return (float)fabs((double)f);
+ }
+@@ -1429,7 +1719,7 @@ opvp_get_papertable_index(gx_device *pdev)
+                 paper = i;
+                 match = true;
+                 break;
+-            } else if ((f = opvp_fabsf(height - paper_h)) < TOLERANCE) {
++            } else if ((f = opvp_fabsf(pdev, height - paper_h)) < TOLERANCE) {
+                 if (f < h_delta) {
+                     h_delta = f;
+                     candidate = i;
+@@ -1442,14 +1732,14 @@ opvp_get_papertable_index(gx_device *pdev)
+         } else if (prev != paper_w) {
+             prev = paper_w;
+             if (paper_w < width) {
+-                if ((f = opvp_fabsf(width - paper_w)) < TOLERANCE) {
++                if ((f = opvp_fabsf(pdev, width - paper_w)) < TOLERANCE) {
+                     if (f < sw_delta) {
+                         sw_delta = f;
+                         smaller  = i;
+                     }
+                 }
+             } else {
+-                if ((f = opvp_fabsf(width - paper_w)) < TOLERANCE) {
++                if ((f = opvp_fabsf(pdev, width - paper_w)) < TOLERANCE) {
+                     if (f < lw_delta) {
+                         lw_delta = f;
+                         larger   = i;
+@@ -1468,7 +1758,7 @@ opvp_get_papertable_index(gx_device *pdev)
+                     sh_delta = 0;
+                     s_candi  = i;
+                     break;
+-                } else if ((f = opvp_fabsf(height - paper_h)) < TOLERANCE) {
++                } else if ((f = opvp_fabsf(pdev, height - paper_h)) < TOLERANCE) {
+                     if (f < sh_delta) {
+                         sh_delta = f;
+                         s_candi  = i;
+@@ -1484,7 +1774,7 @@ opvp_get_papertable_index(gx_device *pdev)
+                     lh_delta = 0;
+                     l_candi  = i;
+                     break;
+-                } else if ((f = opvp_fabsf(height - paper_h)) < TOLERANCE) {
++                } else if ((f = opvp_fabsf(pdev, height - paper_h)) < TOLERANCE) {
+                     if (f < lh_delta) {
+                         lh_delta = f;
+                         l_candi  = i;
+@@ -1560,8 +1850,8 @@ opvp_get_mediasize(gx_device *pdev)
+            (strcmp(region, "oe"  ) == 0)) {
+             unit    = "in";
+         } else {
+-            width  *= MMPI;
+-            height *= MMPI;
++            width  *= (float) MMPI;
++            height *= (float) MMPI;
+             unit    = "mm";
+         }
+     } else {
+@@ -1591,9 +1881,10 @@ opvp_gen_page_info(gx_device *dev)
+     int num_copies = 1;
+     bool landscape;
+     char tbuff[OPVP_BUFF_SIZE];
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     /* copies */
+-    if (!inkjet) {
++    if (!(opdev->globals.inkjet)) {
+         if (dev->IgnoreNumCopies) {
+             num_copies = 1;
+         } else if (dev->NumCopies_set > 0) {
+@@ -1642,14 +1933,13 @@ opvp_set_brush_color(gx_device_opvp *pdev, gx_color_index color,
+         ecode = -1;
+     } else {
+ #if ENABLE_SIMPLE_MODE
+-        brush->colorSpace = colorSpace;
++        brush->colorSpace = pdev->globals.colorSpace;
+ #else
+         opvp_result_t           r = -1;
+         /* call GetColorSpace */
+-        if (apiEntry->opvpGetColorSpace) {
+-            r = apiEntry->opvpGetColorSpace(printerContext,
+-                                   &(brush->colorSpace));
+-        }
++
++        r = gsopvpGetColorSpace((gx_device*)pdev, printerContext,
++                                &(brush->colorSpace));
+         if (r != OPVP_OK) {
+             brush->colorSpace = OPVP_CSPACE_DEVICEKRGB;
+         }
+@@ -1667,7 +1957,7 @@ opvp_set_brush_color(gx_device_opvp *pdev, gx_color_index color,
+
+ static  int
+ opvp_draw_image(
+-    gx_device_opvp *pdev,
++    gx_device_opvp *opdev,
+     int depth,
+     int sw,
+     int sh,
+@@ -1682,35 +1972,36 @@ opvp_draw_image(
+     int                 count;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* image size */
+     count = raster * sh;
+
+     /* call DrawImage */
+-    if (apiEntry->opvpDrawImage) {
+-        r = apiEntry->opvpDrawImage(printerContext,
+-               sw,sh,
+-               raster,
+-               mask ? OPVP_IFORMAT_MASK : OPVP_IFORMAT_RAW,
+-               dw,dh,
+-               /* discard 'const' qualifier */
+-               (void *)data);
+-    }
++    r = gsopvpDrawImage((gx_device*) opdev,
++            opdev->globals.printerContext,
++            sw,sh,
++            raster,
++            mask ? OPVP_IFORMAT_MASK : OPVP_IFORMAT_RAW,
++            dw,dh,
++            /* discard 'const' qualifier */
++            (void *)data);
++
+     if (r != OPVP_OK) {
+         /* call StartDrawImage */
+-        if (apiEntry->opvpStartDrawImage) {
+-            r = apiEntry->opvpStartDrawImage(printerContext,
+-                    sw,sh,
+-                    raster,
+-                    mask ? OPVP_IFORMAT_MASK : OPVP_IFORMAT_RAW,
+-                    dw,dh);
+-        }
++        r = gsopvpStartDrawImage((gx_device*)opdev,
++                opdev->globals.printerContext,
++                sw,sh,
++                raster,
++                mask ? OPVP_IFORMAT_MASK : OPVP_IFORMAT_RAW,
++                dw,dh);
++
+         if (r == OPVP_OK) {
+             /* call TansferDrawImage */
+-            if (apiEntry->opvpTransferDrawImage) {
+-                r = apiEntry->opvpTransferDrawImage(
+-                       printerContext,
++            if (opdev->globals.apiEntry->opvpTransferDrawImage) {
++                r = opdev->globals.apiEntry->opvpTransferDrawImage(
++                       opdev->globals.printerContext,
+                        count,
+                         /* discard 'const' qualifier */
+                        (void *)data);
+@@ -1718,9 +2009,8 @@ opvp_draw_image(
+             if (r != OPVP_OK) ecode = -1;
+
+             /* call EndDrawImage */
+-            if (apiEntry->opvpEndDrawImage) {
+-                apiEntry->opvpEndDrawImage(printerContext);
+-            }
++            gsopvpEndDrawImage((gx_device*)opdev, opdev->globals.printerContext);
++
+         } else {
+             ecode = 0;  /* continue... */
+         }
+@@ -1735,48 +2025,49 @@ opvp_draw_image(
+  * load vector-driver
+  */
+ static  int
+-opvp_load_vector_driver(void)
++opvp_load_vector_driver(gx_device* dev)
+ {
+     char **list = NULL;
+     int i;
+     void *h;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+-    if (handle) {
+-        opvp_unload_vector_driver();
++    if (opdev->globals.handle) {
++        opvp_unload_vector_driver(dev);
+     }
+
+-    if (vectorDriver) {
+-        list = opvp_gen_dynamic_lib_name();
++    if (opdev->globals.vectorDriver) {
++        list = opvp_gen_dynamic_lib_name(dev);
+     }
+
+     if (list) {
+         i = 0;
+         while (list[i]) {
+             if ((h = dlopen(list[i],RTLD_NOW))) {
+-                OpenPrinter = dlsym(h,"opvpOpenPrinter");
+-                ErrorNo = dlsym(h,"opvpErrorNo");
+-                if (OpenPrinter && ErrorNo) {
+-                    handle = h;
++                opdev->globals.OpenPrinter = dlsym(h,"opvpOpenPrinter");
++                opdev->globals.ErrorNo = dlsym(h,"opvpErrorNo");
++                if (opdev->globals.OpenPrinter && opdev->globals.ErrorNo) {
++                    opdev->globals.handle = h;
+                     break;
+                 }
+-                OpenPrinter = NULL;
+-                ErrorNo = NULL;
++                opdev->globals.OpenPrinter = NULL;
++                opdev->globals.ErrorNo = NULL;
+                 /* try version 0.2 driver */
+-                OpenPrinter_0_2 = dlsym(h,"OpenPrinter");
+-                ErrorNo = dlsym(h,"errorno");
+-                if (OpenPrinter_0_2 && ErrorNo) {
+-                    handle = h;
++                opdev->globals.OpenPrinter_0_2 = dlsym(h,"OpenPrinter");
++                opdev->globals.ErrorNo = dlsym(h,"errorno");
++                if (opdev->globals.OpenPrinter_0_2 && opdev->globals.ErrorNo) {
++                    opdev->globals.handle = h;
+                     break;
+                 }
+-                OpenPrinter_0_2 = NULL;
+-                ErrorNo = NULL;
++                opdev->globals.OpenPrinter_0_2 = NULL;
++                opdev->globals.ErrorNo = NULL;
+                 dlclose(h);
+             }
+             i++;
+         }
+     }
+
+-    if (handle) {
++    if (opdev->globals.handle) {
+         return 0;
+     } else {
+         return -1;
+@@ -1787,13 +2078,15 @@ opvp_load_vector_driver(void)
+  * unload vector-driver
+  */
+ static  int
+-opvp_unload_vector_driver(void)
++opvp_unload_vector_driver(gx_device* dev)
+ {
+-    if (handle) {
+-        dlclose(handle);
+-        handle = NULL;
+-        OpenPrinter = NULL;
+-        ErrorNo = NULL;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
++
++    if (opdev->globals.handle) {
++        dlclose(opdev->globals.handle);
++        opdev->globals.handle = NULL;
++        opdev->globals.OpenPrinter = NULL;
++        opdev->globals.ErrorNo = NULL;
+     }
+     return 0;
+ }
+@@ -1810,6 +2103,7 @@ prepare_open(gx_device *dev)
+     int dumFD = -1;
+     opvp_dc_t dumContext = -1;
+     opvp_cspace_t cspace = OPVP_CSPACE_STANDARDRGB;
++    gx_device_opvp *opdev = (gx_device_opvp*) dev;
+
+     /* open dummy device */
+     code = open("/dev/null", O_RDWR);
+@@ -1818,19 +2112,19 @@ prepare_open(gx_device *dev)
+
+     /* load vector driver */
+     if (!ecode) {
+-        if ((code = opvp_load_vector_driver())) {
++        if ((code = opvp_load_vector_driver(dev))) {
+             ecode = code;
+         }
+     }
+
+     /* prepare array of function pointer for PDAPI */
+     if (!ecode) {
+-        if (!apiEntry) {
+-            if (!(apiEntry = calloc(sizeof(opvp_api_procs_t), 1))) {
++        if (!(opdev->globals.apiEntry)) {
++            if (!(opdev->globals.apiEntry = calloc(sizeof(opvp_api_procs_t), 1))) {
+                 ecode = -1;
+             }
+         } else {
+-            memset(apiEntry, 0, sizeof(opvp_api_procs_t));
++            memset(opdev->globals.apiEntry, 0, sizeof(opvp_api_procs_t));
+         }
+     }
+
+@@ -1842,8 +2136,8 @@ prepare_open(gx_device *dev)
+         /* require version 1.0 */
+         apiVersion[0] = 1;
+         apiVersion[1] = 0;
+-        dc = OpenPrinterWrapper(dumFD, (opvp_char_t *)printerModel,
+-          apiVersion,&api_entry);
++        dc = OpenPrinterWrapper(dev, dumFD, (opvp_char_t *)(opdev->globals.printerModel),
++          apiVersion, &api_entry);
+         if (dc == -1) {
+             ecode = -1;
+         } else {
+@@ -1853,33 +2147,33 @@ prepare_open(gx_device *dev)
+
+     /* set apiEntry */
+     if (!ecode) {
+-        nApiEntry = sizeof(opvp_api_procs_t)/sizeof(void *);
+-        memcpy(apiEntry, api_entry, nApiEntry*sizeof(void *));
++        opdev->globals.nApiEntry = sizeof(opvp_api_procs_t)/sizeof(void *);
++        memcpy(opdev->globals.apiEntry, api_entry, opdev->globals.nApiEntry*sizeof(void *));
+     } else {
+-        if (apiEntry) free(apiEntry);
+-        apiEntry = NULL;
++        if (opdev->globals.apiEntry) free(opdev->globals.apiEntry);
++        opdev->globals.apiEntry = NULL;
+     }
+
+     /* check vector fucntion */
+-    if (apiEntry) {
+-        if (!inkjet) {
+-            if (!(apiEntry->opvpNewPath) ||
+-                !(apiEntry->opvpEndPath) ||
+-                !(apiEntry->opvpStrokePath) ||
+-                !(apiEntry->opvpSetCurrentPoint) ||
+-                !(apiEntry->opvpLinePath) ||
+-                !(apiEntry->opvpBezierPath)) {
++    if (opdev->globals.apiEntry) {
++        if (!(opdev->globals.inkjet)) {
++            if (!(opdev->globals.apiEntry->opvpNewPath) ||
++                !(opdev->globals.apiEntry->opvpEndPath) ||
++                !(opdev->globals.apiEntry->opvpStrokePath) ||
++                !(opdev->globals.apiEntry->opvpSetCurrentPoint) ||
++                !(opdev->globals.apiEntry->opvpLinePath) ||
++                !(opdev->globals.apiEntry->opvpBezierPath)) {
+                 /* NOT avail vector drawing mode */
+-                vector = false;
++                opdev->globals.vector = false;
+             }
+         }
+         /* call GetColorSpace */
+-        if (apiEntry->opvpGetColorSpace) {
+-            (void)apiEntry->opvpGetColorSpace(dumContext, &cspace);
++        if (opdev->globals.apiEntry->opvpGetColorSpace) {
++            (void)(opdev->globals.apiEntry->opvpGetColorSpace)(dumContext, &cspace);
+         }
+         if (cspace == OPVP_CSPACE_BW) {
+             /* mono-color */
+-            colorSpace = cspace;
++            opdev->globals.colorSpace = cspace;
+             dev->color_info.num_components = 1;
+             dev->color_info.depth = 1;
+             dev->color_info.max_gray = 0;
+@@ -1888,7 +2182,7 @@ prepare_open(gx_device *dev)
+             dev->color_info.dither_colors = 1;
+         } else if (cspace == OPVP_CSPACE_DEVICEGRAY) {
+             /* gray-scale */
+-            colorSpace = cspace;
++            opdev->globals.colorSpace = cspace;
+             dev->color_info.num_components = 1;
+             dev->color_info.depth = 8;
+             dev->color_info.max_gray = 255;
+@@ -1897,7 +2191,7 @@ prepare_open(gx_device *dev)
+             dev->color_info.dither_colors = 256;
+         } else {
+             /* rgb color */
+-            colorSpace = OPVP_CSPACE_STANDARDRGB;
++            opdev->globals.colorSpace = OPVP_CSPACE_STANDARDRGB;
+             dev->color_info.num_components = 3;
+             dev->color_info.depth = 24;
+             dev->color_info.max_gray = 255;
+@@ -1913,8 +2207,8 @@ prepare_open(gx_device *dev)
+     /* call Closerinter as dummy */
+     if (dumContext != -1) {
+         /* call ClosePrinter */
+-        if (apiEntry->opvpClosePrinter) {
+-            apiEntry->opvpClosePrinter(dumContext);
++        if (opdev->globals.apiEntry->opvpClosePrinter) {
++            opdev->globals.apiEntry->opvpClosePrinter(dumContext);
+         }
+         dumContext = -1;
+     }
+@@ -1926,7 +2220,7 @@ prepare_open(gx_device *dev)
+     }
+
+     /* un-load vector driver */
+-    opvp_unload_vector_driver();
++    opvp_unload_vector_driver(dev);
+
+     return ecode;
+ }
+@@ -1961,51 +2255,52 @@ opvp_open(gx_device *dev)
+     }
+
+     /* set margins */
+-    if (zoomAuto) {
+-        margin_width = (margins[0] + margins[2])
++    if (pdev->globals.zoomAuto) {
++        margin_width = (pdev->globals.margins[0] + pdev->globals.margins[2])
+                      * dev->HWResolution[0];
+-        margin_height = (margins[1] + margins[3])
++        margin_height = (pdev->globals.margins[1] + pdev->globals.margins[3])
+                       * dev->HWResolution[1];
+-        zoom[0] = (dev->width - margin_width) / dev->width;
+-        zoom[1] = (dev->height - margin_height) / dev->height;
+-        if (zoom[0] < zoom[1]) {
+-            zoom[1] = zoom[0];
++        pdev->globals.zoom[0] = (dev->width - margin_width) / dev->width;
++        pdev->globals.zoom[1] = (dev->height - margin_height) / dev->height;
++        if (pdev->globals.zoom[0] < pdev->globals.zoom[1]) {
++            pdev->globals.zoom[1] = pdev->globals.zoom[0];
+         } else {
+-            zoom[0] = zoom[1];
++            pdev->globals.zoom[0] = pdev->globals.zoom[1];
+         }
+     }
+-    if (inkjet) {
+-        if ((margins[0] != 0) ||
+-            (margins[1] != 0) || (margins[3] != 0)) {
+-            shift[0] = margins[0] * dev->HWResolution[0];
+-            shift[1] = (margins[1] + margins[3])
++    if (pdev->globals.inkjet) {
++        if ((pdev->globals.margins[0] != 0) ||
++            (pdev->globals.margins[1] != 0) || (pdev->globals.margins[3] != 0)) {
++            pdev->globals.shift[0] = pdev->globals.margins[0] * dev->HWResolution[0];
++            pdev->globals.shift[1] = (pdev->globals.margins[1] + pdev->globals.margins[3])
+                      * dev->HWResolution[1];
+-            zooming = true;
++            pdev->globals.zooming = true;
+         }
+-        dev->width -= margins[2] * dev->HWResolution[0];
+-        dev->height -= margins[1] * dev->HWResolution[1];
++        dev->width -= (int) (pdev->globals.margins[2] * dev->HWResolution[0]);
++        dev->height -= (int) (pdev->globals.margins[1] * dev->HWResolution[1]);
+     } else {
+-            if ((margins[0] != 0) || (margins[1] != 0)) {
+-                shift[0] = margins[0] * dev->HWResolution[0];
+-                shift[1] = margins[3] * dev->HWResolution[1];
+-                zooming = true;
++            if ((pdev->globals.margins[0] != 0) || (pdev->globals.margins[1] != 0)) {
++                pdev->globals.shift[0] = pdev->globals.margins[0] * dev->HWResolution[0];
++                pdev->globals.shift[1] = pdev->globals.margins[3] * dev->HWResolution[1];
++                pdev->globals.zooming = true;
+             }
+             adj_margins[0] = 0;
+             adj_margins[3] = 0;
+-            adj_margins[1] = dev->height * zoom[1] / dev->HWResolution[1]
++            adj_margins[1] = dev->height * pdev->globals.zoom[1] / dev->HWResolution[1]
+                             - (dev->MediaSize[1] / PS_DPI
+-                             - (margins[1] + margins[3]));
++                             - (pdev->globals.margins[1] + pdev->globals.margins[3]));
+             if (adj_margins[1] < 0) adj_margins[0] = 0;
+-            adj_margins[2] = dev->width * zoom[0] / dev->HWResolution[0]
++            adj_margins[2] = dev->width * pdev->globals.zoom[0] / dev->HWResolution[0]
+                             - (dev->MediaSize[0] / PS_DPI
+-                             - (margins[0] + margins[2]));
++                             - (pdev->globals.margins[0] + pdev->globals.margins[2]));
+             if (adj_margins[2] < 0) adj_margins[2] = 0;
+             gx_device_set_margins(dev, adj_margins, true);
+     }
+-    if ((zoom[0] != 1) || (zoom[1] != 1)) zooming = true;
++    if ((pdev->globals.zoom[0] != 1) || (pdev->globals.zoom[1] != 1))
++        pdev->globals.zooming = true;
+
+     /* open file for output device */
+-    if (!inkjet) {
++    if (!(pdev->globals.inkjet)) {
+         pdev->v_memory = gs_memory_stable(pdev->memory);
+         /* open output stream */
+         code = gdev_vector_open_file_options((gx_device_vector*)dev,
+@@ -2027,7 +2322,7 @@ opvp_open(gx_device *dev)
+                 pdev->bbox_device->memory = gs_memory_stable(dev->memory);
+             }
+         }
+-        outputFD = fileno(gp_get_file(pdev->file));
++        pdev->globals.outputFD = fileno(gp_get_file(pdev->file));
+     } else {
+         /* open printer device */
+         code = gdev_prn_open(dev);
+@@ -2044,13 +2339,13 @@ opvp_open(gx_device *dev)
+         if (code < 0) {
+             return code;
+         }
+-        outputFD = fileno(gp_get_file(rdev->file));
++        pdev->globals.outputFD = fileno(gp_get_file(rdev->file));
+     }
+-    if (outputFD < 0)
+-        return outputFD;
++    if (pdev->globals.outputFD < 0)
++        return pdev->globals.outputFD;
+
+     /* RE-load vector driver */
+-    if ((code = opvp_load_vector_driver())) {
++    if ((code = opvp_load_vector_driver(dev))) {
+         return code;
+     }
+
+@@ -2058,44 +2353,48 @@ opvp_open(gx_device *dev)
+     /* require version 1.0 */
+     apiVersion[0] = 1;
+     apiVersion[1] = 0;
+-    dc = OpenPrinterWrapper(outputFD,(opvp_char_t *)printerModel,
++    dc = OpenPrinterWrapper(dev, pdev->globals.outputFD, (opvp_char_t *)pdev->globals.printerModel,
+       apiVersion,&api_entry);
+-    if (!apiEntry) {
+-        if (!(apiEntry = calloc(sizeof(opvp_api_procs_t), 1))) {
++    if (!(pdev->globals.apiEntry)) {
++        if (!(pdev->globals.apiEntry = calloc(sizeof(opvp_api_procs_t), 1))) {
+             ecode = -1;
+         }
+     } else {
+-        memset(apiEntry, 0, sizeof(opvp_api_procs_t));
++        memset(pdev->globals.apiEntry, 0, sizeof(opvp_api_procs_t));
+     }
+     if (dc == -1) {
+         ecode =  -1;
+-        if (apiEntry) free(apiEntry);
+-        apiEntry = NULL;
+-        opvp_unload_vector_driver();
+-        if (inkjet) gdev_prn_close(dev);
++        if (pdev->globals.apiEntry)
++            free(pdev->globals.apiEntry);
++        pdev->globals.apiEntry = NULL;
++        opvp_unload_vector_driver(dev);
++        if (pdev->globals.inkjet)
++            gdev_prn_close(dev);
+         else gdev_vector_close_file((gx_device_vector *)pdev);
+         return ecode;
+     }
+-    printerContext = dc;
+-    nApiEntry = sizeof(opvp_api_procs_t)/sizeof(void *);
+-    memcpy(apiEntry, api_entry, nApiEntry*sizeof(void *));
++    pdev->globals.printerContext = dc;
++    pdev->globals.nApiEntry = sizeof(opvp_api_procs_t)/sizeof(void *);
++    memcpy(pdev->globals.apiEntry, api_entry, pdev->globals.nApiEntry*sizeof(void *));
+
+     /* initialize */
+-    if ((!ecode) && (!inkjet)) {
++    if ((!ecode) && (!(pdev->globals.inkjet))) {
+         pdev->vec_procs = &opvp_vector_procs;
+-        if (vector) gdev_vector_init((gx_device_vector *)pdev);
++        if (pdev->globals.vector)
++            gdev_vector_init((gx_device_vector *)pdev);
+     }
+
+-    if (apiEntry->opvpQueryColorSpace) {
++    if (pdev->globals.apiEntry->opvpQueryColorSpace ||
++        pdev->globals.apiEntry_0_2->QueryColorSpace) {
+         int n = sizeof(cspace_available);
+         int nn = n;
+         opvp_cspace_t *p = malloc(n*sizeof(opvp_cspace_t));
+
+-        if ((r = apiEntry->opvpQueryColorSpace(printerContext,&nn,p))
++        if ((r = gsopvpQueryColorSpace(dev, pdev->globals.printerContext,&nn,p))
+              == OPVP_PARAMERROR && nn > n) {
+             /* realloc buffer and retry */
+             p = realloc(p,nn*sizeof(opvp_cspace_t));
+-            r = apiEntry->opvpQueryColorSpace(printerContext,&nn,p);
++            r = gsopvpQueryColorSpace(dev, pdev->globals.printerContext,&nn,p);
+         }
+         if (r == OPVP_OK) {
+             int i;
+@@ -2111,12 +2410,12 @@ opvp_open(gx_device *dev)
+     /* start job */
+     if (!ecode) {
+         /* job info */
+-        if (jobInfo) {
+-            if (strlen(jobInfo) > 0) {
+-                job_info = opvp_alloc_string(&job_info,jobInfo);
++        if (pdev->globals.jobInfo) {
++            if (strlen(pdev->globals.jobInfo) > 0) {
++                job_info = opvp_alloc_string(&job_info, pdev->globals.jobInfo);
+             }
+         }
+-        tmp_info = opvp_alloc_string(&tmp_info,opvp_gen_job_info(dev));
++        tmp_info = opvp_alloc_string(&tmp_info, opvp_gen_job_info(dev));
+         if (tmp_info) {
+             if (strlen(tmp_info) > 0) {
+                 if (job_info) {
+@@ -2130,8 +2429,8 @@ opvp_open(gx_device *dev)
+         }
+
+         /* call StartJob */
+-        if (apiEntry->opvpStartJob) {
+-            r = apiEntry->opvpStartJob(printerContext,
++        if (pdev->globals.apiEntry->opvpStartJob) {
++            r = pdev->globals.apiEntry->opvpStartJob(pdev->globals.printerContext,
+               (opvp_char_t *)opvp_to_utf8(job_info));
+         }
+         if (r != OPVP_OK) {
+@@ -2142,9 +2441,9 @@ opvp_open(gx_device *dev)
+     /* start doc */
+     if (!ecode) {
+         /* doc info */
+-        if (docInfo) {
+-            if (strlen(docInfo) > 0) {
+-                doc_info = opvp_alloc_string(&doc_info,docInfo);
++        if (pdev->globals.docInfo) {
++            if (strlen(pdev->globals.docInfo) > 0) {
++                doc_info = opvp_alloc_string(&doc_info, pdev->globals.docInfo);
+             }
+         }
+         tmp_info = opvp_alloc_string(&tmp_info, opvp_gen_doc_info(dev));
+@@ -2161,8 +2460,8 @@ opvp_open(gx_device *dev)
+         }
+
+         /* call StartDoc */
+-        if (apiEntry->opvpStartDoc) {
+-            r = apiEntry->opvpStartDoc(printerContext,
++        if (pdev->globals.apiEntry->opvpStartDoc) {
++            r = pdev->globals.apiEntry->opvpStartDoc(pdev->globals.printerContext,
+               (opvp_char_t *)opvp_to_utf8(doc_info));
+         }
+         if (r != OPVP_OK) {
+@@ -2183,9 +2482,11 @@ opvp_open(gx_device *dev)
+ static  int
+ oprp_open(gx_device *dev)
+ {
++    gx_device_opvp *opdev = (gx_device_opvp*) dev;
++
+     /* set inkjet mode */
+-    vector = false;
+-    inkjet = true;
++    opdev->globals.vector = false;
++    opdev->globals.inkjet = true;
+
+     /* matrix */
+     dev->procs.get_initial_matrix = opvp_get_initial_matrix;
+@@ -2198,24 +2499,24 @@ oprp_open(gx_device *dev)
+ static  void
+ opvp_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)dev;
++    gx_device_opvp * opdev = (gx_device_opvp *)dev;
+     opvp_ctm_t omat;
+
+     gx_default_get_initial_matrix(dev,pmat);
+-    if (zooming) {
++    if (opdev->globals.zooming) {
+         /* gs matrix */
+-        pmat->xx *= zoom[0];
+-        pmat->xy *= zoom[1];
+-        pmat->yx *= zoom[0];
+-        pmat->yy *= zoom[1];
+-        pmat->tx = pmat->tx * zoom[0] + shift[0];
+-        pmat->ty = pmat->ty * zoom[1] + shift[1];
++        pmat->xx *= opdev->globals.zoom[0];
++        pmat->xy *= opdev->globals.zoom[1];
++        pmat->yx *= opdev->globals.zoom[0];
++        pmat->yy *= opdev->globals.zoom[1];
++        pmat->tx = pmat->tx * opdev->globals.zoom[0] + opdev->globals.shift[0];
++        pmat->ty = pmat->ty * opdev->globals.zoom[1] + opdev->globals.shift[1];
+     }
+
+-    if (pdev->is_open) {
++    if (opdev->is_open) {
+         /* call ResetCTM */
+-        if (apiEntry->opvpResetCTM) {
+-            apiEntry->opvpResetCTM(printerContext);
++        if (opdev->globals.apiEntry->opvpResetCTM) {
++            opdev->globals.apiEntry->opvpResetCTM(opdev->globals.printerContext);
+         } else {
+             /* call SetCTM */
+             omat.a = 1;
+@@ -2224,8 +2525,8 @@ opvp_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
+             omat.d = 1;
+             omat.e = 0;
+             omat.f = 0;
+-            if (apiEntry->opvpSetCTM) {
+-                apiEntry->opvpSetCTM(printerContext, &omat);
++            if (opdev->globals.apiEntry->opvpSetCTM) {
++                opdev->globals.apiEntry->opvpSetCTM(opdev->globals.printerContext, &omat);
+             }
+         }
+     }
+@@ -2239,30 +2540,32 @@ opvp_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
+ static  int
+ opvp_output_page(gx_device *dev, int num_copies, int flush)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)dev;
++    gx_device_opvp *opdev = (gx_device_opvp *)dev;
+     int ecode = 0;
+     int code = -1;
+
+-    if (inkjet) return gdev_prn_output_page(dev, num_copies, flush);
++    if (opdev->globals.inkjet)
++        return gdev_prn_output_page(dev, num_copies, flush);
+
+ #ifdef OPVP_IGNORE_BLANK_PAGE
+     if (pdev->in_page) {
+ #else
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+ #endif
+         /* end page */
+-        code = opvp_endpage();
++        code = opvp_endpage(dev);
+         if (code) ecode = code;
+
+-        pdev->in_page = false;
+-        beginPage = false;
++        opdev->in_page = false;
++        opdev->globals.beginPage = false;
+ #ifdef OPVP_IGNORE_BLANK_PAGE
+     }
+ #endif
+
+-    if (vector) {
+-        gdev_vector_reset((gx_device_vector *)pdev);
++    if (opdev->globals.vector) {
++        gdev_vector_reset((gx_device_vector *)dev);
+     }
+
+     code = gx_finish_output_page(dev, num_copies, flush);
+@@ -2289,6 +2592,7 @@ oprp_print_page(gx_device_printer *pdev, gp_file *prn_stream)
+     int rasterWidth;
+     bool start_page = false;
+     bool start_raster = false;
++    gx_device_opvp *opdev = (gx_device_opvp*)pdev;
+ #if ENABLE_SKIP_RASTER
+     int i;
+     byte check;
+@@ -2317,8 +2621,8 @@ oprp_print_page(gx_device_printer *pdev, gp_file *prn_stream)
+
+     /* call StartRaster */
+     if (!ecode) {
+-        if (apiEntry->opvpStartRaster) {
+-            r = apiEntry->opvpStartRaster(printerContext,rasterWidth);
++        if (opdev->globals.apiEntry->opvpStartRaster) {
++            r = opdev->globals.apiEntry->opvpStartRaster(opdev->globals.printerContext,rasterWidth);
+         }
+         if (r != OPVP_OK) {
+             ecode = r;
+@@ -2339,7 +2643,7 @@ oprp_print_page(gx_device_printer *pdev, gp_file *prn_stream)
+         }
+ #if ENABLE_SKIP_RASTER
+         /* check support SkipRaster */
+-        if (apiEntry->opvpSkipRaster) {
++        if (opdev->globals.apiEntry->opvpSkipRaster) {
+             /* check all white */
+             if (pdev->color_info.depth > 8) {
+                 for (check = 0xff, i = 0; i < raster_size; i++)
+@@ -2349,7 +2653,7 @@ oprp_print_page(gx_device_printer *pdev, gp_file *prn_stream)
+                 }
+                 /* if all white call SkipRaster */
+                 if (check == 0xff) {
+-                    r = apiEntry->opvpSkipRaster(printerContext, 1);
++                    r = opdev->globals.apiEntry->opvpSkipRaster(opdev->globals.printerContext, 1);
+                     if (r == OPVP_OK) continue;
+                 }
+             } else {
+@@ -2359,27 +2663,29 @@ oprp_print_page(gx_device_printer *pdev, gp_file *prn_stream)
+                 }
+                 /* if all zero call SkipRaster */
+                 if (check) {
+-                    r = apiEntry->opvpSkipRaster(printerContext, 1);
+-                    if (r == OPVP_OK) continue;
++                    r = opdev->globals.apiEntry->opvpSkipRaster(opdev->globals.printerContext, 1);
++                    if (r == OPVP_OK)
++                        continue;
+                 }
+             }
+         }
+ #endif
+         /* call TransferRasterData */
+         if (!ecode) {
+-            if (apiEntry->opvpTransferRasterData) {
+-                r = apiEntry->opvpTransferRasterData(printerContext,
++            if (opdev->globals.apiEntry->opvpTransferRasterData) {
++                r = opdev->globals.apiEntry->opvpTransferRasterData(opdev->globals.printerContext,
+                                                 raster_size,
+                                                 data);
+             }
+-            if (r != OPVP_OK) ecode = r;
++            if (r != OPVP_OK)
++                ecode = r;
+         }
+     }
+
+     /* call EndRaster */
+     if (start_raster) {
+-        if (apiEntry->opvpEndRaster) {
+-            r = apiEntry->opvpEndRaster(printerContext);
++        if (opdev->globals.apiEntry->opvpEndRaster) {
++            r = opdev->globals.apiEntry->opvpEndRaster(opdev->globals.printerContext);
+         }
+         if (r != OPVP_OK) ecode = r;
+         start_raster = false;
+@@ -2387,7 +2693,7 @@ oprp_print_page(gx_device_printer *pdev, gp_file *prn_stream)
+
+     /* end page */
+     if (start_page) {
+-        code = opvp_endpage();
++        code = opvp_endpage((gx_device*) pdev);
+         if (code) ecode = code;
+         start_page = false;
+     }
+@@ -2411,37 +2717,38 @@ opvp_close(gx_device *dev)
+     int ecode = 0;
+
+     /* finalize */
+-    if (printerContext != -1) {
++    if (pdev->globals.printerContext != -1) {
+         /* call EndDoc */
+-        if (apiEntry->opvpEndDoc) {
+-            apiEntry->opvpEndDoc(printerContext);
++        if (pdev->globals.apiEntry->opvpEndDoc) {
++            pdev->globals.apiEntry->opvpEndDoc(pdev->globals.printerContext);
+         }
+
+         /* call EndJob */
+-        if (apiEntry->opvpEndJob) {
+-            apiEntry->opvpEndJob(printerContext);
++        if (pdev->globals.apiEntry->opvpEndJob) {
++            pdev->globals.apiEntry->opvpEndJob(pdev->globals.printerContext);
+         }
+
+         /* call ClosePrinter */
+-        if (apiEntry->opvpClosePrinter) {
+-            apiEntry->opvpClosePrinter(printerContext);
++        if (pdev->globals.apiEntry->opvpClosePrinter) {
++            pdev->globals.apiEntry->opvpClosePrinter(pdev->globals.printerContext);
+         }
+-        printerContext = -1;
++        pdev->globals.printerContext = -1;
+     }
+
+     /* unload vector driver */
+-    if (apiEntry) free(apiEntry);
+-    apiEntry = NULL;
+-    opvp_unload_vector_driver();
++    if (pdev->globals.apiEntry)
++        free(pdev->globals.apiEntry);
++    pdev->globals.apiEntry = NULL;
++    opvp_unload_vector_driver(dev);
+
+-    if (inkjet) {
++    if (pdev->globals.inkjet) {
+         /* close printer */
+         gdev_prn_close(dev);
+     } else {
+         /* close output stream */
+         gdev_vector_close_file((gx_device_vector *)pdev);
+     }
+-    outputFD = -1;
++    pdev->globals.outputFD = -1;
+
+     return ecode;
+ }
+@@ -2455,6 +2762,7 @@ opvp_map_rgb_color(gx_device *dev,
+ {
+     opvp_cspace_t cs;
+     uint c, m, y, k;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+ #if !(ENABLE_SIMPLE_MODE)
+     gx_device_opvp *pdev;
+@@ -2467,16 +2775,15 @@ opvp_map_rgb_color(gx_device *dev,
+     b = prgb[2];
+
+ #if ENABLE_SIMPLE_MODE
+-    cs = colorSpace;
++    cs = opdev->globals.colorSpace;
+ #else
+     pdev = (gx_device_opvp *)dev;
+     r = -1;
+     cs = OPVP_CSPACE_STANDARDRGB;
+     if (pdev->is_open) {
+         /* call GetColorSpace */
+-        if (apiEntry->opvpGetColorSpace) {
+-            r = apiEntry->opvpGetColorSpace(printerContext, &cs);
+-        }
++
++        r = gsopvpGetColorSpace(dev, opdev->globals.printerContext, &cs);
+         if (r != OPVP_OK) {
+             if (pdev->color_info.depth > 32) {
+                     cs = OPVP_CSPACE_STANDARDRGB64;
+@@ -2555,15 +2862,14 @@ opvp_map_color_rgb(gx_device *dev, gx_color_index color,
+ #endif
+     opvp_cspace_t cs = OPVP_CSPACE_STANDARDRGB;
+     uint c, m, y, k;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+ #if ENABLE_SIMPLE_MODE
+-    cs = colorSpace;
++    cs = opdev->globals.colorSpace;
+ #else
+     /* call GetColorSpace */
+     if (pdev->is_open) {
+-        if (apiEntry->opvpGetColorSpace) {
+-            r = apiEntry->opvpGetColorSpace(printerContext, &cs);
+-        }
++        r = gsopvpGetColorSpace(dev, opdev->globals.printerContext, &cs);
+         if (r != OPVP_OK) {
+             if (pdev->color_info.depth > 32) {
+                 cs = OPVP_CSPACE_STANDARDRGB64;
+@@ -2635,44 +2941,44 @@ opvp_fill_rectangle(
+     int h,
+     gx_color_index color)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)dev;
++    gx_device_opvp *opdev = (gx_device_opvp *)dev;
+     byte data[8] = {0xC0, 0, 0, 0, 0xC0, 0, 0, 0};
+     int code = -1;
+     int ecode = 0;
+     opvp_brush_t brush;
+     opvp_point_t point;
+
+-    if (vector) {
+-        return gdev_vector_fill_rectangle( dev, x, y, w, h, color);
++    if (opdev->globals.vector) {
++        return gdev_vector_fill_rectangle(dev, x, y, w, h, color);
+     }
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+ #if !(ENABLE_SIMPLE_MODE)
+     /* call SaveGS */
+-    if (apiEntry->opvpSaveGS) {
+-        apiEntry->opvpSaveGS(printerContext);
++    if (pdev->globals.apiEntry->opvpSaveGS) {
++        pdev->globals.apiEntry->opvpSaveGS(printerContext);
+     }
+ #endif
+
+     /* one-color */
+-    opvp_set_brush_color(pdev, color, &brush);
++    opvp_set_brush_color(opdev, color, &brush);
+
+     /* call SetFillColor */
+-    if (apiEntry->opvpSetFillColor) {
+-        apiEntry->opvpSetFillColor(printerContext, &brush);
+-    }
++    gsopvpSetFillColor(dev, opdev->globals.printerContext, &brush);
++
+
+     /* call SetCurrentPoint */
+     OPVP_I2FIX(x, point.x);
+     OPVP_I2FIX(y, point.y);
+-    if (apiEntry->opvpSetCurrentPoint) {
+-        apiEntry->opvpSetCurrentPoint(printerContext,point.x, point.y);
++    if (opdev->globals.apiEntry->opvpSetCurrentPoint) {
++        opdev->globals.apiEntry->opvpSetCurrentPoint(opdev->globals.printerContext,point.x, point.y);
+     }
+
+     /* draw image */
+-    code = opvp_draw_image(pdev,
++    code = opvp_draw_image(opdev,
+                            1,
+                            2, 2,
+                            w, h,
+@@ -2684,17 +2990,15 @@ opvp_fill_rectangle(
+     }
+
+     /* restore fill color */
+-    if (vectorFillColor) {
++    if (opdev->globals.vectorFillColor) {
+         /* call SetFillColor */
+-        if (apiEntry->opvpSetFillColor) {
+-            apiEntry->opvpSetFillColor(printerContext,vectorFillColor);
+-        }
++        gsopvpSetFillColor(dev, opdev->globals.printerContext,opdev->globals.vectorFillColor);
+     }
+
+ #if !(ENABLE_SIMPLE_MODE)
+     /* call RestoreGS */
+-    if (apiEntry->opvpRestoreGS) {
+-        apiEntry->opvpRestoreGS(printerContext);
++    if (pdev->globals.apiEntry->opvpRestoreGS) {
++        pdev->globals.opdev->globals.apiEntry->opvpRestoreGS(printerContext);
+     }
+ #endif
+
+@@ -2718,7 +3022,7 @@ opvp_copy_mono(
+     gx_color_index zero,
+     gx_color_index one)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)dev;
++    gx_device_opvp *opdev = (gx_device_opvp *)dev;
+     int code = -1;
+     int ecode = 0;
+     opvp_brush_t brush;
+@@ -2736,7 +3040,8 @@ opvp_copy_mono(
+     bool reverse = false;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* data offset */
+     if (data_x) {
+@@ -2773,8 +3078,8 @@ opvp_copy_mono(
+
+ #if !(ENABLE_SIMPLE_MODE)
+     /* call SaveGS */
+-    if (apiEntry->opvpSaveGS) {
+-        apiEntry->opvpSaveGS(printerContext);
++    if (opdev->globals.apiEntry->opvpSaveGS) {
++        opdev->globals.apiEntry->opvpSaveGS(printerContext);
+     }
+ #endif
+     if (one == gx_no_color_index) {
+@@ -2789,25 +3094,22 @@ opvp_copy_mono(
+     if (zero != gx_no_color_index) {
+         /* not mask */
+         /* Set PaintMode */
+-        if (apiEntry->opvpSetPaintMode) {
+-            apiEntry->opvpSetPaintMode(printerContext,OPVP_PAINTMODE_OPAQUE);
++        if (opdev->globals.apiEntry->opvpSetPaintMode) {
++            opdev->globals.apiEntry->opvpSetPaintMode(opdev->globals.printerContext, OPVP_PAINTMODE_OPAQUE);
+         }
+         /* zero-color */
+-        opvp_set_brush_color(pdev, zero, &brush);
++        opvp_set_brush_color(opdev, zero, &brush);
+
+         /* call SetBgColor */
+-        if (apiEntry->opvpSetBgColor) {
+-            apiEntry->opvpSetBgColor(printerContext, &brush);
+-        }
++        gsopvpSetBgColor(dev, opdev->globals.printerContext, &brush);
++
+     }
+
+     /* one-color */
+-    opvp_set_brush_color(pdev, one, &brush);
++    opvp_set_brush_color(opdev, one, &brush);
+
+     /* call SetFillColor */
+-    if (apiEntry->opvpSetFillColor) {
+-        apiEntry->opvpSetFillColor(printerContext, &brush);
+-    }
++    gsopvpSetFillColor(dev, opdev->globals.printerContext, &brush);
+
+     if (reverse) {
+         /* 0/1 reverse image */
+@@ -2826,12 +3128,12 @@ opvp_copy_mono(
+     /* call SetCurrentPoint */
+     OPVP_I2FIX(x, point.x);
+     OPVP_I2FIX(y, point.y);
+-    if (apiEntry->opvpSetCurrentPoint) {
+-        apiEntry->opvpSetCurrentPoint(printerContext,point.x, point.y);
++    if (opdev->globals.apiEntry->opvpSetCurrentPoint) {
++        opdev->globals.apiEntry->opvpSetCurrentPoint(opdev->globals.printerContext,point.x, point.y);
+     }
+
+     /* draw image */
+-    code = opvp_draw_image(pdev,
++    code = opvp_draw_image(opdev,
+                            1,
+                            w, h,
+                            w, h,
+@@ -2844,23 +3146,21 @@ opvp_copy_mono(
+
+     if (zero != gx_no_color_index) {
+         /* restore PaintMode */
+-        if (apiEntry->opvpSetPaintMode) {
+-            apiEntry->opvpSetPaintMode(printerContext,
++        if (opdev->globals.apiEntry->opvpSetPaintMode) {
++            opdev->globals.apiEntry->opvpSetPaintMode(opdev->globals.printerContext,
+               OPVP_PAINTMODE_TRANSPARENT);
+         }
+     }
+     /* restore fill color */
+-    if (vectorFillColor) {
++    if (opdev->globals.vectorFillColor) {
+         /* call SetFillColor */
+-        if (apiEntry->opvpSetFillColor) {
+-            apiEntry->opvpSetFillColor(printerContext,vectorFillColor);
+-        }
++        gsopvpSetFillColor(dev, opdev->globals.printerContext,opdev->globals.vectorFillColor);
+     }
+
+ #if !(ENABLE_SIMPLE_MODE)
+     /* call RestoreGS */
+-    if (apiEntry->opvpRestoreGS) {
+-        apiEntry->opvpRestoreGS(printerContext);
++    if (opdev->globals.apiEntry->opvpRestoreGS) {
++        opdev->globals.apiEntry->opvpRestoreGS(opdev->globals.printerContext);
+     }
+ #endif
+
+@@ -2887,7 +3187,7 @@ opvp_copy_color(
+     int w,
+     int h)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)dev;
++    gx_device_opvp *opdev = (gx_device_opvp *)dev;
+     int code = -1;
+     int ecode = 0;
+     opvp_point_t point;
+@@ -2902,11 +3202,12 @@ opvp_copy_color(
+     int adj_raster = raster;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* data offset */
+     if (data_x) {
+-        depth = pdev->color_info.depth;
++        depth = opdev->color_info.depth;
+         pixel = (depth + 7) >> 3;
+         byte_length = pixel * w;
+         adj_raster = ((byte_length + 3) >> 2) << 2;
+@@ -2926,21 +3227,21 @@ opvp_copy_color(
+
+ #if !(ENABLE_SIMPLE_MODE)
+     /* call SaveGS */
+-    if (apiEntry->opvpSaveGS) {
+-        apiEntry->opvpSaveGS(printerContext);
++    if (opdev->globals.apiEntry->opvpSaveGS) {
++        opdev->globals.apiEntry->opvpSaveGS(opdev->globals.printerContext);
+     }
+ #endif
+
+     /* call SetCurrentPoint */
+     OPVP_I2FIX(x, point.x);
+     OPVP_I2FIX(y, point.y);
+-    if (apiEntry->opvpSetCurrentPoint) {
+-        apiEntry->opvpSetCurrentPoint(printerContext, point.x, point.y);
++    if (opdev->globals.apiEntry->opvpSetCurrentPoint) {
++        opdev->globals.apiEntry->opvpSetCurrentPoint(opdev->globals.printerContext, point.x, point.y);
+     }
+
+     /* draw image */
+-    code = opvp_draw_image(pdev,
+-                           pdev->color_info.depth,
++    code = opvp_draw_image(opdev,
++                           opdev->color_info.depth,
+                            w, h,
+                            w, h,
+                            adj_raster,
+@@ -2952,8 +3253,8 @@ opvp_copy_color(
+
+ #if !(ENABLE_SIMPLE_MODE)
+     /* call RestoreGS */
+-    if (apiEntry->opvpRestoreGS) {
+-        apiEntry->opvpRestoreGS(printerContext);
++    if (opdev->globals.apiEntry->opvpRestoreGS) {
++        opdev->globals.apiEntry->opvpRestoreGS(opdev->globals.printerContext);
+     }
+ #endif
+
+@@ -2969,7 +3270,7 @@ opvp_copy_color(
+  * get params
+  */
+ static  int
+-_get_params(gs_param_list *plist)
++_get_params(gx_device* dev, gs_param_list *plist)
+ {
+     int code;
+     int ecode = 0;
+@@ -2985,37 +3286,38 @@ _get_params(gs_param_list *plist)
+     gs_param_string mbps;
+     gs_param_string zmps;
+     char buff[OPVP_BUFF_SIZE];
++    gx_device_opvp* opdev = (gx_device_opvp*)dev;
+
+     /* get params */
+
+     /* vector driver name */
+     pname = "Driver";
+-    vdps.data = (byte *)vectorDriver;
+-    vdps.size = (vectorDriver ? strlen(vectorDriver) + 1 : 0);
++    vdps.data = (byte *)opdev->globals.vectorDriver;
++    vdps.size = (opdev->globals.vectorDriver ? strlen(opdev->globals.vectorDriver) + 1 : 0);
+     vdps.persistent = false;
+     code = param_write_string(plist, pname, &vdps);
+     if (code) ecode = code;
+
+     /* printer model name */
+     pname = "Model";
+-    pmps.data = (byte *)printerModel;
+-    pmps.size = (printerModel ? strlen(printerModel) + 1 : 0);
++    pmps.data = (byte *)opdev->globals.printerModel;
++    pmps.size = (opdev->globals.printerModel ? strlen(opdev->globals.printerModel) + 1 : 0);
+     pmps.persistent = false;
+     code = param_write_string(plist, pname, &pmps);
+     if (code) ecode = code;
+
+     /* job info */
+     pname = "JobInfo";
+-    jips.data = (byte *)jobInfo;
+-    jips.size = (jobInfo ? strlen(jobInfo) + 1 : 0);
++    jips.data = (byte *)opdev->globals.jobInfo;
++    jips.size = (opdev->globals.jobInfo ? strlen(opdev->globals.jobInfo) + 1 : 0);
+     jips.persistent = false;
+     code = param_write_string(plist, pname, &jips);
+     if (code) ecode = code;
+
+     /* doc info */
+     pname = "DocInfo";
+-    dips.data = (byte *)docInfo;
+-    dips.size = (docInfo ? strlen(docInfo) + 1 : 0);
++    dips.data = (byte *)opdev->globals.docInfo;
++    dips.size = (opdev->globals.docInfo ? strlen(opdev->globals.docInfo) + 1 : 0);
+     dips.persistent = false;
+     code = param_write_string(plist, pname, &dips);
+     if (code) ecode = code;
+@@ -3052,28 +3354,28 @@ _get_params(gs_param_list *plist)
+     /* margins */
+     memset((void*)buff, 0, OPVP_BUFF_SIZE);
+     pname = "MarginLeft";
+-    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",margins[0]);
++    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",opdev->globals.margins[0]);
+     mlps.data = (byte *)buff;
+     mlps.size = strlen(buff) + 1;
+     mlps.persistent = false;
+     code = param_write_string(plist, pname, &mlps);
+     if (code) ecode = code;
+     pname = "MarginTop";
+-    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",margins[3]);
++    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",opdev->globals.margins[3]);
+     mtps.data = (byte *)buff;
+     mtps.size = strlen(buff) + 1;
+     mtps.persistent = false;
+     code = param_write_string(plist, pname, &mtps);
+     if (code) ecode = code;
+     pname = "MarginRight";
+-    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",margins[2]);
++    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",opdev->globals.margins[2]);
+     mrps.data = (byte *)buff;
+     mrps.size = strlen(buff) + 1;
+     mrps.persistent = false;
+     code = param_write_string(plist, pname, &mrps);
+     if (code) ecode = code;
+     pname = "MarginBottom";
+-    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",margins[1]);
++    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",opdev->globals.margins[1]);
+     mbps.data = (byte *)buff;
+     mbps.size = strlen(buff) + 1;
+     mbps.persistent = false;
+@@ -3082,7 +3384,7 @@ _get_params(gs_param_list *plist)
+
+     /* zoom */
+     pname = "Zoom";
+-    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",zoom[0]);
++    snprintf(buff, OPVP_BUFF_SIZE - 1, "%f",opdev->globals.zoom[0]);
+     zmps.data = (byte *)buff;
+     zmps.size = strlen(buff) + 1;
+     zmps.persistent = false;
+@@ -3105,7 +3407,7 @@ opvp_get_params(gx_device *dev, gs_param_list *plist)
+     if (code) return code;
+
+     /* get params */
+-    return _get_params(plist);
++    return _get_params(dev, plist);
+ }
+
+ /*
+@@ -3121,14 +3423,14 @@ oprp_get_params(gx_device *dev, gs_param_list *plist)
+     if (code) return code;
+
+     /* get params */
+-    return _get_params(plist);
++    return _get_params(dev, plist);
+ }
+
+ /*
+  * put params
+  */
+ static  int
+-_put_params(gs_param_list *plist)
++_put_params(gx_device *dev, gs_param_list *plist)
+ {
+     int code;
+     int ecode = 0;
+@@ -3144,6 +3446,7 @@ _put_params(gs_param_list *plist)
+     gs_param_string mrps;
+     gs_param_string mbps;
+     gs_param_string zmps;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     /* vector driver name */
+     pname = "Driver";
+@@ -3153,10 +3456,10 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, vdps.size + 1);
+         memcpy(buff, vdps.data, vdps.size);
+         buff[vdps.size] = 0;
+-        opvp_alloc_string(&vectorDriver, buff);
++        opvp_alloc_string(&(opdev->globals.vectorDriver), buff);
+         break;
+     case 1:
+-        /* opvp_alloc_string(&vectorDriver, NULL);*/
++        /* opvp_alloc_string(&(opdev->globals.vectorDriver), NULL);*/
+         break;
+     default:
+         ecode = code;
+@@ -3171,10 +3474,10 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, pmps.size + 1);
+         memcpy(buff, pmps.data, pmps.size);
+         buff[pmps.size] = 0;
+-        opvp_alloc_string(&printerModel, buff);
++        opvp_alloc_string(&(opdev->globals.printerModel), buff);
+         break;
+     case 1:
+-        /*opvp_alloc_string(&printerModel, NULL);*/
++        /*opvp_alloc_string(&(opdev->globals.printerModel), NULL);*/
+         break;
+     default:
+         ecode = code;
+@@ -3189,10 +3492,10 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, jips.size + 1);
+         memcpy(buff, jips.data, jips.size);
+         buff[jips.size] = 0;
+-        opvp_alloc_string(&jobInfo, buff);
++        opvp_alloc_string(&(opdev->globals.jobInfo), buff);
+         break;
+     case 1:
+-        /*opvp_alloc_string(&jobInfo, NULL);*/
++        /*opvp_alloc_string(&(opdev->globals.jobInfo), NULL);*/
+         break;
+     default:
+         ecode = code;
+@@ -3207,10 +3510,10 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, dips.size + 1);
+         memcpy(buff, dips.data, dips.size);
+         buff[dips.size] = 0;
+-        opvp_alloc_string(&docInfo, buff);
++        opvp_alloc_string(&(opdev->globals.docInfo), buff);
+         break;
+     case 1:
+-        /*opvp_alloc_string(&docInfo, NULL);*/
++        /*opvp_alloc_string(&(opdev->globals.docInfo), NULL);*/
+         break;
+     default:
+         ecode = code;
+@@ -3256,7 +3559,7 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, mlps.size + 1);
+         memcpy(buff, mlps.data, mlps.size);
+         buff[mlps.size] = 0;
+-        margins[0] = atof(buff);
++        opdev->globals.margins[0] = atof(buff);
+         break;
+     case 1:
+         break;
+@@ -3271,7 +3574,7 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, mtps.size + 1);
+         memcpy(buff, mtps.data, mtps.size);
+         buff[mtps.size] = 0;
+-        margins[3] = atof(buff);
++        opdev->globals.margins[3] = atof(buff);
+         break;
+     case 1:
+         break;
+@@ -3286,7 +3589,7 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, mrps.size + 1);
+         memcpy(buff, mrps.data, mrps.size);
+         buff[mrps.size] = 0;
+-        margins[2] = atof(buff);
++        opdev->globals.margins[2] = atof(buff);
+         break;
+     case 1:
+         break;
+@@ -3301,7 +3604,7 @@ _put_params(gs_param_list *plist)
+         buff = realloc(buff, mbps.size + 1);
+         memcpy(buff, mbps.data, mbps.size);
+         buff[mbps.size] = 0;
+-        margins[1] = atof(buff);
++        opdev->globals.margins[1] = atof(buff);
+         break;
+     case 1:
+         break;
+@@ -3319,15 +3622,15 @@ _put_params(gs_param_list *plist)
+         memcpy(buff, zmps.data, zmps.size);
+         buff[zmps.size] = 0;
+         if (strncasecmp(buff, "Auto", 4)) {
+-            zoom[0] = atof(buff);
+-            if (zoom[0] > 0) {
+-                zoom[1] = zoom[0];
++            opdev->globals.zoom[0] = atof(buff);
++            if (opdev->globals.zoom[0] > 0) {
++                opdev->globals.zoom[1] = opdev->globals.zoom[0];
+             } else {
+-                zoom[0] = zoom[1] = 1;
++                opdev->globals.zoom[0] = opdev->globals.zoom[1] = 1;
+             }
+         } else {
+-            zoom[0] = zoom[1] = 1;
+-            zoomAuto = true;
++            opdev->globals.zoom[0] = opdev->globals.zoom[1] = 1;
++            opdev->globals.zoomAuto = true;
+         }
+         break;
+     case 1:
+@@ -3351,7 +3654,7 @@ opvp_put_params(gx_device *dev, gs_param_list *plist)
+     int code;
+
+     /* put params */
+-    code = _put_params(plist);
++    code = _put_params(dev, plist);
+     if (code) return code;
+
+     /* put default params */
+@@ -3367,7 +3670,7 @@ oprp_put_params(gx_device *dev, gs_param_list *plist)
+     int code;
+
+     /* put params */
+-    code = _put_params(plist);
++    code = _put_params(dev, plist);
+     if (code) return code;
+
+     /* put default params */
+@@ -3444,13 +3747,14 @@ opvp_fill_path(
+ {
+     bool draw_image = false;
+     gs_fixed_rect inner, outer;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     /* check if paths are too complex */
+     if (!checkPath(ppath) || !checkCPath(pxpath)) {
+         return gx_default_fill_path(dev, pgs, ppath, params, pdevc, pxpath);
+     }
+     /* check clippath support */
+-    if (!(apiEntry->opvpSetClipPath)) {
++    if (!(opdev->globals.apiEntry->opvpSetClipPath)) {
+         /* get clipping box area */
+         gx_cpath_inner_box(pxpath,&inner);
+         gx_cpath_outer_box(pxpath,&outer);
+@@ -3462,7 +3766,7 @@ opvp_fill_path(
+         }
+     }
+
+-    if (!vector || draw_image) {
++    if (!(opdev->globals.vector) || draw_image) {
+         return gx_default_fill_path(dev, pgs, ppath, params, pdevc, pxpath);
+     }
+
+@@ -3483,6 +3787,7 @@ opvp_stroke_path(
+ {
+     bool draw_image = false;
+     gs_fixed_rect inner, outer;
++    gx_device_opvp *opdev = (gx_device_opvp *) dev;
+
+     /* check if paths are too complex */
+     if (!checkPath(ppath) || !checkCPath(pxpath)) {
+@@ -3490,7 +3795,7 @@ opvp_stroke_path(
+                                       params, pdcolor, pxpath);
+     }
+     /* check clippath support */
+-    if (!(apiEntry->opvpSetClipPath)) {
++    if (!(opdev->globals.apiEntry->opvpSetClipPath)) {
+         /* get clipping box area */
+         gx_cpath_inner_box(pxpath,&inner);
+         gx_cpath_outer_box(pxpath,&outer);
+@@ -3502,7 +3807,7 @@ opvp_stroke_path(
+         }
+     }
+
+-    if (!vector || draw_image) {
++    if (!(opdev->globals.vector) || draw_image) {
+         return gx_default_stroke_path(dev, pgs, ppath,
+                                       params, pdcolor, pxpath);
+     }
+@@ -3530,7 +3835,9 @@ opvp_fill_mask(
+     gs_logical_operation_t lop,
+     const gx_clip_path *pcpath)
+ {
+-    if (vector) {
++    gx_device_opvp *opdev = (gx_device_opvp*) dev;
++
++    if (opdev->globals.vector) {
+         int code;
+         code = gdev_vector_update_fill_color((gx_device_vector *)dev, NULL, pdcolor);
+         if (code < 0)   return code;
+@@ -3574,6 +3881,7 @@ opvp_begin_typed_image(
+     int p;
+     float mag[2] = {1, 1};
+     const gs_color_space *pcs;
++    gx_device_opvp *opdev = (gx_device_opvp *)dev;
+
+     /* check if paths are too complex */
+     if (pic->type->index != 1 || !checkCPath(pcpath))
+@@ -3757,7 +4065,7 @@ opvp_begin_typed_image(
+                  * 3 planes 24 bits color image
+                  * (8 bits per plane)
+                  */
+-                if (apiEntry->opvpStartDrawImage) {
++                if (opdev->globals.apiEntry->opvpStartDrawImage) {
+                     draw_image = true;
+                 }
+             }
+@@ -3768,54 +4076,51 @@ opvp_begin_typed_image(
+         *pinfo = (gx_image_enum_common_t *)vinfo;
+
+         if (!ecode) {
++            opvp_cspace_t ncspace;
++
+             if (!pim->ImageMask) {
+                 /* call SetPaintMode */
+-                if (apiEntry->opvpSetPaintMode) {
+-                    apiEntry->opvpSetPaintMode(printerContext,
++                if (opdev->globals.apiEntry->opvpSetPaintMode) {
++                    opdev->globals.apiEntry->opvpSetPaintMode(opdev->globals.printerContext,
+                        OPVP_PAINTMODE_OPAQUE);
+                     change_paint_mode = true;
+                 }
+                 /* set color space */
+-                if (apiEntry->opvpSetColorSpace != NULL) {
+-                    opvp_cspace_t ncspace;
+-
+-                    savedColorSpace = colorSpace;
+-                    switch (bits_per_pixel) {
+-                    case 1:
+-                        ncspace = OPVP_CSPACE_DEVICEGRAY;
+-                        bits_per_pixel = 8;
+-                        if (!cspace_available[ncspace]) {
+-                            ncspace = OPVP_CSPACE_STANDARDRGB;
+-                            bits_per_pixel = 24;
+-                        }
+-                        break;
+-                    case 8:
+-                        ncspace = OPVP_CSPACE_DEVICEGRAY;
+-                        if (!cspace_available[ncspace]) {
+-                            ncspace = OPVP_CSPACE_STANDARDRGB;
+-                            bits_per_pixel = 24;
+-                        }
+-                        break;
+-                    case 24:
+-                        ncspace = OPVP_CSPACE_DEVICERGB;
+-                        if (!cspace_available[ncspace]) {
+-                            ncspace = OPVP_CSPACE_STANDARDRGB;
+-                        }
+-                        break;
+-                    default:
++                opdev->globals.savedColorSpace = opdev->globals.colorSpace;
++                switch (bits_per_pixel) {
++                case 1:
++                    ncspace = OPVP_CSPACE_DEVICEGRAY;
++                    bits_per_pixel = 8;
++                    if (!cspace_available[ncspace]) {
++                        ncspace = OPVP_CSPACE_STANDARDRGB;
++                        bits_per_pixel = 24;
++                    }
++                    break;
++                case 8:
++                    ncspace = OPVP_CSPACE_DEVICEGRAY;
++                    if (!cspace_available[ncspace]) {
++                        ncspace = OPVP_CSPACE_STANDARDRGB;
++                        bits_per_pixel = 24;
++                    }
++                    break;
++                case 24:
++                    ncspace = OPVP_CSPACE_DEVICERGB;
++                    if (!cspace_available[ncspace]) {
++                        ncspace = OPVP_CSPACE_STANDARDRGB;
++                    }
++                    break;
++                default:
++                    r = -1;
++                    goto fallthrough;
++                    break;
++                }
++                if (ncspace != opdev->globals.colorSpace) {
++                    if (gsopvpSetColorSpace(dev, opdev->globals.printerContext, ncspace) != OPVP_OK) {
+                         r = -1;
+                         goto fallthrough;
+-                        break;
+-                    }
+-                    if (ncspace != colorSpace) {
+-                        if (apiEntry->opvpSetColorSpace(printerContext,ncspace)
+-                             != OPVP_OK) {
+-                            r = -1;
+-                            goto fallthrough;
+-                        }
+-                        colorSpace = ncspace;
+-                        change_cspace = true;
+                     }
++                    opdev->globals.colorSpace = ncspace;
++                    change_cspace = true;
+                 }
+             }
+         }
+@@ -3832,8 +4137,8 @@ opvp_begin_typed_image(
+                 ctm.d = mtx.yy;
+                 ctm.e = mtx.tx;
+                 ctm.f = mtx.ty;
+-                if (apiEntry->opvpSetCTM) {
+-                    r = apiEntry->opvpSetCTM(printerContext, &ctm);
++                if (opdev->globals.apiEntry->opvpSetCTM) {
++                    r = opdev->globals.apiEntry->opvpSetCTM(opdev->globals.printerContext, &ctm);
+                 }
+                 else r = -1;
+                 if (r != OPVP_OK) ecode = r;
+@@ -3841,38 +4146,33 @@ opvp_begin_typed_image(
+         }
+         if (!ecode) {
+             int dw,dh;
++            opvp_int_t adj_raster;
+
+             /* image size */
+             if (mag[0] != 1) {
+-                dw = floor(vinfo->width * mag[0]+0.5);
++                dw = (int) floor(vinfo->width * mag[0]+0.5);
+             } else {
+                 dw = vinfo->width;
+             }
+             if (mag[1] != 1) {
+-                dh = floor(vinfo->height * mag[1]+0.5);
++                dh = (int) floor(vinfo->height * mag[1]+0.5);
+             } else {
+                 dh = vinfo->height;
+             }
+             /* call StartDrawImage */
+-            if (apiEntry->opvpStartDrawImage) {
+-                opvp_int_t adj_raster;
+-
+-                adj_raster = bits_per_pixel*vinfo->width;
+-                adj_raster = ((adj_raster+31) >> 5) << 2;
+-                r = apiEntry->opvpStartDrawImage(
+-                                        printerContext,
+-                                        vinfo->width,
+-                                        vinfo->height,
+-                                        adj_raster,
+-                                        pim->ImageMask ?
+-                                          OPVP_IFORMAT_MASK:
+-                                          OPVP_IFORMAT_RAW,
+-                                        dw,dh);
+-                if(r != OPVP_OK) {
+-                    if (apiEntry->opvpEndDrawImage) {
+-                        apiEntry->opvpEndDrawImage(printerContext);
+-                    }
+-                }
++            adj_raster = bits_per_pixel*vinfo->width;
++            adj_raster = ((adj_raster+31) >> 5) << 2;
++            r = gsopvpStartDrawImage(dev,
++                                    opdev->globals.printerContext,
++                                    vinfo->width,
++                                    vinfo->height,
++                                    adj_raster,
++                                    pim->ImageMask ?
++                                        OPVP_IFORMAT_MASK:
++                                        OPVP_IFORMAT_RAW,
++                                    dw,dh);
++            if(r != OPVP_OK) {
++                gsopvpEndDrawImage(dev, opdev->globals.printerContext);
+             }
+
+             /* bugfix for 32bit CMYK image print error */
+@@ -3880,23 +4180,20 @@ fallthrough:
+             if(r != OPVP_OK) {
+                 if (change_paint_mode) {
+                     /* restore paint mode */
+-                    if (apiEntry->opvpSetPaintMode) {
+-                        apiEntry->opvpSetPaintMode(printerContext,
++                    if (opdev->globals.apiEntry->opvpSetPaintMode) {
++                        opdev->globals.apiEntry->opvpSetPaintMode(opdev->globals.printerContext,
+                            OPVP_PAINTMODE_TRANSPARENT);
+                     }
+                     change_paint_mode = false;
+                 }
+                 if (change_cspace) {
+                     /* restore color space */
+-                    colorSpace = savedColorSpace;
+-                    if (apiEntry->opvpSetColorSpace) {
+-                        apiEntry->opvpSetColorSpace(printerContext,
+-                           colorSpace);
+-                    }
++                    opdev->globals.colorSpace = opdev->globals.savedColorSpace;
++                    gsopvpSetColorSpace(dev, opdev->globals.printerContext, opdev->globals.colorSpace);
+                     change_cspace = false;
+                 }
+-                if(apiEntry->opvpResetCTM) {
+-                    apiEntry->opvpResetCTM(printerContext); /* reset CTM */
++                if(opdev->globals.apiEntry->opvpResetCTM) {
++                    opdev->globals.apiEntry->opvpResetCTM(opdev->globals.printerContext); /* reset CTM */
+                 }
+                 goto fallback;
+             }
+@@ -3942,6 +4239,7 @@ opvp_image_plane_data(
+     bbox_image_enum *pbe;
+     gx_image_enum *tinfo;
+     const gs_gstate *pgs;
++    gx_device_opvp *opdev = (gx_device_opvp*)(info->dev);
+
+     vinfo = (gdev_vector_image_enum_t *)info;
+
+@@ -4037,7 +4335,7 @@ opvp_image_plane_data(
+             if(color_index == gs_color_space_index_Indexed) {
+                 if (base_color_index == gs_color_space_index_DeviceGray ||
+                    base_color_index == gs_color_space_index_CIEA) {
+-                    if (colorSpace == OPVP_CSPACE_DEVICEGRAY) {
++                    if (opdev->globals.colorSpace == OPVP_CSPACE_DEVICEGRAY) {
+                         /* Convert indexed gray color -> Gray */
+                         if (bits_per_pixel == 8) { /* 8bit image */
+                             dst_bytes = data_bytes;
+@@ -4193,8 +4491,8 @@ opvp_image_plane_data(
+             /* Convert Gray */
+             if(color_index == gs_color_space_index_DeviceGray ||
+                color_index == gs_color_space_index_CIEA) {
+-                if (colorSpace == OPVP_CSPACE_STANDARDRGB
+-                  || colorSpace == OPVP_CSPACE_DEVICERGB) {
++                if (opdev->globals.colorSpace == OPVP_CSPACE_STANDARDRGB
++                  || opdev->globals.colorSpace == OPVP_CSPACE_DEVICERGB) {
+                     /* convert to RGB */
+                     if (bits_per_pixel == 8) { /* 8bit image */
+                         dst_bytes = data_bytes * 3;
+@@ -4206,7 +4504,7 @@ opvp_image_plane_data(
+                                 src_ptr = buf + raster_length * i;
+                                 dst_ptr = tmp_buf + dst_length * i;
+                                 for (j = 0; j < data_bytes; j++) {
+-                                    unsigned char d = floor(
++                                    unsigned char d = (unsigned char) floor(
+                                       imageDecode[0]*255 + src_ptr[j]*
+                                       (imageDecode[1]-imageDecode[0])+0.5);
+
+@@ -4234,7 +4532,7 @@ opvp_image_plane_data(
+                                 for (j = 0; j < vinfo->width; j++) {
+                                     int o = ((src_ptr[j/8] & (1 << (7 - (j & 7))))
+                                               != 0);
+-                                    unsigned char d = floor(
++                                    unsigned char d =  (unsigned char) floor(
+                                       imageDecode[0]*255 + o*
+                                       (imageDecode[1]-imageDecode[0])*255+0.5);
+                                     dst_ptr[j*3] = d; /* R */
+@@ -4250,7 +4548,7 @@ opvp_image_plane_data(
+                             vinfo->bits_per_pixel = 24;
+                         }
+                     }
+-                } else if (colorSpace == OPVP_CSPACE_DEVICEGRAY) {
++                } else if (opdev->globals.colorSpace == OPVP_CSPACE_DEVICEGRAY) {
+                     if (bits_per_pixel == 1) { /* 1bit image */
+                         dst_bytes = vinfo->width;
+                         dst_length = ((dst_bytes + 3) >> 2) << 2;
+@@ -4263,7 +4561,7 @@ opvp_image_plane_data(
+                                 for (j = 0; j < vinfo->width; j++) {
+                                     int o = ((src_ptr[j/8] & (1 << (7 - (j & 7))))
+                                               != 0);
+-                                    unsigned char d = floor(
++                                    unsigned char d = (unsigned char) floor(
+                                       imageDecode[0]*255 + o*
+                                       (imageDecode[1]-imageDecode[0])*255+0.5);
+                                     dst_ptr[j] = d; /* R */
+@@ -4299,8 +4597,8 @@ opvp_image_plane_data(
+         }
+
+         /* call TansferDrawImage */
+-        if (apiEntry->opvpTransferDrawImage) {
+-            apiEntry->opvpTransferDrawImage(printerContext,
++        if (opdev->globals.apiEntry->opvpTransferDrawImage) {
++            opdev->globals.apiEntry->opvpTransferDrawImage(opdev->globals.printerContext,
+                         raster_length * height, (void *)buf);
+         }
+     }
+@@ -4325,21 +4623,20 @@ opvp_image_end_image(gx_image_enum_common_t *info, bool draw_last)
+     gx_device_vector *vdev = (gx_device_vector *)dev;
+     gdev_vector_image_enum_t *vinfo;
+     opvp_ctm_t ctm;
++    gx_device_opvp *opdev = (gx_device_opvp*)dev;
+
+     vinfo = (gdev_vector_image_enum_t *)info;
+
+     if (begin_image) {
+         /* call EndDrawImage */
+-        if (apiEntry->opvpEndDrawImage) {
+-            apiEntry->opvpEndDrawImage(printerContext);
+-        }
++        gsopvpEndDrawImage(dev, opdev->globals.printerContext);
+
+         begin_image = false;
+
+         if (FastImageMode != FastImageNoCTM) {
+             /* call ResetCTM */
+-            if (apiEntry->opvpResetCTM) {
+-                apiEntry->opvpResetCTM(printerContext);
++            if (opdev->globals.apiEntry->opvpResetCTM) {
++                opdev->globals.apiEntry->opvpResetCTM(opdev->globals.printerContext);
+             } else {
+                 /* call SetCTM */
+                 ctm.a = 1;
+@@ -4348,25 +4645,24 @@ opvp_image_end_image(gx_image_enum_common_t *info, bool draw_last)
+                 ctm.d = 1;
+                 ctm.e = 0;
+                 ctm.f = 0;
+-                if (apiEntry->opvpSetCTM) {
+-                    apiEntry->opvpSetCTM(printerContext, &ctm);
++                if (opdev->globals.apiEntry->opvpSetCTM) {
++                    opdev->globals.apiEntry->opvpSetCTM(opdev->globals.printerContext, &ctm);
+                 }
+             }
+         }
+         if (change_paint_mode) {
+             /* restore paint mode */
+-            if (apiEntry->opvpSetPaintMode) {
+-                apiEntry->opvpSetPaintMode(printerContext,
++            if (opdev->globals.apiEntry->opvpSetPaintMode) {
++                opdev->globals.apiEntry->opvpSetPaintMode(opdev->globals.printerContext,
+                    OPVP_PAINTMODE_TRANSPARENT);
+             }
+             change_paint_mode = false;
+         }
+         if (change_cspace) {
+             /* restore color space */
+-            colorSpace = savedColorSpace;
+-            if (apiEntry->opvpSetColorSpace) {
+-                apiEntry->opvpSetColorSpace(printerContext,
+-                   colorSpace);
++            opdev->globals.colorSpace = opdev->globals.savedColorSpace;
++            if (gsopvpSetColorSpace(dev, opdev->globals.printerContext, opdev->globals.colorSpace) != OPVP_OK) {
++                return -1;
+             }
+             change_cspace = false;
+         }
+@@ -4382,20 +4678,20 @@ opvp_image_end_image(gx_image_enum_common_t *info, bool draw_last)
+ static  int
+ opvp_beginpage(gx_device_vector *vdev)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     int code = -1;
+     int ecode = 0;
+
+ #ifdef OPVP_IGNORE_BLANK_PAGE
+-    if (pdev->in_page) return 0;
++    if (opdev->in_page) return 0;
+ #endif
+     /* start page */
+-    code = opvp_startpage((gx_device *)pdev);
++    code = opvp_startpage((gx_device *)opdev);
+     if (code) {
+         ecode = code;
+     } else {
+-        pdev->in_page = true;   /* added '05.12.07 */
+-        beginPage = true;
++        opdev->in_page = true;   /* added '05.12.07 */
++        opdev->globals.beginPage = true;
+     }
+
+     return ecode;
+@@ -4407,18 +4703,19 @@ opvp_beginpage(gx_device_vector *vdev)
+ static  int
+ opvp_setlinewidth(gx_device_vector *vdev, double width)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_fix_t w;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* call SetLineWidth */
+     OPVP_F2FIX(width, w);
+-    if (apiEntry->opvpSetLineWidth) {
+-        r = apiEntry->opvpSetLineWidth(printerContext, w);
++    if (opdev->globals.apiEntry->opvpSetLineWidth) {
++        r = opdev->globals.apiEntry->opvpSetLineWidth(opdev->globals.printerContext, w);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -4433,13 +4730,14 @@ opvp_setlinewidth(gx_device_vector *vdev, double width)
+ static  int
+ opvp_setlinecap(gx_device_vector *vdev, gs_line_cap cap)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_linecap_t linecap;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     switch (cap) {
+     case gs_cap_butt:
+@@ -4458,8 +4756,8 @@ opvp_setlinecap(gx_device_vector *vdev, gs_line_cap cap)
+     }
+
+     /* call SetLineCap */
+-    if (apiEntry->opvpSetLineCap) {
+-        r = apiEntry->opvpSetLineCap(printerContext, linecap);
++    if (opdev->globals.apiEntry->opvpSetLineCap) {
++        r = opdev->globals.apiEntry->opvpSetLineCap(opdev->globals.printerContext, linecap);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -4474,13 +4772,14 @@ opvp_setlinecap(gx_device_vector *vdev, gs_line_cap cap)
+ static  int
+ opvp_setlinejoin(gx_device_vector *vdev, gs_line_join join)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_linejoin_t linejoin;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     switch (join) {
+     case gs_join_miter:
+@@ -4500,8 +4799,8 @@ opvp_setlinejoin(gx_device_vector *vdev, gs_line_join join)
+     }
+
+     /* call SetLineJoin */
+-    if (apiEntry->opvpSetLineJoin) {
+-        r = apiEntry->opvpSetLineJoin(printerContext, linejoin);
++    if (opdev->globals.apiEntry->opvpSetLineJoin) {
++        r = opdev->globals.apiEntry->opvpSetLineJoin(opdev->globals.printerContext, linejoin);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -4516,18 +4815,19 @@ opvp_setlinejoin(gx_device_vector *vdev, gs_line_join join)
+ static  int
+ opvp_setmiterlimit(gx_device_vector *vdev, double limit)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_fix_t l;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* call SetMiterLimit */
+     OPVP_F2FIX(limit, l);
+-    if (apiEntry->opvpSetMiterLimit) {
+-        r = apiEntry->opvpSetMiterLimit(printerContext, l);
++    if (opdev->globals.apiEntry->opvpSetMiterLimit) {
++        r = opdev->globals.apiEntry->opvpSetMiterLimit(opdev->globals.printerContext, l);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -4546,7 +4846,7 @@ opvp_setdash(
+     uint count,
+     double offset)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_fix_t *p = NULL;
+@@ -4554,7 +4854,8 @@ opvp_setdash(
+     int i;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* pattern */
+     if (count) {
+@@ -4570,9 +4871,7 @@ opvp_setdash(
+
+     /* call SetLineDash */
+     if (!ecode) {
+-        if (apiEntry->opvpSetLineDash) {
+-            r = apiEntry->opvpSetLineDash(printerContext, count,p);
+-        }
++        r = gsopvpSetLineDash((gx_device*) vdev, opdev->globals.printerContext, count,p);
+         if (r != OPVP_OK) {
+             ecode = -1;
+         }
+@@ -4581,8 +4880,8 @@ opvp_setdash(
+     /* call SetLineDashOffset */
+     if (!ecode) {
+         OPVP_F2FIX(offset, o);
+-        if (apiEntry->opvpSetLineDashOffset) {
+-            r = apiEntry->opvpSetLineDashOffset(printerContext, o);
++        if (opdev->globals.apiEntry->opvpSetLineDashOffset) {
++            r = opdev->globals.apiEntry->opvpSetLineDashOffset(opdev->globals.printerContext, o);
+         }
+         if (r != OPVP_OK) {
+             ecode = -1;
+@@ -4591,8 +4890,8 @@ opvp_setdash(
+
+     /* call SetLineStyle */
+     if (!ecode) {
+-        if (apiEntry->opvpSetLineStyle) {
+-            r = apiEntry->opvpSetLineStyle(printerContext,
++        if (opdev->globals.apiEntry->opvpSetLineStyle) {
++            r = opdev->globals.apiEntry->opvpSetLineStyle(opdev->globals.printerContext,
+                                   (count ?
+                                    OPVP_LINESTYLE_DASH :
+                                    OPVP_LINESTYLE_SOLID));
+@@ -4613,11 +4912,12 @@ opvp_setdash(
+ static  int
+ opvp_setflat(gx_device_vector *vdev, double flatness)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     int ecode = 0;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* what to do ? */
+
+@@ -4654,26 +4954,26 @@ opvp_setfillcolor(
+     const gs_gstate *pgs, /* added for gs 8.15 */
+     const gx_drawing_color *pdc)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     gx_color_index color;
+     static opvp_brush_t brush;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     if (!gx_dc_is_pure(pdc)) return_error(gs_error_rangecheck);
+
+     /* color */
+-    if (!vectorFillColor) vectorFillColor = &brush;
++    if (!opdev->globals.vectorFillColor)
++        opdev->globals.vectorFillColor = &brush;
+     color = gx_dc_pure_color(pdc);
+-    opvp_set_brush_color(pdev, color, vectorFillColor);
++    opvp_set_brush_color(opdev, color, opdev->globals.vectorFillColor);
+
+     /* call SetFillColor */
+-    if (apiEntry->opvpSetFillColor) {
+-        r = apiEntry->opvpSetFillColor(printerContext, vectorFillColor);
+-    }
++    r = gsopvpSetFillColor((gx_device*) vdev, opdev->globals.printerContext, opdev->globals.vectorFillColor);
+     if (r != OPVP_OK) {
+         ecode = -1;
+     }
+@@ -4690,25 +4990,24 @@ opvp_setstrokecolor(
+     const gs_gstate *pgs, /* added for gs 8.15 */
+     const gx_drawing_color *pdc)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     gx_color_index color;
+     opvp_brush_t brush;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     if (!gx_dc_is_pure(pdc)) return_error(gs_error_rangecheck);
+
+     /* color */
+     color = gx_dc_pure_color(pdc);
+-    opvp_set_brush_color(pdev, color, &brush);
++    opvp_set_brush_color(opdev, color, &brush);
+
+     /* call SetStrokeColor */
+-    if (apiEntry->opvpSetStrokeColor) {
+-        r = apiEntry->opvpSetStrokeColor(printerContext, &brush);
+-    }
++    r = gsopvpSetStrokeColor((gx_device*) vdev, opdev->globals.printerContext, &brush);
+     if (r != OPVP_OK) {
+         ecode = -1;
+     }
+@@ -4728,7 +5027,7 @@ opvp_vector_dopath(
+     gx_path_type_t type,
+     const gs_matrix *pmat)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int code = -1;
+     int ecode = 0;
+@@ -4755,7 +5054,8 @@ opvp_vector_dopath(
+     current.x = current.y = 0;
+ #endif
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     if (gx_path_is_rectangle(ppath, &rect))
+     return (*vdev_proc(vdev, dorect))(vdev,
+@@ -4797,9 +5097,9 @@ opvp_vector_dopath(
+             switch (pop) {
+             case gs_pe_moveto:
+                 /* call SetCurrentPoint */
+-                if (apiEntry->opvpSetCurrentPoint) {
+-                    r = apiEntry->opvpSetCurrentPoint(
+-                       printerContext,
++                if (opdev->globals.apiEntry->opvpSetCurrentPoint) {
++                    r = opdev->globals.apiEntry->opvpSetCurrentPoint(
++                        opdev->globals.printerContext,
+                        opvp_p[npoints-1].x,
+                        opvp_p[npoints-1].y);
+                 }
+@@ -4807,9 +5107,9 @@ opvp_vector_dopath(
+                 break;
+             case gs_pe_lineto:
+                 /* call LinePath */
+-                if (apiEntry->opvpLinePath) {
+-                    r = apiEntry->opvpLinePath(
+-                       printerContext,
++                if (opdev->globals.apiEntry->opvpLinePath) {
++                    r = opdev->globals.apiEntry->opvpLinePath(
++                        opdev->globals.printerContext,
+                        OPVP_PATHOPEN,
+                        npoints - 1,
+                        &(opvp_p[1]));
+@@ -4819,9 +5119,9 @@ opvp_vector_dopath(
+             case gs_pe_curveto:
+                 /* npoints */
+                 /* call BezierPath */
+-                if (apiEntry->opvpBezierPath) {
+-                    r = apiEntry->opvpBezierPath(
+-                       printerContext,
++                if (opdev->globals.apiEntry->opvpBezierPath) {
++                    r = opdev->globals.apiEntry->opvpBezierPath(
++                        opdev->globals.printerContext,
+                        npoints - 1,
+                        &(opvp_p[1])
+                        );
+@@ -4982,7 +5282,7 @@ opvp_vector_dorect(
+     fixed y1,
+     gx_path_type_t type)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int code = -1;
+     int ecode = 0;
+@@ -4991,7 +5291,8 @@ opvp_vector_dorect(
+     _fPoint p;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* begin path */
+     code = (*vdev_proc(vdev, beginpath))(vdev, type);
+@@ -5010,8 +5311,9 @@ opvp_vector_dorect(
+         OPVP_F2FIX(p.y, rectangles[0].p1.y);
+
+         /* call RectanglePath */
+-        if (apiEntry->opvpRectanglePath) {
+-            r = apiEntry->opvpRectanglePath(printerContext,
++        if (opdev->globals.apiEntry->opvpRectanglePath) {
++            r = opdev->globals.apiEntry->opvpRectanglePath(
++                                   opdev->globals.printerContext,
+                                    1,
+                                    rectangles);
+         }
+@@ -5038,22 +5340,23 @@ opvp_vector_dorect(
+ static  int
+ opvp_beginpath(gx_device_vector *vdev, gx_path_type_t type)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* check clip-path */
+     if (type & gx_path_type_clip) {
+-        if (apiEntry->opvpResetClipPath)
+-        apiEntry->opvpResetClipPath(printerContext);
++        if (opdev->globals.apiEntry->opvpResetClipPath)
++        opdev->globals.apiEntry->opvpResetClipPath(opdev->globals.printerContext);
+     }
+
+     /* call NewPath */
+-    if (apiEntry->opvpNewPath) {
+-        r = apiEntry->opvpNewPath(printerContext);
++    if (opdev->globals.apiEntry->opvpNewPath) {
++        r = opdev->globals.apiEntry->opvpNewPath(opdev->globals.printerContext);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -5074,19 +5377,20 @@ opvp_moveto(
+     double y1,
+     gx_path_type_t type)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_point_t p;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* call SetCurrentPoint */
+     OPVP_F2FIX(x1, p.x);
+     OPVP_F2FIX(y1, p.y);
+-    if (apiEntry->opvpSetCurrentPoint) {
+-        r = apiEntry->opvpSetCurrentPoint(printerContext, p.x, p.y);
++    if (opdev->globals.apiEntry->opvpSetCurrentPoint) {
++        r = opdev->globals.apiEntry->opvpSetCurrentPoint(opdev->globals.printerContext, p.x, p.y);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -5107,21 +5411,23 @@ opvp_lineto(
+     double y1,
+     gx_path_type_t type)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_point_t points[1];
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* point */
+     OPVP_F2FIX(x1, points[0].x);
+     OPVP_F2FIX(y1, points[0].y);
+
+     /* call LinePath */
+-    if (apiEntry->opvpLinePath) {
+-        r = apiEntry->opvpLinePath(printerContext, OPVP_PATHOPEN, 1, points);
++    if (opdev->globals.apiEntry->opvpLinePath) {
++        r = opdev->globals.apiEntry->opvpLinePath(
++                  opdev->globals.printerContext, OPVP_PATHOPEN, 1, points);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -5146,13 +5452,14 @@ opvp_curveto(
+     double y3,
+     gx_path_type_t type)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_point_t points[4];
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* points */
+     OPVP_F2FIX(x0, points[0].x);
+@@ -5165,8 +5472,9 @@ opvp_curveto(
+     OPVP_F2FIX(y3, points[3].y);
+
+     /* call BezierPath */
+-    if (apiEntry->opvpBezierPath) {
+-        r = apiEntry->opvpBezierPath(printerContext,
++    if (opdev->globals.apiEntry->opvpBezierPath) {
++        r = opdev->globals.apiEntry->opvpBezierPath(
++                            opdev->globals.printerContext,
+                             3,
+                             &(points[1])
+                             );
+@@ -5190,21 +5498,23 @@ opvp_closepath(
+     double y_start,
+     gx_path_type_t type)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+     opvp_point_t points[1];
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* point */
+     OPVP_F2FIX(x_start, points[0].x);
+     OPVP_F2FIX(y_start, points[0].y);
+
+     /* call LinePath */
+-    if (apiEntry->opvpLinePath) {
+-        r = apiEntry->opvpLinePath(printerContext, OPVP_PATHCLOSE, 1, points);
++    if (opdev->globals.apiEntry->opvpLinePath) {
++        r = opdev->globals.apiEntry->opvpLinePath(
++                          opdev->globals.printerContext, OPVP_PATHCLOSE, 1, points);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -5219,16 +5529,17 @@ opvp_closepath(
+ static  int
+ opvp_endpath(gx_device_vector *vdev, gx_path_type_t type)
+ {
+-    gx_device_opvp *pdev = (gx_device_opvp *)vdev;
++    gx_device_opvp *opdev = (gx_device_opvp *)vdev;
+     opvp_result_t r = -1;
+     int ecode = 0;
+
+     /* check page-in */
+-    if (opvp_check_in_page(pdev)) return -1;
++    if (opvp_check_in_page(opdev))
++        return -1;
+
+     /* call EndPath */
+-    if (apiEntry->opvpEndPath) {
+-        r = apiEntry->opvpEndPath(printerContext);
++    if (opdev->globals.apiEntry->opvpEndPath) {
++        r = opdev->globals.apiEntry->opvpEndPath(opdev->globals.printerContext);
+     }
+     if (r != OPVP_OK) {
+         ecode = -1;
+@@ -5238,9 +5549,9 @@ opvp_endpath(gx_device_vector *vdev, gx_path_type_t type)
+         /* fill mode */
+         if (type & gx_path_type_even_odd) {
+             /* call SetFillMode */
+-            if (apiEntry->opvpSetFillMode) {
+-                r = apiEntry->opvpSetFillMode(
+-                   printerContext,
++            if (opdev->globals.apiEntry->opvpSetFillMode) {
++                r = opdev->globals.apiEntry->opvpSetFillMode(
++                   opdev->globals.printerContext,
+                    OPVP_FILLMODE_EVENODD
+                 );
+             }
+@@ -5249,9 +5560,9 @@ opvp_endpath(gx_device_vector *vdev, gx_path_type_t type)
+             }
+         } else {
+             /* call SetFillMode */
+-            if (apiEntry->opvpSetFillMode) {
+-                r = apiEntry->opvpSetFillMode(
+-                   printerContext,
++            if (opdev->globals.apiEntry->opvpSetFillMode) {
++                r = opdev->globals.apiEntry->opvpSetFillMode(
++                   opdev->globals.printerContext,
+                    OPVP_FILLMODE_WINDING
+                 );
+             }
+@@ -5262,16 +5573,16 @@ opvp_endpath(gx_device_vector *vdev, gx_path_type_t type)
+
+         if (type & gx_path_type_stroke) {
+             /* call StrokeFillPath */
+-            if (apiEntry->opvpStrokeFillPath) {
+-                r = apiEntry->opvpStrokeFillPath(printerContext);
++            if (opdev->globals.apiEntry->opvpStrokeFillPath) {
++                r = opdev->globals.apiEntry->opvpStrokeFillPath(opdev->globals.printerContext);
+             }
+             if (r != OPVP_OK) {
+                 ecode = -1;
+             }
+         } else {
+             /* call FillPath */
+-            if (apiEntry->opvpFillPath) {
+-                r = apiEntry->opvpFillPath(printerContext);
++            if (opdev->globals.apiEntry->opvpFillPath) {
++                r = opdev->globals.apiEntry->opvpFillPath(opdev->globals.printerContext);
+             }
+             if (r != OPVP_OK) {
+                 ecode = -1;
+@@ -5279,9 +5590,9 @@ opvp_endpath(gx_device_vector *vdev, gx_path_type_t type)
+         }
+     } else if (type & gx_path_type_clip) {
+         /* call SetClipPath */
+-        if (apiEntry->opvpSetClipPath) {
+-            r = apiEntry->opvpSetClipPath(
+-               printerContext,
++        if (opdev->globals.apiEntry->opvpSetClipPath) {
++            r = opdev->globals.apiEntry->opvpSetClipPath(
++               opdev->globals.printerContext,
+                (type & gx_path_type_even_odd
+                             ? OPVP_CLIPRULE_EVENODD
+                             : OPVP_CLIPRULE_WINDING));
+@@ -5291,8 +5602,8 @@ opvp_endpath(gx_device_vector *vdev, gx_path_type_t type)
+         }
+     } else if (type & gx_path_type_stroke) {
+         /* call StrokePath */
+-        if (apiEntry->opvpStrokePath) {
+-            r = apiEntry->opvpStrokePath(printerContext);
++        if (opdev->globals.apiEntry->opvpStrokePath) {
++            r = opdev->globals.apiEntry->opvpStrokePath(opdev->globals.printerContext);
+         }
+         if (r != OPVP_OK) {
+             ecode = -1;
+diff --git a/contrib/opvp/opvp.h b/contrib/opvp/opvp.h
+index 426e8cf..db09046 100644
+--- a/contrib/opvp/opvp.h
++++ b/contrib/opvp/opvp.h
+@@ -160,7 +160,7 @@ typedef struct _opvp_brushdata {
+ #elif defined(__HP_cc)
+         opvp_byte_t data[1];
+ #else
+-        opvp_byte_t data[];
++        opvp_byte_t data[1];
+ #endif
+
+ } opvp_brushdata_t;
+@@ -222,8 +222,8 @@ typedef	struct _opvp_api_procs {
+         opvp_result_t (*opvpEndDoc)(opvp_dc_t);
+         opvp_result_t (*opvpStartPage)(opvp_dc_t,const opvp_char_t*);
+         opvp_result_t (*opvpEndPage)(opvp_dc_t);
+-        opvp_result_t (*opvpQueryDeviceCapability)(opvp_dc_t,opvp_flag_t,opvp_int_t*,opvp_byte_t*);
+-        opvp_result_t (*opvpQueryDeviceInfo)(opvp_dc_t,opvp_flag_t,opvp_int_t*,opvp_char_t*);
++        opvp_result_t (*opvpQueryDeviceCapability)(opvp_dc_t, opvp_queryinfoflags_t,opvp_int_t*,opvp_byte_t*);
++        opvp_result_t (*opvpQueryDeviceInfo)(opvp_dc_t, opvp_queryinfoflags_t,opvp_int_t*,opvp_char_t*);
+         opvp_result_t (*opvpResetCTM)(opvp_dc_t);
+         opvp_result_t (*opvpSetCTM)(opvp_dc_t,const opvp_ctm_t*);
+         opvp_result_t (*opvpGetCTM)(opvp_dc_t,opvp_ctm_t*);
+@@ -287,8 +287,7 @@ typedef	struct _opvp_api_procs {
+ } opvp_api_procs_t;
+
+ /* Function prototype */
+-opvp_dc_t opvpOpenPrinter(
+-        opvp_int_t outputFD,
++extern opvp_dc_t opvpOpenPrinter(opvp_int_t outputFD,
+         const opvp_char_t *printerModel,
+         const opvp_int_t apiVersion[2],
+         opvp_api_procs_t **apiProcs);
+diff --git a/contrib/opvp/opvp_0_2_0.h b/contrib/opvp/opvp_0_2_0.h
+index 6030971..8518b7e 100644
+--- a/contrib/opvp/opvp_0_2_0.h
++++ b/contrib/opvp/opvp_0_2_0.h
+@@ -210,7 +210,7 @@ typedef	struct	_OPVP_CTM {
+ typedef	struct	_OPVP_api_procs {
+         int	(*OpenPrinter)(int,char *,int *,struct _OPVP_api_procs **);
+         int	(*ClosePrinter)(int);
+-        int	(*StartJob)(int,char *);
++        int	(*StartJob)(int, char *);
+         int	(*EndJob)(int);
+         int	(*StartDoc)(int,char *);
+         int	(*EndDoc)(int);
+@@ -238,7 +238,7 @@ typedef	struct	_OPVP_api_procs {
+         int	(*GetAlphaConstant)(int,float *);
+         int	(*SetLineWidth)(int,OPVP_Fix);
+         int	(*GetLineWidth)(int,OPVP_Fix *);
+-        int	(*SetLineDash)(int,OPVP_Fix *,int);
++        int	(*SetLineDash)(int, int, OPVP_Fix *);
+         int	(*GetLineDash)(int,OPVP_Fix *,int *);
+         int	(*SetLineDashOffset)(int,OPVP_Fix);
+         int	(*GetLineDashOffset)(int,OPVP_Fix *);
+diff --git a/contrib/opvp/opvpharness.c b/contrib/opvp/opvpharness.c
+new file mode 100644
+index 0000000..95919f4
+--- /dev/null
++++ b/contrib/opvp/opvpharness.c
+@@ -0,0 +1,947 @@
++/* Test harness for checking results after
++   removal of globals in opvp device. Note,
++   0.2 API not tested. Assumption is OpenPrinter
++   is the first method called and ClosePrinter
++   will be the final method called. If not,
++   there will be problems. */
++
++#include "opvp.h"
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++
++/* Yes globals, but here we don't care */
++FILE *pFile = NULL;
++
++/* Graphic state members of API that are set and get. */
++typedef struct opvp_gstate_s {
++    opvp_ctm_t ctm;
++    opvp_cspace_t colorspace;
++    opvp_fillmode_t fill_mode;
++    opvp_float_t alpha;
++    opvp_fix_t line_width;
++    opvp_int_t line_dash_n;
++    opvp_fix_t *line_dash_array;
++    opvp_fix_t dash_offset;
++    opvp_linestyle_t line_style;
++    opvp_linecap_t line_cap;
++    opvp_linejoin_t line_join;
++    opvp_fix_t miter_limit;
++    opvp_paintmode_t paintmode;
++} opvp_gstate_t;
++
++opvp_gstate_t opv_gstate;
++
++static opvp_result_t
++opvpClosePrinter(opvp_dc_t printerContext)
++{
++    fputs("opvpClosePrinter\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fclose(pFile);
++
++    if (opv_gstate.line_dash_array != NULL)
++        free(opv_gstate.line_dash_array);
++
++    return 0;
++}
++
++static opvp_result_t
++opvpStartJob(opvp_dc_t printerContext, const opvp_char_t *job_info)
++{
++    fputs("opvpStartJob\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tjob_info = %s\n", job_info);
++    return 0;
++}
++
++static opvp_result_t
++opvpEndJob(opvp_dc_t printerContext)
++{
++    fputs("opvpEndJob\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpAbortJob(opvp_dc_t printerContext)
++{
++    fputs("opvpAbortJob\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpStartDoc(opvp_dc_t printerContext, const opvp_char_t *docinfo)
++{
++    fputs("opvpStartDoc\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tjob_info = %s\n", docinfo);
++    return 0;
++}
++
++static opvp_result_t
++opvpEndDoc(opvp_dc_t printerContext)
++{
++    fputs("opvpEndDoc\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpStartPage(opvp_dc_t printerContext, const opvp_char_t *pageinfo)
++{
++    fputs("opvpStartPage\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tjob_info = %s\n", pageinfo);
++    return 0;
++}
++
++static opvp_result_t
++opvpEndPage(opvp_dc_t printerContext)
++{
++    fputs("opvpEndPage\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++/* Not used */
++static opvp_result_t
++opvpQueryDeviceCapability(opvp_dc_t printerContext, opvp_flag_t flag, opvp_int_t *a, opvp_byte_t *b)
++{
++    fputs("opvpQueryDeviceCapability\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++/* Not used */
++static opvp_result_t
++opvpQueryDeviceInfo(opvp_dc_t printerContext, opvp_flag_t flag, opvp_int_t *a, opvp_char_t *b)
++{
++    fputs("opvpQueryDeviceInfo\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpResetCTM(opvp_dc_t printerContext)
++{
++    fputs("opvpResetCTM\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    opv_gstate.ctm.a = 1.0;
++    opv_gstate.ctm.b = 0.0;
++    opv_gstate.ctm.c = 0.0;
++    opv_gstate.ctm.d = 1.0;
++    opv_gstate.ctm.e = 0.0;
++    opv_gstate.ctm.f = 0.0;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetCTM(opvp_dc_t printerContext, const opvp_ctm_t *pctm)
++{
++    fputs("opvpSetCTM\n", pFile);
++    opv_gstate.ctm = *pctm;
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tctm.a = %f\n", pctm->a);
++    fprintf(pFile, "\tctm.b = %f\n", pctm->b);
++    fprintf(pFile, "\tctm.c = %f\n", pctm->c);
++    fprintf(pFile, "\tctm.d = %f\n", pctm->d);
++    fprintf(pFile, "\tctm.e = %f\n", pctm->e);
++    fprintf(pFile, "\tctm.f = %f\n", pctm->f);
++    return 0;
++}
++
++static opvp_result_t
++opvpGetCTM(opvp_dc_t printerContext, opvp_ctm_t *pctm)
++{
++    fputs("opvpGetCTM\n", pFile);
++    *pctm = opv_gstate.ctm;
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpInitGS(opvp_dc_t printerContext)
++{
++    fputs("opvpInitGS\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpSaveGS(opvp_dc_t printerContext)
++{
++    fputs("opvpSaveGS\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpRestoreGS(opvp_dc_t printerContext)
++{
++    fputs("opvpRestoreGS\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpQueryColorSpace(opvp_dc_t printerContext, opvp_int_t *n, opvp_cspace_t *colorspace)
++{
++    fputs("opvpQueryColorSpace\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *n = 0;
++    *colorspace = opv_gstate.colorspace;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetColorSpace(opvp_dc_t printerContext, opvp_cspace_t colorspace)
++{
++    fputs("opvpSetColorSpace\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tcolorspace = %d\n", colorspace);
++    opv_gstate.colorspace = colorspace;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetColorSpace(opvp_dc_t printerContext, opvp_cspace_t *colorspace)
++{
++    fputs("opvpGetColorSpace\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *colorspace = opv_gstate.colorspace;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetFillMode(opvp_dc_t printerContext, opvp_fillmode_t fillmode)
++{
++    fputs("opvpSetFillMode\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tfillmode = %d\n", fillmode);
++    opv_gstate.fill_mode = fillmode;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetFillMode(opvp_dc_t printerContext, opvp_fillmode_t *fillmode)
++{
++    fputs("opvpGetFillMode\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *fillmode = opv_gstate.fill_mode;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetAlphaConstant(opvp_dc_t printerContext, opvp_float_t alpha)
++{
++    fputs("opvpSetAlphaConstant\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\talpha = %f\n", alpha);
++    opv_gstate.alpha = alpha;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetAlphaConstant(opvp_dc_t printerContext, opvp_float_t *alpha)
++{
++    fputs("opvpGetAlphaConstant\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *alpha = opv_gstate.alpha;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetLineWidth(opvp_dc_t printerContext, opvp_fix_t width)
++{
++    fputs("opvpSetLineWidth\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\twidth = %d\n", width);
++    opv_gstate.line_width = width;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetLineWidth(opvp_dc_t printerContext, opvp_fix_t *width)
++{
++    fputs("opvpGetLineWidth\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *width = opv_gstate.line_width;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetLineDash(opvp_dc_t printerContext, opvp_int_t n, const opvp_fix_t *dash)
++{
++    int k;
++
++    fputs("opvpSetLineDash\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tn = %d\n", n);
++    opv_gstate.line_dash_n = n;
++
++    if (opv_gstate.line_dash_array != NULL)
++        free(opv_gstate.line_dash_array);
++
++    opv_gstate.line_dash_array = (opvp_fix_t*) malloc(n * sizeof(opvp_fix_t));
++    if (opv_gstate.line_dash_array == NULL) {
++        fprintf(pFile,"\t Error in dash array allocation.  Exiting.");
++        fclose(pFile);
++        exit(-1);
++    }
++
++    for (k = 0; k < n; k++) {
++        opv_gstate.line_dash_array[k] =  dash[k];
++        fprintf(pFile, "\tdash[%d] = %d\n", k, dash[k]);
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpGetLineDash(opvp_dc_t printerContext, opvp_int_t *n, opvp_fix_t *dash)
++{
++    fputs("opvpGetLineDash\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++
++    *n = opv_gstate.line_dash_n;
++    dash = opv_gstate.line_dash_array;
++
++    return 0;
++}
++
++static opvp_result_t
++opvpSetLineDashOffset(opvp_dc_t printerContext, opvp_fix_t offset)
++{
++    fputs("opvpSetLineDashOffset\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\toffset = %d\n", offset);
++    opv_gstate.dash_offset = offset;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetLineDashOffset(opvp_dc_t printerContext, opvp_fix_t *offset)
++{
++    fputs("opvpGetLineDashOffset\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *offset = opv_gstate.dash_offset;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetLineStyle(opvp_dc_t printerContext, opvp_linestyle_t style)
++{
++    fputs("opvpSetLineStyle\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tstyle = %d\n", style);
++    opv_gstate.line_style = style;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetLineStyle(opvp_dc_t printerContext, opvp_linestyle_t *style)
++{
++    fputs("opvpGetLineStyle\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *style = opv_gstate.line_style;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetLineCap(opvp_dc_t printerContext, opvp_linecap_t cap)
++{
++    fputs("opvpSetLineCap\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tcap = %d\n", cap);
++    opv_gstate.line_cap = cap;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetLineCap(opvp_dc_t printerContext, opvp_linecap_t *cap)
++{
++    fputs("opvpGetLineCap\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *cap = opv_gstate.line_cap;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetLineJoin(opvp_dc_t printerContext, opvp_linejoin_t join)
++{
++    fputs("opvpSetLineJoin\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tjoin = %d\n", join);
++    opv_gstate.line_join = join;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetLineJoin(opvp_dc_t printerContext, opvp_linejoin_t *join)
++{
++    fputs("opvpGetLineJoin\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *join = opv_gstate.line_join;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetMiterLimit(opvp_dc_t printerContext, opvp_fix_t miter)
++{
++    fputs("opvpSetMiterLimit\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tmiter = %d\n", miter);
++    opv_gstate.miter_limit = miter;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetMiterLimit(opvp_dc_t printerContext, opvp_fix_t *miter)
++{
++    fputs("opvpGetMiterLimit\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *miter = opv_gstate.miter_limit;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetPaintMode(opvp_dc_t printerContext, opvp_paintmode_t paintmode)
++{
++    fputs("opvpSetPaintMode\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tpaintmode = %d\n", paintmode);
++    opv_gstate.paintmode = paintmode;
++    return 0;
++}
++
++static opvp_result_t
++opvpGetPaintMode(opvp_dc_t printerContext, opvp_paintmode_t *paintmode)
++{
++    fputs("opvpGetPaintMode\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    *paintmode = opv_gstate.paintmode;
++    return 0;
++}
++
++static opvp_result_t
++opvpSetStrokeColor(opvp_dc_t printerContext, const opvp_brush_t *strokecolor)
++{
++    int k;
++
++    fputs("opvpSetStrokeColor\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    if (strokecolor ==  NULL) {
++        fprintf(pFile, "\tstrokecolor is NULL\n");
++    } else {
++        fprintf(pFile, "\tstrokecolor.colorSpace = %d\n", strokecolor->colorSpace);
++
++        for (k = 0; k < 4; k++) {
++            fprintf(pFile, "\tstrokecolor.color[%d] = %d\n", k, strokecolor->color[k]);
++        }
++
++        fprintf(pFile, "\tstrokecolor.xorg = %d\n", strokecolor->xorg);
++        fprintf(pFile, "\tstrokecolor.yorg = %d\n", strokecolor->yorg);
++
++        if (strokecolor->pbrush ==  NULL) {
++            fprintf(pFile, "\tstrokecolor.pbrush is NULL\n");
++        } else {
++            fprintf(pFile, "\tstrokecolor.pbrush.type = %d\n", strokecolor->pbrush->type);
++            fprintf(pFile, "\tstrokecolor.pbrush.width = %d\n", strokecolor->pbrush->width);
++            fprintf(pFile, "\tstrokecolor.pbrush.height = %d\n", strokecolor->pbrush->height);
++            fprintf(pFile, "\tstrokecolor.pbrush.pitch = %d\n", strokecolor->pbrush->pitch);
++        }
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpSetFillColor(opvp_dc_t printerContext, const opvp_brush_t *fillcolor)
++{
++    int k;
++
++    fputs("opvpSetFillColor\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    if (fillcolor ==  NULL) {
++        fprintf(pFile, "\tfillcolor is NULL\n");
++    } else {
++        fprintf(pFile, "\tfillcolor.colorSpace = %d\n", fillcolor->colorSpace);
++
++        for (k = 0; k < 4; k++) {
++            fprintf(pFile, "\tfillcolor.color[%d] = %d\n", k, fillcolor->color[k]);
++        }
++
++        fprintf(pFile, "\tfillcolor.xorg = %d\n", fillcolor->xorg);
++        fprintf(pFile, "\tfillcolor.yorg = %d\n", fillcolor->yorg);
++
++        if (fillcolor->pbrush ==  NULL) {
++            fprintf(pFile, "\tfillcolor.pbrush is NULL\n");
++        } else {
++            fprintf(pFile, "\tfillcolor.pbrush.type = %d\n", fillcolor->pbrush->type);
++            fprintf(pFile, "\tfillcolor.pbrush.width = %d\n", fillcolor->pbrush->width);
++            fprintf(pFile, "\tfillcolor.pbrush.height = %d\n", fillcolor->pbrush->height);
++            fprintf(pFile, "\tfillcolor.pbrush.pitch = %d\n", fillcolor->pbrush->pitch);
++        }
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpSetBgColor(opvp_dc_t printerContext, const opvp_brush_t *bgcolor)
++{
++    int k;
++
++    fputs("opvpSetBgColor\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    if (bgcolor ==  NULL) {
++        fprintf(pFile, "\tfillcbgcolorolor is NULL\n");
++    } else {
++        fprintf(pFile, "\tbgcolor.colorSpace = %d\n", bgcolor->colorSpace);
++
++        for (k = 0; k < 4; k++) {
++            fprintf(pFile, "\tbgcolor.color[%d] = %d\n", k, bgcolor->color[k]);
++        }
++
++        fprintf(pFile, "\tbgcolor.xorg = %d\n", bgcolor->xorg);
++        fprintf(pFile, "\tbgcolor.yorg = %d\n", bgcolor->yorg);
++
++        if (bgcolor->pbrush ==  NULL) {
++            fprintf(pFile, "\tbgcolor.pbrush is NULL\n");
++        } else {
++            fprintf(pFile, "\tbgcolor.pbrush.type = %d\n", bgcolor->pbrush->type);
++            fprintf(pFile, "\tbgcolor.pbrush.width = %d\n", bgcolor->pbrush->width);
++            fprintf(pFile, "\tbgcolor.pbrush.height = %d\n", bgcolor->pbrush->height);
++            fprintf(pFile, "\tbgcolor.pbrush.pitch = %d\n", bgcolor->pbrush->pitch);
++        }
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpNewPath(opvp_dc_t printerContext)
++{
++    fputs("opvpNewPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpEndPath(opvp_dc_t printerContext)
++{
++    fputs("opvpEndPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpStrokePath(opvp_dc_t printerContext)
++{
++    fputs("opvpStrokePath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpFillPath(opvp_dc_t printerContext)
++{
++    fputs("opvpFillPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpStrokeFillPath(opvp_dc_t printerContext)
++{
++    fputs("opvpStrokeFillPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpSetClipPath(opvp_dc_t printerContext, opvp_cliprule_t cliprule)
++{
++    fputs("opvpSetClipPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tcliprule = %d\n", cliprule);
++    return 0;
++}
++
++static opvp_result_t
++opvpResetClipPath(opvp_dc_t printerContext)
++{
++    fputs("opvpResetClipPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpSetCurrentPoint(opvp_dc_t printerContext, opvp_fix_t pointx, opvp_fix_t pointy)
++{
++    fputs("opvpSetCurrentPoint\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tpointx = %d\n", pointx);
++    fprintf(pFile, "\tpointy = %d\n", pointy);
++    return 0;
++}
++
++static opvp_result_t
++opvpLinePath(opvp_dc_t printerContext, opvp_pathmode_t pathmode, opvp_int_t npoints, const opvp_point_t *points)
++{
++    int k;
++
++    fputs("opvpLinePath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tpathmode = %d\n", pathmode);
++    fprintf(pFile, "\tnpoints = %d\n", npoints);
++
++    for (k = 0; k < npoints; k++) {
++        fprintf(pFile, "\tpoints[%d].x = %d\n", k, points[k].x);
++        fprintf(pFile, "\tpoints[%d].y = %d\n", k, points[k].y);
++    }
++    return 0;
++}
++
++/* Not used */
++static opvp_result_t
++opvpPolygonPath(opvp_dc_t printerContext, opvp_int_t n, const opvp_int_t *m, const opvp_point_t *p)
++{
++    fputs("opvpPolygonPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpRectanglePath(opvp_dc_t printerContext, opvp_int_t n, const opvp_rectangle_t *rects)
++{
++    int k;
++
++    fputs("opvpRectanglePath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tn = %d\n", n);
++
++    for (k = 0; k < n; k++) {
++        fprintf(pFile, "\trects[%d].p0.x = %d\n", k, rects[k].p0.x);
++        fprintf(pFile, "\trects[%d].p0.y = %d\n", k, rects[k].p0.y);
++        fprintf(pFile, "\trects[%d].p1.x = %d\n", k, rects[k].p1.x);
++        fprintf(pFile, "\trects[%d].p1.y = %d\n", k, rects[k].p1.y);
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpRoundRectanglePath(opvp_dc_t printerContext, opvp_int_t n, const opvp_roundrectangle_t *rects)
++{
++    int k;
++
++    fputs("opvpRoundRectanglePath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tn = %d\n", n);
++
++    for (k = 0; k < n; k++) {
++        fprintf(pFile, "\trects[%d].p0.x = %d\n", k, rects[k].p0.x);
++        fprintf(pFile, "\trects[%d].p0.y = %d\n", k, rects[k].p0.y);
++        fprintf(pFile, "\trects[%d].p1.x = %d\n", k, rects[k].p1.x);
++        fprintf(pFile, "\trects[%d].p1.y = %d\n", k, rects[k].p1.y);
++        fprintf(pFile, "\trects[%d].xellipse = %d\n", k, rects[k].xellipse);
++        fprintf(pFile, "\trects[%d].yellipse = %d\n", k, rects[k].yellipse);
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpBezierPath(opvp_dc_t printerContext, opvp_int_t n, const opvp_point_t *points)
++{
++    int k;
++
++    fputs("opvpBezierPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tn = %d\n", n);
++
++    for (k = 0; k < n; k++) {
++        fprintf(pFile, "\tpoints[%d].x = %d\n", k, points[k].x);
++        fprintf(pFile, "\trects[%d].y = %d\n", k, points[k].y);
++
++    }
++    return 0;
++}
++
++/* Not used */
++static opvp_result_t
++opvpArcPath(opvp_dc_t printerContext, opvp_arcmode_t mode, opvp_arcdir_t dir,
++    opvp_fix_t a, opvp_fix_t b, opvp_fix_t c, opvp_fix_t d, opvp_fix_t e, opvp_fix_t f,
++    opvp_fix_t g, opvp_fix_t h)
++{
++    fputs("opvpArcPath\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpDrawImage(opvp_dc_t printerContext, opvp_int_t sw, opvp_int_t sh, opvp_int_t raster,
++    opvp_imageformat_t format, opvp_int_t dw, opvp_int_t dh, const void *data)
++{
++    int k;
++    unsigned char *data_char = (unsigned char*) data;
++
++    fputs("opvpDrawImage\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tsw = %d\n", sw);
++    fprintf(pFile, "\tsh = %d\n", sh);
++    fprintf(pFile, "\traster = %d\n", raster);
++    fprintf(pFile, "\tformat = %d\n", format);
++    fprintf(pFile, "\tdw = %d\n", dw);
++    fprintf(pFile, "\tdh = %d\n", dh);
++
++    /* No idea how big data is here... Try sw, as byte? */
++    for (k = 0; k < sw; k++) {
++        fprintf(pFile, "\tdata[%d] = %d\n", k, data_char[k]);
++    }
++
++    return 0;
++}
++
++static opvp_result_t
++opvpStartDrawImage(opvp_dc_t printerContext, opvp_int_t sw, opvp_int_t sh, opvp_int_t raster,
++    opvp_imageformat_t format, opvp_int_t dw, opvp_int_t dh)
++{
++    fputs("opvpStartDrawImage\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tsw = %d\n", sw);
++    fprintf(pFile, "\tsh = %d\n", sh);
++    fprintf(pFile, "\traster = %d\n", raster);
++    fprintf(pFile, "\tformat = %d\n", format);
++    fprintf(pFile, "\tdw = %d\n", dw);
++    fprintf(pFile, "\tdh = %d\n", dh);
++    return 0;
++}
++
++static opvp_result_t
++opvpTransferDrawImage(opvp_dc_t printerContext, opvp_int_t count, const void *data)
++{
++    int k;
++    unsigned char *data_char = (unsigned char*) data;
++
++    fputs("opvpTransferDrawImage\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\tcount = %d\n", count);
++
++    for (k = 0; k < count; k++) {
++        fprintf(pFile, "\tdata[%d] = %d\n", k, data_char[k]);
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpEndDrawImage(opvp_dc_t printerContext)
++{
++    fputs("opvpEndDrawImage\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++/* not used */
++static opvp_result_t
++opvpStartScanline(opvp_dc_t printerContext, opvp_int_t a)
++{
++    fputs("opvpStartScanline\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++/* not used */
++static opvp_result_t
++opvpScanline(opvp_dc_t printerContext, opvp_int_t a, const opvp_int_t *b)
++{
++    fputs("opvpScanline\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++/* not used */
++static opvp_result_t
++opvpEndScanline(opvp_dc_t printerContext)
++{
++    fputs("opvpEndScanline\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpStartRaster(opvp_dc_t printerContext, opvp_int_t width)
++{
++    fputs("opvpStartRaster\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\twidth = %d\n", width);
++    return 0;
++}
++
++static opvp_result_t
++opvpTransferRasterData(opvp_dc_t printerContext, opvp_int_t raster_size, const opvp_byte_t *data)
++{
++    int k;
++
++    fputs("opvpTransferRasterData\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\traster_size = %d\n", raster_size);
++
++    for (k = 0; k < raster_size; k++) {
++        fprintf(pFile, "\tdata[%d] = %d\n", k, data[k]);
++    }
++    return 0;
++}
++
++static opvp_result_t
++opvpSkipRaster(opvp_dc_t printerContext, opvp_int_t a)
++{
++    fputs("opvpSkipRaster\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    fprintf(pFile, "\ta = %d\n", a);
++    return 0;
++}
++
++static opvp_result_t
++opvpEndRaster(opvp_dc_t printerContext)
++{
++    fputs("opvpEndRaster\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpStartStream(opvp_dc_t printerContext)
++{
++    fputs("opvpStartStream\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++/* Not used */
++static opvp_result_t
++opvpTransferStreamData(opvp_dc_t printerContext, opvp_int_t a, const void *b)
++{
++    fputs("opvpTransferStreamData\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++static opvp_result_t
++opvpEndStream(opvp_dc_t printerContext)
++{
++    fputs("opvpEndStream\n", pFile);
++    fprintf(pFile, "\tContext = %d\n", printerContext);
++    return 0;
++}
++
++opvp_int_t opvpErrorNo;
++
++opvp_dc_t
++opvpOpenPrinter(opvp_int_t outputFD, const opvp_char_t *printerModel, const opvp_int_t apiVersion[2],
++        opvp_api_procs_t **apiProcs)
++{
++    static opvp_api_procs_t procs;
++    opvp_fix_t fixed_value;
++
++    procs.opvpEndStream = opvpEndStream;
++    procs.opvpClosePrinter = opvpClosePrinter;
++    procs.opvpStartJob = opvpStartJob;
++    procs.opvpEndJob = opvpEndJob;
++    procs.opvpAbortJob = opvpAbortJob;
++    procs.opvpStartDoc = opvpStartDoc;
++    procs.opvpEndDoc = opvpEndDoc;
++    procs.opvpStartPage = opvpStartPage;
++    procs.opvpEndPage = opvpEndPage;
++    procs.opvpQueryDeviceCapability = opvpQueryDeviceCapability;
++    procs.opvpQueryDeviceInfo = opvpQueryDeviceInfo;
++    procs.opvpResetCTM = opvpResetCTM;
++    procs.opvpSetCTM = opvpSetCTM;
++    procs.opvpGetCTM = opvpGetCTM;
++    procs.opvpInitGS = opvpInitGS;
++    procs.opvpSaveGS = opvpSaveGS;
++    procs.opvpRestoreGS = opvpRestoreGS;
++    procs.opvpQueryColorSpace = opvpQueryColorSpace;
++    procs.opvpSetColorSpace = opvpSetColorSpace;
++    procs.opvpGetColorSpace = opvpGetColorSpace;
++    procs.opvpSetFillMode = opvpSetFillMode;
++    procs.opvpGetFillMode = opvpGetFillMode;
++    procs.opvpSetAlphaConstant = opvpSetAlphaConstant;
++    procs.opvpGetAlphaConstant = opvpGetAlphaConstant;
++    procs.opvpSetLineWidth = opvpSetLineWidth;
++    procs.opvpGetLineWidth = opvpGetLineWidth;
++    procs.opvpSetLineDash = opvpSetLineDash;
++    procs.opvpSetLineDash = opvpSetLineDash;
++    procs.opvpGetLineDash = opvpGetLineDash;
++    procs.opvpSetLineDashOffset = opvpSetLineDashOffset;
++    procs.opvpGetLineDashOffset = opvpGetLineDashOffset;
++    procs.opvpSetLineStyle = opvpSetLineStyle;
++    procs.opvpGetLineStyle = opvpGetLineStyle;
++    procs.opvpSetLineCap = opvpSetLineCap;
++    procs.opvpGetLineCap = opvpGetLineCap;
++    procs.opvpSetLineJoin = opvpSetLineJoin;
++    procs.opvpGetLineJoin = opvpGetLineJoin;
++    procs.opvpSetMiterLimit = opvpSetMiterLimit;
++    procs.opvpGetMiterLimit = opvpGetMiterLimit;
++    procs.opvpSetPaintMode = opvpSetPaintMode;
++    procs.opvpGetPaintMode = opvpGetPaintMode;
++    procs.opvpSetStrokeColor = opvpSetStrokeColor;
++    procs.opvpSetFillColor = opvpSetFillColor;
++    procs.opvpSetBgColor = opvpSetBgColor;
++    procs.opvpNewPath = opvpNewPath;
++    procs.opvpEndPath = opvpEndPath;
++    procs.opvpStrokePath = opvpStrokePath;
++    procs.opvpFillPath = opvpFillPath;
++    procs.opvpStrokeFillPath = opvpStrokeFillPath;
++    procs.opvpSetClipPath = opvpSetClipPath;
++    procs.opvpResetClipPath = opvpResetClipPath;
++    procs.opvpSetCurrentPoint = opvpSetCurrentPoint;
++    procs.opvpLinePath = opvpLinePath;
++    procs.opvpPolygonPath = opvpPolygonPath;
++    procs.opvpRectanglePath = opvpRectanglePath;
++    procs.opvpRoundRectanglePath = opvpRoundRectanglePath;
++    procs.opvpBezierPath = opvpBezierPath;
++    procs.opvpArcPath = opvpArcPath;
++    procs.opvpDrawImage = opvpDrawImage;
++    procs.opvpStartDrawImage = opvpStartDrawImage;
++    procs.opvpTransferDrawImage = opvpTransferDrawImage;
++    procs.opvpEndDrawImage = opvpEndDrawImage;
++    procs.opvpStartScanline = opvpStartScanline;
++    procs.opvpScanline = opvpScanline;
++    procs.opvpEndScanline = opvpEndScanline;
++    procs.opvpStartRaster = opvpStartRaster;
++    procs.opvpTransferRasterData = opvpTransferRasterData;
++    procs.opvpSkipRaster = opvpSkipRaster;
++    procs.opvpEndRaster = opvpEndRaster;
++    procs.opvpStartStream = opvpStartStream;
++    procs.opvpTransferStreamData = opvpTransferStreamData;
++    procs.opvpEndStream = opvpEndStream;
++
++    *apiProcs = &procs;
++
++    OPVP_F2FIX(1.0, fixed_value);
++
++    opv_gstate.ctm.a = 1.0;
++    opv_gstate.ctm.b = 0.0;
++    opv_gstate.ctm.c = 0.0;
++    opv_gstate.ctm.d = 1.0;
++    opv_gstate.ctm.e = 0.0;
++    opv_gstate.ctm.f = 0.0;
++    opv_gstate.colorspace = OPVP_CSPACE_DEVICERGB;
++    opv_gstate.fill_mode = OPVP_FILLMODE_EVENODD;
++    opv_gstate.alpha = 1.0;
++    opv_gstate.line_width = fixed_value;
++    opv_gstate.line_dash_n = 0;
++    opv_gstate.line_dash_array = NULL;
++    opv_gstate.dash_offset = fixed_value;
++    opv_gstate.line_style = OPVP_LINESTYLE_SOLID;
++    opv_gstate.line_cap = OPVP_LINECAP_BUTT;
++    opv_gstate.line_join = OPVP_LINEJOIN_MITER;
++    opv_gstate.miter_limit = fixed_value;
++    opv_gstate.paintmode = OPVP_PAINTMODE_OPAQUE;
++    opv_gstate.colorspace = OPVP_CSPACE_DEVICERGB;
++
++    pFile = fopen("opvp_command_dump.txt","w");
++    if (pFile != NULL)
++    {
++        fputs("opvpOpenPrinter\n", pFile);
++        return 0;
++    }
++    return -1;
++}
+--
+2.40.0
diff --git a/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0002.patch b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0002.patch
new file mode 100644
index 0000000000..6ac25f0d71
--- /dev/null
+++ b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-33871-0002.patch
@@ -0,0 +1,43 @@
+From 7145885041bb52cc23964f0aa2aec1b1c82b5908 Mon Sep 17 00:00:00 2001
+From: Zdenek Hutyra <zhutyra@centrum.cz>
+Date: Mon, 22 Apr 2024 13:33:47 +0100
+Subject: [PATCH 7/7] OPVP device - prevent unsafe parameter change with SAFER
+
+Bug #707754 "OPVP device - Arbitrary code execution via custom Driver library"
+
+The "Driver" parameter for the "opvp"/"oprp" device specifies the name
+of a dynamic library and allows any library to be loaded.
+
+The patch does not allow changing this parameter after activating path
+control.
+
+This addresses CVE-2024-33871
+
+CVE: CVE-2024-33871
+
+Upstream-Status: Backport [https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=7145885041bb52cc2396]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ contrib/opvp/gdevopvp.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/contrib/opvp/gdevopvp.c b/contrib/opvp/gdevopvp.c
+index 64afbfe..f49a380 100644
+--- a/contrib/opvp/gdevopvp.c
++++ b/contrib/opvp/gdevopvp.c
+@@ -3453,6 +3453,12 @@ _put_params(gx_device *dev, gs_param_list *plist)
+     code = param_read_string(plist, pname, &vdps);
+     switch (code) {
+     case 0:
++        if (gs_is_path_control_active(dev->memory)
++            && (!opdev->globals.vectorDriver || strlen(opdev->globals.vectorDriver) != vdps.size
++                || memcmp(opdev->globals.vectorDriver, vdps.data, vdps.size) != 0)) {
++            param_signal_error(plist, pname, gs_error_invalidaccess);
++            return_error(gs_error_invalidaccess);
++        }
+         buff = realloc(buff, vdps.size + 1);
+         memcpy(buff, vdps.data, vdps.size);
+         buff[vdps.size] = 0;
+--
+2.40.0
diff --git a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
index 083ee4b337..36c5aa3285 100644
--- a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
+++ b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
@@ -46,6 +46,8 @@ SRC_URI_BASE = "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/d
                 file://CVE-2024-33870.patch \
                 file://CVE-2024-33869-0001.patch \
                 file://CVE-2024-33869-0002.patch \
+                file://CVE-2024-33871-0001.patch \
+                file://CVE-2024-33871-0002.patch \
 "
 
 SRC_URI = "${SRC_URI_BASE} \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 4/7] ghostscript: fix CVE-2024-29510
  2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
                   ` (2 preceding siblings ...)
  2024-05-30 18:38 ` [OE-core][kirkstone 3/7] ghostscript: fix CVE-2024-33871 Steve Sakoman
@ 2024-05-30 18:38 ` Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 5/7] ghostscript: fix CVE-2023-52722 Steve Sakoman
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:38 UTC (permalink / raw)
  To: openembedded-core

From: Archana Polampalli <archana.polampalli@windriver.com>

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
 .../ghostscript/CVE-2024-29510.patch          | 84 +++++++++++++++++++
 .../ghostscript/ghostscript_9.55.0.bb         |  1 +
 2 files changed, 85 insertions(+)
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2024-29510.patch

diff --git a/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-29510.patch b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-29510.patch
new file mode 100644
index 0000000000..0234c79c7d
--- /dev/null
+++ b/meta/recipes-extended/ghostscript/ghostscript/CVE-2024-29510.patch
@@ -0,0 +1,84 @@
+From 3b1735085ecef20b29e8db3416ab36de93e86d1f Mon Sep 17 00:00:00 2001
+From: Ken Sharp <Ken.Sharp@artifex.com>
+Date: Thu, 21 Mar 2024 09:01:15 +0000
+Subject: [PATCH 4/5] Uniprint device - prevent string configuration changes
+ when SAFER
+
+Bug #707662
+
+We cannot sanitise the string arguments used by the Uniprint device
+because they can potentially include anything.
+
+This commit ensures that these strings are locked and cannot be
+changed by PostScript once SAFER is activated. Full configuration from
+the command line is still possible (see the *.upp files in lib).
+
+This addresses CVE-2024-29510
+
+CVE: CVE-2024-29510
+
+Upstream-Status: Backport [https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=3b1735085ecef20b29e]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ devices/gdevupd.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/devices/gdevupd.c b/devices/gdevupd.c
+index 6635984..7952165 100644
+--- a/devices/gdevupd.c
++++ b/devices/gdevupd.c
+@@ -1886,6 +1886,16 @@ out on this copies.
+       if(!upd_strings[i]) continue;
+       UPD_PARAM_READ(param_read_string,upd_strings[i],value,udev->memory);
+       if(0 == code) {
++        if (gs_is_path_control_active(udev->memory)) {
++            if (strings[i].size != value.size)
++              error = gs_error_invalidaccess;
++            else {
++                if (strings[i].data && memcmp(strings[i].data, value.data, strings[i].size) != 0)
++                    error = gs_error_invalidaccess;
++            }
++            if (error < 0)
++                goto exit;
++        }
+          if(0 <= error) error |= UPD_PUT_STRINGS;
+          UPD_MM_DEL_PARAM(udev->memory, strings[i]);
+          if(!value.size) {
+@@ -1903,6 +1913,26 @@ out on this copies.
+       if(!upd_string_a[i]) continue;
+       UPD_PARAM_READ(param_read_string_array,upd_string_a[i],value,udev->memory);
+       if(0 == code) {
++          if (gs_is_path_control_active(udev->memory)) {
++              if (string_a[i].size != value.size)
++                  error = gs_error_invalidaccess;
++              else {
++                  int loop;
++                  for (loop = 0;loop < string_a[i].size;loop++) {
++                      gs_param_string *tmp1 = (gs_param_string *)&(string_a[i].data[loop]);
++                      gs_param_string *tmp2 = (gs_param_string *)&value.data[loop];
++
++                      if (tmp1->size != tmp2->size)
++                          error = gs_error_invalidaccess;
++                      else {
++                          if (tmp1->data && memcmp(tmp1->data, tmp2->data, tmp1->size) != 0)
++                              error = gs_error_invalidaccess;
++                      }
++                  }
++              }
++            if (error < 0)
++                goto exit;
++          }
+          if(0 <= error) error |= UPD_PUT_STRING_A;
+          UPD_MM_DEL_APARAM(udev->memory, string_a[i]);
+          if(!value.size) {
+@@ -2097,6 +2127,7 @@ transferred into the device-structure. In the case of "uniprint", this may
+       if(0 > code) error = code;
+    }
+
++exit:
+    if(0 < error) { /* Actually something loaded without error */
+
+       if(!(upd = udev->upd)) {
+--
+2.40.0
diff --git a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
index 36c5aa3285..1fd08d1cfe 100644
--- a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
+++ b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
@@ -48,6 +48,7 @@ SRC_URI_BASE = "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/d
                 file://CVE-2024-33869-0002.patch \
                 file://CVE-2024-33871-0001.patch \
                 file://CVE-2024-33871-0002.patch \
+                file://CVE-2024-29510.patch \
 "
 
 SRC_URI = "${SRC_URI_BASE} \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 5/7] ghostscript: fix CVE-2023-52722
  2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
                   ` (3 preceding siblings ...)
  2024-05-30 18:38 ` [OE-core][kirkstone 4/7] ghostscript: fix CVE-2024-29510 Steve Sakoman
@ 2024-05-30 18:38 ` Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 6/7] util-linux: Fix CVE-2024-28085 Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 7/7] git: Fix multiple CVEs Steve Sakoman
  6 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:38 UTC (permalink / raw)
  To: openembedded-core

From: Archana Polampalli <archana.polampalli@windriver.com>

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
 .../ghostscript/CVE-2023-52722.patch          | 43 +++++++++++++++++++
 .../ghostscript/ghostscript_9.55.0.bb         |  1 +
 2 files changed, 44 insertions(+)
 create mode 100644 meta/recipes-extended/ghostscript/ghostscript/CVE-2023-52722.patch

diff --git a/meta/recipes-extended/ghostscript/ghostscript/CVE-2023-52722.patch b/meta/recipes-extended/ghostscript/ghostscript/CVE-2023-52722.patch
new file mode 100644
index 0000000000..8fbfc9ef09
--- /dev/null
+++ b/meta/recipes-extended/ghostscript/ghostscript/CVE-2023-52722.patch
@@ -0,0 +1,43 @@
+From 1ff9a695947967d2d327c45bf5145dd381fc1745 Mon Sep 17 00:00:00 2001
+From: Chris Liddell <chris.liddell@artifex.com>
+Date: Tue, 12 Sep 2023 10:46:10 +0100
+Subject: [PATCH 5/5] In SAFER (default) don't allow eexec seeds other than the
+ Type 1 standard
+
+CVE: CVE-2023-52722
+
+Upstream-Status: Backport [https://cgit.ghostscript.com/cgi-bin/cgit.cgi/ghostpdl.git/commit/?id=1ff9a695947967d2d327]
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ psi/zmisc1.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/psi/zmisc1.c b/psi/zmisc1.c
+index 3c47e99..81556ac 100644
+--- a/psi/zmisc1.c
++++ b/psi/zmisc1.c
+@@ -93,6 +93,9 @@ zexE(i_ctx_t *i_ctx_p)
+
+     if (code < 0)
+         return code;
++    if (gs_is_path_control_active(imemory) != 0 && state.cstate != 55665) {
++        return_error(gs_error_rangecheck);
++    }
+     return filter_write(i_ctx_p, code, &s_exE_template, (stream_state *)&state, 0);
+ }
+
+@@ -130,6 +133,11 @@ zexD(i_ctx_t *i_ctx_p)
+     }
+     if (code < 0)
+         return code;
++
++    if (gs_is_path_control_active(imemory) != 0 && state.cstate != 55665) {
++        return_error(gs_error_rangecheck);
++    }
++
+     /*
+      * If we're reading a .PFB file, let the filter know about it,
+      * so it can read recklessly to the end of the binary section.
+--
+2.40.0
diff --git a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
index 1fd08d1cfe..2e332b1589 100644
--- a/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
+++ b/meta/recipes-extended/ghostscript/ghostscript_9.55.0.bb
@@ -49,6 +49,7 @@ SRC_URI_BASE = "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/d
                 file://CVE-2024-33871-0001.patch \
                 file://CVE-2024-33871-0002.patch \
                 file://CVE-2024-29510.patch \
+                file://CVE-2023-52722.patch \
 "
 
 SRC_URI = "${SRC_URI_BASE} \
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 6/7] util-linux: Fix CVE-2024-28085
  2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
                   ` (4 preceding siblings ...)
  2024-05-30 18:38 ` [OE-core][kirkstone 5/7] ghostscript: fix CVE-2023-52722 Steve Sakoman
@ 2024-05-30 18:38 ` Steve Sakoman
  2024-05-30 18:38 ` [OE-core][kirkstone 7/7] git: Fix multiple CVEs Steve Sakoman
  6 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:38 UTC (permalink / raw)
  To: openembedded-core

From: Soumya Sambu <soumya.sambu@windriver.com>

wall in util-linux through 2.40, often installed with setgid
tty permissions, allows escape sequences to be sent to other
users' terminals through argv. (Specifically, escape sequences
received from stdin are blocked, but escape sequences received
from argv are not blocked.) There may be plausible scenarios
where this leads to account takeover.

CVE-2024-28085-0005 is the CVE fix and CVE-2024-28085-0001,
CVE-2024-28085-0002, CVE-2024-28085-0003, CVE-2024-28085-0004
are dependent commits to fix the CVE.

References:
https://nvd.nist.gov/vuln/detail/CVE-2024-28085

Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
 meta/recipes-core/util-linux/util-linux.inc   |   5 +
 .../util-linux/CVE-2024-28085-0001.patch      | 202 ++++++++++++++++
 .../util-linux/CVE-2024-28085-0002.patch      | 172 ++++++++++++++
 .../util-linux/CVE-2024-28085-0003.patch      | 223 ++++++++++++++++++
 .../util-linux/CVE-2024-28085-0004.patch      |  36 +++
 .../util-linux/CVE-2024-28085-0005.patch      |  34 +++
 6 files changed, 672 insertions(+)
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch
 create mode 100644 meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch

diff --git a/meta/recipes-core/util-linux/util-linux.inc b/meta/recipes-core/util-linux/util-linux.inc
index 982ec669a2..f8841e6be0 100644
--- a/meta/recipes-core/util-linux/util-linux.inc
+++ b/meta/recipes-core/util-linux/util-linux.inc
@@ -35,6 +35,11 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin
            file://run-ptest \
            file://display_testname_for_subtest.patch \
            file://avoid_parallel_tests.patch \
+           file://CVE-2024-28085-0001.patch \
+           file://CVE-2024-28085-0002.patch \
+           file://CVE-2024-28085-0003.patch \
+           file://CVE-2024-28085-0004.patch \
+           file://CVE-2024-28085-0005.patch \
            "
 
 SRC_URI[sha256sum] = "634e6916ad913366c3536b6468e7844769549b99a7b2bf80314de78ab5655b83"
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch
new file mode 100644
index 0000000000..7ce2d6c567
--- /dev/null
+++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0001.patch
@@ -0,0 +1,202 @@
+From 8a7b8456d1dc0e7ca557d1ac31f638986704757f Mon Sep 17 00:00:00 2001
+From: наб <nabijaczleweli@nabijaczleweli.xyz>
+Date: Wed Mar 15 16:16:31 2023 +0100
+Subject: [PATCH] write: correctly handle wide characters
+
+Do this by replacing fputc_careful() (notice that the description said
+it's locale-aware ‒ it very much is /not/), with a fputs_careful() which
+does the same thing, but if it were to output a byte in the \123 format,
+first it checks whether this byte starts a valid multibyte character.
+
+If it does, and that character is printable, write it verbatim.
+This means that
+  echo 'foo åäö ąęćźżń bar' | write nabijaczleweli pts/4
+instead of
+  foo \303\245\303\244\303\266
+  \304\205\304\231\304\207\305\272\305\274\305\204 bar
+yields
+  foo åäö ąęćźżń bar
+or, more realistically, from a message I got earlier today,
+  Filip powiedzia\305\202 \305\274e zap\305\202aci jutro
+becomes
+  Filip powiedział że zapłaci jutro
+
+Invalid/non-printable sequences get processed as before.
+
+Line reading in write must become getline() to avoid dealing with
+partial characters: for example on input consisting solely of
+ąęćźżń, where every {1} is an instance, the output would be
+  {42}ąęć\305\272żń{84}ąęćź\305\274ń{84}ąęćźż\305\204{39}
+with just fixed-512 fgets()
+
+Bug-Debian: https://bugs.debian.org/826596
+
+CVE: CVE-2024-28085
+
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/8a7b8456d1dc0e7ca557d1ac31f638986704757f]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ include/carefulputc.h | 62 +++++++++++++++++++++++++++++++------------
+ login-utils/last.c    |  4 +--
+ term-utils/write.c    | 25 +++++------------
+ 3 files changed, 53 insertions(+), 38 deletions(-)
+
+diff --git a/include/carefulputc.h b/include/carefulputc.h
+index 66a0f15..2506614 100644
+--- a/include/carefulputc.h
++++ b/include/carefulputc.h
+@@ -1,31 +1,59 @@
+ #ifndef UTIL_LINUX_CAREFULPUTC_H
+ #define UTIL_LINUX_CAREFULPUTC_H
+
+-/*
+- * A putc() for use in write and wall (that sometimes are sgid tty).
+- * It avoids control characters in our locale, and also ASCII control
+- * characters.   Note that the locale of the recipient is unknown.
+-*/
+ #include <stdio.h>
+ #include <string.h>
+ #include <ctype.h>
++#ifdef HAVE_WIDECHAR
++#include <wctype.h>
++#endif
++#include <stdbool.h>
+
+ #include "cctype.h"
+
+-static inline int fputc_careful(int c, FILE *fp, const char fail)
++/*
++ * A puts() for use in write and wall (that sometimes are sgid tty).
++ * It avoids control and invalid characters.
++ * The locale of the recipient is nominally unknown,
++ * but it's a solid bet that the encoding is compatible with the author's.
++ */
++static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf)
+ {
+-	int ret;
+-
+-	if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n')
+-		ret = putc(c, fp);
+-	else if (!c_isascii(c))
+-		ret = fprintf(fp, "\\%3o", (unsigned char)c);
+-	else {
+-		ret = putc(fail, fp);
+-		if (ret != EOF)
+-			ret = putc(c ^ 0x40, fp);
++	int ret = 0;
++
++	for (size_t slen = strlen(s); *s; ++s, --slen) {
++		if (*s == '\n')
++			ret = fputs(cr_lf ? "\r\n" : "\n", fp);
++		else if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r')
++			ret = putc(*s, fp);
++		else if (!c_isascii(*s)) {
++#ifdef HAVE_WIDECHAR
++			wchar_t w;
++			size_t clen = mbtowc(&w, s, slen);
++			switch(clen) {
++				case (size_t)-2:  // incomplete
++				case (size_t)-1:  // EILSEQ
++					mbtowc(NULL, NULL, 0);
++				nonprint:
++					ret = fprintf(fp, "\\%3hho", *s);
++					break;
++				default:
++					if(!iswprint(w))
++						goto nonprint;
++					ret = fwrite(s, 1, clen, fp);
++					s += clen - 1;
++					slen -= clen - 1;
++					break;
++			}
++#else
++			ret = fprintf(fp, "\\%3hho", *s);
++#endif
++		} else
++			ret = fputs((char[]){ ctrl, *s ^ 0x40, '\0' }, fp);
++		if (ret < 0)
++			return EOF;
+	}
+-	return (ret < 0) ? EOF : 0;
++	return 0;
+ }
+
+ static inline void fputs_quoted_case(const char *data, FILE *out, int dir)
+diff --git a/login-utils/last.c b/login-utils/last.c
+index f3272ca..aacd1f6 100644
+--- a/login-utils/last.c
++++ b/login-utils/last.c
+@@ -403,7 +403,6 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
+	char		final[512];
+	char		utline[sizeof(p->ut_line) + 1];
+	char		domain[256];
+-	char		*s;
+	int		mins, hours, days;
+	int		r, len;
+	struct last_timefmt *fmt;
+@@ -559,8 +558,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
+	/*
+	 *	Print out "final" string safely.
+	 */
+-	for (s = final; *s; s++)
+-		fputc_careful(*s, stdout, '*');
++	fputs_careful(final, stdout, '*', false);
+
+	if (len < 0 || (size_t)len >= sizeof(final))
+		putchar('\n');
+diff --git a/term-utils/write.c b/term-utils/write.c
+index 50f18dc..710a58c 100644
+--- a/term-utils/write.c
++++ b/term-utils/write.c
+@@ -223,21 +223,6 @@ static void signal_handler(int signo)
+	signal_received = signo;
+ }
+
+-/*
+- * write_line - like fputs(), but makes control characters visible and
+- *     turns \n into \r\n.
+- */
+-static void write_line(char *s)
+-{
+-	while (*s) {
+-		const int c = *s++;
+-
+-		if ((c == '\n' && fputc_careful('\r', stdout, '^') == EOF)
+-		    || fputc_careful(c, stdout, '^') == EOF)
+-			err(EXIT_FAILURE, _("carefulputc failed"));
+-	}
+-}
+-
+ /*
+  * do_write - actually make the connection
+  */
+@@ -247,7 +232,8 @@ static void do_write(const struct write_control *ctl)
+	struct passwd *pwd;
+	time_t now;
+	struct tm *tm;
+-	char *host, line[512];
++	char *host, *line = NULL;
++	size_t linelen = 0;
+	struct sigaction sigact;
+
+	/* Determine our login name(s) before the we reopen() stdout */
+@@ -286,11 +272,14 @@ static void do_write(const struct write_control *ctl)
+	free(host);
+	printf("\r\n");
+
+-	while (fgets(line, sizeof(line), stdin) != NULL) {
++	while (getline(&line, &linelen, stdin) >= 0) {
+		if (signal_received)
+			break;
+-		write_line(line);
++
++		if (fputs_careful(line, stdout, '^', true) == EOF)
++			err(EXIT_FAILURE, _("carefulputc failed"));
+	}
++	free(line);
+	printf("EOF\r\n");
+ }
+
+--
+2.40.0
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch
new file mode 100644
index 0000000000..1fceebbdb4
--- /dev/null
+++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0002.patch
@@ -0,0 +1,172 @@
+From 27ee6446503af7ec0c2647704ca47ac4de3852ef Mon Sep 17 00:00:00 2001
+From: наб <nabijaczleweli@nabijaczleweli.xyz>
+Date: Wed, 15 Mar 2023 16:16:43 +0100
+Subject: [PATCH] wall: convert homebrew buffering to open_memstream()
+
+The struct buffer system duplicates a plethora of standard I/O
+functions (including a fork of fputc_careful())
+and adds a lot of complexity ‒ open_memstream() is standard,
+and fits perfectly into this niche
+
+CVE: CVE-2024-28085
+
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/27ee6446503af7ec0c2647704ca47ac4de3852ef]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ term-utils/wall.c | 95 ++++++++++-------------------------------------
+ 1 file changed, 20 insertions(+), 75 deletions(-)
+
+diff --git a/term-utils/wall.c b/term-utils/wall.c
+index c601d3e..a51a928 100644
+--- a/term-utils/wall.c
++++ b/term-utils/wall.c
+@@ -274,74 +274,22 @@ int main(int argc, char **argv)
+	exit(EXIT_SUCCESS);
+ }
+
+-struct buffer {
+-	size_t	sz;
+-	size_t	used;
+-	char	*data;
+-};
+-
+-static void buf_enlarge(struct buffer *bs, size_t len)
++static void buf_putc_careful(FILE *fs, int c)
+ {
+-	if (bs->sz == 0 || len > bs->sz - bs->used) {
+-		bs->sz += len < 128 ? 128 : len;
+-		bs->data = xrealloc(bs->data, bs->sz);
+-	}
+-}
+-
+-static void buf_puts(struct buffer *bs, const char *s)
+-{
+-	size_t len = strlen(s);
+-
+-	buf_enlarge(bs, len + 1);
+-	memcpy(bs->data + bs->used, s, len + 1);
+-	bs->used += len;
+-}
+-
+-static void __attribute__((__format__ (__printf__, 2, 3)))
+-	buf_printf(struct buffer *bs, const char *fmt, ...)
+-{
+-	int rc;
+-	va_list ap;
+-	size_t limit;
+-
+-	buf_enlarge(bs, 0);	/* default size */
+-	limit = bs->sz - bs->used;
+-
+-	va_start(ap, fmt);
+-	rc = vsnprintf(bs->data + bs->used, limit, fmt, ap);
+-	va_end(ap);
+-
+-	if (rc >= 0 && (size_t) rc >= limit) {	/* not enough, enlarge */
+-		buf_enlarge(bs, (size_t)rc + 1);
+-		limit = bs->sz - bs->used;
+-		va_start(ap, fmt);
+-		rc = vsnprintf(bs->data  + bs->used, limit, fmt, ap);
+-		va_end(ap);
+-	}
+-
+-	if (rc > 0)
+-		bs->used += rc;
+-}
+-
+-static void buf_putc_careful(struct buffer *bs, int c)
+-{
+-	if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n') {
+-		buf_enlarge(bs, 1);
+-		bs->data[bs->used++] = c;
+-	} else if (!c_isascii(c))
+-		buf_printf(bs, "\\%3o", (unsigned char)c);
+-	else {
+-		char tmp[] = { '^', c ^ 0x40, '\0' };
+-		buf_puts(bs, tmp);
+-	}
++	if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n')
++		fputc(c, fs);
++	else if (!c_isascii(c))
++		fprintf(fs, "\\%3o", (unsigned char)c);
++	else
++		fputs((char[]){ '^', c ^ 0x40, '\0' }, fs);
+ }
+
+ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		     size_t *mbufsize, int print_banner)
+ {
+-	struct buffer _bs = {.used = 0}, *bs = &_bs;
+	register int ch, cnt;
+-	char *p, *lbuf;
++	char *p, *lbuf, *retbuf;
++	FILE * fs = open_memstream(&retbuf, mbufsize);
+	long line_max;
+
+	line_max = sysconf(_SC_LINE_MAX);
+@@ -379,15 +327,15 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		 */
+		/* snprintf is not always available, but the sprintf's here
+		   will not overflow as long as %d takes at most 100 chars */
+-		buf_printf(bs, "\r%*s\r\n", TERM_WIDTH, " ");
++		fprintf(fs, "\r%*s\r\n", TERM_WIDTH, " ");
+
+		snprintf(lbuf, line_max,
+				_("Broadcast message from %s@%s (%s) (%s):"),
+				whom, hostname, where, date);
+-		buf_printf(bs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf);
++		fprintf(fs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf);
+		free(hostname);
+	}
+-	buf_printf(bs, "%*s\r\n", TERM_WIDTH, " ");
++	fprintf(fs, "%*s\r\n", TERM_WIDTH, " ");
+
+	 if (mvec) {
+		/*
+@@ -396,11 +344,11 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		int i;
+
+		for (i = 0; i < mvecsz; i++) {
+-			buf_puts(bs, mvec[i]);
++			fputs(mvec[i], fs);
+			if (i < mvecsz - 1)
+-				buf_puts(bs, " ");
++				fputc(' ', fs);
+		}
+-		buf_puts(bs, "\r\n");
++		fputs("\r\n", fs);
+	} else {
+		/*
+		 * read message from <file>
+@@ -428,23 +376,20 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		while (fgets(lbuf, line_max, stdin)) {
+			for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
+				if (cnt == TERM_WIDTH || ch == '\n') {
+-					for (; cnt < TERM_WIDTH; ++cnt)
+-						buf_puts(bs, " ");
+-					buf_puts(bs, "\r\n");
++					fprintf(fs, "%*s\r\n", TERM_WIDTH - cnt, "");
+					cnt = 0;
+				}
+				if (ch == '\t')
+					cnt += (7 - (cnt % 8));
+				if (ch != '\n')
+-					buf_putc_careful(bs, ch);
++					buf_putc_careful(fs, ch);
+			}
+		}
+	}
+-	buf_printf(bs, "%*s\r\n", TERM_WIDTH, " ");
++	fprintf(fs, "%*s\r\n", TERM_WIDTH, " ");
+
+	free(lbuf);
+
+-	bs->data[bs->used] = '\0';	/* be paranoid */
+-	*mbufsize = bs->used;
+-	return bs->data;
++	fclose(fs);
++	return retbuf;
+ }
+--
+2.40.0
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch
new file mode 100644
index 0000000000..55eba9cc49
--- /dev/null
+++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0003.patch
@@ -0,0 +1,223 @@
+From aa13246a1bf1be9e4f6eb331f4d4d2dbc875e22f Mon Sep 17 00:00:00 2001
+From: наб <nabijaczleweli@nabijaczleweli.xyz>
+Date: Wed, 15 Mar 2023 16:16:48 +0100
+Subject: [PATCH] wall: use fputs_careful()
+
+LINE_MAX only applies to teletypes in canonical mode: when stdin is a
+file, it could still very much tear; start off at 512 for the sprintf(),
+then use getline() like in write.
+
+The line wrapping has one suboptimal edge-case:
+  $ wall < all
+
+  Broadcast message from nabijaczleweli@tarta (pts/4) (Tue Mar 14 22:31:25
+  2023):
+
+  ^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_
+  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJ
+  KLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?\200\201\202\203\204\205\206
+  \207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232
+  \233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256
+  \257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302
+  \303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326
+  \327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352
+  \353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376
+  \377
+but that's a pathological input, and the result is still infinitely
+better than it was before, so fixing that is more trouble than it's
+worth.
+
+Bug-Debian: https://bugs.debian.org/826596
+
+CVE: CVE-2024-28085
+
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/aa13246a1bf1be9e4f6eb331f4d4d2dbc875e22f]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ include/carefulputc.h | 42 +++++++++++++++++++++++++++++++++---------
+ login-utils/last.c    |  2 +-
+ term-utils/wall.c     | 38 ++++++--------------------------------
+ term-utils/write.c    |  2 +-
+ 4 files changed, 41 insertions(+), 43 deletions(-)
+
+diff --git a/include/carefulputc.h b/include/carefulputc.h
+index 2506614..89f8a99 100644
+--- a/include/carefulputc.h
++++ b/include/carefulputc.h
+@@ -6,6 +6,7 @@
+ #include <ctype.h>
+ #ifdef HAVE_WIDECHAR
+ #include <wctype.h>
++#include <wchar.h>
+ #endif
+ #include <stdbool.h>
+
+@@ -15,18 +16,35 @@
+  * A puts() for use in write and wall (that sometimes are sgid tty).
+  * It avoids control and invalid characters.
+  * The locale of the recipient is nominally unknown,
+- * but it's a solid bet that the encoding is compatible with the author's.
++ * but it's a solid bet that it's compatible with the author's.
++ * Use soft_width=0 to disable wrapping.
+  */
+-static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf)
++static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool cr_lf, int soft_width)
+ {
+-	int ret = 0;
++	int ret = 0, col = 0;
+
+	for (size_t slen = strlen(s); *s; ++s, --slen) {
+-		if (*s == '\n')
++		if (*s == '\t')
++			col += (7 - (col % 8)) - 1;
++		else if (*s == '\r')
++			col = -1;
++		else if (*s == '\a')
++			--col;
++
++		if ((soft_width && col >= soft_width) || *s == '\n') {
++			if (soft_width) {
++				fprintf(fp, "%*s", soft_width - col, "");
++				col = 0;
++			}
+			ret = fputs(cr_lf ? "\r\n" : "\n", fp);
+-		else if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r')
++			if (*s == '\n' || ret < 0)
++				goto wrote;
++		}
++
++		if (isprint(*s) || *s == '\a' || *s == '\t' || *s == '\r') {
+			ret = putc(*s, fp);
+-		else if (!c_isascii(*s)) {
++			++col;
++		} else if (!c_isascii(*s)) {
+ #ifdef HAVE_WIDECHAR
+			wchar_t w;
+			size_t clen = mbtowc(&w, s, slen);
+@@ -35,21 +53,27 @@ static inline int fputs_careful(const char * s, FILE *fp, const char ctrl, bool
+				case (size_t)-1:  // EILSEQ
+					mbtowc(NULL, NULL, 0);
+				nonprint:
+-					ret = fprintf(fp, "\\%3hho", *s);
++					col += ret = fprintf(fp, "\\%3hho", *s);
+					break;
+				default:
+					if(!iswprint(w))
+						goto nonprint;
+					ret = fwrite(s, 1, clen, fp);
++					if (soft_width)
++						col += wcwidth(w);
+					s += clen - 1;
+					slen -= clen - 1;
+					break;
+			}
+ #else
+-			ret = fprintf(fp, "\\%3hho", *s);
++			col += ret = fprintf(fp, "\\%3hho", *s);
+ #endif
+-		} else
++		} else {
+			ret = fputs((char[]){ ctrl, *s ^ 0x40, '\0' }, fp);
++			col += 2;
++		}
++
++	wrote:
+		if (ret < 0)
+			return EOF;
+	}
+diff --git a/login-utils/last.c b/login-utils/last.c
+index aacd1f6..43c5429 100644
+--- a/login-utils/last.c
++++ b/login-utils/last.c
+@@ -558,7 +558,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
+	/*
+	 *	Print out "final" string safely.
+	 */
+-	fputs_careful(final, stdout, '*', false);
++	fputs_careful(final, stdout, '*', false, 0);
+
+	if (len < 0 || (size_t)len >= sizeof(final))
+		putchar('\n');
+diff --git a/term-utils/wall.c b/term-utils/wall.c
+index a51a928..377db45 100644
+--- a/term-utils/wall.c
++++ b/term-utils/wall.c
+@@ -274,29 +274,13 @@ int main(int argc, char **argv)
+	exit(EXIT_SUCCESS);
+ }
+
+-static void buf_putc_careful(FILE *fs, int c)
+-{
+-	if (isprint(c) || c == '\a' || c == '\t' || c == '\r' || c == '\n')
+-		fputc(c, fs);
+-	else if (!c_isascii(c))
+-		fprintf(fs, "\\%3o", (unsigned char)c);
+-	else
+-		fputs((char[]){ '^', c ^ 0x40, '\0' }, fs);
+-}
+-
+ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		     size_t *mbufsize, int print_banner)
+ {
+-	register int ch, cnt;
+-	char *p, *lbuf, *retbuf;
++	char *lbuf, *retbuf;
+	FILE * fs = open_memstream(&retbuf, mbufsize);
+-	long line_max;
+-
+-	line_max = sysconf(_SC_LINE_MAX);
+-	if (line_max <= 0)
+-		line_max = 512;
+-
+-	lbuf = xmalloc(line_max);
++	size_t lbuflen = 512;
++	lbuf = xmalloc(lbuflen);
+
+	if (print_banner == TRUE) {
+		char *hostname = xgethostname();
+@@ -329,7 +313,7 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		   will not overflow as long as %d takes at most 100 chars */
+		fprintf(fs, "\r%*s\r\n", TERM_WIDTH, " ");
+
+-		snprintf(lbuf, line_max,
++		snprintf(lbuf, lbuflen,
+				_("Broadcast message from %s@%s (%s) (%s):"),
+				whom, hostname, where, date);
+		fprintf(fs, "%-*.*s\007\007\r\n", TERM_WIDTH, TERM_WIDTH, lbuf);
+@@ -373,18 +357,8 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		/*
+		 * Read message from stdin.
+		 */
+-		while (fgets(lbuf, line_max, stdin)) {
+-			for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
+-				if (cnt == TERM_WIDTH || ch == '\n') {
+-					fprintf(fs, "%*s\r\n", TERM_WIDTH - cnt, "");
+-					cnt = 0;
+-				}
+-				if (ch == '\t')
+-					cnt += (7 - (cnt % 8));
+-				if (ch != '\n')
+-					buf_putc_careful(fs, ch);
+-			}
+-		}
++		while (getline(&lbuf, &lbuflen, stdin) >= 0)
++			fputs_careful(lbuf, fs, '^', true, TERM_WIDTH);
+	}
+	fprintf(fs, "%*s\r\n", TERM_WIDTH, " ");
+
+diff --git a/term-utils/write.c b/term-utils/write.c
+index 710a58c..1d57fce 100644
+--- a/term-utils/write.c
++++ b/term-utils/write.c
+@@ -276,7 +276,7 @@ static void do_write(const struct write_control *ctl)
+		if (signal_received)
+			break;
+
+-		if (fputs_careful(line, stdout, '^', true) == EOF)
++		if (fputs_careful(line, stdout, '^', true, 0) == EOF)
+			err(EXIT_FAILURE, _("carefulputc failed"));
+	}
+	free(line);
+--
+2.40.0
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch
new file mode 100644
index 0000000000..af39931b3f
--- /dev/null
+++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0004.patch
@@ -0,0 +1,36 @@
+From 07f0f0f5bd1e5e2268257ae1ff6d76a9b6c6ea8b Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Wed, 17 Jan 2024 12:37:08 +0100
+Subject: [PATCH] wall: fix calloc cal [-Werror=calloc-transposed-args]
+
+term-utils/wall.c:143:37: error: xcalloc sizes specified with sizeof in the earlier argument and not in the later argument [-Werror=calloc-transposed-args]
+  143 |         buf->groups = xcalloc(sizeof(*buf->groups), buf->ngroups);
+      |                                     ^
+term-utils/wall.c:143:37: note: earlier argument should specify number of elements, later size of each element
+
+Signed-off-by: Karel Zak <kzak@redhat.com>
+
+CVE: CVE-2024-28085
+
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/07f0f0f5bd1e5e2268257ae1ff6d76a9b6c6ea8b]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ term-utils/wall.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/term-utils/wall.c b/term-utils/wall.c
+index 377db45..85c006a 100644
+--- a/term-utils/wall.c
++++ b/term-utils/wall.c
+@@ -135,7 +135,7 @@ static struct group_workspace *init_group_workspace(const char *group)
+
+	buf->requested_group = get_group_gid(group);
+	buf->ngroups = sysconf(_SC_NGROUPS_MAX) + 1;  /* room for the primary gid */
+-	buf->groups = xcalloc(sizeof(*buf->groups), buf->ngroups);
++	buf->groups = xcalloc(buf->ngroups, sizeof(*buf->groups));
+
+	return buf;
+ }
+--
+2.40.0
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch
new file mode 100644
index 0000000000..a2b914d580
--- /dev/null
+++ b/meta/recipes-core/util-linux/util-linux/CVE-2024-28085-0005.patch
@@ -0,0 +1,34 @@
+From 404b0781f52f7c045ca811b2dceec526408ac253 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Thu, 21 Mar 2024 11:16:20 +0100
+Subject: [PATCH] wall: fix escape sequence Injection [CVE-2024-28085]
+
+Let's use for all cases the same output function.
+
+Reported-by: Skyler Ferrante <sjf5462@rit.edu>
+Signed-off-by: Karel Zak <kzak@redhat.com>
+
+CVE: CVE-2024-28085
+
+Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/404b0781f52f7c045ca811b2dceec526408ac253]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ term-utils/wall.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/term-utils/wall.c b/term-utils/wall.c
+index 85c006a..0212c03 100644
+--- a/term-utils/wall.c
++++ b/term-utils/wall.c
+@@ -328,7 +328,7 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
+		int i;
+
+		for (i = 0; i < mvecsz; i++) {
+-			fputs(mvec[i], fs);
++			fputs_careful(mvec[i], fs, '^', true, TERM_WIDTH);
+			if (i < mvecsz - 1)
+				fputc(' ', fs);
+		}
+--
+2.40.0
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 7/7] git: Fix multiple CVEs
  2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
                   ` (5 preceding siblings ...)
  2024-05-30 18:38 ` [OE-core][kirkstone 6/7] util-linux: Fix CVE-2024-28085 Steve Sakoman
@ 2024-05-30 18:38 ` Steve Sakoman
  6 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-05-30 18:38 UTC (permalink / raw)
  To: openembedded-core

From: Soumya Sambu <soumya.sambu@windriver.com>

CVE-2024-32002:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, repositories with submodules can be
crafted in a way that exploits a bug in Git whereby it can be fooled into
writing files not into the submodule's worktree but into a `.git/` directory.
This allows writing a hook that will be executed while the clone operation
is still running, giving the user no opportunity to inspect the code that is
being executed. The problem has been patched in versions 2.45.1, 2.44.1,
2.43.4, 2.42.2, 2.41.1, 2.40.2, and 2.39.4. If symbolic link support is
disabled in Git (e.g. via `git config --global core.symlinks false`), the
described attack won't work. As always, it is best to avoid cloning
repositories from untrusted sources.

CVE-2024-32004:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, an attacker can prepare a local repository
in such a way that, when cloned, will execute arbitrary code during the
operation. The problem has been patched in versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4. As a workaround, avoid cloning repositories
from untrusted sources.

CVE-2024-32020:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, local clones may end up hardlinking files
into the target repository's object database when source and target repository
reside on the same disk. If the source repository is owned by a different user,
then those hardlinked files may be rewritten at any point in time by the
untrusted user. Cloning local repositories will cause Git to either copy or
hardlink files of the source repository into the target repository. This
significantly speeds up such local clones compared to doing a "proper" clone and
saves both disk space and compute time. When cloning a repository located on the
same disk that is owned by a different user than the current user we also end up
creating such hardlinks. These files will continue to be owned and controlled by
the potentially-untrusted user and can be rewritten by them at will in the
future. The problem has been patched in versions 2.45.1, 2.44.1, 2.43.4, 2.42.2,
2.41.1, 2.40.2, and 2.39.4.

CVE-2024-32021:
Git is a revision control system. Prior to versions 2.45.1, 2.44.1, 2.43.4,
2.42.2, 2.41.1, 2.40.2, and 2.39.4, when cloning a local source repository that
contains symlinks via the filesystem, Git may create hardlinks to arbitrary
user-readable files on the same filesystem as the target repository in the
`objects/` directory. Cloning a local repository over the filesystem may
creating hardlinks to arbitrary user-owned files on the same filesystem in the
target Git repository's `objects/` directory. When cloning a repository over the
filesystem (without explicitly specifying the `file://` protocol or `--no-local`),
the optimizations for local cloning will be used, which include attempting to
hard link the object files instead of copying them. While the code includes checks
against symbolic links in the source repository, which were added during the fix
for CVE-2022-39253, these checks can still be raced because the hard link
operation ultimately follows symlinks. If the object on the filesystem appears as
a file during the check, and then a symlink during the operation, this will allow
the adversary to bypass the check and create hardlinks in the destination objects
directory to arbitrary, user-readable files. The problem has been patched in
versions 2.45.1, 2.44.1, 2.43.4, 2.42.2, 2.41.1, 2.40.2, and 2.39.4.

CVE-2024-32465:
Git is a revision control system. The Git project recommends to avoid working in
untrusted repositories, and instead to clone it first with `git clone --no-local`
to obtain a clean copy. Git has specific protections to make that a safe
operation even with an untrusted source repository, but vulnerabilities allow
those protections to be bypassed. In the context of cloning local repositories
owned by other users, this vulnerability has been covered in CVE-2024-32004. But
there are circumstances where the fixes for CVE-2024-32004 are not enough: For
example, when obtaining a `.zip` file containing a full copy of a Git repository,
it should not be trusted by default to be safe, as e.g. hooks could be configured
to run within the context of that repository. The problem has been patched in
versions 2.45.1, 2.44.1, 2.43.4, 2.42.2, 2.41.1, 2.40.2, and 2.39.4. As a
workaround, avoid using Git in repositories that have been obtained via archives
from untrusted sources.

References:
https://nvd.nist.gov/vuln/detail/CVE-2024-32002
https://nvd.nist.gov/vuln/detail/CVE-2024-32004
https://nvd.nist.gov/vuln/detail/CVE-2024-32020
https://nvd.nist.gov/vuln/detail/CVE-2024-32021
https://nvd.nist.gov/vuln/detail/CVE-2024-32465

Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
 .../git/git/CVE-2024-32002-0001.patch         |  69 ++++++
 .../git/git/CVE-2024-32002-0002.patch         | 213 ++++++++++++++++++
 .../git/git/CVE-2024-32002-0003.patch         | 141 ++++++++++++
 .../git/git/CVE-2024-32002-0004.patch         | 150 ++++++++++++
 .../git/git/CVE-2024-32004-0001.patch         |  95 ++++++++
 .../git/git/CVE-2024-32004-0002.patch         | 187 +++++++++++++++
 .../git/git/CVE-2024-32004-0003.patch         | 158 +++++++++++++
 .../git/git/CVE-2024-32020.patch              | 114 ++++++++++
 .../git/git/CVE-2024-32021-0001.patch         |  89 ++++++++
 .../git/git/CVE-2024-32021-0002.patch         |  65 ++++++
 .../git/git/CVE-2024-32465.patch              | 206 +++++++++++++++++
 meta/recipes-devtools/git/git_2.35.7.bb       |  11 +
 12 files changed, 1498 insertions(+)
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32020.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch
 create mode 100644 meta/recipes-devtools/git/git/CVE-2024-32465.patch

diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch
new file mode 100644
index 0000000000..c424562e05
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0001.patch
@@ -0,0 +1,69 @@
+From 21496b4c60b2327417c63fc9762096037a185be3 Mon Sep 17 00:00:00 2001
+From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+Date: Thu, 1 Sep 2022 01:17:54 +0200
+Subject: [PATCH] submodule--helper: use xstrfmt() in clone_submodule()
+
+Use xstrfmt() in clone_submodule() instead of a "struct strbuf" in two
+cases where we weren't getting anything out of using the "struct
+strbuf".
+
+This changes code that was was added along with other uses of "struct
+strbuf" in this function in ee8838d1577 (submodule: rewrite
+`module_clone` shell function in C, 2015-09-08).
+
+Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+Reviewed-by: Glen Choo <chooglen@google.com>
+Signed-off-by: Junio C Hamano <gitster@pobox.com>
+
+CVE: CVE-2024-32002
+
+Upstream-Status: Backport [https://github.com/git/git/commit/21496b4c60b2327417c63fc9762096037a185be3]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ builtin/submodule--helper.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
+index c5d3fc3..79868c3 100644
+--- a/builtin/submodule--helper.c
++++ b/builtin/submodule--helper.c
+@@ -1761,12 +1761,11 @@ static int clone_submodule(struct module_clone_data *clone_data)
+	sm_gitdir = absolute_pathdup(sb.buf);
+	strbuf_reset(&sb);
+
+-	if (!is_absolute_path(clone_data->path)) {
+-		strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_data->path);
+-		clone_data->path = strbuf_detach(&sb, NULL);
+-	} else {
++	if (!is_absolute_path(clone_data->path))
++		clone_data->path = xstrfmt("%s/%s", get_git_work_tree(),
++					   clone_data->path);
++	else
+		clone_data->path = xstrdup(clone_data->path);
+-	}
+
+	if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
+		die(_("refusing to create/use '%s' in another submodule's "
+@@ -1813,14 +1812,16 @@ static int clone_submodule(struct module_clone_data *clone_data)
+			die(_("clone of '%s' into submodule path '%s' failed"),
+			    clone_data->url, clone_data->path);
+	} else {
++		char *path;
++
+		if (clone_data->require_init && !access(clone_data->path, X_OK) &&
+		    !is_empty_dir(clone_data->path))
+			die(_("directory not empty: '%s'"), clone_data->path);
+		if (safe_create_leading_directories_const(clone_data->path) < 0)
+			die(_("could not create directory '%s'"), clone_data->path);
+-		strbuf_addf(&sb, "%s/index", sm_gitdir);
+-		unlink_or_warn(sb.buf);
+-		strbuf_reset(&sb);
++		path = xstrfmt("%s/index", sm_gitdir);
++		unlink_or_warn(path);
++		free(path);
+	}
+
+	connect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch
new file mode 100644
index 0000000000..36cdb746a7
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0002.patch
@@ -0,0 +1,213 @@
+From 6fac5b2f352efc8c246d6d5be63a66b7b0fc0209 Mon Sep 17 00:00:00 2001
+From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+Date: Thu, 1 Sep 2022 01:17:56 +0200
+Subject: [PATCH] submodule--helper: add "const" to passed "module_clone_data"
+
+Add "const" to the "struct module_clone_data" that we pass to
+clone_submodule(), which makes the ownership clear, and stops us from
+clobbering the "clone_data->path".
+
+We still need to add to the "reference" member, which is a "struct
+string_list". Let's do this by having clone_submodule() create its
+own, and copy the contents over, allowing us to pass it as a
+separate parameter.
+
+This new "struct string_list" still leaks memory, just as the "struct
+module_clone_data" did before. let's not fix that for now, to fix that
+we'll need to add some "goto cleanup" to the relevant code. That will
+eventually be done in follow-up commits, this change makes it easier
+to fix the memory leak.
+
+The scope of the new "reference" variable in add_submodule() could be
+narrowed to the "else" block, but as we'll eventually free it with a
+"goto cleanup" let's declare it at the start of the function.
+
+Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+Reviewed-by: Glen Choo <chooglen@google.com>
+Signed-off-by: Junio C Hamano <gitster@pobox.com>
+
+CVE: CVE-2024-32002
+
+Upstream-Status: Backport [https://github.com/git/git/commit/6fac5b2f352efc8c246d6d5be63a66b7b0fc0209]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ builtin/submodule--helper.c | 52 ++++++++++++++++++++-----------------
+ 1 file changed, 28 insertions(+), 24 deletions(-)
+
+diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
+index 79868c3..d1d64db 100644
+--- a/builtin/submodule--helper.c
++++ b/builtin/submodule--helper.c
+@@ -1630,14 +1630,13 @@ struct module_clone_data {
+	const char *name;
+	const char *url;
+	const char *depth;
+-	struct string_list reference;
+	unsigned int quiet: 1;
+	unsigned int progress: 1;
+	unsigned int dissociate: 1;
+	unsigned int require_init: 1;
+	int single_branch;
+ };
+-#define MODULE_CLONE_DATA_INIT { .reference = STRING_LIST_INIT_NODUP, .single_branch = -1 }
++#define MODULE_CLONE_DATA_INIT { .single_branch = -1 }
+
+ struct submodule_alternate_setup {
+	const char *submodule_name;
+@@ -1750,22 +1749,24 @@ static void prepare_possible_alternates(const char *sm_name,
+	free(error_strategy);
+ }
+
+-static int clone_submodule(struct module_clone_data *clone_data)
++static int clone_submodule(const struct module_clone_data *clone_data,
++			   struct string_list *reference)
+ {
+	char *p, *sm_gitdir;
+	char *sm_alternate = NULL, *error_strategy = NULL;
+	struct strbuf sb = STRBUF_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
++	const char *clone_data_path;
+
+	submodule_name_to_gitdir(&sb, the_repository, clone_data->name);
+	sm_gitdir = absolute_pathdup(sb.buf);
+	strbuf_reset(&sb);
+
+	if (!is_absolute_path(clone_data->path))
+-		clone_data->path = xstrfmt("%s/%s", get_git_work_tree(),
+-					   clone_data->path);
++		clone_data_path = xstrfmt("%s/%s", get_git_work_tree(),
++					  clone_data->path);
+	else
+-		clone_data->path = xstrdup(clone_data->path);
++		clone_data_path = xstrdup(clone_data->path);
+
+	if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
+		die(_("refusing to create/use '%s' in another submodule's "
+@@ -1775,7 +1776,7 @@ static int clone_submodule(struct module_clone_data *clone_data)
+		if (safe_create_leading_directories_const(sm_gitdir) < 0)
+			die(_("could not create directory '%s'"), sm_gitdir);
+
+-		prepare_possible_alternates(clone_data->name, &clone_data->reference);
++		prepare_possible_alternates(clone_data->name, reference);
+
+		strvec_push(&cp.args, "clone");
+		strvec_push(&cp.args, "--no-checkout");
+@@ -1784,10 +1785,10 @@ static int clone_submodule(struct module_clone_data *clone_data)
+		if (clone_data->progress)
+			strvec_push(&cp.args, "--progress");
+		if (clone_data->depth && *(clone_data->depth))
+-			strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
+-		if (clone_data->reference.nr) {
++				strvec_pushl(&cp.args, "--depth", clone_data->depth, NULL);
++		if (reference->nr) {
+			struct string_list_item *item;
+-			for_each_string_list_item(item, &clone_data->reference)
++			for_each_string_list_item(item, reference)
+				strvec_pushl(&cp.args, "--reference",
+					     item->string, NULL);
+		}
+@@ -1802,7 +1803,7 @@ static int clone_submodule(struct module_clone_data *clone_data)
+
+		strvec_push(&cp.args, "--");
+		strvec_push(&cp.args, clone_data->url);
+-		strvec_push(&cp.args, clone_data->path);
++		strvec_push(&cp.args, clone_data_path);
+
+		cp.git_cmd = 1;
+		prepare_submodule_repo_env(&cp.env_array);
+@@ -1810,25 +1811,25 @@ static int clone_submodule(struct module_clone_data *clone_data)
+
+		if(run_command(&cp))
+			die(_("clone of '%s' into submodule path '%s' failed"),
+-			    clone_data->url, clone_data->path);
++			    clone_data->url, clone_data_path);
+	} else {
+		char *path;
+
+-		if (clone_data->require_init && !access(clone_data->path, X_OK) &&
+-		    !is_empty_dir(clone_data->path))
+-			die(_("directory not empty: '%s'"), clone_data->path);
+-		if (safe_create_leading_directories_const(clone_data->path) < 0)
+-			die(_("could not create directory '%s'"), clone_data->path);
++		if (clone_data->require_init && !access(clone_data_path, X_OK) &&
++		    !is_empty_dir(clone_data_path))
++			die(_("directory not empty: '%s'"), clone_data_path);
++		if (safe_create_leading_directories_const(clone_data_path) < 0)
++			die(_("could not create directory '%s'"), clone_data_path);
+		path = xstrfmt("%s/index", sm_gitdir);
+		unlink_or_warn(path);
+		free(path);
+	}
+
+-	connect_work_tree_and_git_dir(clone_data->path, sm_gitdir, 0);
++	connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);
+
+-	p = git_pathdup_submodule(clone_data->path, "config");
++	p = git_pathdup_submodule(clone_data_path, "config");
+	if (!p)
+-		die(_("could not get submodule directory for '%s'"), clone_data->path);
++		die(_("could not get submodule directory for '%s'"), clone_data_path);
+
+	/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
+	git_config_get_string("submodule.alternateLocation", &sm_alternate);
+@@ -1853,6 +1854,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
+ {
+	int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
+	struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
++	struct string_list reference = STRING_LIST_INIT_NODUP;
+
+	struct option module_clone_options[] = {
+		OPT_STRING(0, "prefix", &clone_data.prefix,
+@@ -1867,7 +1869,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
+		OPT_STRING(0, "url", &clone_data.url,
+			   N_("string"),
+			   N_("url where to clone the submodule from")),
+-		OPT_STRING_LIST(0, "reference", &clone_data.reference,
++		OPT_STRING_LIST(0, "reference", &reference,
+			   N_("repo"),
+			   N_("reference repository")),
+		OPT_BOOL(0, "dissociate", &dissociate,
+@@ -1905,7 +1907,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
+		usage_with_options(git_submodule_helper_usage,
+				   module_clone_options);
+
+-	clone_submodule(&clone_data);
++	clone_submodule(&clone_data, &reference);
+	return 0;
+ }
+
+@@ -3029,6 +3031,7 @@ static int add_submodule(const struct add_data *add_data)
+ {
+	char *submod_gitdir_path;
+	struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
++	struct string_list reference = STRING_LIST_INIT_NODUP;
+
+	/* perhaps the path already exists and is already a git repo, else clone it */
+	if (is_directory(add_data->sm_path)) {
+@@ -3045,6 +3048,7 @@ static int add_submodule(const struct add_data *add_data)
+		free(submod_gitdir_path);
+	} else {
+		struct child_process cp = CHILD_PROCESS_INIT;
++
+		submod_gitdir_path = xstrfmt(".git/modules/%s", add_data->sm_name);
+
+		if (is_directory(submod_gitdir_path)) {
+@@ -3084,13 +3088,13 @@ static int add_submodule(const struct add_data *add_data)
+		clone_data.quiet = add_data->quiet;
+		clone_data.progress = add_data->progress;
+		if (add_data->reference_path)
+-			string_list_append(&clone_data.reference,
++			string_list_append(&reference,
+					   xstrdup(add_data->reference_path));
+		clone_data.dissociate = add_data->dissociate;
+		if (add_data->depth >= 0)
+			clone_data.depth = xstrfmt("%d", add_data->depth);
+
+-		if (clone_submodule(&clone_data))
++		if (clone_submodule(&clone_data, &reference))
+			return -1;
+
+		prepare_submodule_repo_env(&cp.env_array);
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch
new file mode 100644
index 0000000000..bb5702e122
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0003.patch
@@ -0,0 +1,141 @@
+From e77b3da6bb60e9af5963c9e42442afe53af1780b Mon Sep 17 00:00:00 2001
+From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+Date: Thu, 1 Sep 2022 01:14:08 +0200
+Subject: [PATCH] submodule--helper: fix a leak in "clone_submodule"
+
+Fix a memory leak of the "clone_data_path" variable that we copy or
+derive from the "struct module_clone_data" in clone_submodule(). This
+code was refactored in preceding commits, but the leak has been with
+us since f8eaa0ba98b (submodule--helper, module_clone: always operate
+on absolute paths, 2016-03-31).
+
+For the "else" case we don't need to xstrdup() the "clone_data->path",
+and we don't need to free our own "clone_data_path". We can therefore
+assign the "clone_data->path" to our own "clone_data_path" right away,
+and only override it (and remember to free it!) if we need to
+xstrfmt() a replacement.
+
+In the case of the module_clone() caller it's from "argv", and doesn't
+need to be free'd, and in the case of the add_submodule() caller we
+get a pointer to "sm_path", which doesn't need to be directly free'd
+either.
+
+Fixing this leak makes several tests pass, so let's mark them as
+passing with TEST_PASSES_SANITIZE_LEAK=true.
+
+Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
+Reviewed-by: Glen Choo <chooglen@google.com>
+Signed-off-by: Junio C Hamano <gitster@pobox.com>
+
+CVE: CVE-2024-32002
+
+Upstream-Status: Backport [https://github.com/git/git/commit/e77b3da6bb60e9af5963c9e42442afe53af1780b]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ builtin/submodule--helper.c   | 10 +++++-----
+ t/t1500-rev-parse.sh          |  1 +
+ t/t6008-rev-list-submodule.sh |  1 +
+ t/t7414-submodule-mistakes.sh |  2 ++
+ t/t7506-status-submodule.sh   |  1 +
+ t/t7507-commit-verbose.sh     |  2 ++
+ 6 files changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
+index d1d64db..1158dcc 100644
+--- a/builtin/submodule--helper.c
++++ b/builtin/submodule--helper.c
+@@ -1756,17 +1756,16 @@ static int clone_submodule(const struct module_clone_data *clone_data,
+	char *sm_alternate = NULL, *error_strategy = NULL;
+	struct strbuf sb = STRBUF_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
+-	const char *clone_data_path;
++	const char *clone_data_path = clone_data->path;
++	char *to_free = NULL;;
+
+	submodule_name_to_gitdir(&sb, the_repository, clone_data->name);
+	sm_gitdir = absolute_pathdup(sb.buf);
+	strbuf_reset(&sb);
+
+	if (!is_absolute_path(clone_data->path))
+-		clone_data_path = xstrfmt("%s/%s", get_git_work_tree(),
+-					  clone_data->path);
+-	else
+-		clone_data_path = xstrdup(clone_data->path);
++		clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(),
++						    clone_data->path);
+
+	if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
+		die(_("refusing to create/use '%s' in another submodule's "
+@@ -1847,6 +1846,7 @@ static int clone_submodule(const struct module_clone_data *clone_data,
+	strbuf_release(&sb);
+	free(sm_gitdir);
+	free(p);
++	free(to_free);
+	return 0;
+ }
+
+diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
+index 2c429f9..81de584 100755
+--- a/t/t1500-rev-parse.sh
++++ b/t/t1500-rev-parse.sh
+@@ -4,6 +4,7 @@ test_description='test git rev-parse'
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
++TEST_PASSES_SANITIZE_LEAK=true
+ . ./test-lib.sh
+
+ test_one () {
+diff --git a/t/t6008-rev-list-submodule.sh b/t/t6008-rev-list-submodule.sh
+index a0a070b..2cdef6f 100755
+--- a/t/t6008-rev-list-submodule.sh
++++ b/t/t6008-rev-list-submodule.sh
+@@ -8,6 +8,7 @@ test_description='git rev-list involving submodules that this repo has'
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
++TEST_PASSES_SANITIZE_LEAK=true
+ . ./test-lib.sh
+
+ test_expect_success 'setup' '
+diff --git a/t/t7414-submodule-mistakes.sh b/t/t7414-submodule-mistakes.sh
+index cf95603..101afff 100755
+--- a/t/t7414-submodule-mistakes.sh
++++ b/t/t7414-submodule-mistakes.sh
+@@ -1,6 +1,8 @@
+ #!/bin/sh
+
+ test_description='handling of common mistakes people may make with submodules'
++
++TEST_PASSES_SANITIZE_LEAK=true
+ . ./test-lib.sh
+
+ test_expect_success 'create embedded repository' '
+diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
+index 459300c..d050091 100755
+--- a/t/t7506-status-submodule.sh
++++ b/t/t7506-status-submodule.sh
+@@ -2,6 +2,7 @@
+
+ test_description='git status for submodule'
+
++TEST_PASSES_SANITIZE_LEAK=true
+ . ./test-lib.sh
+
+ test_create_repo_with_commit () {
+diff --git a/t/t7507-commit-verbose.sh b/t/t7507-commit-verbose.sh
+index bd0ae4b..916470c 100755
+--- a/t/t7507-commit-verbose.sh
++++ b/t/t7507-commit-verbose.sh
+@@ -1,6 +1,8 @@
+ #!/bin/sh
+
+ test_description='verbose commit template'
++
++TEST_PASSES_SANITIZE_LEAK=true
+ . ./test-lib.sh
+
+ write_script "check-for-diff" <<\EOF &&
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch b/meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch
new file mode 100644
index 0000000000..f2af2b48de
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32002-0004.patch
@@ -0,0 +1,150 @@
+From 97065761333fd62db1912d81b489db938d8c991d Mon Sep 17 00:00:00 2001
+From: Johannes Schindelin <johannes.schindelin@gmx.de>
+Date: Fri, 22 Mar 2024 11:19:22 +0100
+Subject: [PATCH] submodules: submodule paths must not contain symlinks
+
+When creating a submodule path, we must be careful not to follow
+symbolic links. Otherwise we may follow a symbolic link pointing to
+a gitdir (which are valid symbolic links!) e.g. while cloning.
+
+On case-insensitive filesystems, however, we blindly replace a directory
+that has been created as part of the `clone` operation with a symlink
+when the path to the latter differs only in case from the former's path.
+
+Let's simply avoid this situation by expecting not ever having to
+overwrite any existing file/directory/symlink upon cloning. That way, we
+won't even replace a directory that we just created.
+
+This addresses CVE-2024-32002.
+
+Reported-by: Filip Hejsek <filip.hejsek@gmail.com>
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+
+CVE: CVE-2024-32002
+
+Upstream-Status: Backport [https://github.com/git/git/commit/97065761333fd62db1912d81b489db938d8c991d]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ builtin/submodule--helper.c | 35 +++++++++++++++++++++++++++++++
+ t/t7406-submodule-update.sh | 42 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 77 insertions(+)
+
+diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
+index 1158dcc..d4147d8 100644
+--- a/builtin/submodule--helper.c
++++ b/builtin/submodule--helper.c
+@@ -1749,11 +1749,34 @@ static void prepare_possible_alternates(const char *sm_name,
+	free(error_strategy);
+ }
+
++static int dir_contains_only_dotgit(const char *path)
++{
++	DIR *dir = opendir(path);
++	struct dirent *e;
++	int ret = 1;
++
++	if (!dir)
++		return 0;
++
++	e = readdir_skip_dot_and_dotdot(dir);
++	if (!e)
++		ret = 0;
++	else if (strcmp(DEFAULT_GIT_DIR_ENVIRONMENT, e->d_name) ||
++		 (e = readdir_skip_dot_and_dotdot(dir))) {
++		error("unexpected item '%s' in '%s'", e->d_name, path);
++		ret = 0;
++	}
++
++	closedir(dir);
++	return ret;
++}
++
+ static int clone_submodule(const struct module_clone_data *clone_data,
+			   struct string_list *reference)
+ {
+	char *p, *sm_gitdir;
+	char *sm_alternate = NULL, *error_strategy = NULL;
++	struct stat st;
+	struct strbuf sb = STRBUF_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	const char *clone_data_path = clone_data->path;
+@@ -1772,6 +1795,10 @@ static int clone_submodule(const struct module_clone_data *clone_data,
+		      "git dir"), sm_gitdir);
+
+	if (!file_exists(sm_gitdir)) {
++		if (clone_data->require_init && !stat(clone_data_path, &st) &&
++		    !is_empty_dir(clone_data_path))
++			die(_("directory not empty: '%s'"), clone_data_path);
++
+		if (safe_create_leading_directories_const(sm_gitdir) < 0)
+			die(_("could not create directory '%s'"), sm_gitdir);
+
+@@ -1811,6 +1838,14 @@ static int clone_submodule(const struct module_clone_data *clone_data,
+		if(run_command(&cp))
+			die(_("clone of '%s' into submodule path '%s' failed"),
+			    clone_data->url, clone_data_path);
++
++		if (clone_data->require_init && !stat(clone_data_path, &st) &&
++		    !dir_contains_only_dotgit(clone_data_path)) {
++			char *dot_git = xstrfmt("%s/.git", clone_data_path);
++			unlink(dot_git);
++			free(dot_git);
++			die(_("directory not empty: '%s'"), clone_data_path);
++		}
+	} else {
+		char *path;
+
+diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
+index 53d419c..00ffdb6 100755
+--- a/t/t7406-submodule-update.sh
++++ b/t/t7406-submodule-update.sh
+@@ -1062,4 +1062,46 @@ test_expect_success 'submodule update --quiet passes quietness to fetch with a s
+	)
+ '
+
++test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \
++	'submodule paths must not follow symlinks' '
++	# This is only needed because we want to run this in a self-contained
++	# test without having to spin up an HTTP server; However, it would not
++	# be needed in a real-world scenario where the submodule is simply
++	# hosted on a public site.
++	test_config_global protocol.file.allow always &&
++	# Make sure that Git tries to use symlinks on Windows
++	test_config_global core.symlinks true &&
++	tell_tale_path="$PWD/tell.tale" &&
++	git init hook &&
++	(
++		cd hook &&
++		mkdir -p y/hooks &&
++		write_script y/hooks/post-checkout <<-EOF &&
++		echo HOOK-RUN >&2
++		echo hook-run >"$tell_tale_path"
++		EOF
++		git add y/hooks/post-checkout &&
++		test_tick &&
++		git commit -m post-checkout
++	) &&
++	hook_repo_path="$(pwd)/hook" &&
++	git init captain &&
++	(
++		cd captain &&
++		git submodule add --name x/y "$hook_repo_path" A/modules/x &&
++		test_tick &&
++		git commit -m add-submodule &&
++		printf .git >dotgit.txt &&
++		git hash-object -w --stdin <dotgit.txt >dot-git.hash &&
++		printf "120000 %s 0\ta\n" "$(cat dot-git.hash)" >index.info &&
++		git update-index --index-info <index.info &&
++		test_tick &&
++		git commit -m add-symlink
++	) &&
++	test_path_is_missing "$tell_tale_path" &&
++	test_must_fail git clone --recursive captain hooked 2>err &&
++	grep "directory not empty" err &&
++	test_path_is_missing "$tell_tale_path"
++'
++
+ test_done
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch b/meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch
new file mode 100644
index 0000000000..410f3bc5e1
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32004-0001.patch
@@ -0,0 +1,95 @@
+From 5c5a4a1c05932378d259b1fdd9526cab971656a2 Mon Sep 17 00:00:00 2001
+From: Filip Hejsek <filip.hejsek@gmail.com>
+Date: Sun, 28 Jan 2024 04:29:33 +0100
+Subject: [PATCH] t0411: add tests for cloning from partial repo
+
+Cloning from a partial repository must not fetch missing objects into
+the partial repository, because that can lead to arbitrary code
+execution.
+
+Add a couple of test cases, pretending to the `upload-pack` command (and
+to that command only) that it is working on a repository owned by
+someone else.
+
+Helped-by: Jeff King <peff@peff.net>
+Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com>
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+
+CVE: CVE-2024-32004
+
+Upstream-Status: Backport [https://github.com/git/git/commit/5c5a4a1c05932378d259b1fdd9526cab971656a2]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ t/t0411-clone-from-partial.sh | 60 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 60 insertions(+)
+ create mode 100755 t/t0411-clone-from-partial.sh
+
+diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
+new file mode 100755
+index 0000000..fb72a0a
+--- /dev/null
++++ b/t/t0411-clone-from-partial.sh
+@@ -0,0 +1,60 @@
++#!/bin/sh
++
++test_description='check that local clone does not fetch from promisor remotes'
++
++. ./test-lib.sh
++
++test_expect_success 'create evil repo' '
++	git init tmp &&
++	test_commit -C tmp a &&
++	git -C tmp config uploadpack.allowfilter 1 &&
++	git clone --filter=blob:none --no-local --no-checkout tmp evil &&
++	rm -rf tmp &&
++
++	git -C evil config remote.origin.uploadpack \"\$TRASH_DIRECTORY/fake-upload-pack\" &&
++	write_script fake-upload-pack <<-\EOF &&
++		echo >&2 "fake-upload-pack running"
++		>"$TRASH_DIRECTORY/script-executed"
++		exit 1
++	EOF
++	export TRASH_DIRECTORY &&
++
++	# empty shallow file disables local clone optimization
++	>evil/.git/shallow
++'
++
++test_expect_failure 'local clone must not fetch from promisor remote and execute script' '
++	rm -f script-executed &&
++	test_must_fail git clone \
++		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
++		evil clone1 2>err &&
++	! grep "fake-upload-pack running" err &&
++	test_path_is_missing script-executed
++'
++
++test_expect_failure 'clone from file://... must not fetch from promisor remote and execute script' '
++	rm -f script-executed &&
++	test_must_fail git clone \
++		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
++		"file://$(pwd)/evil" clone2 2>err &&
++	! grep "fake-upload-pack running" err &&
++	test_path_is_missing script-executed
++'
++
++test_expect_failure 'fetch from file://... must not fetch from promisor remote and execute script' '
++	rm -f script-executed &&
++	test_must_fail git fetch \
++		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
++		"file://$(pwd)/evil" 2>err &&
++	! grep "fake-upload-pack running" err &&
++	test_path_is_missing script-executed
++'
++
++test_expect_success 'pack-objects should fetch from promisor remote and execute script' '
++	rm -f script-executed &&
++	echo "HEAD" | test_must_fail git -C evil pack-objects --revs --stdout >/dev/null 2>err &&
++	grep "fake-upload-pack running" err &&
++	test_path_is_file script-executed
++'
++
++test_done
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch b/meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch
new file mode 100644
index 0000000000..1727f81950
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32004-0002.patch
@@ -0,0 +1,187 @@
+From 17d3883fe9c88b823002ad9fafb42313ddc3d3d5 Mon Sep 17 00:00:00 2001
+From: Johannes Schindelin <johannes.schindelin@gmx.de>
+Date: Mon, 8 Aug 2022 13:27:47 +0000
+Subject: [PATCH] setup: prepare for more detailed "dubious ownership" messages
+
+When verifying the ownership of the Git directory, we sometimes would
+like to say a bit more about it, e.g. when using a platform-dependent
+code path (think: Windows has the permission model that is so different
+from Unix'), but only when it is a appropriate to actually say
+something.
+
+To allow for that, collect that information and hand it back to the
+caller (whose responsibility it is to show it or not).
+
+Note: We do not actually fill in any platform-dependent information yet,
+this commit just adds the infrastructure to be able to do so.
+
+Based-on-an-idea-by: Junio C Hamano <gitster@pobox.com>
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+Signed-off-by: Junio C Hamano <gitster@pobox.com>
+
+CVE: CVE-2024-32004
+
+Upstream-Status: Backport [https://github.com/git/git/commit/17d3883fe9c88b823002ad9fafb42313ddc3d3d5]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ compat/mingw.c    |  2 +-
+ compat/mingw.h    |  2 +-
+ git-compat-util.h |  5 ++++-
+ setup.c           | 25 +++++++++++++++----------
+ 4 files changed, 21 insertions(+), 13 deletions(-)
+
+diff --git a/compat/mingw.c b/compat/mingw.c
+index 41fc163..9306a0e 100644
+--- a/compat/mingw.c
++++ b/compat/mingw.c
+@@ -2658,7 +2658,7 @@ static PSID get_current_user_sid(void)
+	return result;
+ }
+
+-int is_path_owned_by_current_sid(const char *path)
++int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
+ {
+	WCHAR wpath[MAX_PATH];
+	PSID sid = NULL;
+diff --git a/compat/mingw.h b/compat/mingw.h
+index ffa53a4..a1a69c5 100644
+--- a/compat/mingw.h
++++ b/compat/mingw.h
+@@ -457,7 +457,7 @@ char *mingw_query_user_email(void);
+  * Verifies that the specified path is owned by the user running the
+  * current process.
+  */
+-int is_path_owned_by_current_sid(const char *path);
++int is_path_owned_by_current_sid(const char *path, struct strbuf *report);
+ #define is_path_owned_by_current_user is_path_owned_by_current_sid
+
+ /**
+diff --git a/git-compat-util.h b/git-compat-util.h
+index 1c651c8..27b84b8 100644
+--- a/git-compat-util.h
++++ b/git-compat-util.h
+@@ -23,6 +23,9 @@
+ #include <crtdbg.h>
+ #endif
+
++struct strbuf;
++
++
+ #define _FILE_OFFSET_BITS 64
+
+
+@@ -475,7 +478,7 @@ static inline void extract_id_from_env(const char *env, uid_t *id)
+	}
+ }
+
+-static inline int is_path_owned_by_current_uid(const char *path)
++static inline int is_path_owned_by_current_uid(const char *path, struct strbuf *report)
+ {
+	struct stat st;
+	uid_t euid;
+diff --git a/setup.c b/setup.c
+index 8686ffe..1ad7330 100644
+--- a/setup.c
++++ b/setup.c
+@@ -1128,16 +1128,17 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
+  * added, for bare ones their git directory.
+  */
+ static int ensure_valid_ownership(const char *gitfile,
+-				const char *worktree, const char *gitdir)
++				  const char *worktree, const char *gitdir,
++				  struct strbuf *report)
+ {
+	struct safe_directory_data data = {
+		.path = worktree ? worktree : gitdir
+	};
+
+	if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
+-	   (!gitfile || is_path_owned_by_current_user(gitfile)) &&
+-	   (!worktree || is_path_owned_by_current_user(worktree)) &&
+-	   (!gitdir || is_path_owned_by_current_user(gitdir)))
++	    (!gitfile || is_path_owned_by_current_user(gitfile, report)) &&
++	    (!worktree || is_path_owned_by_current_user(worktree, report)) &&
++	    (!gitdir || is_path_owned_by_current_user(gitdir, report)))
+		return 1;
+
+	/*
+@@ -1177,6 +1178,7 @@ enum discovery_result {
+  */
+ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
+							  struct strbuf *gitdir,
++							  struct strbuf *report,
+							  int die_on_error)
+ {
+	const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
+@@ -1264,7 +1266,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
+
+			if (ensure_valid_ownership(gitfile,
+						 dir->buf,
+-				 (gitdir_path ? gitdir_path : gitdirenv))) {
++				 (gitdir_path ? gitdir_path : gitdirenv), report)) {
+				strbuf_addstr(gitdir, gitdirenv);
+				ret = GIT_DIR_DISCOVERED;
+			} else
+@@ -1287,7 +1289,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
+		}
+
+		if (is_git_directory(dir->buf)) {
+-			if (!ensure_valid_ownership(NULL, NULL, dir->buf))
++			if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
+				return GIT_DIR_INVALID_OWNERSHIP;
+			strbuf_addstr(gitdir, ".");
+			return GIT_DIR_BARE;
+@@ -1320,7 +1322,7 @@ int discover_git_directory(struct strbuf *commondir,
+		return -1;
+
+	cwd_len = dir.len;
+-	if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
++	if (setup_git_directory_gently_1(&dir, gitdir, NULL, 0) <= 0) {
+		strbuf_release(&dir);
+		return -1;
+	}
+@@ -1367,7 +1369,7 @@ int discover_git_directory(struct strbuf *commondir,
+ const char *setup_git_directory_gently(int *nongit_ok)
+ {
+	static struct strbuf cwd = STRBUF_INIT;
+-	struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
++	struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT, report = STRBUF_INIT;
+	const char *prefix = NULL;
+	struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
+
+@@ -1392,7 +1394,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
+		die_errno(_("Unable to read current working directory"));
+	strbuf_addbuf(&dir, &cwd);
+
+-	switch (setup_git_directory_gently_1(&dir, &gitdir, 1)) {
++	switch (setup_git_directory_gently_1(&dir, &gitdir, &report, 1)) {
+	case GIT_DIR_EXPLICIT:
+		prefix = setup_explicit_git_dir(gitdir.buf, &cwd, &repo_fmt, nongit_ok);
+		break;
+@@ -1424,12 +1426,14 @@ const char *setup_git_directory_gently(int *nongit_ok)
+		if (!nongit_ok) {
+			struct strbuf quoted = STRBUF_INIT;
+
++			strbuf_complete(&report, '\n');
+			sq_quote_buf_pretty(&quoted, dir.buf);
+			die(_("detected dubious ownership in repository at '%s'\n"
++			      "%s"
+			      "To add an exception for this directory, call:\n"
+			      "\n"
+			      "\tgit config --global --add safe.directory %s"),
+-			    dir.buf, quoted.buf);
++			    dir.buf, report.buf, quoted.buf);
+		}
+		*nongit_ok = 1;
+		break;
+@@ -1508,6 +1512,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
+
+	strbuf_release(&dir);
+	strbuf_release(&gitdir);
++	strbuf_release(&report);
+	clear_repository_format(&repo_fmt);
+
+	return prefix;
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch b/meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch
new file mode 100644
index 0000000000..08ca1e596d
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32004-0003.patch
@@ -0,0 +1,158 @@
+From f4aa8c8bb11dae6e769cd930565173808cbb69c8 Mon Sep 17 00:00:00 2001
+From: Johannes Schindelin <johannes.schindelin@gmx.de>
+Date: Wed, 10 Apr 2024 14:39:37 +0200
+Subject: [PATCH] fetch/clone: detect dubious ownership of local repositories
+
+When cloning from somebody else's repositories, it is possible that,
+say, the `upload-pack` command is overridden in the repository that is
+about to be cloned, which would then be run in the user's context who
+started the clone.
+
+To remind the user that this is a potentially unsafe operation, let's
+extend the ownership checks we have already established for regular
+gitdir discovery to extend also to local repositories that are about to
+be cloned.
+
+This protection extends also to file:// URLs.
+
+The fixes in this commit address CVE-2024-32004.
+
+Note: This commit does not touch the `fetch`/`clone` code directly, but
+instead the function used implicitly by both: `enter_repo()`. This
+function is also used by `git receive-pack` (i.e. pushes), by `git
+upload-archive`, by `git daemon` and by `git http-backend`. In setups
+that want to serve repositories owned by different users than the
+account running the service, this will require `safe.*` settings to be
+configured accordingly.
+
+Also note: there are tiny time windows where a time-of-check-time-of-use
+("TOCTOU") race is possible. The real solution to those would be to work
+with `fstat()` and `openat()`. However, the latter function is not
+available on Windows (and would have to be emulated with rather
+expensive low-level `NtCreateFile()` calls), and the changes would be
+quite extensive, for my taste too extensive for the little gain given
+that embargoed releases need to pay extra attention to avoid introducing
+inadvertent bugs.
+
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+
+CVE: CVE-2024-32004
+
+Upstream-Status: Backport [https://github.com/git/git/commit/f4aa8c8bb11dae6e769cd930565173808cbb69c8]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ cache.h                       | 12 ++++++++++++
+ path.c                        |  2 ++
+ setup.c                       | 21 +++++++++++++++++++++
+ t/t0411-clone-from-partial.sh |  6 +++---
+ 4 files changed, 38 insertions(+), 3 deletions(-)
+
+diff --git a/cache.h b/cache.h
+index 281f00a..a59bdbe 100644
+--- a/cache.h
++++ b/cache.h
+@@ -615,6 +615,18 @@ void set_git_work_tree(const char *tree);
+
+ #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
+
++/*
++ * Check if a repository is safe and die if it is not, by verifying the
++ * ownership of the worktree (if any), the git directory, and the gitfile (if
++ * any).
++ *
++ * Exemptions for known-safe repositories can be added via `safe.directory`
++ * config settings; for non-bare repositories, their worktree needs to be
++ * added, for bare ones their git directory.
++ */
++void die_upon_dubious_ownership(const char *gitfile, const char *worktree,
++				const char *gitdir);
++
+ void setup_work_tree(void);
+ /*
+  * Find the commondir and gitdir of the repository that contains the current
+diff --git a/path.c b/path.c
+index d73146b..ae1fb01 100644
+--- a/path.c
++++ b/path.c
+@@ -840,6 +840,7 @@ const char *enter_repo(const char *path, int strict)
+		if (!suffix[i])
+			return NULL;
+		gitfile = read_gitfile(used_path.buf);
++		die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
+		if (gitfile) {
+			strbuf_reset(&used_path);
+			strbuf_addstr(&used_path, gitfile);
+@@ -850,6 +851,7 @@ const char *enter_repo(const char *path, int strict)
+	}
+	else {
+		const char *gitfile = read_gitfile(path);
++		die_upon_dubious_ownership(gitfile, NULL, path);
+		if (gitfile)
+			path = gitfile;
+		if (chdir(path))
+diff --git a/setup.c b/setup.c
+index 1ad7330..475c92e 100644
+--- a/setup.c
++++ b/setup.c
+@@ -1151,6 +1151,27 @@ static int ensure_valid_ownership(const char *gitfile,
+	return data.is_safe;
+ }
+
++void die_upon_dubious_ownership(const char *gitfile, const char *worktree,
++				const char *gitdir)
++{
++	struct strbuf report = STRBUF_INIT, quoted = STRBUF_INIT;
++	const char *path;
++
++	if (ensure_valid_ownership(gitfile, worktree, gitdir, &report))
++		return;
++
++	strbuf_complete(&report, '\n');
++	path = gitfile ? gitfile : gitdir;
++	sq_quote_buf_pretty(&quoted, path);
++
++	die(_("detected dubious ownership in repository at '%s'\n"
++	      "%s"
++	      "To add an exception for this directory, call:\n"
++	      "\n"
++	      "\tgit config --global --add safe.directory %s"),
++	    path, report.buf, quoted.buf);
++}
++
+ enum discovery_result {
+	GIT_DIR_NONE = 0,
+	GIT_DIR_EXPLICIT,
+diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
+index fb72a0a..eb3360d 100755
+--- a/t/t0411-clone-from-partial.sh
++++ b/t/t0411-clone-from-partial.sh
+@@ -23,7 +23,7 @@ test_expect_success 'create evil repo' '
+	>evil/.git/shallow
+ '
+
+-test_expect_failure 'local clone must not fetch from promisor remote and execute script' '
++test_expect_success 'local clone must not fetch from promisor remote and execute script' '
+	rm -f script-executed &&
+	test_must_fail git clone \
+		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+@@ -32,7 +32,7 @@ test_expect_failure 'local clone must not fetch from promisor remote and execute
+	test_path_is_missing script-executed
+ '
+
+-test_expect_failure 'clone from file://... must not fetch from promisor remote and execute script' '
++test_expect_success 'clone from file://... must not fetch from promisor remote and execute script' '
+	rm -f script-executed &&
+	test_must_fail git clone \
+		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+@@ -41,7 +41,7 @@ test_expect_failure 'clone from file://... must not fetch from promisor remote a
+	test_path_is_missing script-executed
+ '
+
+-test_expect_failure 'fetch from file://... must not fetch from promisor remote and execute script' '
++test_expect_success 'fetch from file://... must not fetch from promisor remote and execute script' '
+	rm -f script-executed &&
+	test_must_fail git fetch \
+		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32020.patch b/meta/recipes-devtools/git/git/CVE-2024-32020.patch
new file mode 100644
index 0000000000..4dfe742ff7
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32020.patch
@@ -0,0 +1,114 @@
+From 1204e1a824c34071019fe106348eaa6d88f9528d Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Mon, 15 Apr 2024 13:30:41 +0200
+Subject: [PATCH]  builtin/clone: refuse local clones of unsafe repositories
+
+When performing a local clone of a repository we end up either copying
+or hardlinking the source repository into the target repository. This is
+significantly more performant than if we were to use git-upload-pack(1)
+and git-fetch-pack(1) to create the new repository and preserves both
+disk space and compute time.
+
+Unfortunately though, performing such a local clone of a repository that
+is not owned by the current user is inherently unsafe:
+
+  - It is possible that source files get swapped out underneath us while
+    we are copying or hardlinking them. While we do perform some checks
+    here to assert that we hardlinked the expected file, they cannot
+    reliably thwart time-of-check-time-of-use (TOCTOU) style races. It
+    is thus possible for an adversary to make us copy or hardlink
+    unexpected files into the target directory.
+
+    Ideally, we would address this by starting to use openat(3P),
+    fstatat(3P) and friends. Due to platform compatibility with Windows
+    we cannot easily do that though. Furthermore, the scope of these
+    fixes would likely be quite broad and thus not fit for an embargoed
+    security release.
+
+  - Even if we handled TOCTOU-style races perfectly, hardlinking files
+    owned by a different user into the target repository is not a good
+    idea in general. It is possible for an adversary to rewrite those
+    files to contain whatever data they want even after the clone has
+    completed.
+
+Address these issues by completely refusing local clones of a repository
+that is not owned by the current user. This reuses our existing infra we
+have in place via `ensure_valid_ownership()` and thus allows a user to
+override the safety guard by adding the source repository path to the
+"safe.directory" configuration.
+
+This addresses CVE-2024-32020.
+
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+
+CVE: CVE-2024-32020
+
+Upstream-Status: Backport [https://github.com/git/git/commit/1204e1a824c34071019fe106348eaa6d88f9528d]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ builtin/clone.c           | 14 ++++++++++++++
+ t/t0033-safe-directory.sh | 24 ++++++++++++++++++++++++
+ 2 files changed, 38 insertions(+)
+
+diff --git a/builtin/clone.c b/builtin/clone.c
+index 4541a55..11f6b4b 100644
+--- a/builtin/clone.c
++++ b/builtin/clone.c
+@@ -312,6 +312,20 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+	int iter_status;
+	struct strbuf realpath = STRBUF_INIT;
+
++	/*
++	 * Refuse copying directories by default which aren't owned by us. The
++	 * code that performs either the copying or hardlinking is not prepared
++	 * to handle various edge cases where an adversary may for example
++	 * racily swap out files for symlinks. This can cause us to
++	 * inadvertently use the wrong source file.
++	 *
++	 * Furthermore, even if we were prepared to handle such races safely,
++	 * creating hardlinks across user boundaries is an inherently unsafe
++	 * operation as the hardlinked files can be rewritten at will by the
++	 * potentially-untrusted user. We thus refuse to do so by default.
++	 */
++	die_upon_dubious_ownership(NULL, NULL, src_repo);
++
+	mkdir_if_missing(dest->buf, 0777);
+
+	iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
+diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
+index 239d93f..751cba5 100755
+--- a/t/t0033-safe-directory.sh
++++ b/t/t0033-safe-directory.sh
+@@ -46,4 +46,28 @@ test_expect_success 'safe.directory=*, but is reset' '
+	expect_rejected_dir
+ '
+
++test_expect_success 'local clone of unowned repo refused in unsafe directory' '
++	test_when_finished "rm -rf source" &&
++	git init source &&
++	(
++		sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
++		test_commit -C source initial
++	) &&
++	test_must_fail git clone --local source target &&
++	test_path_is_missing target
++'
++
++test_expect_success 'local clone of unowned repo accepted in safe directory' '
++	test_when_finished "rm -rf source" &&
++	git init source &&
++	(
++		sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
++		test_commit -C source initial
++	) &&
++	test_must_fail git clone --local source target &&
++	git config --global --add safe.directory "$(pwd)/source/.git" &&
++	git clone --local source target &&
++	test_path_is_dir target
++'
++
+ test_done
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch b/meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch
new file mode 100644
index 0000000000..cc33c54faa
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32021-0001.patch
@@ -0,0 +1,89 @@
+From 150e6b0aedf57d224c3c49038c306477fa159886 Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Mon, 15 Apr 2024 13:30:26 +0200
+Subject: [PATCH] builtin/clone: stop resolving symlinks when copying files
+
+When a user performs a local clone without `--no-local`, then we end up
+copying the source repository into the target repository directly. To
+optimize this even further, we try to hardlink files into place instead
+of copying data over, which helps both disk usage and speed.
+
+There is an important edge case in this context though, namely when we
+try to hardlink symlinks from the source repository into the target
+repository. Depending on both platform and filesystem the resulting
+behaviour here can be different:
+
+  - On macOS and NetBSD, calling link(3P) with a symlink target creates
+    a hardlink to the file pointed to by the symlink.
+
+  - On Linux, calling link(3P) instead creates a hardlink to the symlink
+    itself.
+
+To unify this behaviour, 36596fd2df (clone: better handle symlinked
+files at .git/objects/, 2019-07-10) introduced logic to resolve symlinks
+before we try to link(3P) files. Consequently, the new behaviour was to
+always create a hard link to the target of the symlink on all platforms.
+
+Eventually though, we figured out that following symlinks like this can
+cause havoc when performing a local clone of a malicious repository,
+which resulted in CVE-2022-39253. This issue was fixed via 6f054f9fb3
+(builtin/clone.c: disallow `--local` clones with symlinks, 2022-07-28),
+by refusing symlinks in the source repository.
+
+But even though we now shouldn't ever link symlinks anymore, the code
+that resolves symlinks still exists. In the best case the code does not
+end up doing anything because there are no symlinks anymore. In the
+worst case though this can be abused by an adversary that rewrites the
+source file after it has been checked not to be a symlink such that it
+actually is a symlink when we call link(3P). Thus, it is still possible
+to recreate CVE-2022-39253 due to this time-of-check-time-of-use bug.
+
+Remove the call to `realpath()`. This doesn't yet address the actual
+vulnerability, which will be handled in a subsequent commit.
+
+Reported-by: Apple Product Security <product-security@apple.com>
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+
+CVE: CVE-2024-32021
+
+Upstream-Status: Backport [https://github.com/git/git/commit/150e6b0aedf57d224c3c49038c306477fa159886]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ builtin/clone.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/builtin/clone.c b/builtin/clone.c
+index 11f6b4b..2778d20 100644
+--- a/builtin/clone.c
++++ b/builtin/clone.c
+@@ -310,7 +310,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+	int src_len, dest_len;
+	struct dir_iterator *iter;
+	int iter_status;
+-	struct strbuf realpath = STRBUF_INIT;
+
+	/*
+	 * Refuse copying directories by default which aren't owned by us. The
+@@ -362,8 +361,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+		if (unlink(dest->buf) && errno != ENOENT)
+			die_errno(_("failed to unlink '%s'"), dest->buf);
+		if (!option_no_hardlinks) {
+-			strbuf_realpath(&realpath, src->buf, 1);
+-			if (!link(realpath.buf, dest->buf))
++			if (!link(src->buf, dest->buf))
+				continue;
+			if (option_local > 0)
+				die_errno(_("failed to create link '%s'"), dest->buf);
+@@ -377,8 +375,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+		strbuf_setlen(src, src_len);
+		die(_("failed to iterate over '%s'"), src->buf);
+	}
+-
+-	strbuf_release(&realpath);
+ }
+
+ static void clone_local(const char *src_repo, const char *dest_repo)
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch b/meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch
new file mode 100644
index 0000000000..2151d3d0ea
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32021-0002.patch
@@ -0,0 +1,65 @@
+From d1bb66a546b4bb46005d17ba711caaad26f26c1e Mon Sep 17 00:00:00 2001
+From: Patrick Steinhardt <ps@pks.im>
+Date: Mon, 15 Apr 2024 13:30:31 +0200
+Subject: [PATCH] builtin/clone: abort when hardlinked source and target file
+ differ
+
+When performing local clones with hardlinks we refuse to copy source
+files which are symlinks as a mitigation for CVE-2022-39253. This check
+can be raced by an adversary though by changing the file to a symlink
+after we have checked it.
+
+Fix the issue by checking whether the hardlinked destination file
+matches the source file and abort in case it doesn't.
+
+This addresses CVE-2024-32021.
+
+Reported-by: Apple Product Security <product-security@apple.com>
+Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
+Signed-off-by: Patrick Steinhardt <ps@pks.im>
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+
+CVE: CVE-2024-32021
+
+Upstream-Status: Backport [https://github.com/git/git/commit/d1bb66a546b4bb46005d17ba711caaad26f26c1e]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ builtin/clone.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/builtin/clone.c b/builtin/clone.c
+index 2778d20..54eb441 100644
+--- a/builtin/clone.c
++++ b/builtin/clone.c
+@@ -361,8 +361,27 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+		if (unlink(dest->buf) && errno != ENOENT)
+			die_errno(_("failed to unlink '%s'"), dest->buf);
+		if (!option_no_hardlinks) {
+-			if (!link(src->buf, dest->buf))
++			if (!link(src->buf, dest->buf)) {
++				struct stat st;
++
++				/*
++				 * Sanity-check whether the created hardlink
++				 * actually links to the expected file now. This
++				 * catches time-of-check-time-of-use bugs in
++				 * case the source file was meanwhile swapped.
++				 */
++				if (lstat(dest->buf, &st))
++					die(_("hardlink cannot be checked at '%s'"), dest->buf);
++				if (st.st_mode != iter->st.st_mode ||
++				    st.st_ino != iter->st.st_ino ||
++				    st.st_dev != iter->st.st_dev ||
++				    st.st_size != iter->st.st_size ||
++				    st.st_uid != iter->st.st_uid ||
++				    st.st_gid != iter->st.st_gid)
++					die(_("hardlink different from source at '%s'"), dest->buf);
++
+				continue;
++			}
+			if (option_local > 0)
+				die_errno(_("failed to create link '%s'"), dest->buf);
+			option_no_hardlinks = 1;
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git/CVE-2024-32465.patch b/meta/recipes-devtools/git/git/CVE-2024-32465.patch
new file mode 100644
index 0000000000..f9e2c1dc5f
--- /dev/null
+++ b/meta/recipes-devtools/git/git/CVE-2024-32465.patch
@@ -0,0 +1,206 @@
+From 7b70e9efb18c2cc3f219af399bd384c5801ba1d7 Mon Sep 17 00:00:00 2001
+From: Jeff King <peff@peff.net>
+Date: Tue, 16 Apr 2024 04:35:33 -0400
+Subject: [PATCH] upload-pack: disable lazy-fetching by default
+
+The upload-pack command tries to avoid trusting the repository in which
+it's run (e.g., by not running any hooks and not using any config that
+contains arbitrary commands). But if the server side of a fetch or a
+clone is a partial clone, then either upload-pack or its child
+pack-objects may run a lazy "git fetch" under the hood. And it is very
+easy to convince fetch to run arbitrary commands.
+
+The "server" side can be a local repository owned by someone else, who
+would be able to configure commands that are run during a clone with the
+current user's permissions. This issue has been designated
+CVE-2024-32004.
+
+The fix in this commit's parent helps in this scenario, as well as in
+related scenarios using SSH to clone, where the untrusted .git directory
+is owned by a different user id. But if you received one as a zip file,
+on a USB stick, etc, it may be owned by your user but still untrusted.
+
+This has been designated CVE-2024-32465.
+
+To mitigate the issue more completely, let's disable lazy fetching
+entirely during `upload-pack`. While fetching from a partial repository
+should be relatively rare, it is certainly not an unreasonable workflow.
+And thus we need to provide an escape hatch.
+
+This commit works by respecting a GIT_NO_LAZY_FETCH environment variable
+(to skip the lazy-fetch), and setting it in upload-pack, but only when
+the user has not already done so (which gives us the escape hatch).
+
+The name of the variable is specifically chosen to match what has
+already been added in 'master' via e6d5479e7a (git: extend
+--no-lazy-fetch to work across subprocesses, 2024-02-27). Since we're
+building this fix as a backport for older versions, we could cherry-pick
+that patch and its earlier steps. However, we don't really need the
+niceties (like a "--no-lazy-fetch" option) that it offers. By using the
+same name, everything should just work when the two are eventually
+merged, but here are a few notes:
+
+  - the blocking of the fetch in e6d5479e7a is incomplete! It sets
+    fetch_if_missing to 0 when we setup the repository variable, but
+    that isn't enough. pack-objects in particular will call
+    prefetch_to_pack() even if that variable is 0. This patch by
+    contrast checks the environment variable at the lowest level before
+    we call the lazy fetch, where we can be sure to catch all code
+    paths.
+
+    Possibly the setting of fetch_if_missing from e6d5479e7a can be
+    reverted, but it may be useful to have. For example, some code may
+    want to use that flag to change behavior before it gets to the point
+    of trying to start the fetch. At any rate, that's all outside the
+    scope of this patch.
+
+  - there's documentation for GIT_NO_LAZY_FETCH in e6d5479e7a. We can
+    live without that here, because for the most part the user shouldn't
+    need to set it themselves. The exception is if they do want to
+    override upload-pack's default, and that requires a separate
+    documentation section (which is added here)
+
+  - it would be nice to use the NO_LAZY_FETCH_ENVIRONMENT macro added by
+    e6d5479e7a, but those definitions have moved from cache.h to
+    environment.h between 2.39.3 and master. I just used the raw string
+    literals, and we can replace them with the macro once this topic is
+    merged to master.
+
+At least with respect to CVE-2024-32004, this does render this commit's
+parent commit somewhat redundant. However, it is worth retaining that
+commit as defense in depth, and because it may help other issues (e.g.,
+symlink/hardlink TOCTOU races, where zip files are not really an
+interesting attack vector).
+
+The tests in t0411 still pass, but now we have _two_ mechanisms ensuring
+that the evil command is not run. Let's beef up the existing ones to
+check that they failed for the expected reason, that we refused to run
+upload-pack at all with an alternate user id. And add two new ones for
+the same-user case that both the restriction and its escape hatch.
+
+Signed-off-by: Jeff King <peff@peff.net>
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+
+CVE: CVE-2024-32465
+
+Upstream-Status: Backport [https://github.com/git/git/commit/7b70e9efb18c2cc3f219af399bd384c5801ba1d7]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ Documentation/git-upload-pack.txt | 16 ++++++++++++++++
+ builtin/upload-pack.c             |  2 ++
+ promisor-remote.c                 | 10 ++++++++++
+ t/t0411-clone-from-partial.sh     | 18 ++++++++++++++++++
+ 4 files changed, 46 insertions(+)
+
+diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
+index 8f87b23..eba0e81 100644
+--- a/Documentation/git-upload-pack.txt
++++ b/Documentation/git-upload-pack.txt
+@@ -56,6 +56,22 @@ ENVIRONMENT
+	admins may need to configure some transports to allow this
+	variable to be passed. See the discussion in linkgit:git[1].
+
++`GIT_NO_LAZY_FETCH`::
++	When cloning or fetching from a partial repository (i.e., one
++	itself cloned with `--filter`), the server-side `upload-pack`
++	may need to fetch extra objects from its upstream in order to
++	complete the request. By default, `upload-pack` will refuse to
++	perform such a lazy fetch, because `git fetch` may run arbitrary
++	commands specified in configuration and hooks of the source
++	repository (and `upload-pack` tries to be safe to run even in
++	untrusted `.git` directories).
+++
++This is implemented by having `upload-pack` internally set the
++`GIT_NO_LAZY_FETCH` variable to `1`. If you want to override it
++(because you are fetching from a partial clone, and you are sure
++you trust it), you can explicitly set `GIT_NO_LAZY_FETCH` to
++`0`.
++
+ SEE ALSO
+ --------
+ linkgit:gitnamespaces[7]
+diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
+index 125af53..9ecaafe 100644
+--- a/builtin/upload-pack.c
++++ b/builtin/upload-pack.c
+@@ -34,6 +34,8 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
+
+	packet_trace_identity("upload-pack");
+	read_replace_refs = 0;
++	/* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
++	xsetenv("GIT_NO_LAZY_FETCH", "1", 0);
+
+	argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
+
+diff --git a/promisor-remote.c b/promisor-remote.c
+index db2ebdc..e73df68 100644
+--- a/promisor-remote.c
++++ b/promisor-remote.c
+@@ -19,6 +19,16 @@ static int fetch_objects(struct repository *repo,
+	int i;
+	FILE *child_in;
+
++	/* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
++	if (git_env_bool("GIT_NO_LAZY_FETCH", 0)) {
++		static int warning_shown;
++		if (!warning_shown) {
++			warning_shown = 1;
++			warning(_("lazy fetching disabled; some objects may not be available"));
++		}
++		return -1;
++	}
++
+	child.git_cmd = 1;
+	child.in = -1;
+	if (repo != the_repository)
+diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
+index eb3360d..b3d6ddc 100755
+--- a/t/t0411-clone-from-partial.sh
++++ b/t/t0411-clone-from-partial.sh
+@@ -28,6 +28,7 @@ test_expect_success 'local clone must not fetch from promisor remote and execute
+	test_must_fail git clone \
+		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+		evil clone1 2>err &&
++	grep "detected dubious ownership" err &&
+	! grep "fake-upload-pack running" err &&
+	test_path_is_missing script-executed
+ '
+@@ -37,6 +38,7 @@ test_expect_success 'clone from file://... must not fetch from promisor remote a
+	test_must_fail git clone \
+		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+		"file://$(pwd)/evil" clone2 2>err &&
++	grep "detected dubious ownership" err &&
+	! grep "fake-upload-pack running" err &&
+	test_path_is_missing script-executed
+ '
+@@ -46,6 +48,7 @@ test_expect_success 'fetch from file://... must not fetch from promisor remote a
+	test_must_fail git fetch \
+		--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+		"file://$(pwd)/evil" 2>err &&
++	grep "detected dubious ownership" err &&
+	! grep "fake-upload-pack running" err &&
+	test_path_is_missing script-executed
+ '
+@@ -57,4 +60,19 @@ test_expect_success 'pack-objects should fetch from promisor remote and execute
+	test_path_is_file script-executed
+ '
+
++test_expect_success 'clone from promisor remote does not lazy-fetch by default' '
++	rm -f script-executed &&
++	test_must_fail git clone evil no-lazy 2>err &&
++	grep "lazy fetching disabled" err &&
++	test_path_is_missing script-executed
++'
++
++test_expect_success 'promisor lazy-fetching can be re-enabled' '
++	rm -f script-executed &&
++	test_must_fail env GIT_NO_LAZY_FETCH=0 \
++		git clone evil lazy-ok 2>err &&
++	grep "fake-upload-pack running" err &&
++	test_path_is_file script-executed
++'
++
+ test_done
+--
+2.40.0
diff --git a/meta/recipes-devtools/git/git_2.35.7.bb b/meta/recipes-devtools/git/git_2.35.7.bb
index 9e7b0a8cff..94352d38ef 100644
--- a/meta/recipes-devtools/git/git_2.35.7.bb
+++ b/meta/recipes-devtools/git/git_2.35.7.bb
@@ -12,6 +12,17 @@ SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \
            file://0001-config.mak.uname-do-not-force-RHEL-7-specific-build-.patch \
            file://CVE-2023-29007.patch \
            file://CVE-2023-25652.patch \
+           file://CVE-2024-32002-0001.patch \
+           file://CVE-2024-32002-0002.patch \
+           file://CVE-2024-32002-0003.patch \
+           file://CVE-2024-32002-0004.patch \
+           file://CVE-2024-32004-0001.patch \
+           file://CVE-2024-32004-0002.patch \
+           file://CVE-2024-32004-0003.patch \
+           file://CVE-2024-32020.patch \
+           file://CVE-2024-32021-0001.patch \
+           file://CVE-2024-32021-0002.patch \
+           file://CVE-2024-32465.patch \
            "
 
 S = "${WORKDIR}/git-${PV}"
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2024-07-04 12:32 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-07-04 12:32 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Monday, July 8

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/7103

The following changes since commit fbc8f5381e8e1da0d06f7f8e5b8c63a49b1858c2:

  man-pages: remove conflict pages (2024-06-21 12:37:32 -0700)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Archana Polampalli (1):
  gstreamer1.0-plugins-base: fix CVE-2024-4453

Jonas Gorski (1):
  linuxloader: add -armhf on arm only for TARGET_FPU 'hard'

Jose Quaresma (1):
  openssh: fix CVE-2024-6387

Poonam Jadhav (2):
  glibc-tests: correctly pull in the actual tests when installing -ptest
    package
  glibc-tests: Add missing bash ptest dependency

Siddharth Doshi (1):
  OpenSSL: Security fix for CVE-2024-5535

Vijay Anusuri (1):
  wget: Fix for CVE-2024-38428

 meta/classes/linuxloader.bbclass              |    2 +-
 .../openssh/openssh/CVE-2024-6387.patch       |   27 +
 .../openssh/openssh_8.9p1.bb                  |    1 +
 .../openssl/openssl/CVE-2024-5535_1.patch     |  115 ++
 .../openssl/openssl/CVE-2024-5535_2.patch     |   44 +
 .../openssl/openssl/CVE-2024-5535_3.patch     |   84 ++
 .../openssl/openssl/CVE-2024-5535_4.patch     |  178 +++
 .../openssl/openssl/CVE-2024-5535_5.patch     | 1175 +++++++++++++++++
 .../openssl/openssl/CVE-2024-5535_6.patch     |   45 +
 .../openssl/openssl/CVE-2024-5535_7.patch     |   68 +
 .../openssl/openssl/CVE-2024-5535_8.patch     |  273 ++++
 .../openssl/openssl/CVE-2024-5535_9.patch     |  205 +++
 .../openssl/openssl_3.0.14.bb                 |    9 +
 meta/recipes-core/glibc/glibc-tests_2.35.bb   |    4 +-
 meta/recipes-core/glibc/glibc/run-ptest       |    2 +-
 .../wget/wget/CVE-2024-38428.patch            |   79 ++
 meta/recipes-extended/wget/wget_1.21.4.bb     |    1 +
 .../CVE-2024-4453.patch                       |   65 +
 .../gstreamer1.0-plugins-base_1.20.7.bb       |    1 +
 19 files changed, 2374 insertions(+), 4 deletions(-)
 create mode 100644 meta/recipes-connectivity/openssh/openssh/CVE-2024-6387.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_1.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_2.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_3.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_4.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_5.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_6.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_7.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_8.patch
 create mode 100644 meta/recipes-connectivity/openssl/openssl/CVE-2024-5535_9.patch
 create mode 100644 meta/recipes-extended/wget/wget/CVE-2024-38428.patch
 create mode 100644 meta/recipes-multimedia/gstreamer/gstreamer1.0-plugins-base/CVE-2024-4453.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2024-08-30 12:52 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-08-30 12:52 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Tuesday, September 3

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/7295

The following changes since commit 963085afced737863cf4ff8515a1cf08365d5d87:

  libsoup: fix compile error on centos7 (2024-08-23 14:34:03 -0700)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Divya Chellam (1):
  bind: Upgrade 9.18.24 -> 9.18.28

Hitendra Prajapati (1):
  vim: upgrade from 9.0.2190 -> 9.1.0114

Hugo SIMELIERE (1):
  cryptodev-module: Fix build for linux 5.10.220

Ming Liu (1):
  grub: fs/fat: Don't error when mtime is 0

Peter Marko (2):
  libyaml: Ignore CVE-2024-35325
  curl: Ignore CVE-2024-32928

Siddharth Doshi (1):
  vim: Upgrade 9.1.0114 -> 9.1.0682

 ...1-fs-fat-Don-t-error-when-mtime-is-0.patch | 70 +++++++++++++++++++
 meta/recipes-bsp/grub/grub2.inc               |  1 +
 .../bind/{bind_9.18.24.bb => bind_9.18.28.bb} |  2 +-
 .../cryptodev/cryptodev-module_1.12.bb        |  1 +
 .../0001-Fix-build-for-linux-5.10.220.patch   | 32 +++++++++
 meta/recipes-support/curl/curl_7.82.0.bb      |  2 +
 meta/recipes-support/libyaml/libyaml_0.2.5.bb |  2 +
 ...m-add-knob-whether-elf.h-are-checked.patch | 39 -----------
 .../vim/{vim-tiny_9.0.bb => vim-tiny_9.1.bb}  |  0
 meta/recipes-support/vim/vim.inc              |  5 +-
 .../vim/{vim_9.0.bb => vim_9.1.bb}            |  0
 11 files changed, 111 insertions(+), 43 deletions(-)
 create mode 100644 meta/recipes-bsp/grub/files/0001-fs-fat-Don-t-error-when-mtime-is-0.patch
 rename meta/recipes-connectivity/bind/{bind_9.18.24.bb => bind_9.18.28.bb} (97%)
 create mode 100644 meta/recipes-kernel/cryptodev/files/0001-Fix-build-for-linux-5.10.220.patch
 delete mode 100644 meta/recipes-support/vim/files/vim-add-knob-whether-elf.h-are-checked.patch
 rename meta/recipes-support/vim/{vim-tiny_9.0.bb => vim-tiny_9.1.bb} (100%)
 rename meta/recipes-support/vim/{vim_9.0.bb => vim_9.1.bb} (100%)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2024-12-11 14:47 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2024-12-11 14:47 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Friday, December 13

Passed a-full on autobuilder:

https://valkyrie.yoctoproject.org/#/builders/29/builds/615

The following changes since commit e42b6a40a3a01e328966bb5ee1bb3e0993975b15:

  resulttool: Improve repo layout for oeselftest results (2024-12-04 05:50:49 -0800)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Alexander Kanavin (1):
  dbus: disable assertions and enable only modular tests

Divya Chellam (1):
  libpam: fix CVE-2024-10041

Jiaying Song (1):
  python3-requests: fix CVE-2024-35195

Khem Raj (1):
  unzip: Fix configure tests to use modern C

Peter Marko (2):
  libsdl2: ignore CVE-2020-14409 and CVE-2020-14410
  rootfs-postcommands.bbclass: make opkg status reproducible

Ross Burton (1):
  sanity: check for working user namespaces

 meta/classes/rootfs-postcommands.bbclass      |   4 +
 meta/classes/sanity.bbclass                   |  24 ++++
 meta/recipes-core/dbus/dbus_1.14.8.bb         |   3 +-
 .../python3-requests/CVE-2024-35195.patch     | 121 ++++++++++++++++++
 .../python/python3-requests_2.27.1.bb         |   4 +-
 .../pam/libpam/CVE-2024-10041.patch           |  98 ++++++++++++++
 meta/recipes-extended/pam/libpam_1.5.2.bb     |   1 +
 ...rrect-system-headers-and-prototypes-.patch | 112 ++++++++++++++++
 meta/recipes-extended/unzip/unzip_6.0.bb      |   1 +
 .../libsdl2/libsdl2_2.0.20.bb                 |   3 +
 10 files changed, 368 insertions(+), 3 deletions(-)
 create mode 100644 meta/recipes-devtools/python/python3-requests/CVE-2024-35195.patch
 create mode 100644 meta/recipes-extended/pam/libpam/CVE-2024-10041.patch
 create mode 100644 meta/recipes-extended/unzip/unzip/0001-configure-Add-correct-system-headers-and-prototypes-.patch

-- 
2.34.1



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2025-02-12 14:21 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2025-02-12 14:21 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Friday, February 14

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/valkyrie/#/builders/29/builds/1001

The following changes since commit a397c152abf4f3da1323594e79ebac844a2c9f45:

  glibc: stable 2.35 branch updates (2025-01-30 08:17:32 -0800)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Bruce Ashfield (2):
  linux-yocto/5.15: update to v5.15.176
  linux-yocto/5.15: update to v5.15.178

Khem Raj (1):
  python3: Treat UID/GID overflow as failure

Nikhil R (1):
  glibc: Suppress GCC -Os warning on user2netname for sunrpc

Pedro Ferreira (1):
  rust-common.bbclass: soft assignment for RUSTLIB path

Peter Marko (1):
  cmake: apply parallel build settings to ptest tasks

Praveen Kumar (1):
  go: Fix CVE-2024-45336

 meta/classes/cmake.bbclass                    |   2 +
 meta/classes/rust-common.bbclass              |   2 +-
 ...press-gcc-os-warning-on-user2netname.patch |  61 +++
 meta/recipes-core/glibc/glibc_2.35.bb         |   1 +
 meta/recipes-devtools/go/go-1.17.13.inc       |   1 +
 .../go/go-1.21/CVE-2024-45336.patch           | 394 ++++++++++++++++++
 ...e-treat-overflow-in-UID-GID-as-failu.patch |  40 ++
 .../python/python3_3.10.16.bb                 |   1 +
 .../linux/linux-yocto-rt_5.15.bb              |   6 +-
 .../linux/linux-yocto-tiny_5.15.bb            |   6 +-
 meta/recipes-kernel/linux/linux-yocto_5.15.bb |  26 +-
 11 files changed, 520 insertions(+), 20 deletions(-)
 create mode 100644 meta/recipes-core/glibc/glibc/0003-sunrpc-suppress-gcc-os-warning-on-user2netname.patch
 create mode 100644 meta/recipes-devtools/go/go-1.21/CVE-2024-45336.patch
 create mode 100644 meta/recipes-devtools/python/python3/0001-gh-107811-tarfile-treat-overflow-in-UID-GID-as-failu.patch

-- 
2.43.0



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2025-03-14 14:10 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2025-03-14 14:10 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Tuesday, March 18

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/valkyrie/#/builders/29/builds/1187

The following changes since commit 0216c229d5c60d0023b0a7d6e8ee41bdfa16f8ef:

  tzcode-native: Fix compiler setting from 2023d version (2025-03-07 07:00:55 -0800)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Ashish Sharma (1):
  ruby: Fix CVE-2025-27219

Divya Chellam (1):
  vim: Upgrade 9.1.1043 -> 9.1.1115

Hitendra Prajapati (2):
  grub: Fix multiple CVEs
  grub: Fix multiple CVEs

Peter Marko (2):
  puzzles: ignore three new CVEs for a different puzzles
  libarchive: patch CVE-2025-25724

Zhang Peng (1):
  mpg123: fix CVE-2024-10573

 .../0001-misc-Implement-grub_strlcpy.patch    |  68 ++
 .../grub/files/CVE-2024-45774.patch           |  40 +
 .../grub/files/CVE-2024-45775.patch           |  41 +
 .../grub/files/CVE-2024-45776.patch           |  42 +
 .../grub/files/CVE-2024-45777.patch           |  60 ++
 .../files/CVE-2024-45778_CVE-2024-45779.patch |  58 ++
 .../grub/files/CVE-2024-45780.patch           |  96 ++
 .../grub/files/CVE-2024-45781.patch           |  38 +
 .../files/CVE-2024-45782_CVE-2024-56737.patch |  39 +
 .../grub/files/CVE-2024-45783.patch           |  42 +
 .../grub/files/CVE-2025-0622-01.patch         |  39 +
 .../grub/files/CVE-2025-0622-02.patch         |  44 +
 .../grub/files/CVE-2025-0622-03.patch         |  41 +
 .../grub/files/CVE-2025-0624.patch            |  87 ++
 ...025-0685_CVE-2025-0686_CVE-2025-0689.patch | 380 +++++++
 .../files/CVE-2025-0678_CVE-2025-1125.patch   |  90 ++
 .../grub/files/CVE-2025-0690.patch            |  75 ++
 .../grub/files/CVE-2025-1118.patch            |  40 +
 meta/recipes-bsp/grub/grub2.inc               |  18 +
 .../ruby/ruby/CVE-2025-27219.patch            |  31 +
 meta/recipes-devtools/ruby/ruby_3.1.3.bb      |   1 +
 .../libarchive/CVE-2025-25724.patch           |  40 +
 .../libarchive/libarchive_3.6.2.bb            |   1 +
 .../mpg123/mpg123/CVE-2024-10573.patch        | 978 ++++++++++++++++++
 .../mpg123/mpg123_1.29.3.bb                   |   4 +-
 meta/recipes-sato/puzzles/puzzles_git.bb      |   2 +
 meta/recipes-support/vim/vim.inc              |   4 +-
 27 files changed, 2396 insertions(+), 3 deletions(-)
 create mode 100644 meta/recipes-bsp/grub/files/0001-misc-Implement-grub_strlcpy.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45774.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45775.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45776.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45777.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45778_CVE-2024-45779.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45780.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45781.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45782_CVE-2024-56737.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-45783.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-0622-01.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-0622-02.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-0622-03.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-0624.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-0677_CVE-2025-0684_CVE-2025-0685_CVE-2025-0686_CVE-2025-0689.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-0678_CVE-2025-1125.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-0690.patch
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-1118.patch
 create mode 100644 meta/recipes-devtools/ruby/ruby/CVE-2025-27219.patch
 create mode 100644 meta/recipes-extended/libarchive/libarchive/CVE-2025-25724.patch
 create mode 100644 meta/recipes-multimedia/mpg123/mpg123/CVE-2024-10573.patch

-- 
2.43.0



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2025-09-30 19:50 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2025-09-30 19:50 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone ande have comments back by
end of day Thursday, October 2

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/valkyrie/#/builders/29/builds/2467

The following changes since commit d381eeb5e70bd0ce9e78032c909e4a23564f4dd7:

  build-appliance-image: Update to kirkstone head revision (2025-09-19 07:04:23 -0700)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Divya Chellam (1):
  vim: upgrade 9.1.1652 -> 9.1.1683

Gyorgy Sarvari (1):
  libhandy: update git branch name

Praveen Kumar (1):
  go: fix CVE-2025-47907

Soumya Sambu (1):
  python3-jinja2: upgrade 3.1.4 -> 3.1.6

Yogita Urade (3):
  grub2: fix CVE-2024-56738
  curl: fix CVE-2025-9086
  tiff: fix CVE-2025-9900

 .../grub/files/CVE-2024-56738.patch           |  75 ++++
 meta/recipes-bsp/grub/grub2.inc               |   1 +
 meta/recipes-devtools/go/go-1.17.13.inc       | 125 ++++---
 .../go/go-1.21/CVE-2025-47907-pre-0001.patch  | 354 ++++++++++++++++++
 .../go/go-1.21/CVE-2025-47907-pre-0002.patch  | 232 ++++++++++++
 .../go/go-1.21/CVE-2025-47907.patch           | 327 ++++++++++++++++
 ...inja2_3.1.4.bb => python3-jinja2_3.1.6.bb} |   5 +-
 meta/recipes-gnome/libhandy/libhandy_1.5.0.bb |   2 +-
 .../libtiff/tiff/CVE-2025-9900.patch          |  57 +++
 meta/recipes-multimedia/libtiff/tiff_4.3.0.bb |   1 +
 .../curl/curl/CVE-2025-9086.patch             |  55 +++
 meta/recipes-support/curl/curl_7.82.0.bb      |   1 +
 meta/recipes-support/vim/vim.inc              |   4 +-
 13 files changed, 1174 insertions(+), 65 deletions(-)
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2024-56738.patch
 create mode 100644 meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0001.patch
 create mode 100644 meta/recipes-devtools/go/go-1.21/CVE-2025-47907-pre-0002.patch
 create mode 100644 meta/recipes-devtools/go/go-1.21/CVE-2025-47907.patch
 rename meta/recipes-devtools/python/{python3-jinja2_3.1.4.bb => python3-jinja2_3.1.6.bb} (82%)
 create mode 100644 meta/recipes-multimedia/libtiff/tiff/CVE-2025-9900.patch
 create mode 100644 meta/recipes-support/curl/curl/CVE-2025-9086.patch

-- 
2.43.0



^ permalink raw reply	[flat|nested] 22+ messages in thread

* [OE-core][kirkstone 0/7] Patch review
@ 2025-11-19 20:42 Steve Sakoman
  0 siblings, 0 replies; 22+ messages in thread
From: Steve Sakoman @ 2025-11-19 20:42 UTC (permalink / raw)
  To: openembedded-core

Please review this set of changes for kirkstone and have comments back by
end of day Friday, November 21

Passed a-full on autobuilder:

https://autobuilder.yoctoproject.org/valkyrie/#/builders/29/builds/2748

The following changes since commit 8aad87c12a809d790175b9848f5802d0a28eecac:

  goarch.bbclass: do not leak TUNE_FEATURES into crosssdk task signatures (2025-11-13 08:39:38 -0800)

are available in the Git repository at:

  https://git.openembedded.org/openembedded-core-contrib stable/kirkstone-nut
  https://git.openembedded.org/openembedded-core-contrib/log/?h=stable/kirkstone-nut

Gyorgy Sarvari (1):
  musl: patch CVE-2025-26519

Richard Purdie (1):
  oe-build-perf-report: relax metadata matching rules

Soumya Sambu (2):
  elfutils: Fix CVE-2025-1376
  elfutils: Fix CVE-2025-1377

Vijay Anusuri (3):
  xwayland: Fix for CVE-2025-62229
  xwayland: Fix for CVE-2025-62230
  xwayland: Fix for CVE-2025-62231

 .../musl/musl/CVE-2025-26519-1.patch          | 39 ++++++++
 .../musl/musl/CVE-2025-26519-2.patch          | 38 ++++++++
 meta/recipes-core/musl/musl_git.bb            |  4 +-
 .../elfutils/elfutils_0.186.bb                |  2 +
 .../elfutils/files/CVE-2025-1376.patch        | 58 ++++++++++++
 .../elfutils/files/CVE-2025-1377.patch        | 68 ++++++++++++++
 .../xwayland/xwayland/CVE-2025-62229.patch    | 89 ++++++++++++++++++
 .../xwayland/xwayland/CVE-2025-62230-1.patch  | 63 +++++++++++++
 .../xwayland/xwayland/CVE-2025-62230-2.patch  | 92 +++++++++++++++++++
 .../xwayland/xwayland/CVE-2025-62231.patch    | 53 +++++++++++
 .../xwayland/xwayland_22.1.8.bb               |  4 +
 scripts/lib/build_perf/report.py              |  9 +-
 12 files changed, 515 insertions(+), 4 deletions(-)
 create mode 100644 meta/recipes-core/musl/musl/CVE-2025-26519-1.patch
 create mode 100644 meta/recipes-core/musl/musl/CVE-2025-26519-2.patch
 create mode 100644 meta/recipes-devtools/elfutils/files/CVE-2025-1376.patch
 create mode 100644 meta/recipes-devtools/elfutils/files/CVE-2025-1377.patch
 create mode 100644 meta/recipes-graphics/xwayland/xwayland/CVE-2025-62229.patch
 create mode 100644 meta/recipes-graphics/xwayland/xwayland/CVE-2025-62230-1.patch
 create mode 100644 meta/recipes-graphics/xwayland/xwayland/CVE-2025-62230-2.patch
 create mode 100644 meta/recipes-graphics/xwayland/xwayland/CVE-2025-62231.patch

-- 
2.43.0



^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2025-11-19 20:42 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-30 18:37 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
2024-05-30 18:38 ` [OE-core][kirkstone 1/7] ghostscript: fix CVE-2024-33870 Steve Sakoman
2024-05-30 18:38 ` [OE-core][kirkstone 2/7] ghostscript: fix CVE-2024-33869 Steve Sakoman
2024-05-30 18:38 ` [OE-core][kirkstone 3/7] ghostscript: fix CVE-2024-33871 Steve Sakoman
2024-05-30 18:38 ` [OE-core][kirkstone 4/7] ghostscript: fix CVE-2024-29510 Steve Sakoman
2024-05-30 18:38 ` [OE-core][kirkstone 5/7] ghostscript: fix CVE-2023-52722 Steve Sakoman
2024-05-30 18:38 ` [OE-core][kirkstone 6/7] util-linux: Fix CVE-2024-28085 Steve Sakoman
2024-05-30 18:38 ` [OE-core][kirkstone 7/7] git: Fix multiple CVEs Steve Sakoman
  -- strict thread matches above, loose matches on Subject: below --
2025-11-19 20:42 [OE-core][kirkstone 0/7] Patch review Steve Sakoman
2025-09-30 19:50 Steve Sakoman
2025-03-14 14:10 Steve Sakoman
2025-02-12 14:21 Steve Sakoman
2024-12-11 14:47 Steve Sakoman
2024-08-30 12:52 Steve Sakoman
2024-07-04 12:32 Steve Sakoman
2024-04-17 20:35 Steve Sakoman
2024-02-06 15:45 Steve Sakoman
2024-01-17 15:58 Steve Sakoman
2023-11-08 22:52 Steve Sakoman
2023-10-30  2:20 Steve Sakoman
2023-04-15 15:26 Steve Sakoman
2022-08-04 14:06 Steve Sakoman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox