From the blog

ICYMI: improved C++ vulnerability coverage and CodeQL support for Lombok

In the ever-evolving software development landscape, static application security solutions face a unique challenge: as applications grow in complexity, they rely heavily on a diverse array of libraries, frameworks, and custom code. Ensuring the security of such intricate systems requires a meticulous approach—and not all solutions are created equal. The effectiveness of a static application security solution hinges on its ability to provide extensive vulnerability coverage and support for a wide range of languages and frameworks. Code scanning, for example, is equipped with broad coverage for the most popular languages and frameworks and can scrutinize all parts of the codebase, leaving no stone unturned. This approach leads to the identification of an expansive array of vulnerabilities, including those specific to certain technologies or development patterns. The result is a more thorough and reliable assessment of an organization’s security posture. We’re always looking for ways to help you detect more vulnerabilities in your codebase, so today, we’re highlighting two releases aimed at providing better coverage for both languages and frameworks, improved C++ vulnerability coverage and Lombok support. Improved C++ vulnerability coverage Detecting vulnerabilities in C++ code is uniquely challenging because of the language’s low-level memory manipulation, complexity, undefined behavior, platform discrepancies, and the absence of built-in memory safety features. Legacy code, concurrency issues, and dynamic memory allocation further compound this difficulty. Addressing these vulnerabilities must be done with precision, including rigorous code reviews, extensive testing, and the adoption of secure coding practices. CodeQL for C and C++ has recently gained increased support for detecting complex memory corruption vulnerabilities. Broadly speaking, these vulnerabilities are all related to dereferencing pointers that should not be dereferenced at a given point in the code. For those who are interested in delving deeper into the technical aspects of this topic, below we’ll explore a couple of new kinds of vulnerabilities CodeQL can now detect. An in depth look at CodeQL’s new C++ vulnerability coverage The default query suite can now detect double-free and use-after-free vulnerabilities using the queries cpp/double-free and cpp/use-after-free. These are classic memory corruption issues that C and C++ developers constantly have to keep in mind to avoid creating serious security incidents. In addition, the default query suite now also detects dereferences that look suspicious in general using the query cpp/redundant-null-check-simple. Finding “suspicious dereferences” in general is very hard since there are so many ways to make the dereference “obviously” safe. The query gets around these problems by finding dereferences that are always performed regardless of the result of a null check, or where a null check is always performed after the dereference (which suggests that the pointer may, in fact, sometimes be null). The security-extended suite has also gained much better support for reasoning about buffer overflows with two new queries cpp/overrun-write and cpp/invalid-pointer-deref, which detect different kinds of pointer dereferences that may be out of bounds. Both cpp/invalid-pointer-deref and cpp/overrun-write perform a novel analysis that finds the size of an allocation by doing two “parallel” dataflow analyses (one dataflow analysis to track the pointer and another dataflow analysis to track the size of the allocation), which enable us to find places in the code where a pointer dereference is incorrectly guarded. Such “off by one” errors are very common, and we have confirmed that cpp/invalid-pointer-deref finds existing CVEs such as https://www.cvedetails.com/cve/CVE-2018-14599/. This […]

Read More

Win64 Clang Toolchains in RAD Studio 12

This blog post is based on a pre-release version of the RAD Studio software and it has been written with specific permission by Embarcadero. No feature is committed until the product GA release. RAD Studio 12 is just around the corner, and we have exciting news to share! In August, we ran an unusual webinar where we shared a behind-the-scenes look at some technology we’ve been working on for C++Builder and the C++ side of RAD Studio. One of the things we previewed was an upgraded Clang-based Win64 compiler – though not just an upgrade but some major technological improvements to core areas, with a new STL, a new linker, and more. It is a thorough rework of the entire toolchain with a strong eye to making the right decisions for quality and longevity. Table of Contents New Clang Platform standards High performance for the compiled code. Optimised runtimes Excellent language standards compatibility. Excellent quality in all areas, such as exception handling A robust STL. A linker that can handle anything Tech details Status Toolchains in version 12.0 Overall New Clang The C++ compiler is foundational to RAD Studio. Through the Clang & LLVM work, we make LLVM available to Delphi. And, of course, we need a modern, powerful C++ compiler to provide our C++ developers with the best source compatibility, libraries, app performance, and more. Our goals for the work are: Very high quality. A robust STL. A linker that can handle anything and any quantity you give it. Excellent quality in all areas, such as exception handling Excellent language standards compatibility. High performance for the compiled code. Optimised runtimes. Match platform standards as much as possible How are we meeting those? Let’s go in reverse order. Platform standards The new toolchain is based on Clang 15*. The previous toolchain used the ELF object file format, a primarily Unix/Linux format, for historical reasons that are actually (long story) related to Kylix. For this toolchain, we are moving to COFF, which is the standard object file format for Windows compilers of any compiled language. Similarly, we are using the PDB debug format, which again is the standard. While we are not officially supporting any third party tools, there are many tools developers use which understand COFF & PDB and we hope that by adhering to the platform norms, we open up the opportunity to use a wide variety of tools with your apps and C++Builder. [*] Clang 15 was current when this work started, and we are avoiding changing the wheels while the car is in motion. We plan to remain up to date and move forward with Clang itself in future. High performance for the compiled code. While we are aiming for correct compiled code behaviour above all else, we are also aiming for high performance. The new toolchain’s technology generates more optimized code, and allows additional optimisations that were not previously possible in future. Optimised runtimes A C++ toolchain has multiple layers: a C runtime (providing things like printing to a console or file IO), a C++ runtime (providing things like exception handling), and the STL (providing C++ library functions like standard IO, algorithms, collections, etc.) For our toolchain, we are replacing all three. Image showing three layers of the C++ runtime: standard library, C++ RTL, and C […]

Read More

Stacklet Applies Generative AI to Simplify Cloud Governance

Stacklet today provided early access to a Jun0 tool that leverages generative artificial intelligence (AI) to improve cloud governance and reduce costs. Stacklet CEO Travis Stanfield said the goal is to make it possible to automatically surface recommendations and implement policies using a mix of large language models (LLMs) trained using data collected via the company’s Stacklet AssetDB database. Accessed via a natural language interface, Jun0 makes it possible to declaratively govern cloud computing environments via text-based queries to generate policies that can be implemented as code; that eliminates the need for specialized programming expertise, he added. IT teams can use text to launch queries pertaining to any operations, cost, security and compliance issues and then visually test the policies created as part of a dry run before implementing them at scale. In effect, Jun0 substantially reduces the level of expertise required to successfully manage cloud computing environments by making it simpler to create governance policies, noted Stanfield. DevOps teams are generally tasked with making sure cloud computing environments are optimally managed using policies that are usually implemented as code within a DevOps workflow. Implementing policy-as-code, however, typically involves mastering a domain-specific programming language. Stacklet is now making a case for a higher level of abstraction that eliminates the need to master yet another programming language to govern cloud computing environments. It’s still early days as far as the adoption of generative AI is concerned within DevOps workflows, but it’s already clear that implementing best practices is about to become substantially easier. In essence, DevOps practices are about to become democratized in a way that reduces the cognitive load required to implement them. In addition to increasing the number of application environments a DevOps team may be able to effectively manage, generative AI will make DevOps accessible to a wider range of organizations that previously would not have been able to hire and retain software engineers. Many of those software engineers should also be able to spend more time addressing more complex issues rather than, for example, writing scripts to ensure that only certain classes of workloads are allowed to run on a particular cloud service within a period of time which results in lower costs. Unfortunately, DevOps teams are already playing catch-up when it comes to having access to generative AI tools. Developers are already taking advantage of generative AI tools to create more code faster. As that code moves through DevOps pipelines, it’s apparent the overall size of the codebase that DevOps teams are being required to manage is only going to increase. Most organizations are not going to be able to hire a small army of software engineers to manage that codebase, so the tooling provided to existing DevOps teams will need to improve. The issue now is narrowing the gap between now and when next-generation AI tools are made generally available. One way or another, however, it’s clear that the way DevOps is managed will never be the same again.

Read More

Learn About Useful Shared Mutexes Locking In Modern C++

A concurrency support library is designed to solve problems in modern C++ that arise with multi-thread development. This library includes built-in support for threads (std::thread), atomic operations (std::atomic), mutual exclusion (std::mutex), condition variables (std::condition_variable), and many other features. In C++14, in addition to mutex, there is a shared_mutex which is an instance of the class located in header. In this post, we explain using shared mutexes locking in Modern C++. What is a mutex (mutual exclusion) in C++? Mutual Exclusion is a property of concurrency control and in programming, the Mutual Exclusion is a data exclusion method to lock and unlock data that provides exclusive access to a resource. This is mostly needed when we use shared data in multi-thread and multi-task operations in parallel programming. In C++, we can use std::mutex to define mutex data variables to protect his shared data from being simultaneously accessed by multiple threads. Here is an example of how we can use std::mutex with its lock() and unlock() methods,   std::mutex mtx;   mtx.lock();   // do operations mtx.unlock();   What is a shared mutex in modern C++? The shared mutex comes with C++14, it is an instance of the class located in header and used with the shared_mutex class name in mutual exclusion operations of threads. The shared_mutex class is a part of the thread support library, it is a synchronization primitive for the thread operations that can be used to protect shared data when multiple threads try to access. Here is how we can define a shared mutex by using std::shared_mutex.   std::shared_mutex ;   Is there an example about shared mutexes (std::shared mutex)? Here is a simple example about std::shared_mutex with its try_lock_shared() and unlock_shared() methods that comes with C++17.   std::shared_mutex sharedmutex;   // in a thread function sharedmutex.try_lock_shared(); // do operations sharedmutex.unlock_shared();   How to use shared lock unlock mutexes methods? A shared_mutex has lock() and unlock() methods as in mutex type, In C++17, it is improved and supports the additional methods lock_shared, unlock_shared, and try_lock_shared. Simply these are: lock_shared (C++17) The lock_shared method is used to block the calling thread until the thread obtains shared ownership of the mutex. unlock_shared (C++17) The unlock_shared method is used to release shared ownership of the mutex held by the calling thread. try_lock_shared (C++17) The try_lock_shared method is used to obtain shared ownership of the mutex without blocking. Return type is can be  true if the method obtains ownership, or false if it cannot. Is there a full example of how to use shared mutexes (std::shared mutex) in C++? Let’s assume that we have a global val and we read data by a getv() and we write data by putv() functions, and we run these functions in threads. Here is a full and simple example about shared mutexes (std::shared mutex). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43   #include #include #include #include   std::shared_mutex sharedmutex;   int val=500;   void putv( int v ) {   sharedmutex.lock();   std::this_thread::sleep_for(std::chrono::microseconds(2));  //some latency simulation val = v;   sharedmutex.unlock(); }   void getv( int &v ) {   sharedmutex.lock_shared();   std::this_thread::sleep_for(std::chrono::microseconds(2));  // some latency simulation   v = val;   sharedmutex.unlock_shared(); }     int main() {   int readval;   std::thread t1( getv , std::ref( readval ) );   std::thread t2( putv , 100); […]

Read More

Survey Surfaces Benefits of Applying AI to FinOps

A survey of 200 enterprise IT decision-makers published this week found organizations that have infused artificial intelligence (AI) into financial operations (FinOps) workflows to reduce IT costs are 53% more likely to report cost savings of more than 20%. Conducted by the market research firm Foundry on behalf of Tangoe, a provider of tools for managing IT and telecommunications expenses, the survey found organizations that embraced FinOps without any AI capabilities averaged less than 10% in cost savings. The top three drivers for adopting FinOps/cloud cost management programs are the need to increase cloud resource production and performance (70%), reduce budgets (60%) and rising costs (58%), and simpler overall program management (50%), the survey found. Major benefits included productivity savings (46%), cost savings (43%) and reduced security risks (43%). Nearly two-thirds of respondents cited service utilization and right-sizing of services as another reason to embrace FinOps. FinOps describes a methodology for embedding programmatic controls within DevOps workflows to reduce costs. In the face of increased economic headwinds, IT leaders are looking to reduce cloud computing costs, but it’s turning out to be more challenging than many of them anticipated. Cloud infrastructure is typically provisioned by developers using infrastructure-as-code (IaC) tools with little to no supervision. The reason for this is developers have long argued that waiting for an IT team to provision cloud infrastructure took too long. Developers would be more productive if they just provisioned cloud infrastructure themselves. However, after ten years of cloud computing, it’s become apparent there are a lot of wasted cloud infrastructure resources. Developers who don’t pay the monthly bills for cloud services tend to view available infrastructure resources as essentially infinite. It’s usually not until someone from the finance department starts raising cost concerns that developers even become aware there might be an issue. The challenge is that adopting FinOps best practices is not quite as easy as it might seem. In fact, more than half (54%) of survey respondents cited challenges in building the right process and human support systems for FinOps into workflows that have been in place for years. Chris Ortbals, chief product officer for Tangoe, said the simplest path to FinOps is to rely on a software-as-a-service (SaaS) platform designed from the ground up to leverage AI to help IT teams manage cloud computing and telecommunications expenses both before and after applications are deployed. Each DevOps team will ultimately need to determine how much they will implement metrics to foster more efficient consumption of cloud computing resources. The more aware of those costs DevOps teams are, the more likely that better decisions about what types of workloads should be run where and, just as importantly in the age of the cloud, at what time, given all the pricing options provided. Developers, of course, tend to jealously guard their prerogatives. Convincing them to give up their ability to provision cloud infrastructure on demand is going to be a challenge, at least until someone makes it plain how much all those cloud instances wind up costing the organization each and every month.

Read More

What Are The Amazing Containers In Modern C++?

Containers are powerful data storage arrays in modern C++ and they are very useful to iterate and search data with their amazing methods and properties. The C++ Standards library defines 4 container types. In this post, we explain containers in modern C++. What is a container in modern C++? Containers are modern data storage arrays in modern C++ and they are very useful to iterate and search data with their amazing methods and properties. A container is a holder object that stores data elements (a collection of data objects). They are implemented as a class template to define objects that can be used with modern rules of C++ (The rule of 6), they allow great flexibility in the different data types supported as elements, they can be used with int, float, double, etc. or with struct types, they can be used with other modern types of C++, lambdas and templates. Thus, the developer can create different data sets in memory, these can be static or dynamic, they are safe and optimized well. Basically, a container manages the storage space for its elements and provides properties and methods to access and operate on them, these methods and properties can be either directly or through iterators. They are mostly dynamic data structures, and they are well optimized for the memory management and performance. In C++, there are four main types of containers, Sequence Containers (vectors, arrays, …) Associative Containers (maps, sets, …) Unordered Associative Containers (unordered_set, unordered_map, …) Container Adapters (stack, queue, priority_queue) Now, let’s see each of them. What are sequence containers in modern C++? In C++, the Sequence Containers are class templates of container types of modern C++ that can be used to implement data structure types (vector, array,…) where they can be accessed sequentially. They are a kind of data types, but objects of classes and they can use methods of its classes, optimized for many modern C++ algorithms and methods. The sequence containers are; std::array : a class template for the static contiguous array (modern C array) std::vector : a class template for the dynamic contiguous array ( modern dynamic C arrays) std::deque : a class template for the double-ended queue std::list : a class template for the doubly-linked list (modern linked list) std::forward_list : a class template for the singly-linked list (modern linked list) What are sequence containers in modern C++? Associative Containers are class templates of container types that can be used to implement sorted data structures where can be quickly searched. They are sorted by keys. We can say they are about O(log n) complexity data structures. The associative containers are; std::map : a class template for the collection of key-value pairs, its keys are unique and it is sorted by keys std::set : a class template for the collection of unique keys, it is sorted by keys  multiset : a class template for the collection of keys, it is sorted by keys multimap : a class template for the collection of key-value pairs, it is sorted by keys  What are associative containers in modern C++? Unordered Associative Containers are class templates of container types that can be used to implement unsorted (hashed) data structures where they can be quickly searched. They are about O(1) amortized, O(n) worst-case complexity data structures. The unsorted associative containers are; unordered_set : a class template for […]

Read More

What Are The Differences Between Mutex And Shared Mutex In C++?

The concurrency support library in modern C++ is designed to solve read and write data securely in thread operations that allow us to develop faster multi-thread apps. This library includes built-in support for threads (std::thread), atomic operations (std::atomic), mutual exclusion (std::mutex), condition variables (std::condition_variable), and many other features. In C++14, in addition to mutex, there is a shared mutex (std::shared_mutex) which is an instance of the class located in header. In this post, we explain a frequently asked mutex question in modern C++, what are the differences between mutex and shared_mutex? What is a mutex (std::shared_mutex) in C++? Mutual Exclusion is a property of concurrency control and in programming, the Mutual Exclusion is a data exclusion method to lock and unlock data that provides exclusive access to a resource. This is mostly needed when we use shared data in multi-thread and multi-task operations in parallel programming. In C++, we can use std::mutex to define mutex data variables to protect his shared data from being simultaneously accessed by multiple threads. Here is an example of how we can use std::mutex with its lock() and unlock() methods,   std::mutex mtx;   mtx.lock();   // do operations mtx.unlock();   Here are more details and examples about std::mutex. What is a shared mutex (std::shared_mutex) in C++? The shared mutex comes with C++14, it is an instance of the class located in header and used with the shared_mutex class name in mutual exclusion operations of threads. The shared_mutex class is a part of the thread support library. It is a synchronization primitive for the thread operations that can be used to protect shared data when multiple threads try to access. Here is a simple example about std::shared_mutex with its try_lock_shared() and unlock_shared() methods that comes with C++17.   std::shared_mutex sharedmutex;   // in a thread function sharedmutex.try_lock_shared(); // do operations sharedmutex.unlock_shared();   Here are more details and a full example about shared_mutex. ———- LINK TO Learn About Useful Shared Mutexes Locking In Modern C++ —————— What are the differences between std::mutex and std::shared_mutex? While the std::mutex guarantees exclusive access to some kind of critical resource, the shared_mutex class extends this feature by a shared and exclusive level of accesses. The shared_mutex can be used in exclusive access level to prevent access of any other thread from acquiring the mutex, as in std::mutex. No matter if the other thread is trying to acquire shared or exclusive access. The shared_mutex can be used in the shared access level to allow multiple threads to acquire the mutex, but all of them are only in shared mode. In thread operations, exclusive access is not granted until all of the previously shared holders have returned the mutex. As long as an exclusive request is waiting, new shared ones are queued to be granted after the exclusive access. For more information about shared mutex feature, please see https://open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3659.html C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs. There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, […]

Read More

Getting RCE in Chrome with incomplete object initialization in the Maglev compiler

In this post I’ll exploit CVE-2023-4069, a type confusion vulnerability that I reported in July 2023. The vulnerability—which allows remote code execution (RCE) in the renderer sandbox of Chrome by a single visit to a malicious site—is found in v8, the Javascript engine of Chrome. It was filed as bug 1465326 and subsequently fixed in version 115.0.5790.170/.171. Vulnerabilities like this are often the starting point for a “one-click” exploit, which compromises the victim’s device when they visit a malicious website. What’s more, renderer RCE in Chrome allows an attacker to compromise and execute arbitrary code in the Chrome renderer process. That being said, the renderer process has limited privilege and such a vulnerability needs to be chained with a second “sandbox escape” vulnerability (either another vulnerability in the Chrome browser process or one in the operating system) to compromise Chrome itself or the device. While many of the most powerful and sophisticated “one-click” attacks are highly targeted, and average users may be more at risk from less sophisticated attacks such as phishing, users should still keep Chrome up-to-date and enable automatic updates, as vulnerabilities in v8 can often be exploited relatively quickly. The current vulnerability, CVE-2023-4069, exists in the Maglev compiler, a new mid-tier JIT compiler in Chrome that optimizes Javascript functions based on previous knowledge of the input types. This kind of optimization is called speculative optimization and care must be taken to make sure that these assumptions on the inputs are still valid when the optimized code is used. The complexity of the JIT engine has led to many security issues in the past and has been a popular target for attackers. Maglev compiler The Maglev compiler is a mid-tier JIT compiler used by v8. Compared to the top-tier JIT compiler, TurboFan, Maglev generates less optimized code but with a faster compilation speed. Having multiple JIT compilers is common in Javascript engines, the idea being that with multiple tier compilers, you’ll find a more optimal tradeoff between compilation time and runtime optimization. Generally speaking, when a function is first run, slow bytecode is generated, as the function is run more often, it may get compiled into more optimized code, first from a lowest-tier JIT compiler. If the function gets used more often, then its optimization tier gets moved up, resulting in better runtime performance—but at the expense of a longer compilation time. The idea here is that for code that runs often, the runtime cost will likely outweigh the compile time cost. You can consult An Introduction to Speculative Optimization in v8 by Benedikt Meurer for more details of how the compilation process works. The Maglev compiler is enabled by default starting from version 114 of Chrome. Similar to TurboFan, it goes through the bytecode of a Javascript function, taking into account the feedback that was collected from previous runs, and transforms the bytecode into more optimized code. However, unlike TurboFan, which first transforms bytecodes into a “Sea of Nodes”, Maglev uses an intermediate representation and first transforms bytecodes into SSA (Static Single-Assignment) nodes, which are declared in the file maglev-ir.h. At the time of writing, the compilation process of Maglev consists mainly of two phases of optimizations: the first phase involves building a graph from the SSA nodes, while the second phase consists of optimizing the representations […]

Read More

The Growing Impact of Generative AI on Low-Code/No-Code Development

No-code/low-code platforms, once a disruptor in the realm of software development, are now embracing the capabilities of generative AI to create even more dynamic experiences. This union of convenience and innovation redefines how users interact with their software. Imagine a scenario where crafting complex instructions like “Deploy endpoint protection to noncompliant devices” becomes as simple as conversing with your application. The fusion of generative AI and no-code/low-code platforms empowers users to shape their software’s behavior without delving into intricate technicalities. Users can input prompts such as “Generate a code snippet for converting date formats” or “Create a workflow that automates inventory updates.” By translating natural language into action, this approach streamlines development and fosters creativity. An Amalgamation of Generative AI and No-Code/Low-Code Beyond buzzwords, the amalgamation of generative AI with no-code/low-code platforms offers tangible benefits. The efficiency gains that occur when users can sidestep the need for manual configurations and directly communicate their intentions are both remarkable and unprecedented. Accessibility is enhanced, enabling non-technical individuals to actively participate in application development. Moreover, innovative use cases emerge, allowing organizations to streamline complex workflows with ease. As with any transformative technology, challenges emerge alongside benefits. Privacy concerns loom large when dealing with data input into generative AI models. Striking a balance between providing valuable insights and safeguarding sensitive information becomes paramount. Additionally, the inherently non-deterministic nature of generative AI can lead to varying outcomes, requiring careful consideration of use cases to ensure reliable results. As this collaboration matures, the landscape of software development is poised for significant change. Conversational interfaces that empower users to dictate software behaviors will continue to evolve, reducing implementation and configuration overhead. Imagine a future where complex workflows are summoned with a simple request or applications are custom-built based on natural language blueprints. This shift will not only streamline development but also democratize technology, making it accessible to a broader audience. The integration of generative AI with no-code/low-code platforms allows users to express their creativity more freely. By enabling natural language prompts like “Design an app to manage inventory with automatic restocking” or “Build a workflow that offboards a user across Google, Slack, and Salesforce,” users can drive software behaviors without being constrained by technical jargon. This fusion redefines the efficiency of software interaction. Tasks that previously required meticulous configuration or coding can now be executed through simple prompts. Whether generating email templates, creating data transformation scripts, or orchestrating multi-step workflows, the convenience of natural language input eliminates barriers and accelerates results. A Democratic Approach Looking forward, the integration of generative AI in no-code/low-code platforms points toward a more democratic approach to software development. This convergence will enable a broader range of individuals to participate actively, regardless of their coding expertise. By simplifying the process and making it more inclusive, we’re shaping a future where software truly adapts to human intent. As businesses continue to harness the potential of generative AI and no-code/low-code platforms, adaptation and learning will be key. Embracing this transformation requires a shift in mindset, and understanding that software can be molded through conversations and prompts. As technology matures, the barriers between user intent and software behavior will fade, ushering in an era where technological fluency is defined by our ability to communicate rather than code. Speculating on how this shift will impact the day-to-day […]

Read More

Coordinated Disclosure: 1-Click RCE on GNOME (CVE-2023-43641)

Today, in coordination with Ilya Lipnitskiy (the maintainer of libcue) and the distros mailing list, the GitHub Security Lab is disclosing CVE-2023-43641, a memory corruption vulnerability in libcue. We have also sent a text-only version of this blog post to the oss-security list. It’s quite likely that you have never heard of libcue before, and are wondering why it’s important. This situation is neatly illustrated by xkcd 2347: libcue is a library used for parsing cue sheets—a metadata format for describing the layout of the tracks on a CD. Cue sheets are often used in combination with the FLAC audio file format, which means that libcue is a dependency of some audio players, such as Audacious. But the reason why I decided to audit libcue for security vulnerabilities is that it’s used by tracker-miners: an application that’s included with GNOME—the default graphical desktop environment of many open source operating systems. The purpose of tracker-miners is to index the files in your home directory to make them easily searchable. For example, the index is used by this search bar: The index is automatically updated when you add or modify a file in certain subdirectories of your home directory, in particular including ~/Downloads. To make a long story short, that means that inadvertently clicking a malicious link is all it takes for an attacker to exploit CVE-2023-43641 and get code execution on your computer: The video shows me clicking a link in a webpage, which causes a cue sheet to be downloaded. Because the file is saved to ~/Downloads, it is then automatically scanned by tracker-miners. And because it has a .cue filename extension, tracker-miners uses libcue to parse the file. The file exploits the vulnerability in libcue to gain code execution and pop a calculator. Cue sheets are just one of many file formats supported by tracker-miners. For example, it also includes scanners for HTML, JPEG, and PDF. I am delaying publication of the proof of concept (PoC) used in the video, to give users time to install the patch. But if you’d like to test if your system is vulnerable, try downloading this file, which contains a much simpler version of the PoC that merely causes a (benign) crash. The offsets in the full PoC need to be tuned for different distributions. I have only done this for Ubuntu 23.04 and Fedora 38, the most recent releases of Ubuntu and Fedora at this time. In my testing, I have found that the PoC works very reliably when run on the correct distribution (and will trigger a SIGSEGV when run on the wrong distribution). I have not created PoCs for any other distributions, but I believe that all distributions that run GNOME are potentially exploitable. The bug in libcue libcue is quite a small project. It’s primarily a bison grammar for cue sheets, with a few data structures for storing the parsed data. A simple example of a cue sheet looks like this: REM GENRE “Pop, dance pop” REM DATE 1987 PERFORMER “Rick Astley” TITLE “Whenever You Need Somebody” FILE “Whenever You Need Somebody.mp3” MP3 TRACK 01 AUDIO TITLE “Never Gonna Give You Up” PERFORMER “Rick Astley” SONGWRITER “Mike Stock, Matt Aitken, Pete Waterman” INDEX 01 00:00:00 TRACK 02 AUDIO TITLE “Whenever You Need Somebody” PERFORMER “Rick Astley” SONGWRITER “Mike Stock, […]

Read More