GSoC 2025, Building a Semantic Search Engine for Any Video
Hello, openSUSE community!
My name is Akash Kumar, and I was a Google Summer of Code (GSoC) 2025 mentee with the openSUSE organization. This blog post highlights the project I developed during this mentorship program, which openSUSE and its mentors helped make possible. This summer, I had the incredible opportunity to contribute to the project titled “Create open source sample microservice workload deployments and interfaces.” The goal was to build a functional, open-source workload that could provide relevant analytics for a specific use case.
For my project, I chose to tackle a common but complex problem: searching for content inside a video. This blog post details the outcome of my GSoC project: a full, end-to-end semantic video search engine.
The Problem: Beyond Keywords
Ever tried to find a specific moment in a long video? You might remember the scene vividly - a character gives a crucial speech, or there’s a beautiful, silent shot of a landscape - but you can’t remember the exact timestamp. You end up scrubbing back and forth, wasting minutes, or even hours.
Traditional video search relies on titles, descriptions, and manual tags. It’s limited. It can’t tell you what’s inside the video.
As part of my GSoC deliverable, I set out to solve this. I wanted to build a system that lets you search through a video’s content using natural language. I wanted to be able to ask, “find the scene where they discuss the secret plan in the warehouse,” and get an instant result.
The Big Picture: A Two-Act Play
The entire system is divided into two main parts:
- The Ingestion Pipeline (The Heavy Lifting): An offline process that takes a raw video file and uses a suite of AI models to analyze it, understand it, and store that understanding in a specialized database.
- The Search Application (The Payoff): A real-time web application with a backend API and a frontend UI that lets users perform searches and interact with the results.
Let’s walk through how it all works, step by step.
Part 1: The Ingestion Pipeline - Teaching the Machine to Watch TV
This is where the magic begins. We take a single .mp4 file and deconstruct it into a rich, multi-modal dataset.
Step 1: Deconstructing the Video (Extraction)
First, we break the video down into its fundamental atoms: shots, sounds, and words. I used a series of specialized AI models for this:
-
Shot Detection (
TransNetV2): The video is scanned to identify every single camera cut, creating a “skeleton” of the video’s structure. -
Transcription & Diarization (
WhisperX): The audio is extracted, and WhisperX transcribes all spoken dialogue into text. Crucially, it also performs diarization—identifying who spoke and when, assigning generic labels likeSPEAKER_00andSPEAKER_01. -
Visual Captioning (
BLIP): For every single shot, we extract a keyframe and ask the BLIP model to generate a one-sentence description of what it sees (e.g., “a man in a suit is standing in front of a car”). -
Action & Audio Recognition (
VideoMAE,AST): We go even deeper, analyzing the video clips to detect actions (“talking,” “running”) and the audio to identify non-speech events (“music,” “applause,” “engine sounds”).
At the end of this step, we have a mountain of raw, timestamped data.
Step 1.5: The Human in the Loop (Speaker ID)
The AI knows that different people are speaking, but it doesn’t know their names. This is where a little human intelligence goes a long way. The pipeline automatically pauses and launches a simple web tool. In this tool, I can see all the dialogue for SPEAKER_00, play a few clips to hear their voice, and map them to their real name, like “John Wick.” This simple, one-time step makes the final data infinitely more useful.
Step 2: Finding the Narrative (Intelligent Segmentation)
Searching through hundreds of tiny, 2-second shots isn’t a great user experience. We need to group related shots into coherent scenes or segments. A single conversation might involve 20 shots, but it’s one single event.
To solve this, I developed a “Boundary Scoring” algorithm. It iterates through every shot and calculates a “change score” to the next one, based on a weighted combination of factors:
- Has the topic of conversation changed? (semantic text similarity)
- Have the visuals changed significantly?
- Did the person speaking change?
- Did the background sounds or actions change?
If the total change score is high, we declare a “hard boundary” and start a new segment. This transforms a chaotic list of shots into a clean list of meaningful scenes.
Step 3: Adding a Layer of Genius (LLM Enrichment)
With our coherent segments defined, we bring in a Large Language Model (like Google’s Gemini) to act as an expert video analyst. For each segment, we feed the LLM all the context we’ve gathered—the transcript, the speakers, the visual descriptions, the actions—and ask it to generate:
- A short, descriptive Title.
- A concise 2-3 sentence Summary.
- A list of 5-7 relevant Keywords.
This adds a layer of human-like understanding, making the data even richer and more searchable.
Step 4: Preparing for Search (Indexing)
The final step is to prepare this data for lightning-fast search. We use a vector database (ChromaDB). The core idea is to convert text into numerical representations called embeddings.
The key innovation here is our hybrid embedding strategy. For each segment, we create two distinct embeddings:
- Text Embedding: Based on the transcript and summary. This represents what was said.
- Visual Embedding: Based on the visual captions and actions. This represents what was shown.
These embeddings are stored in ChromaDB. Now, the video is fully processed and ready to be searched.
Part 2: The Search Application - Reaping the Rewards
This is where all the offline work pays off. The application consists of a backend “brain” and a frontend “face.”
The Brains: The FastAPI Backend
The backend API is the engine of our search. When it receives a query, it follows a precise, high-speed process:
- Vectorize Query: The user’s query is converted into the same type of numerical vector using the same model from the indexing step.
- Hybrid Search: It queries ChromaDB twice in parallel—once against the text embeddings and once against the visual embeddings.
- Re-Rank & Fuse: It takes both sets of results and merges them using an algorithm called Reciprocal Rank Fusion (RRF). This is incredibly powerful. A segment that ranks highly on both the text and visual search (e.g., a character says “Look at the helicopter” while a helicopter is on screen) gets a massive score boost and shoots to the top of the list.
- Respond: The backend fetches the full metadata for the top-ranked results and sends it back to the frontend as a clean JSON response.
The Face: The Streamlit UI
The frontend is a simple, clean web interface built with Streamlit. It features a search bar, a video player, and a results area. When you click “Play” on a search result, it instantly jumps the video player to the exact start time of that segment. It’s fast, intuitive, and incredibly satisfying to use.
The Final Result & GSoC Experience
Imagine searching for “a tense negotiation in a warehouse.” The system finds it in seconds because:
- The Text Search matches the dialogue about “the deal,” “the money,” and “the terms.”
- The Visual Search matches the AI captions like “two men sitting at a table” and “a dimly lit, large room.”
- The RRF algorithm sees that both signals point to the same segment and ranks it as the #1 result.
This project was a fascinating journey into the world of multi-modal AI. It demonstrates that by combining the strengths of different models, we can deconstruct unstructured data like video and reassemble it into a smart, searchable, and genuinely useful asset.
I want to extend a huge thank you to my mentor, @bwgartner, and the entire openSUSE community for their support and guidance throughout the summer. Participating in GSoC with openSUSE has been an invaluable learning experience.
The days of aimless scrubbing may soon be behind us. If you’re interested in trying it out or contributing, you can find the entire project on GitHub: https://github.com/AkashKumar7902/video-seach-engine.
Budapest Audio Expo 2025
Last year’s Budapest Audio Expo was the first hifi event I had truly enjoyed in years. Needless to say, I spent a day this weekend at the Audio Expo again :-) Building on last year’s experience, I chose to visit the expo on Sunday. There were fewer people and better-sounding systems.
TL;DR:
If I had to sum up the expo in a one statement: Made in Hungary audio rivals the rest of the world in quality, while often being available at a much more affordable price. My top three favorite sounds came from systems with components mostly made in Hungary: Dorn / Heed, NCS Audio / Qualiton, and Popori / 72 Audio (in alphabetical order :-) ). I have listened to quite a few systems costing a lot more. However, these were the systems that I enjoyed listening to the most.
Dorn / Heed
Dorn / Heed Audio holds a special place in my heart. Not just there: I listen to a full Heed system at home. I was very happy to see them at the event. You could listen there to their latest speaker, connected to an Elixir (amplifier) and an Abacus (DAC). I listened to the exact same setup just a few weeks ago in their show room. Here they sounded even better. As you can see on the photos, “just” a pair of bookshelf speakers, still they could fill the room with clean sound. No matter their size, bass was also detailed and loud enough (disclaimer: there was no Metallica in the playlist, which might have changed this opinion ;-) ). Probably one of the cheapest systems on display at the Expo (not counting DIY), but still one of the best sounding. Natural, life-like sound, a joy to listen to. I went back there to rest, when I was tired from all the artificially sounding systems.
- Dorn (speakers): https://www.facebook.com/profile.php?id=100093087444699
- Heed (everything else): https://heedaudio.com/

Audio Expo 2025: Heed / Dorn

Audio Expo 2025: Heed / Dorn
NCS Audio / PRAUDIO / Qualiton
I first wrote about NCS Audio three years ago. Last year I called Reference One Premium the best value speaker at the expo, as it sounded equally good or sometimes even better than speakers costing an order of magnitude more. Well, nothing has changed from this point of view.
This year NCS Audio shared a room with PRAUDIO and Qualiton. I had a chance to participate in a quick demo, where we learned more about the various digital and analog sources and the speakers, and then listened to them. It was a kind of stereotypical hifi event: songs I listened many times in various rooms during the day. Still, it was good, as it was a wide selection of music, and they sounded just as good as I expected them :-)
- NCS Audio: https://www.ncsaudio.eu/
- PRAUDIO: https://praudio.hu/
- Qualiton: https://qualiton.eu/

Audio Expo 2025: NCS Audio

Audio Expo 2025: NCS Audio
Popori / 72 Audio
While most rooms featured devices, which are in production and available on the market, the room of 72 Audio was different. Everything we listened to, except for the electrostatic speakers from Popori Acoustics, were hand built long time ago. I was rude, as I responded to a text message while sitting in the back row and listening to the music in the room. While I was typing, the music stopped. A new song started, and suddenly I looked up confused: for a moment I was looking for the lady singing. Of course, she was not in the room, just the recording :-) Well, my ears are very difficult to trick, and it only works, when my mind is somewhere else. This was just the third time happening to me.
- Popori Acoustics: https://poporiacoustics.com/
- 72 Audio: https://www.72audio.com/

Audio Expo 2025: Popori Acoustics / 72 Audio
Disappointments
Of course, not everything was perfect. I do not want to say names here, just a few experiences.
I have seen ads about a pair of streaming speakers multiple times a day for the past few months. Finally I had a chance to listen to them. Well. Extreme amount of details. Extreme amount of bass, my weakness. Still, everything sounded too much processed, too artificial. Not my world.
Recently I learned about a speaker brand, developed and manufactured in the city of a close friend. Of course I became curious, how it sounds. Well, practically it’s a high-end home theater speaker. My immediate reaction was that I was looking around where can I watch the film. The exact same song, which was perfectly life-like on the NCS Reference One speakers, sounded like a background music of a movie on this lot more expensive system.
The hosts in most rooms were really kind, helpful, smiling. Not everywhere. When someone blocks the exit and tries to push a catalog in my hands without much communication, that’s a guarantee that I do not want to return there. Luckily this mentality was not typical at all at this event.
Others
Of course I cannot describe everything from a large expo in a single blog. But other than my top 3 favorites, there were a few more I definitely have to mention.
-
Allegro Audio was good, as always. They also had a Made in Hungary component, the Flow amplifier.
-
Hobby Audio was playing music from a tape using a self-built amplifier and pair of speakers. They looked DIY, and they were actually DIY, but had a much more natural sound than some of the much more expensive systems at the expo.

Audio Expo 2025: Audio Hobby
-
Natural Distortion demonstrated a prototype DAC and amplifier. Some of the features are still under development, none-the-less what already worked that sounded really nice and natural. A story definitely worth to follow!
-
Sound Mania had a nice sounding pair of speakers from Odeon Audio. Well, they look a kind of strange, but sound surprisingly good :-)

Audio Expo 2025: Sound Mania

Audio Expo 2025: Sound Mania
Disclaimers
I did not listen to everything. I skipped rooms with headphones, and probably two rooms at the end of a corridor which were always full when I tried to get in. Nobody asked me to shut up about stuff I did not like, I just do not like to be negative on things what are mostly subjective. Neither did anybody promise me money or any kind of audio equipment to write nice things, even if I would not mind receiving a new pair of speakers, an amplifier and a DAC :-)
Closing words
I borrow my closing words from my blog last year: I really hope that next year we will have a similarly good Audio Expo in Budapest!
openSUSE Leap Ready for Liftoff
Users are stepping forward to share how Linux distributions like openSUSE power their projects or interests as users in the community prepare for the next enduring release of openSUSE Leap.
Releases like Leap 16 can be used for aviation tracking and it is one of several use cases for the distribution.
“I’ve been feeding data since 2018 to FlightRadar24, and a few years ago I started sending to OpenSky Network and Plane Finder,” wrote one openSUSE user on the project’s mailing list. “My average distance is around 170 nautical miles.”
In the Mississippi Delta, the user, Malcolm, uses openSUSE as the backbone of these high-tech air traffic monitoring systems.
FlightRadar24, OpenSky Network and Plane Finder collect and share real-time aircraft data from ADS-B receivers worldwide, which allows users to track flights on interactive maps.
Using a stick PC with an Intel Celeron J4125 processor, a 26-inch ADS-B antenna, filters and amplifiers, and openSUSE’s reliability, Malcolm tracks more than 2,000 aircraft a day.
The setup runs with x86_64 hardware, while a Raspberry Pi 3 doubles as a GPS time server, keeping the system and local network synchronized. The systemd services manage the various software packages provided by the tracking networks. Leap’s stability and enduring maintenance and security provide users with an ideal distribution to deploy and enjoy.
Stories like this highlight the use cases that will shape Leap 16’s rollout. The distribution, which bridges community-driven development and enterprise-grade readiness, is expected to serve an even wider range of scenarios. From IoT devices and lab environments to production servers and specialized hobbyist setups, Leap 16 marks the start of a new lifecycle plan for the distribution.
Members of the openSUSE Project are trying to showcase how people use openSUSE . If you have a use cases for Leap 16 that you want to share, comment on the project’s mailing list.
People can leave feedback on survey.opensuse.org regarding the release of Leap 16.
Tumbleweed – Review of the week 2025/40
Dear Tumbleweed users and hackers,
The last trimester of 2025 has begun, and the northern hemisphere of the planet is getting colder; days are grey and short. What could be better than updating your Tumbleweed system? Only one thing: contributing to the package pool! Remind yourself: openSUSE is maintained by a vibrant community, and everybody is invited to help make the distributions better. Of course, Tumbleweed does not want to steal the spotlight from Leap 16.0 this week
Tumbleweed has seen a total of five snapshots (0925, 0929, 0930, 1001, and 1002) this week, bringing you these changes:
- GNOME 49.0: GDM has switched to dynamic users to support multi seat setups. We have seen issues with machines that had an /etc/nsswitch.conf without ‘systemd’ registered as lookup for ‘passwd, shadow, and groups’. Have a look at https://bugzilla.opensuse.org/show_bug.cgi?id=1250513 for details
- Coreutils 9.8
- Poppler 25.09.1
- Boost 1.89
- Meson 1.9.1
- strace 6.17
- AppStream 1.1.0
- Ghostscript 10
- LLVM 21.1.2
- PHP 8.4.13
- Linux kernel 6.16.9 & 6.17.0
- linux-glibc-devel 6.17
- Postgresql 18.0
- Mesa 25.2.3 & 25.2.4
- cURL 8.16.0
- Mozilla Firefox 143.0.3
The testing areas are currently looking into these areas of development:
- KDE Plasma 6.5 beta
- Systemd 258
- Rust 1.90
- ffmpeg-8 as default ffmpeg-implementation
Tomato and burrata pasta with basil Parmesan

End of summmer means home-grown tomatoes. Credits for this luscious Italian recipe from foodblogger Notorious Foodie. For full recipe see below. Their presentation beats mine, of course (make sure to turn the music on as well!).




- Slice in half ~400g of sweet, plump tomatoes – any small variety you like, datterini, piccolo, cherry – I used piccolo here
- In a med-heat pan, add 4tbsp EV olive oil, followed by 3 cloves garlic, half a shallot, 1 peperoncino / red chilli – fry ~4 mins till oil is infused and fragrant
- Add in tomatoes and season with sea salt + black pepp and basil – allow to cook for 15-20 mins, lid on – careful heat isn’t too high, you want a gentle simmer
- Remove lid and deglaze with a 200ml white wine – I used this Soave Classico from Inama Vigneti
- Allow to reduce for further 10 mins – you should see the tomato skins loosen and fall off – at this point, remove as many skins as poss + the garlic, basil, shallot and peperoncino, they’ve done their work
- Remove from heat and add sauce to pot along with 1 whole burrata
- Add 2tbsp olive oil and blitz together till smooth and creamy – taste and adjust for seasoning
- Add spaghetti to salted boiling water and add sauce back into the pan to heat up
- Throw your al dente pasta into the sauce along with some pasta water and continue melding together till perfectly cooked – once almost done, kill heat, add in some grated parmigiano and combine
- Basil Parmesan: add 75g cold parmigiano + a handful of basil leaves to a food processor and blitz till crumbly and bright green – this stuff is amazing
- Plate up, spooning over more of the tomato burrata sauce and sprinkling over your basil parm
Version 4.10.1 of syslog-ng now available
Version 4.10.1 is a bugfix release, not needed by most users. It fixes the syslog-ng container and platform support in some less common situations.
Before you begin
I assume that most people are lazy and/or overbooked, just like me. So, if you already have syslog-ng 4.10.0 up and running, and packaged for your platform, just skip this bugfix release.
What is fixed?
- You can now compile syslog-ng on FreeBSD 15 again.
- The syslog-ng container has Python support working again.
- Stackdump support compiles only on glibc Linux systems, but it also used to be enabled on others when libunwind was present. This problem affected embedded Linux systems using alternative libc implementations like OpenWRT and Gentoo in some cases. It is now turned off by default, therefore it needs to be explicitly enabled.
What is next?
If you are switching to 4.10.X now, using 4.10.1 might spare you some extra debugging. Especially if you are developing for an embedded system.

syslog-ng logo
Next Chapter Opens with Leap 16 Release
CA / CS / JA / LT / SV / ES / ZH-TW
Members of openSUSE Project are thrilled to announce the release of openSUSE Leap 16.
This major version update of our fixed-release community-Linux distribution has a fresh software stack and introduces an unmatched maintenance- and security-support cycle, a new installer and simplified migration options.
“Vendors and developers should give Leap and Leap Micro a serious look and consider it as the target platform for their solutions,” said release manager Lubos Kocman. “You get 24 months of free maintenance and security updates. No other community distro offers that at no cost.”
Leap 16 as a community-supported platform will shape open-source development breakthroughs and real-world solutions in the years ahead. The release is 2038 safe and comes with 32-bit (ia32) support disabled by default. It gives users the option to enable it manually and enjoy gaming with Steam, which still relies on 32-bit libraries. The hardware requirements have changed. Leap 16 now requires x86-64-v2 as a minimum CPU architecture level, which generally means CPUs bought in 2008 or later. Users with older hardware can migrate to Slowroll or Tumbleweed.
Leap 16 channels community and enterprise distribution code by building on the foundation of SUSE Linux Enterprise Server (SLES), bringing source and binary identicality with it. Users have the option to seamlessly migrate from openSUSE Leap 16 to SLES 16. Developers can use openSUSE Leap to create, test and run workloads for later deployment on SLES.
Leap 16 ships with the new Agama installer, which offers a more modern setup experience over the deprecated YaST-based installer. Leap 16 further supports parallel downloads in the package manager Zypper to speed up software installations and updates.
Migration also gets easier with this major version update. The new openSUSE Migration tool allows users to seamlessly upgrade from Leap 15 to Leap 16 as well as to migrate to Slowroll, Tumbleweed or SLES.
Leap 16 marks the start of a new life-cycle plan. Unless the project makes strategic changes, annual minor releases are expected to continue until 2031 with the release of Leap 16.6. A successor to Leap 16 is expected in 2032. Leap Micro, the project’s immutable server distribution, is adopting the same schedule.
The release comes with SELinux as the Linux Security Module (LSM) . AppArmor remains an option that can be selected post installation. Changes in Leap related to AppArmor and 32-bit support offer a transition period for users.
More advancements will come as Leap 16 evolves toward its final release next decade as automation, containerization, system tooling and hardware encryption mature.
Those who wish to develop for Leap 16 are encouraged to participate in the weekly feature review meeting on Mondays.
Known bugs for Leap 16 can be found on the project’s wiki.
People can leave feedback about the release of Leap 16 at survey.opensuse.org.
Migrating to openSUSE Leap 16.0 with opensuse-migration-tool
Over the years, I have noticed that the biggest challenges during upgrades usually involve 3rd-party repositories, mostly due to their unavailability for the new release or delays in catching up.
Another challenge has been constant changes to distribution repositories. For example, in Leap 15.3 we removed the ports repositories as part of the Closing the Leap Gap initiative and also introduced SLE Update repositories.
Now, with Leap 16.0, update repositories are being removed entirely. Leap Micro 6.X also no longer has dedicated update repositories.
In the past, users had to manually modify distribution repositories. Fortunately, openSUSE-repos automates this process and puts distribution repositories under RPM management. This is now the default behavior for both Leap Micro 6 and Leap 16. This dramatically simplified the whole upgrade and distribution migration process.
Why use opensuse-migration-tool
Upgrading your system doesn’t have to be scary or complicated. The opensuse-migration-tool is designed to make the process simple, safe, and predictable. I got inspired by our jeos-firstboot, which uses dialog for smooth interactions. The tool also greets you with a nice green dialog, thanks to a customized dialogrc—giving it that familiar openSUSE look and feel right from the start.
Here’s what it can do for you:
- Install updated distribution repository definitions automatically
- Disable non-distribution repositories to avoid conflicts
- Run
zypper dupfor a smooth, safe upgrade - Offer post-upgrade scripts to adopt new defaults—or keep your preferred settings, for example AppArmor vs SELinux
- Perform pre-migration checks to make sure your system is ready, including verifying
x86_64-v2support - Reboot
- Optional snapper-rollback or simply boot to older snapshot from grub
The tool isn’t limited to just Leap n → Leap n+1. You can also upgrade to SUSE Linux Enterprise, Slowroll, or Tumbleweed. Slowroll → Tumbleweed upgrades work too, and recent requests include Leap Micro → Slowroll Micro. As long as it’s an upgrade, it will simply work.
Want to see it in action? Check out LowTechLinux’s opensuse-migration-tool review on YouTube for a hands-on demo and external validation.
Getting started
In case the tool is not yet installed on your system do sudo zypper in opensuse-migration-tool
If you are using the tool for the first time or just want to check it out, run it in test mode:
/usr/sbin/opensuse-migration-tool --dry-run # no need to use sudo in dry-run mode
This will not show exactly what will be upgraded, but it will give you a good idea of what the tool can do and it will not make any changes to your system.
Once you feel confident, run:
sudo opensuse-migration-tool
The tool will offer to disable non-distribution repositories, which is strongly recommended. It will then trigger zypper dup --r and automatically rerun zypper if any issues occur.
The tool also performs pre-migration system checks. If you are affected by any issues, you might want to run the latest version directly from git. Contributions are welcome.
git clone https://github.com/openSUSE/opensuse-migration-tool.git
cd opensuse-migration-tool
./opensuse-migration-tool --dry-run
Further documentation
More information can be found at openSUSE System Upgrade. This document also suggests how to perform a manual upgrade to 16.0, although I would not recommend it, especially given the positive feedback we have received for the tool.
Make sure to read Leap 16.0 release notes as well as Known bugs wiki prior to upgrading.
Future plans
I plan to provide an optional GTK4 interface that preserves the shared migration logic and power of Bash. This will use custom GTK4 dialogs to keep the openSUSE look and feel, but it will be invoked similarly to zenity. Here’s a sneak peek from the first two dialogs:
People can leave feedback on survey.opensuse.org after the general availability of the release today at 12:00 UTC when the survey becomes published regarding the release of Leap 16.
The only benchmark that matters is...
…the one that emulates your real workload. And for me (and probably many of you reading this), that would be “build a kernel as fast as possible.” And for that, I recommend the simple kcbench.
I kcbench mentioned it a few years ago, when writing about a new workstation that Level One Techs set up for me, and I’ve been using that as my primary workstation ever since (just over 5 years!).
SUSE Security Team Spotlight Summer 2025
Table of Contents
- 1) Introduction
- 2) systemd v258: Local Root Exploit in new systemd-machined API found in Release Candidates
- 3) logrotate: Issues in drop-in Configuration Files
- 4) GNOME 49: D-Bus and Polkit Changes in new Major Version Release
- 5) Kea DHCP: Follow-Up Review of Network Attack Surface
- 6) chrony: Issues in chronyc Socket Creation
- 7) pwaccessd: New Varlink Service for Reading User Account Information
- 8) sysextmgr: New Varlink Service for Managing systemd-sysext Images
- 9) bash-git-prompt: Predictable Temporary File Name Offers Local Attack Surface (CVE-2025-61659)
- 10) steam-powerbuttond: Insecure Operation in Home Directories
- 11) Conclusion
- Change History
1) Introduction
Autumn is already palpable for many of us these days and this means it is time to take a look back at what happened in our team during the summer months. We have not published any dedicated security reports during that time; instead we have all the more to cover in this edition of the spotlight series which discusses code review efforts that did not lead to major findings or otherwise did not qualify for a dedicated report.
This is also the first anniversary of the spotlight series, which we started in August 2024 with the first summer spotlight edition. We are happy to provide our readers with interesting content about the daily work in our team and are looking forward to more anniversaries to come.
In this issue we will cover a local root exploit we discovered in systemd
v258-rc4 before it became part of a stable release, problems
found in logrotate drop-in configuration files, changes
in D-Bus configuration files related to the GNOME version 49
release, and a follow-up code review of the Kea DHCP server
suite. Furthermore we found a symlink attack issue in
chronyc, proactively reviewed new Varlink
services developed by fellow SUSE engineers and discovered a
local privilege escalation issue in bash-git-prompt. Finally we
will talk about a problematic script used on Steam Deck
devices.
2) systemd v258: Local Root Exploit in new systemd-machined API found in Release Candidates
At the beginning of August one of our systemd maintainers asked us to review
D-Bus and Polkit API changes in a release candidate of
systemd 258. This major version update of systemd contains many API additions
e.g. in systemd-resolved, systemd-homed, systemd-machined and
systemd-nsresourced.
While looking into these changes we found an issue in systemd-machined. This
daemon can be used to manage virtual machines and containers alike.
In upstream commit adaff8eb35d a new Polkit
action “org.freedesktop.machine1.register-machine” has been added, which was
accessible to locally logged in users without authentication (Polkit yes
setting). The purpose of this new API is to allow users to register existing
containers with systemd-machined, that have been created by other means.
There exist two D-Bus methods which employ this Polkit action: “RegisterMachine” and “RegisterMachineWithNetwork”. Both accept a rather long list of parameters to describe the container which is supposed to be registered with the daemon. The following command line performs an example registration of a fake container:
$ gdbus call -y -d org.freedesktop.machine1 -o /org/freedesktop/machine1 \
-m org.freedesktop.machine1.Manager.RegisterMachineWithNetwork \
mymachine '[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]' myservice container \
$$ $PWD '[1, 2, 3]'
Among these parameters is the process ID (PID) of the leader process of the
container. In this example $$, i.e. the shell’s own PID, is passed as leader
PID. The release candidate implementation of systemd-machined failed to
verify whether this process is owned by the caller and an actual member of an
unprivileged user namespace belonging to a container.
The first problematic aspect we noticed about this was that systemd-machined
can send SIGTERM to the process group the given leader PID belongs to (e.g.
when registering a new container using the same name), allowing a trivial
local Denial-of-Service against arbitrary other processes. Far more
problematic was something else that we noticed: the unprivileged user was able
to enter a shell in such a crafted container, like this:
user$ machinectl shell mymachine
# full root privileges, this happens in the actual host's file system
container-root# touch /evil
Since the leader PID in this case is a process belonging to the host’s initial namespaces, the root shell for the “container” is actually a root shell in the host itself, giving full root privileges over the system.
This problem is found in all release candidates of systemd v258. We reported the problem privately to systemd security, and upstream developed bugfixes right away while still in the RC phase. The local root exploit was never present in any stable release version and thus end users are not affected by the problem, which is also why no CVE was assigned.
The Bugfix
To address the issue, systemd-machined now verifies that the leader PID
specified by the client is actually owned by the caller. Furthermore the
authentication requirements for Polkit action “register-machine” have been
raised to auth_admin_keep even for local users.
While writing this very summary we noticed that one aspect of the issue had
been overlooked and was not fixed for the stable release: the verification of
the user namespace membership of the target process. Thus it is still possible
to gain a root shell this way, but only after authenticating as admin, which
means the caller already needs admin privileges to trigger the exploit. This
aspect has now been addressed for future releases by
upstream, which is important, because upstream intends to relax the
authentication requirements for this action to yes again at a later time.
Increase in Complexity in systemd
With this version of systemd we are seeing a noticeable increase in complexity
in the implementation of a number of systemd components. In the area of
container management the complexity is pretty much by design, given the
intricacy of the different namespace mechanisms playing together, partly
under the control of unprivileged users. There is also the addition of
Varlink for Inter-Process-Communication, however, which
means that two different interfaces for D-Bus and Varlink now exist in parallel
for some services. This is also the case for systemd-machined.
While the D-Bus and Varlink interfaces usually call into shared functions for most of the business logic and share the same Polkit actions, there is necessarily a certain amount of redundancy in parsing and evaluation of input parameters. As a result this also increases the burden on code reviewers which now need to keep track of two different entry paths to the same logic.
We are not yet completely finished with reviewing all notable changes in systemd v258 but intend to complete the effort within the next couple of weeks. We are happy that our review efforts already prevented a local root exploit in software as widespread as systemd from ending up in production environments.
3) logrotate: Issues in drop-in Configuration Files
Missing su <user> <group> Directives
Recently we noticed that there exist a number of packages in openSUSE
Tumbleweed which trigger a
“logrotate-user-writable-log-dir” rpmlint
diagnostic. This diagnostic is emitted when a
package contains a logrotate drop-in configuration file (e.g. in
/etc/logrotate.d) which points the logrotate daemon to a log directory which
is controlled by non-root accounts, where it will operate with full root
privileges.
Operating as root in locations controlled by other users is generally very
difficult to get right and can easily lead to privilege escalation from a
service user to root e.g. via symlink attacks. logrotate
offers a su <user> <group> syntax to
instruct the daemon to perform a privilege drop to the user owning the
directory to avoid any security implications.
To start with, we had a look at the implementation of the logrotate daemon, to judge what the impact would be, when a rogue service user account tries to perform an attack against logrotate when it starts rotating logs in a directory controlled by the compromised user. The results are as follows:
- the daemon performs a sanity check on the directory to operate on and rejects any log directories which are writable by world or a non-root group. This does not include the case where the log directory is owned by a non-root user, however.
- the system calls used by logrotate always include safe flags for opening log files which will prevent trivial symlink attacks by service users from succeeding. There could still be more intricate attacks when a parent directory of the log directory is also owned by a non-root user account. This is not a common setup, however, and we could not find any package where this is the case.
In summary we believe that there are no overly dangerous situations that can
result from a missing su <user> <group> directive in affected logrotate
configuration files. Still we decided that it will be better to fix existing
packages and enforce that packages emitting this rpmlint diagnostic are not
allowed into openSUSE in the future. To this end we fixed a couple of
openSUSE-specific logrotate drop-in configuration files as well as an upstream
configuration file in Munge.
Problems with Scripts Embedded in Configuration
While looking into the credentials mismatch issue we noticed that logrotate
can end up in even more complex usage scenarios. The configuration file format
allows shell scripts to be embedded that will be executed after rotating
logfiles, for example. These scripts always run with full root privileges,
independently of an existing su <user> <group> directive. The likeliness of
security issues is higher in this case and issues are harder to detect, since
this is package-specific code possibly running as root in untrusted
directories.
While exploring all embedded scripts found in logrotate drop-in configuration files in openSUSE Tumbleweed we found out that in most cases such scripts are only used to restart a systemd service or to send a signal to a daemon running in the background. In a few cases the scripts have been problematic, as is described in the following sub-sections.
python-mailman (CVE-2025-53882)
In the python-mailman package we found two problems in the embedded shell script, which consisted of these two lines:
/bin/kill -HUP $(</run/mailman/master.pid) 2>/dev/null || true
@BINDIR@/mailman reopen >/dev/null 2>&1 || true
For one, SIGHUP was sent to a PID obtained from /run/mailman/master.pid,
which is under the control of the mailman service user. This would allow a
compromised mailman user to direct SIGHUP to arbitrary processes in the
system.
Furthermore the command line /usr/bin/mailman reopen was executed with full
root privileges, which results in output like this:
Usage: mailman [OPTIONS] COMMAND [ARGS]...
Try 'mailman -h' for help.
Error: If you are sure you want to run as root, specify --run-as-root.
This shows that the intended reopen of logfiles doesn’t work as expected.
Otherwise one might think that nothing harmful happens. This is not true,
however. This invocation of mailman still leads to the full initialization
of the logging system and all the logfiles in /var/log/mailman are
created, if not already existing, with full root privileges. Symbolic links
are followed, if necessary.
This means a compromised mailman user can e.g. create a symlink
/var/log/mailman/bounce.log → /etc/evil-file. After the logrotate script
runs /etc/evil-file will be created. The files will be created with
root-ownership, so the only impact of this should be the creation of new empty
files owned by root in the system. This can still have security impact when
such empty state files control sensitive settings of other programs in the
system.
To fix this issue the sending of SIGHUP was completely dropped and the
reopen command is invoked via sudo as the dedicated mailman service user
and group. The logrotate drop-in configuration file containing the
problematic script is specific to openSUSE, thus we assigned a CVE for this
issue to make our users aware.
sssd
The sssd package has a very similar issue in its
example logrotate configuration, where a SIGHUP
signal is sent to a PID controlled by the sssd service user:
/bin/kill -HUP `cat @pidpath@/sssd.pid 2>/dev/null` 2> /dev/null || true
We created a public upstream GitHub issue to make the developers aware of the problem. There is no fix available yet for the issue.
Icinga2 (CVE-2025-61909)
In our icinga2 package there is yet another instance of sending a signal
(SIGUSR1) to a PID controlled by the unprivileged icinga service user:
/bin/kill -USR1 $(cat /run/icinga2/icinga2.pid 2> /dev/null) 2>/dev/null || true
We wanted to change that into a systemctl reload icinga2.service instead,
only to find out that upstream’s reload script is affected by the same
issue. We reported the problem to upstream and they
fixed it and assigned a CVE by now.
exim (CVE-2025-53881)
Our exim package contained a problematic prerotate shell script in its
logrotate configuration which allows escalation from
the mail user/group to root, when it runs. The
shell script is rather complex and tries to generate a statistics report
creating temporary files as root in the log directory owned by the
unprivileged mail user.
To fix this, the script has been adjusted to use a private temporary directory for the report, instead. An update containing the fix will soon be available for openSUSE Tumbleweed.
This again is an openSUSE specific logrotate configuration file, thus we assigned a CVE to mark the problem.
Possible Improvements in logrotate
The issues we uncovered show also room for improvement in logrotate itself to
prevent such situations in the first place. For one, the daemon could refuse
to work on directories owned by non-root users, like it does for
world-writable directories. Furthermore scripts could be executed using the
same su <user> <group> credentials that are used for rotating the logs.
We did not reach out to upstream about these suggestions yet, but will keep you informed about any developments in this area.
4) GNOME 49: D-Bus and Polkit Changes in new Major Version Release
GNOME 49 was recently released and our GNOME maintainers asked us to look into a number of D-Bus and Polkit changes that appeared in related packages. We encountered nothing too exciting this time:
-
GDM: Two changes appeared in GNOME’s display manager:
- Some polkit actions are now tied to the
gdmgroup instead of to thegdmuser. This is related to the display manager now using dynamic user accounts. - The
gdmgroup is now allowed to access smart cards managed bypcscd. This is supposed to fix a bug report where smart cards could not be accessed by GDM. Why this bug never occurred before is not completely clear, the Polkit settings are acceptable in any case.
- Some polkit actions are now tied to the
-
gnome-initial-setup: This package received the same
change as GDM, Polkit actions are now tied to the
gdmgroup, not the user. -
gnome-remote-desktop: This is the same as in
gnome-initial-setup, Polkit actions are now tied to the
gdmgroup instead of the user. -
mutter: This part of GNOME (a Wayland compositor
and X11 window manager) now contains a
backlight-helper. Locally logged in regular users are allowed to execute this program withrootprivileges to control the backlight of mobile devices. We have seen this helper program before in thegnome-settings-daemonpackage. It is a minimal C program consisting of 200 lines of code and we could not find any issues in it.
5) Kea DHCP: Follow-Up Review of Network Attack Surface
Earlier this year we reported a number of local security issues pertaining to the REST API in Kea DHCP. In a follow-up review we focused on the network attack surface, which usually is the more interesting part when dealing with a DHCP server suite. Alas, while looking at the network logic we stumbled over another minor local security issue regarding a temporary change to the process’s umask. Upstream addressed the problem in the meantime.
Following the actual network processing logic in Kea’s code base is no easy task. The C++ coding style uses a high level of abstraction which leads to many indirections. Untrusted data received from network peers travels far in the code without clear logical boundaries where data is verified before further processing takes place. The code base contains a lot of comments, which usually is a good thing, but in this instance it felt nearly too verbose to us, making it hard to find the relevant bits.
On the positive side of things Kea is already a matured project and there were no easy pickings to be found. Upstream also integrated AFL fuzzing into their testing infrastructure, which should allow them to find network security issues proactively. Consequently we have been unable to find any security issues in the network processing in Kea.
Kea offers advanced features like configuring custom behaviour depending on specific DHCP header fields. This naturally comes with quite some additional complexity. In this light we believe Kea is well suited for large organizations, but we would recommend a simpler DHCP server implementation for small environments where such features are not needed, to reduce attack surface.
6) chrony: Issues in chronyc Socket Creation
This finding resulted from our logrotate configuration
file investigation discussed above. chrony is the
default NTP time synchronization program used in openSUSE and a number of
other Linux distributions. It ships a logrotate drop-in configuration
file that contains this postrotate shell code:
postrotate
/usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
endscript
chronyc is the client utility used to talk to the chronyd daemon
component. The communication mechanism used for this is a UNIX domain socket
placed in /run/chrony/chronyd.sock. chronyc is invoked as root in the
logrotate context above. At first we believed this should not be a problem,
since any privileged process should be allowed to talk to chronyd. While
looking at the strace output of the command line above the following system
call caught our attention, however:
chmod("/run/chrony/chronyc.6588.sock", 0666) = 0
The /run/chrony directory is owned by the chrony service user:
drwxr-x--- 3 chrony chrony 100 Sep 25 09:45 .
These are the same credentials used by the chronyd daemon. When root
performs the chmod call above, then a compromised chrony service user has
an opportunity to perform a symlink attack, directing the chmod() operation
to arbitrary files on the system, making them world-writable, thus making
possible a chrony to root privilege escalation. A couple of years ago we
found a somewhat similar symlink attack in the area
of the pidfile creation performed by the daemon.
We approached upstream about the issue on July 15 by creating a private
issue in their GitLab project. The bugfix
turned out rather complex. The problem here is that the UNIX domain socket
used by chrony is datagram-oriented (SOCK_DGRAM). This means there is no
connection established between client and server. For the server being able to
send back data to the client, the client needs to bind its socket into the
file system as well and grant the server-side access to it. On Linux an
autobind feature exists for Unix domain sockets, which will automatically
assign an abstract address to the client socket, which is not visible in the
file system. This feature is not available on other UNIX systems, however,
that chrony also intends to support.
For these reasons the upstream approach to fix this involves the creation of
an unpredictably named sub-directory in /run/chrony to place the client-end
socket into. The directory is only writable for the client and the
unpredictable directory name is not known in advance, thus no symlinks can be
placed into the path anymore.
7) pwaccessd: New Varlink Service for Reading User Account Information
A fellow SUSE engineer recently finished development on
pwaccessd, a daemon providing user account information
via Varlink. This novel approach to providing account information allows, for
example, to grant regular users access to their own shadow entry, which would
otherwise only be accessible to root.
At the end of June we have been asked to review the new daemon for its security. We had a couple of hardening recommendations and found an instance of possible log spoofing, but have otherwise been satisfied with the implementation. Bugfixes and improvements have been incorporated and the new service is now ready to be used in production.
8) sysextmgr: New Varlink Service for Managing systemd-sysext Images
sysextmgr is another new Varlink service developed by SUSE, which this time helps with the management of systemd-sysext images on openSUSE MicroOS. We noticed the addition of this service to openSUSE via our monitoring of newly added systemd services in the distribution. While looking into the Varlink API we discovered a number of issues in the service like Denial-of-Service attack surface and some minor symlink issues. The issues could be resolved quickly and we are now happy with the state of the service.
9) bash-git-prompt: Predictable Temporary File Name Offers Local Attack Surface (CVE-2025-61659)
Our team is currently undertaking an effort to have a look at all kinds of
shell related drop-in code like command-specific shell completion support and
files installed into /etc/profile.d to manipulate the shell environment.
Any packages can install such files and they can easily lead to security
problems when things are not done right.
The amount of such files in a complete Linux distribution is huge, naturally,
thus this is a long-term task that will require time to produce a complete
list of findings. A first finding in the
bash-git-prompt package already resulted from this, however.
This package installs shell code into /etc/profile.d/bash-git-prompt.sh
which enables an interactive Git prompt which will be displayed as soon as the
Bash shell enters a Git repository. This prompt contains information about
the current repository, the number of modified files and other things that can
be configured by users. The prompt feature using default settings becomes
active as soon as the package is installed.
While looking into the shell code that implements all this we noticed the use
of a predictable temporary file in
/tmp/git-index-private$$. bash-git-prompt copies the Git index file found
in the current Git repository to this location. It turns out that this copy
operation happens every time the interactive shell user enters a new command
while being located in a Git repository. The temporary file is soon deleted
again when the Git bash prompt has been fully rendered by the program.
Since an interactive bash shell session is a long-lived process it is rather simple for other users in the system to pre-create the temporary file in question and cause all kinds of issues:
- Denial-of-Service: by blocking the path, the Git prompt setup will fail to complete and the prompt will be broken. By placing a FIFO named pipe in this location the victim’s shell will even lock up completely.
- information leak: the copy of the Git index is made using the umask of
the shell. When the default umask
022is used, then the copy of the Git index becomes world-readable in/tmp. If the victim’s Git repository contains non-public data then part of that data (e.g. file names of pending change sets) leaks to other users in the system. - integrity violation: when a local attacker places crafted data in the
location of the temporary file and denies write access, then
bash-git-promptfails to write the desired Git index data to this location, but will not stop execution despite this error. The crafted Git index data will be fed to various invocations of thegitcommand line utility, possibly leading to a crafted bash prompt or even leading to some forms of code execution. To determine the full extent of this, a low level analysis of the handling of the binary Git index format would be necessary.
The problem was discovered independently a while ago already, which is why
there exists a public GitHub issue for it. An upstream
author attempted to fix the issue, but rolled back the changes due to a
regression and nothing happened since. The issue was introduced via commit
38f7dbc0bb8 in bash-git-prompt version 2.6.1. We
added a simple patch to our packaging of bash-git-prompt
which should address all issues for users of openSUSE.
At the end of September we requested a CVE from Mitre to track this issue and they assigned CVE-2025-61659.
10) steam-powerbuttond: Insecure Operation in Home Directories
Our team’s monitoring of newly added systemd services in openSUSE led us to steam-powerbuttond. It derives from a script found on the SteamOS Linux distribution for use on Steam Deck gaming devices.
The main component of this package is a Python script which runs as a systemd
service with full root privileges. This script contains various security
issues. During startup the script attempts to
determine who “the first user” in the system is, by parsing the output of who
| head -1. This user’s home directory is then used for operations later on,
when a power button press event is detected. After processing the event, the
file /home/{user}/.steam/steam.pid is read and used for accessing
/proc/{pid}/cmdline.
This logic leads to various possible issues, ranging from the the wrong user being selected initially, to denial-of-service when unexpected file content is placed in the unprivileged user’s home directory. We contacted one of the original upstream authors about this and offered coordinated disclosure. It turned out that the project is not supposed to be used anymore, however, and as a result the GitHub repository has been archived by the maintainer.
The openSUSE steam-powerbuttond package is now waiting to be replaced by a
new script that is supposed to be found in SteamOS.
11) Conclusion
This edition of the SUSE security team spotlight was quite packed with topics. We hope this can give you an insight into all the different kind of activities we end up in on our mission to improve the security of open source software, in the Linux ecosystem in general and openSUSE in particular. We’re looking forward to the next issue of the spotlight series in about three months from now.
Change History
| 2025-10-23 | Updated the logrotate Icinga2 sub-section to include the upstream CVE and a link to the upstream security advisory. |