InFeeo
Global
All
New
Language
Channel

c/technology

Technology

Owner @master@master · 4988 posts · 1 joined · Status active · Posting permission: Every logged-in user can post

I auto-configure my reverse proxy and uptime monitoring using DNS-DS(facebook.com)
This post has NOT been generated using AI. Like most of those who I believe would be reading this blog, I run my own home lab. My setup has, over the years, evolved from an old laptop running just my media centre, only accessible on my home network. Today, it is a more elaborate setup with containers running on two hosts on my local network, a third host running local LLMs, and a fourth (thin) host in the cloud running a reverse proxy. The reverse proxy forwards requests to services running in the hosts on my local network, allowing me to access some services from anywhere. I like the setup. In essence, it is quite simple. All I have to deal with is a container engine (I use Podman Quadlet) and my reverse proxy, outside the actual services deployed in the lab. I have avoided jumping into the Kubernetes (or similar) bandwagon, as I still don’t think the overhead is justified as yet.
Jurassic Park computers in excruciating detail(fabiensanglard.net)
After I mentioned a Jurassic Park anecdote the other day, I watched the movie again. I must have seen it at least ten times now. This time, I researched every computer/software I spotted. EDIT: Just when I was putting the final touches on this article, I read the sad news that Sam Neill, who played paleontologist Alan Grant in JP, has passed away today. R.I.P Sam. Surprisingly, the first computer visible is not on the island Isla Nublar but in Alan Grant and Ellie Sattler's mobile trailer. It is an Apple Powerbook 100, visible in the image below on the left side. This machine specs reminds me of how awful '90s laptop screens, based on a passive matrix, were. Definitely something I don't miss from that era. All computers and software are located in the Control Room on the desks of two engineers, Dennis Nedry and Ray Arnold. Dennis Nedry's desk is an indescribable mess with three machines (two macs, one SGI), three monitors, one PDA, and storage devices. Ray Arnold's desk is much tidier. It features a CCTV screen, storage devices, two computers (a Mac and a SGI), and two monitors. In the back of the Control Room, we can make out a giant screen and a supercomputer with tall panels and blinking red lights. The book The Making Of Jurassic Park has interesting details about how they designed the Control Room. This means, adjusted for inflation, Apple and SGI loaned roughly $4,000,000 of 2026 dollars for the production of Jurassic Park. Ray Arnold's workstation is a SGI R4000 Indigo. It is barely visible in two shots. Blink and you will miss it at 54:48. We get a somewhat better view of it towards the end of the movie thanks to a Velociraptor that never skips leg-day. For the needs of the movie, that SGIs came in handy to run real-time 3D animation of the Hurricane. Or did they? A dynamic and interactive method was employed to create the graphics, both on the big screen and on the computer monitors at each individual station. A makeshift room was built adjacent to the set, then equipped with a battery of Silicon Graphics and Apple Macintosh computer systems. Stored on computer disks were animations generated over a period of six months by a four-man computer graphics team headed by Michael Backes. Responding to cues received via radio from the set, Backes and his team were able to feed their graphics directly to the appropriate monitors on stage, making it seem as though the actors involved were actually calling up the imagery. Dennis Nedry's powerhouse workstation is an SGI IRIS Crimson. It is such a beast that it won't fit on his desk. It is on the floor on the right of his desk (red box). Most of the time it is used to display a 3D chess game (monitor the right end of Dennis desk). The SGI Crimson is rarely visible on screen. It is briefly visible after Dennis's "white rabbit" lockdown brings Samuel Jackson into a depression. The SGI Crimson was a very powerful workstation released in 1992. Its main appeal was its panel of real-time 3D graphics cards. The CPU was also very powerful with hardware Floating-Point Unit, a luxury for 3D graphics. Both Dennis and Ray use PLI Mini Arrays for their backup. Dennis has an impressive stack of five on the left-end of his desk. There is a continuity error in the movie. See how the stack of PLI is facing left in this early shot. Later in the movie, after Ray takes over Dennis's desk, we can see the PLIs have magically rotated to face the developer. On Ray's desk we also find a smaller stack of two PLIs. There is a close-up shot when John Hammond follows the jeeps' progress on the CCTV. Despite the attention to detail, it seems the PLIs were not connected since the LEDs are all blank. In Macs Place of Spring 1993 we can find an ad on page 38 giving more details about the capacity. Since John Hammond "spared no expense", it is fair to say he picked 1GiB version at $3,598 a piece. That would give them 7 GiB of storage for a 2026 equivalent of $33,223.70. In 2026, 7 GiB of HDD would cost $0.49. Seven GiB was a MASSIVE amount in 1993 when a high-end PC would come with 120 MiB HDD. The Motorola Envoy is a personal digital assistant used by Dennis. It is visible next to his right elbow in the image below. It is an extremely impressive device for the early '90s. It is a foldable that features an antenna when deployed (video). The hardware of the Motorola Envoy included a Motorola Dragon I/68349 microprocessor, 4 MB of read only memory (ROM), 1 MB of random access memory (RAM), and an LCD. Of particular interest were the wireless communications capabilities of the Envoy. Its built-in communication components included a radio modem capable of 4,800 bits per second communication, a fax and data modem, and an infrared transceiver capable of 38.4 kbit/s of data transfer. Dennis must have used it since we see it moved and partially unfolded later in the movie. It is unclear how Jurassic Park crew got their hands on a Motorola Envoy. The movie was shot from August to November 1992. Motorola only finished the PDA in mid-1994 but delayed releasing it to February 1995[1]. The supercomputer of the control room looks a lot like five Thinking Machines CM-5 with there characteristic front panel with thousands of red blinking LEDs. With a pricetag of "only" $46,000 per machine, it is very possible these were authentic. The CM-5 was released in 1991[2]. In 1993 it was still considered the most powerful computer in the world[3]. Each machine was called a "node", featuring a Sparc CPU, four vector units, and 32 MiB RAM. As many nodes as needed could be connected together to form a mesh. The National Center for Atmospheric Research (NCAR) build a 32-node supercomputer with CM-5[4]. Does the red LED pattern in the front panel mean anything? Absolutely not, they were randomly generated[5]. One of the very best monitors money could buy in 1993 was the SuperMatch 20-T. The twenty means 20" and T meant Trinitron. The SuperMatch was featured on the cover of MacUser in Feb 92. In MacUser of Oct 94, page 180 (out of 252!!), we can see it cost $2,589 ($6,000 in 2026). 20" monitors were considered absolutely massive in 1993 and only seen in professional workspaces. A typical PC would come with a 15" CRT. 21" is almost the maximum CRTs reached, their depth and weight made them very hard to move. They were replaced by LCD around 2005. The monitor features a particular "chin". The absolutely gorgeous SGI Hardware Developer Handbook, on page 4-59, reveals this is a 19" Mitsubishi HL7965 Monitor which SGI rebranded. It likely cost as much as the SuperMatch 20-T. On Ray Arnold's desk, we can notice a weird keyboard with a connector on the side. This is a SGI Granite Keyboard (Indigo Style)[6]. It is a pretty cool keyboard with two ADB connectors on each side. The keyboard can be connected to the workstation from either side and the mouse is to be daisy-chained into the other port. Ray is seen using the same keyboard later. If you look closely at the screen, it looks like status network was aliased to ping CLI. Dennis Nedry uses two Macintosh Quadra 700. Apple must have been very happy with the product placement. Although they usually require their computers not to be used for nefarious activity which is not the case here. Released in 1991, The Quadra 700 ran on Motorola 68040 @ 25 MHz with 4 MB RAM, expandable to 68 MB. HDD sizes available were 80 and 160 MB. Ray also uses a Macintosh Quadra 700 but he has only one on his desk. Dennis negotiates with his co-conspirator located in the harbor to give him time to make it there. It happens via a VC on the Mac. Why not on a SGI? Because the whole thing was faked via Quicktime Video player running on System 7. The cursor on the progress bar is clearly visible. This is 1-minute clip. Even the mouse cursor is still on the "play" button of the Quicktime window. Quicktime is used earlier in the movie. When Dennis is revealed to be working at Jurassic Park, he had Jaws played on his left screen[7]. IRIX System Usage utility, named gr_osview can be seen a few times. It looks like a powerful tool, able to report not only user time, sys time, but also interrupt overhead and even gfx overhead according to IRIX - Desktop User’s Guide on p182. Despite reports that monitors screens were faked via remote operators, gr_osview seems to react appropriately to keystrokes in the sequence above. Maybe this one was actually live. When Ray accidentally locks down the whole system, Nedry's face superimposed onto an Elvis Presley jumpsuit shows up on his Macintosh. That is the UI of the "White Rabbit", which Ray Arnold mentions when he explains the lockdown to Ellie Sattler. The filename whte_rbt.obj is not mentioned in the movie, only in the novel. Michael Crichton, the author of Jurassic Park was actually a highly capable programmer. The legendary "It's a Unix system. I know this" sequence was done using an experimental SGI file explorer application named fsn. Lex Murphy takes over Dennis's SGI Crimson and opens the /usr directory. SGI was super happy to see this since they mentioned "YOU SAW IT IN JURASSIC PARK!" on their website[8]. IRIX supported spaces in file and directory names. I assume they put a dot between Visitors and Center for style. Nedryland is the system modestly named by Dennis Nedry to control Jurassic Park. We can catch a few glimpses of the name on screen when the system successfully reboots. There is very little online about how these screens were created except that they were created by Michael Backes and his team. Fans have recreated Nedryland. Checkout JPOS NEDRYLAND YouTube channel to see it in action. Some code associated with Nedryland is visible on screen. It looks like actual source code[9] with Classic Mac OS API functions calls. Later during the faked video-conference, we can see more files belonging to a Nedryland directory. One last detail for the road. The book on the top of Dennis's shelf (upper-right) is System 7 Revealed by Anthony Meadow. Wow they really did pay attention to every detail!
Debian Bookworm v12.15 Released(spi-inc.org)
Updated Debian 12: 12.15 released July 11th, 2026 The Debian project is pleased to announce the fifteenth and final update of its oldstable distribution Debian 12 (codename bookworm). This point release mainly adds corrections for security issues, along with a few adjustments for serious problems. Security advisories have already been published separately and are referenced where available. Please note that the point release does not constitute a new version of Debian 12 but only updates some of the packages included. There is no need to throw away old bookworm media. After installation, packages can be upgraded to the current versions using an up-to-date Debian mirror. Those who frequently install updates from security.debian.org won't have to update many packages, and most such updates are included in the point release. New installation images will be available soon at the regular locations. Upgrading an existing installation to this revision can be achieved by pointing the package management system at one of Debian's many HTTP mirrors. A comprehensive list of mirrors is available at: https://www.debian.org/mirror/list Noteworthy updates fwupd and Secure Boot CA expiry fwupd has been updated to upstream version 2.0.20, which has the ability to update the Secure Boot certificate authority (CA), Key Exchange Key (KEK) and revocation (DBX) databases. The 2013 UEFI Secure Boot CA installed by default on most PCs and used to sign bootloaders has now expired. Future updates to shim-signed could therefore lead to systems being unable to boot with Secure Boot enabled. Users are strongly advised to apply CA, KEK and DBX updates from their system OEM in line with the following guidance: https://wiki.debian.org/SecureBoot/CAChanges#What_should_I_do.3F geoip-database reverted For licensing reasons geoip-database has been reverted to a version dated approximately December 2019. As a result, applications using this database might use out-of-date allocation information. More recent versions of geoip-database (GeoLite) are not compatible with the Debian Free Software Guidelines and cannot be distributed. Consumers of this data are strongly encouraged to obtain a GeoLite license directly and cease reliance on the geoip-database package. End of Debian support for bookworm This update marks the end of Debian Release Team, Debian Security Team and Debian Backports support for version 12. Ongoing support for some architectures will be provided by the Debian Long Term Support team supported by Freexian. Users are advised to upgrade systems to Debian 13 trixie. Miscellaneous Bugfixes This oldstable update adds a few important corrections to the following packages: Package Reason 7zip New upstream stable release; fix buffer overflow issues [CVE-2026-48092 CVE-2026-48095]; fix memory disclosure issue [CVE-2026-48101]; fix out-of-bounds read issues [CVE-2026-48102 CVE-2026-48103 CVE-2026-48111 CVE-2026-48112]; fix uninitialised memory read issue [CVE-2026-48104] apache2 Fix HTTP/2 request DoS and file handle exhaustion [CVE-2026-49975 CVE-2026-48913]; fix proxy, DAV, LDAP, SSL, XML and header memory/crash issues [CVE-2026-29167 CVE-2026-34355 CVE-2026-34356 CVE-2026-42535 CVE-2026-42536 CVE-2026-43951 CVE-2026-44185]; fix proxy FTP directory listing XSS and backend loop [CVE-2026-29170 CVE-2026-44186]; restrict htaccess expression file access [CVE-2026-44119]; fix regex parsing underflow [CVE-2026-44631]; correct SSI, file-cache, WebDAV DELETE and proxy health-check handling; update documentation and tests appstream Rebuild with updated libxmlb base-files Update for the point release beets Fix XSS vulnerability [CVE-2026-42052]; fix build-time test failures calibre Fix various potential security issues; read resources only from book contents [CVE-2026-33206]; keep extracted files within container dir [CVE-2026-30853]; prevent reading background images from outside the config dir [CVE-2026-33205] cdebootstrap Rebuild with updated xz-utils chrony Ensure if-up/down hook scripts exit successfully cloud-init Fix OpenStack bond initialisation composer Fix support for new GitHub token format [CVE-2026-45793] curl Fix cache poisoning issue [CVE-2025-10148]; fix data leak issues [CVE-2025-14524 CVE-2026-3783]; fix incorrect connection re-use issues [CVE-2025-14819 CVE-2026-3784 CVE-2026-5773 CVE-2026-7168] dar Rebuild with updated libgcrypt20 dcmtk Fix NULL pointer dereference issues [CVE-2022-4981 CVE-2025-14841]; fix memory corruption issues [CVE-2025-2357 CVE-2025-9732 CVE-2025-14607]; fix command injection issue [CVE-2026-5663]; fix buffer overflow issues [CVE-2026-10194 CVE-2026-12805] debian-installer Bump linux ABI 6.1.0-50; rebuild for point release debian-installer-netboot-images Rebuild from proposed updates debian-security-support Prepare support limitations ahead of transition to LTS delve Fix failure to build on 4th generation EYPC processors dhcpcd5 Fix NULL pointer dereference issue [CVE-2025-70102]; fix out-of-bounds write issue [CVE-2026-56114] firewalld Fix DBUS policy checking [CVE-2026-4948] fwupd Rebuild with updated libjcat, libxmlb; add support for updating DBX and KEK stores; rebuild in a clean environment geoip-database Revert to a DFSG-compatible version ghdl Rebuild with updated gcc-12 giflib Fix memory corruption issues [CVE-2026-23868 CVE-2026-26740] gnome-firmware Rebuild with updated libxmlb; backport patch for libfwupd3 compatibility gnome-software Rebuild with updated libxmlb; backport patch for libfwupd3 compatibility graphite2 Fix out-of-bounds write [CVE-2026-50593] gss Fix build failures caused by an expired Kerberos ticket; avoid krb5context self-tests with timebomb horizon Fix escaping of special characters in project ironic Fix file disclosure via image sources [CVE-2025-44021]; fix console command injection [CVE-2026-42510]; fix Swift token disclosure [CVE-2026-42997]; fix unsafe template execution [CVE-2026-44916] keystone Fix behaviour of user_enabled_invert [CVE-2026-40683]; prevent unauthorized EC2 credential creation and deletion [CVE-2026-33551] libapache-session-browseable-perl Improve entropy of generated session IDs libbytes-random-secure-perl Fix incorrect usage of seed in PRNG [CVE-2026-11625] libcaca Prevent undefined behaviour in overflow check [CVE-2026-42046] libcrypt-pbkdf2-perl Change default hash algorithm to HMAC-SHA256 and default iterations to 600,000 [CVE-2026-9641]; generate salts using Crypt::URandom [CVE-2026-9638]; use a constant-time comparison in `validate` to avoid timing attacks [CVE-2017-20240] libhtml-gumbo-perl Fix uninitialized memory access [CVE-2025-15646] libhtml-parser-perl Fix heap-use-after-free in _decode_entities [CVE-2026-8829] libjcat Add support for ed25519 types and SHA512 hashes libnet-cidr-lite-perl Fix IP/CIDR parser validation: reject non-ASCII digits and trailing newlines [CVE-2026-55190]; reject zero-padded CIDR masks [CVE-2026-45191] libreoffice Gracefully handle failure in graphite2 libvncserver Fix buffer overflow and out-of-bounds write [CVE-2026-44988 CVE-2026-50538] libxml-libxml-perl Fix out-of-bounds read [CVE-2026-8177] libxml2 Fix catalogue recursion and duplicate-catalog handling [CVE-2025-8732 CVE-2026-0990 CVE-2026-0992]; limit RelaxNG include recursion [CVE-2026-0989]; fix xmllint shell memory leak [CVE-2026-1757]; correct schematron regression-test outputs [CVE-2025-49794 CVE-2025-49796]; fix XML writer and schematron memory leaks; mitigate RelaxNG validation use-after-free; update catalogue and RelaxNG regression tests libxmlb Add support for zstd decompression; fix XMLb store/truncation validation; correct query binding/index handling; fix XML export and empty text() handling linuxcnc Sanitize module names mariadb New upstream stable release; fix code execution issues [CVE-2025-13699 CVE-2026-44168 CVE-2026-48163 CVE-2026-48165 CVE-2026-49261]; fix denial of service issues [CVE-2026-21968 CVE-2026-34303]; fix logging bypass issue [CVE-2026-3494]; fix path traversal issue [CVE-2026-44171]; fix SQL injection issue [CVE-2026-44172]; fix incomplete privilege check issue [CVE-2026-44173]; fix Illegal mix of collations error; fix Mroonga hangs on invalid index flag; fix crash in information_schema.table_constraints mesa Fix WebGPU/SPIR-V allocation handling [CVE-2026-40393] modsecurity Prevent denial of service in hexDecode handling [CVE-2026-30923]; prevent denial of service in SSN/CPF/SVNR verification [CVE-2026-42268] mxml Fix out-of-bounds read [CVE-2026-5037] node-flatted Fix prototype pollution issue [CVE-2026-33228] node-jschardet Fix build link references node-regexpp Add missing link to undici-types ojalgo Reduce frequency of built-time test failures openslide Fix possible code execution issue [CVE-2026-48977] p7zip New upstream stable release; fix buffer overflow issues [CVE-2026-48092 CVE-2026-48095]; fix memory disclosure issue [CVE-2026-48101]; fix out-of-bounds read issues [CVE-2026-48102 CVE-2026-48103 CVE-2026-48111 CVE-2026-48112]; fix uninitialised memory read issue [CVE-2026-48104] php-guzzlehttp-psr7 Fix Host authority validation [CVE-2026-48998]; reject control characters in URI hosts [CVE-2026-49214]; harden ServerRequest globals handling; normalise global header values; encode literal plus signs in query helpers phpunit Fix unsafe deserialization in PHPT code coverage handling [CVE-2026-24765] plasma-discover Backport patch for libfwupd3 compatibility prometheus Fix date-sensitive build-time test protobuf Fix parser recursion limits [CVE-2024-7254 CVE-2025-4565 CVE-2026-0994 CVE-2026-6409] pydantic Fix denial of service in email verification [CVE-2024-3772] pymatgen Fix denial of service in GaussianInput.from_string [CVE-2022-42964] python-ase Disable unreliable built-time test python-django Update test suite following changes in python3.13 python-filelock Fix symlink vulnerabilies [CVE-2025-68146 CVE-2026-22701] python-markdown Fix parsing of bogus HTML markup [CVE-2025-69534] python-pyramid Fix information disclosure issue [CVE-2023-40587] python-xmltodict Fix XML injection issue [CVE-2025-9375] python3.11 Prevent incorrect tar archive handling [CVE-2025-13462]; ensure bytecode-only imports use normal security checks [CVE-2026-2297]; reject unsafe cookie values [CVE-2026-3644]; prevent XML parser crashes [CVE-2026-4224]; prevent browser command injection [CVE-2026-4519]; prevent bz2/lzma decompressor memory corruption [CVE-2026-6100]; restore XML autopkgtests qemu Rebuild with updated gnutls28 rhino Fix denial of service issue [CVE-2025-66453] rlottie Fix out-of-bounds read issue [CVE-2026-10305]; fix denial of service issues [CVE-2026-47319 CVE-2026-47320] rsync Reject excessively long HTTP proxy response lines [CVE-2026-45232] ruby-css-parser Fix validation of HTTPS certificates for remote CSS [CVE-2026-44312] rust-time Fix denial of service [CVE-2026-25727] science.js Fix build time race condition sentry-python Fix subprocess environment sanitisation [CVE-2024-40647] shim New upstream release; build with default gcc; set SBAT revocation level to 2025021800 shim-helpers-amd64-signed Update to shim 16.1-2~deb12u1 shim-helpers-arm64-signed Update to shim 16.1-2~deb12u1 shim-helpers-i386-signed Update to shim 16.1-2~deb12u1 shim-signed Ensure Secure Boot compatibility with 2023 Microsoft UEFI CA; check for likely boot issues before installation; combine and verify multiple shim signatures; update signed shim binaries sqlite-utils Add dependency on python3-click-default-group sshfs-fuse Add contain_symlinks option to prevent symlink escape attacks [CVE-2026-47187]; reject hostname option injection via bracketed mount source [CVE-2026-48711] sylpheed Fix link checking [CVE-2021-37746] user-mode-linux Rebuild with updated linux vitrage Fix remote code execution vulnerability [CVE-2026-28370] wireless-regdb New upstream stable release; update regulatory information for several countries xz-utils Fix buffer overflow issue [CVE-2026-34743] Security Updates This revision adds the following security updates to the oldstable release. The Security Team has already released an advisory for each of these updates: Advisory ID Package DLA-4627 kernel-wedge DLA-4628 linux-base DLA-4632 atril DLA-4633 libreoffice DLA-4635 firefox-esr DLA-4636 thunderbird DLA-4637 libconfig-inifiles-perl DLA-4638 libgd-perl DLA-4639 libhttp-daemon-perl DLA-4642 u-boot DLA-4643 imagemagick DLA-4644 libmatio DLA-4648 libtext-csv-xs-perl DLA-4651 python-urllib3 DLA-4654 chromium DLA-4656 tor DLA-4657 sogo DLA-4658 librabbitmq DLA-4662 jq DLA-4665 linux-signed-amd64 DLA-4665 linux-signed-arm64 DLA-4665 linux-signed-i386 DLA-4665 linux DLA-4666 openvpn DLA-4667 nginx DLA-4668 sympa DLA-4669 php8.2 DLA-4672 chromium DLA-4674 chromium DSA-6250 chromium DSA-6266 nghttp2 DSA-6267 thunderbird DSA-6269 postgresql-15 DSA-6271 gsasl DSA-6272 nodejs DSA-6273 chromium DSA-6275 linux-signed-amd64 DSA-6275 linux-signed-arm64 DSA-6275 linux-signed-i386 DSA-6275 linux DSA-6276 ffmpeg DSA-6277 openjpeg2 DSA-6278 nginx DSA-6279 redis DSA-6281 gnutls28 DSA-6282 rsync DSA-6283 firefox-esr DSA-6285 bind9 DSA-6286 evince DSA-6287 chromium DSA-6288 thunderbird DSA-6289 openvpn DSA-6292 haveged DSA-6293 krb5 DSA-6294 libgcrypt20 DSA-6297 samba DSA-6299 kdenlive DSA-6300 node-shell-quote DSA-6301 roundcube DSA-6302 starlette DSA-6306 linux-signed-amd64 DSA-6306 linux-signed-arm64 DSA-6306 linux-signed-i386 DSA-6306 linux DSA-6308 nagios4 DSA-6309 exim4 DSA-6310 imagemagick DSA-6313 dovecot DSA-6316 chromium DSA-6317 php-symfony-contracts DSA-6317 symfony DSA-6319 yelp DSA-6320 php-twig DSA-6321 ceph DSA-6322 frr DSA-6323 apache2 DSA-6324 request-tracker5 DSA-6325 chromium DSA-6326 nginx DSA-6327 request-tracker4 DSA-6328 tomcat10 DSA-6330 strongswan DSA-6331 keystone DSA-6332 okular DSA-6333 mistral DSA-6334 poppler DSA-6335 openssl DSA-6336 jackson-core DSA-6336 jackson-databind DSA-6336 jackson-dataformat-smile DSA-6337 chromium DSA-6338 libdbi-perl DSA-6339 libinput DSA-6341 ironic DSA-6341 python-oslo.messaging DSA-6344 chromium DSA-6352 chromium Removed packages The following packages were removed due to circumstances beyond our control: Package Reason smb4k Unable to continue security support Debian Installer The installer has been updated to include the fixes incorporated into oldstable by the point release. URLs The complete lists of packages that have changed with this revision: https://deb.debian.org/debian/dists/bookworm/ChangeLog The current oldstable distribution: https://deb.debian.org/debian/dists/oldstable/ Proposed updates to the oldstable distribution: https://deb.debian.org/debian/dists/oldstable-proposed-updates oldstable distribution information (release notes, errata etc.): https://www.debian.org/releases/oldstable/ Security announcements and information: https://www.debian.org/security/ About Debian The Debian Project is an association of Free Software developers who volunteer their time and effort in order to produce the completely free operating system Debian. Contact Information For further information, please visit the Debian web pages at https://www.debian.org/, send mail to , or contact the stable release team at .
System call instrumentation on Linux/x86-64 using memory-indirect calls(dl.acm.org)
Diverting trains of thought, wasting precious time In my last post I identified some approaches to system call instrumentation on x86-64 Linux that combine instruction punning with the memory-indirect call and (most eccentrically) lcall (“far call”) instructions. I mentioned these have some interesting differences with the direct relative jmp or register-indirect call used by straightforward instruction punning or zpoline approaches. These differences appear to be fractionally useful if you care about saving a small amount of memory (relative to E9Patch), keeping the memory map simple for debugging purposes (cf. an incidental downside of E9Patch that might bite when debugging low-level code), about minimising introduction of new instructions for security reasons (an advantage of the memory-indirect approach over conventional trampolines), and/or about keeping the standard hardware null-pointer trapping in place even for function pointers, while avoiding any need for special low memory-mapping privileges or not-so-ubiquitous CPU features (advantages over zpoline). In this post I'll cover more details about how to make this work, especially around the segmentation features on which far calls rely. I've implemented one variant of the idea (the %rax-relative lcall one) on the use-lcall branch of my libsystrap repository. “Details” is the word; if you're not into details you probably don't need this post, and I'm putting this here partly so that anyone searching on related topics might benefit from what I've learned. Let's recap from last time the picture we need for our %rax-relative far calls. How does this work? For any system call that we patched to instead be a far call indirecting %rax-relativewise via the low 2GB, our lcall *0xnnnn(%rax) instruction we will read the six-byte far address 0x1f1f:0x1f1f1f1f. The 16-bit selector 0x1f1f denotes an LDT entry, number 0x3e3 (discard the bottom three bits of 0x1f1f). So if we put our handler code at 0x1f1f1f1f, and install an LDT entry at slot number 0x3e3, with base address zero, we can start to handle these calls. (The base address doesn't have to be zero... I will come back to this. And we don't have to pick 0x1f as our repeating byte—if our LDT is otherwise empty, then any selector ending 7 or f will map to an LDT entry we can use, so we have 32 byte values to play with. 0x1f is good because it's always an illegal instruction in x86—just in case this memory gets executed by mistake somehow.) Let's look at the modify_ldt system call. It's a very confusing beast for a number of reasons. Firstly, despite the name, it can be used to read the LDT as well as writing it. Secondly, there are two flavours of write operation. Thirdly, it uses different data formats for reading and writing. The manual page gives it the following signature: ... while noting that glibc provides no wrapper, so in reality we have to use syscall(). We get the read function if passing func equal to 0, and two different write functions if passing func equal to 1 or 17 (0x11). Although the manual page is not clear on this, the read function (func == 0) will read raw LDT entries in the hardware-defined format. This is C-ified by Linux, inside the kernel, as follows (from Linux 6.18). One entry is eight bytes in size, and decoding its idiosyncratic narrow-width fields requires reading the Intel documentation. By contrast, the write function updates a single entry, at the given index, where the entry is described by the user_desc structure as seen in the manual page. This lacks some of the hardware's fields—but offers friendlier names for those if does have, and does not fragment long fields over many small pieces owing to Intel's piecemeal hardware evolution. It does betray its age a little though, since it uses only a 32-bit unsigned integer for the base and limit fields. The two write operations, 0x1 and 0x11, differ only in that the kernel's internal write_ldt() is called with parameter oldmode equal to 1 for 0x1 (the older operation) and 0 for 0x11 (the newer one). The differences are only as follows. Overall, old mode is less expressive; it is more clear-happy and less set-happy. So there is no reason to use it; it exists for compatibility. Finally, modify_ldt has a fourth operation, the undocumented “read default” function (func == 2) which currently reads a collection of zero bytes so is not especially useful. The kernel's logic to populate the actual LDT entry looks like the following (from Linux 6.18, fill_ldt() in arch/x86/include/asm/desc.h): (The code further up the call chain that reaches here, modify_ldt and write_ldt, lies elsewhere.) You can also see in the above code that Linux won't let us create a 64-bit code segment either—not only because the base and limit fields of user_desc are not wide enough, but also because the long-mode l bit is hard-wired to 0. This is documented in the manual page. Why is this? The relevant bit of kernel code above hints that user_64bit_mode() is part of the explanation; let's take a look at it. In short, the kernel is assuming that our friendly 0x33 (__USER_CS) is the only long-mode user-accessible segment selector. It uses this fact to make it simple to test whether a process's userland is running in 64-bit mode: is %cs set to that unique selector? The “overridden by sysret” is meanwhile referring to some behaviour of one of the “other” far-calling primitives of 64-bit x86, namely sysret that is the converse of syscall. Much like the instructions we've been thinking about, sysret does a far indirect jump, to some target code segment (in user space). However, in 64-bit mode it works in a “special” (hacky) way. ... where the “fixed values” look like this: In other words, the OS has configured a model-specific register (MSR) with some code segment selector of its choosing. In principle, this could point into either the GDT or LDT. That configured value is used to restore %cs. Then, the private architectural state that caches the GDT/LDT contents (currently in-use segment descriptors) is initialized with a “universal” “expected” values, namely the fields that specify (deep breath) a ring-3 zero-base max-limit page-granularity non-system readable executable code segment that is long-mode if and only if the default current operand size at the site of the sysret itself is 64 bits. It's up to the OS to ensure that the GDT/LDT contents match these fixed values, i.e. that that is what the GDT/LDT contains at the MSR-selected entry. In practice, on Linux achieves that in a particular way: the configured selector always points into the GDT, and Linux permits no long-mode segments in the LDT. Therefore we can never be attempting to sysret into one of those. All this seems a missed opportunity in some sense. If Linux wanted to (it doesn't), it could expose more of the underlying x86 architecture to its user programs. There's another restriction of this form.... Our long call has a selector 0x1f1f and an offset 0x1f1f1f1f. This offset seems a bit extraneous, because we're free to define the base address of our segment descriptor. We could make it point straight to our handler code... but then we'd have to call it with offset zero, which we are not doing! We are calling it with offset 0x1f1f1f1f. For such a callable segment, could we declare it as not needing or taking an offset? In short, yes: the hardware lets us do this. It allows for a special kind of pesudo-segment, a call gate. Such an entry defines a call entry point rather than a segment of text per se. But no; Linux won't let us create call gates in the LDT even though the hardware allows them. The idea of call gates is not-so-uncannily similar to system calls: a key purpose of call gates is as opportunities to change the current privilege level, e.g. to transition from ring 3 (unprivileged user code) to ring 0 (kernel mode), because the descriptor records the privilege level with which the jumped-to code will run. Call gates don't have to be used for privilege transition though—a call gate can retain the current privilege level too, making it effectively an opaque procedure call entry point recorded in the LDT (or GDT) and callable by a 16-bit segment selector (the offset is thrown away). Indeed, a traditional way to implement system calls on Intel hardware is exactly to define one or more call gates. One classic way to make a system call in pre-Linux Unix systems running on x86 was lcall 7, i.e. a call to the first entry in the LDT, which would be set up as the unique system call gate. According to the System V ABI supplement for the i386, which is (to my knowledge) still deemed current on 32-bit platforms including Linux, support for an exit() system call made by lcall 7 is the only mandated system call interface (p50 of that PDF). It appears Linux no longer supports this, if it ever did, as it does not create the necessary call gate in the LDT (at least on my system; it may be possible to cajole it into doing so, but personality(PER_SVR4) or similar do not suffice). At the very start of this work I was hoping we might be able simply and cleanly to turn system calls into via-call-gate far calls. That is not possible, unfortunately. Partly that's because there's no 2-byte form that calls the LDT entry whose index is in %rax: we know that all far calls indirect through memory, not just registers, and that an arbitrary (punned) 16-bit selector might nominate either GDT or LDT. After that became clear, I was next hoping there might be a longer encoding of call that takes the segment selector from a register (hand-waving away the GDT issue for now) and the offset from an immediate. If such an encoding existed, then we could pun with im-pun-ity: the register would select a call gate and the offset, read punningly from the instruction stream, would be thrown away. Sadly, there's also no form of call like this. And there's also a much more boring reason why this won't work. Linux rather rudely does not let us define call gates. Call gates are deemed to be a kind of “system” descriptor. The s bit of the descriptor is for “system” but is inverted: a system segment must have the s bit set to 0. From the above code we can see that only a non-system descriptor can be created by modify_ldt(): no field in the user_desc structure gives us control of this bit, which is unconditionally set to 1. If we're going to use lcall at all, we've established that we need to call a 32-bit segment and that it must be an ordinary text segment, not a call gate. The resulting handler is a slightly odd beast. It necessarily starts in 32-bit mode, but the handler code we want to run is 64-bit (for emulating or wrapping a 64-bit system call). So I coded it up as simply immediately switching back to 64-bit mode, by jumping to its next instruction addressed via the __USER_CS code segment, i.e. the unique 64-bit code segment that Linux creates for us. Now I've got my head around all this I plan to rewrite my trampoline somewhat, but for now it looks like this: ... after the jump, it also pushes %rax and then loads the “real” handler address straight out of the eight bytes immediately following the instruction. (My rewrite will use %rcx for any scratch needs and skip the push, because system calls are expected to clobber %rcx. And I should probably not do the gross data-in-instruction-stream thing.) Despite branching out of user code using a far call to a 32-bit code segment, one quirk of all this is that we will return to the caller purely in 64-bit code, without ever going back through 32-bit mode. How to actually perform the return will turn out to be non-obvious.... Our far call operation is from a 64-bit code segment, to a 32-bit code segment identified by a 16:32 far address, and has the default operand width for such calls. What is that width? It's 32 bits. (We did not use the rex.W prefix which would let us use a 16:64 memory operand indirectly; it would require an extra byte for the prefix, and in our pun context we literally don't have space.) What does that width mean? Clearly it selects the width of the far address loaded (from our stepping-stone location), It also selects the width of the return address saved on the stack: that, too, will be a 16:32 value: a 32-bit offset followed by a 16-bit segment selector. Therefore, the top 32 bits of our return address will be discarded. That's a problem! We need them if we're to get back to the system call site. The simple fix is to keep a look-up table of system call sites, keyed on their lower 32 bits, and only use the far-call instrumentation for some subset of system call sites for which these keys are unique. It's unlikely that wouldn't cover all syscalls, but if we do find a duplicate, we need to trap it some other way. Such a look-up table is not without cost. In my prototype I use a binary search over a sorted array... elegant but somewhat slow. A faster approach might be to “burn an LDT entry”. This works for the %rip-relative lcall only. The byte value that we surround our text with need not be 1f— it could be any two-hex-digit value ending 7 or f whose corresponding LDT entry is free. (Recall: the low three bits of this byte value must all be 1, as only these denote a user-privilege entry in the LDT.) We do only have 32 of these byte-repeated LDT entries to play with, however. So to quickly restore our return address, we issue a different LDT entry for every loaded binary—or, more precisely, for every aligned 4GB region that contains system calls trapped in this way. Each LDT entry points to a different handler, although all are mutually similar: restore the top 32 bits of the on-stack return address, then proceed. Each handler knows the 32-bit value it must restore, because it is used only from a given 4GB region. It's unfortunate that this works only for the %rip-relative lcall, since it'd be really useful to have a good solution also for the %rax-relative ones. Although those only work in 50% of puns anyway, our low-2GB stepping stone area is shared across the whole address space so we cannot tailor it to a particular 4GB region. Note, however, that our return address recovery is uncannily similar to the return address validation done by existing approaches based on zpoline-style handlers that must check for null pointer errors (zpoline, lazypoline, K23). We expect it to have a similar overhead,while being needed in strictly fewer cases. What if the guest program wants to use the LDT for its own purposes? Wine and Dosemu are the canonical examples but perhaps there are others. In principle this is fine, as long as they check for a free entry (rather than expecting entries at specific indices to be free) and do not end up racing with our code. I don't yet know whether these hold or can be made to hold. We have plenty of entries, since we are liable to use few or no entries besides the 32 that have byte-repeating selector values. (But see “LDT punning” for one exception to that.) Since when we use the far call recipes, the segment we call through is a 32-bit one, we temporarily have at our disposal all the affordances of “proper” segmentation: non-zero base addresses and (should we wish them) non-ignored segment limits. Recall that in 64-bit mode, unless selecting through %fs or %gs (e.g. for thread-local storage) segment bases are hard-wired to zero and limits are mostly ignored. (Limits can optionally be re-enabled, on sufficiently recent but not too recent AMD hardware (search for “LMSLE”) but not, I think, any Intel hardware. I have a vague memory of discovering that Intel did eventually implement this, using an incompatible MSR, but I think I dreamt it.) While we are in 32-bit mode, the brief return to “proper” segmentation lets us play some games. In essence, the contents of an LDT entry are a secret maintained for us by the kernel. I am pretty sure the only interface for accessing them is modify_ldt() (which also provides a read interface, despite its name) and we are between the user code and this system call. So if we wanted to store our system call handler at a secret randomized address, we could do that by randomising the segment base field in the LDT. We simply arrange that when adding 0x1f1f1f1f to it modulo 232, we get the actual handler address. It doesn't have to live literally at linear address 0x1f1f1f1f. The reason I am hedging with the “pretty sure” thing is that there is a “load segment limit” instruction which will retrieve the limit field (“unscrambled” meaning pieced together from its various fragmentary bit-fields) for an arbitrary segment selector. I'm not aware of anything that will retrieve the base address, and of course the LDT itself is not in user-addressable memory. Is this useful, security-wise? Perhaps, but I don't have anything concrete. At a very hand-wavy level, exploits often want to perform system calls, so by making it harder to find the “true” code path that performs a syscall, we may make exploits harder. However, the “soft” system call paths that we are providing using this lcall malarkey are, necessarily, still effective at making system calls; perhaps if there were some extra checking along these paths, which an attacker were trying to evade, this secrecy could be useful, but for now I am just noting the trick in passing. When we land in a 32-bit code segment, the relevant stack pointer will be the %esp register, i.e. the low 32 bits of the %rsp register. So, we will have to provide a stack located in the low 4GB. This is easy to achieve in my use case. It's fortuitous that I want to use these techniques in a library for trapping system calls, where that library is in fact linked into a chain loader that (e.g.) implements a strace-like tool. The use of the chain loader guarantees that we get control from the beginning of execution, and the strace-like nature means we already want to observe all system calls—including, bootstrappingly, all memory-mapping operations that might introduce new system call sites, and also all those that might map a new stack. It also means we have control of the stack at start-of-day—“start” as seen not only by the loaded executable but even by the “real” (chained-to) dynamic linker. By default, the kernel will allocate a stack fairly high, but we can simply switch to a low stack when we run the chained-to dynamic linker; it does not seem to mind. We do, however need to split the possibly-large blocks of strings (I call them “asciz data”) from the on-stack pointer structures that reference them (often called argv and envp). Most code does not mind this split at all. Caveat: I have written code that does mind, in liballocs, which I'd have to update a little not to be wrongfooted by this physically split stack. Stacks are not all alike; the initial stack, created by the kernel during execve(), need not be created the same was as a user thread stack. According to Rich Felker, who would know, Linux reserves 128kB for the initial stack but will attempt to grow it larger on demand. By contrast, libpthread will map an entire stack and, contrary to expectations, neither glibc's nor musl's pthread_create() implementations (at least in the old-ish source trees that I have handy) will map a thread stack with MAP_GROWSDOWN. They just map the entire stack from the off. Although they also include a guard area, it's used to catch small overflows, but not to trigger growth. We need a low stack for a subtly broader reason than for executing 32-bit code. We need it very slightly sooner than we execute any such code: simply for calling out of 64-bit code, to 32-bit code. When I first tested my lcall approach, my 32-bit test code did not use the stack at all, yet still I found the lcall was mysteriously segfaulting, with messages like the below (visible from dmesg). This threw me for a minute. “error 6” refers to a user-mode store to memory (see this great page by Chris Siebenmann)... but I'm doing a call? Of course, a call stores to the stack and the stack is the problem. Here %rsp is 0x00007fffcbd695f0 and the CPU is trying to store a return address at 0xcbd695ec, i.e. its 32-bit truncation (minus four). We infer that if we long-call into a 32-bit code segment, even (morally) before it jumps, the CPU wants to push the return address through %esp not through %rsp. I suppose that's reasonable, because it's assumed the call-to-32-bit will end with a ret-from-32-bit. Under this assumption, the return address we push must be accessible through %esp, so it must be stored to the lower 4GB. (Of course, our particular code invalidates this assumption! As mentioned above, my handler path immediately switches back to 64-bit mode, so we return without ever doing a 32-bit ret.) Some things I checked for completeness: if we do rex.W lcall to a 64-bit segment, how wide is the return address pushed, and does %rsp truncation occur? Answers: 16 bytes of which only 10 are used and no, of course not. In x86, many instructions have an operand width. I can movb to copy a byte, movw to copy a two-byte “word”, movd to ocpy a 32-bit double-word and movq to copy a 64-bit quad-word. Although I hadn't thought about it much before, calls also have an operand width. But what does it refer to? From our earlier rex.W lcall example, we know that the widths a call is working with include both the width of the offset jumped to (4 or 8 bytes) and the width of the return address pushed onto the stack (likewise; of course the 16-bit selector is pushed too, in a long call, and the whole package padded to a word boundary). There's a related but different width we saw with the need for a low stack: the width of the stack address read from the stack pointer as accessed by the call instruction itself. Our previous low-stack surprise call to a 32-bit segment, even though it was executing starting in 64-bit mode, somehow triggered only a 32-bit register read, from %esp, not a 64-bit one from %rsp If it had done the latter, the segfault in the previous section would not have happened. Does a rex.W lcall to a 32-bit code segment also trigger such a segfault? Yes. We can infer that the stack pointer read width, effective at a call instruction, is determined by the target code segment and not by the operand width of the call instruction itself. There are narrower calls too, of course: even in 64-bit mode we can try to do: ... or the obvious lcall variants. What does the “w” refer to? When I try, I get a general protection fault, for reasons unclear. Do these also affect the width of the stack pointer (%esp versus %rsp) used to address the stack during the push? I doubt it but I confess I haven't been able to check. (However, this article shows that LLVM and binutils are confused about callw instructions: they think any immediate displacement is only 16 bits wide, but actually the processor heeds the full 32 bits and the size-override prefix is ignored. Christopher Domas's sandsifter tool, documented here, also found that Intel processors ignore the override but AMD ones heed it. This affects decode, i.e. the width of the immediate operand in the instruction stream, but also operation: whether the jump target is truncated to 16 bits. Do AMD processors perform this truncation? I suspect so but I don't know.) Just as calls can have their operand size overridden, they can have their segment overridden. What does this do? I haven't tested, but this article suggests that segment override applies to memory-indirect calls only, and overrides the usual use of %ds for loading the memory operand. It would make conceptual sense to override the stack segment of a call, but I believe overriding the stack segment is not supported, for any instruction (corroboration). I've not implemented this, but since we're contemplating the %rax-relative thing that works in only 50% of cases, there's a second idea that is not crazy to consider: it should work in roughly 12.5% of cases. I'll call it LDT punning. If we can't use %rip-relative punning, it's probably because the successor bytes pun to only a small displacement, landing somewhere in already-allocated memory such as another part of the same library's text. If they land in the bytes 00 84 c0 74 40 0f, say, then these themselves pun as a stepping stone: they denote offset 0x74c08400 in the segment selected by the 16-bit value 0x400f, i.e. LDT entry 0x801. (Recall that the LDT is indexed by a 13-bit value and the lower 3 bits of the selector must all be 1.) We could allocate a unique LDT entry to handle these, assuming entry 0x801 is otherwise unused. In the LDT entry, we set the 32-bit segment base address to the linear address of our handler minus 0x74c08400 (modulo 32). These may use non-byte-repeating 16-bit selectors, so we are choosing from a much wider space than our 32 byte-repeating values. One of the reasons my low-2GB %rax-punning lcall hack was appealing is that most executables nowadays are position-independent (PIE) and so the low 2GB of the address space often has little content. However, if we do have a non-PIE executable that is linked at a low address range, what can we do? We not only start to collide with stuff in the low 2GB, but negative-pun displacements are mostly intractable for both %rip-relative and %rax-relative cases. If facing a non-small negative displacement in a non-PIE code context, do all our recipes fail? We can still do %rbp-relative punning for frames that save a frame pointer, modulo the obviously increased contention for low-4GB addresses. We can still try the LDT punning trick, at 12.5% likelihood of success. But both of these are a bit desperate. To jump somewhere else punny within the low 4GB, we can fall back to E9Patch's 5-byte techniques; it also suffers from unusable negative-displacement puns but its (palatable) “jump padding” and (nasty) “neighbour eviction” recipes give it more wiggle room to find a viable target. In my case I am tempted to say... do we care? Perhaps a trap via SIGSYS is not so bad in those cases. PIE executables are rare, and executables contain few system calls (compared to the C library). Furthermore, thanks to my next observation, we only need any of these tactics for a slim minority of system calls in the first place.... All the while during this post and last, we have been ignoring an important fact about system call instructions. In most cases, they are preceded by an immediate move into %rax. If we control that immediate, we control the system call number. It is safe to patch the immediate if that %rax value does not leak out, i.e. is not used by any other instruction. Patching the immediate to a high value allows us to use a zpoline-style %rax-relative register-indirect call in place of the ensuing system call, without inheriting the disadvantages of the zpoline itself (mapping low, defeating null pointer checking, etc). After checking that it's safe, we'd simply patch both the system call and the write to %rax, so that the end result is calling our handler, at some address higher up in the first 4GB. I have found that 90% of syscalls can be classified as following this pattern by a very stupid conservative analysis, which I have coded up as an awk script over objdump --visualize-jumps. Therefore, all the punny techniques we've been talking about are needed only in the remaining 10% of awkward cases. We can think of the patch to the immediate field as a “relocation” to the syscall: it lets us change the binding, i.e. the effective %rax value that reaches the site of the call. (This view makes sense to me, anyway, but I have linking on the brain.) Phew! That's all the corners I've explored so far. I started all this thinking there wasn't enough here to be worth writing up as a research paper, but I'm now starting to doubt that. I'd need to measure performance, which for lcall may not be great (but will be better than double traps). I suspect that combining all the above does yield a system call trapping solution for x86 that is a “better” compromise, in some sense, at least in some practical scenarios, than what's in the literature already. I mainly want system call trapping for liballocs, where I do need to avoid the run-time baggage of K23-esque ptrace helpers or zpoline-style disruptions to null pointer trapping. I also value minimal intrusion on debuggability, hence my aversion to E9Patch-style funky noise in the memory map or disrupted control flow within patched functions. So I think these techniques are worth adopting, at least for me. To avoid debug-time confusion I now also want to write that pun-aware disassembler, however! [/research] [all entries] permalink contact