Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: Build an OpenJDK JVM with PAC/BTI on Azure Cobalt 100

description: Learn how to compile OpenJDK with branch protection on an Azure Cobalt 100 Arm VM and verify PAC/BTI support in the resulting JVM.

draft: true
cascade:
draft: true

minutes_to_complete: 30

who_is_this_for: This Learning Path is for developers who want to build and validate an OpenJDK JVM with PAC/BTI support on Azure Cobalt 100 Arm-based virtual machines.

learning_objectives:
- Provision an Azure Cobalt 100 Arm-based virtual machine with Ubuntu Pro 24.04 LTS.
- Build OpenJDK on Arm64 with branch protection support enabled.
- Verify PAC/BTI readiness in the installed JVM runtime.

prerequisites:
- A [Microsoft Azure](https://azure.microsoft.com/) account with access to Cobalt 100 based instances (Dpsv6)


author: Doug Anson

### Tags
skilllevels: Introductory
subjects: Performance and Architecture
cloud_service_providers:
- Microsoft Azure

armips:
- Neoverse

tools_software_languages:
- Java
- OpenJDK
- Bash

operatingsystems:
- Linux

further_reading:
- resource:
title: Azure Virtual Machines documentation
link: https://learn.microsoft.com/en-us/azure/virtual-machines/
type: documentation
- resource:
title: OpenJDK build documentation
link: https://openjdk.org/groups/build/doc/building.html
type: documentation
- resource:
title: OpenJDK source repository
link: https://github.com/openjdk/jdk
type: documentation
- resource:
title: Arm A64 instruction reference
link: https://developer.arm.com/documentation/100076/latest/
type: documentation


### FIXED, DO NOT MODIFY
# ================================================================================
weight: 1 # _index.md always has weight of 1 to order correctly
layout: "learningpathall" # All files under learning paths have this same wrapper
learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content.
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# ================================================================================
# FIXED, DO NOT MODIFY THIS FILE
# ================================================================================
weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation.
title: "Next Steps" # Always the same, html page title.
layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing.
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Understand Azure Cobalt 100, OpenJDK, and Armv9 PAC/BTI

weight: 2

layout: "learningpathall"
---

## Azure Cobalt 100 Arm-based processor

Azure’s Cobalt 100 is Microsoft’s first-generation, in-house Arm-based processor. Built on Arm Neoverse N2, Cobalt 100 is a 64-bit CPU that delivers strong performance and energy efficiency for cloud-native, scale-out Linux workloads such as web and application servers, data analytics, open-source databases, and caching systems. Running at 3.4 GHz, Cobalt 100 allocates a dedicated physical core for each vCPU, which helps ensure consistent and predictable performance.

To learn more, see the Microsoft blog [Announcing the preview of new Azure VMs based on the Azure Cobalt 100 processor](https://techcommunity.microsoft.com/blog/azurecompute/announcing-the-preview-of-new-azure-vms-based-on-the-azure-cobalt-100-processor/4146353).

## OpenJDK and the PAC/BTI Arm v9 instructions

OpenJDK is the open-source reference implementation of Java Platform, Standard Edition (Java SE). It provides the core compiler, runtime, and class libraries you use to build and run Java applications across operating systems and hardware platforms. OpenJDK forms the basis for most modern Java distributions, while different vendors package and support their own builds.

Armv9 Pointer Authentication (PAC) and Branch Target Identification (BTI) are security features designed to make control-flow attacks harder. PAC helps protect return addresses and pointers by adding a cryptographic signature that is checked before the pointer is used, which can detect tampering such as return-oriented programming attempts. BTI complements this by restricting where indirect branches are allowed to land, helping prevent attackers from jumping into unintended instruction sequences. Together, PAC and BTI strengthen software defenses at the instruction-set level, especially for modern operating systems, hypervisors, and applications that need improved resistance to memory-corruption exploits.

## What you've learned and what's next

You now have the background on Azure Cobalt 100, OpenJDK, and Armv9 PAC/BTI features.

Next, you'll create an Arm-based Azure VM, build OpenJDK with branch protection, and validate PAC/BTI readiness in the installed JVM.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: Create an Azure Cobalt 100 Arm64 virtual machine
weight: 3

### FIXED, DO NOT MODIFY
layout: learningpathall
---

## Prerequisites and setup

There are several common ways to create an Arm-based Cobalt 100 virtual machine, and you can choose the method that best fits your workflow or requirements:

- The Azure Portal
- The Azure CLI
- An infrastructure as code (IaC) tool

In this section, you'll launch the Azure Portal to create a virtual machine with the Arm-based Azure Cobalt 100 processor.

This Learning Path focuses on general-purpose virtual machines in the Dpsv6 series. For more information, see the [Microsoft Azure guide for the Dpsv6 size series](https://learn.microsoft.com/en-us/azure/virtual-machines/sizes/general-purpose/dpsv6-series).

While the steps to create this instance are included here for convenience, you can also refer to the [Deploy a Cobalt 100 virtual machine on Azure Learning Path](/learning-paths/servers-and-cloud-computing/cobalt/).

## Create an Arm-based Azure virtual machine

Creating a virtual machine based on Azure Cobalt 100 is no different from creating any other virtual machine in Azure. To create an Azure virtual machine:

- Launch the Azure portal and navigate to **Virtual Machines**.
- Select **Create**, and select **Virtual Machine** from the drop-down list.
- Inside the **Basic** tab, fill in the instance details such as **Virtual machine name** and **Region**.
- Select the image for your virtual machine (for example, Ubuntu Pro 24.04 LTS) and select **Arm64** as the VM architecture.
- In the **Size** field, select **See all sizes** and select the D-Series v6 family of virtual machines.
- Select **D4ps_v6** from the list as shown in the diagram below:

![Azure Portal showing D-Series v6 VM size selection with D4ps_v6 highlighted#center](images/instance.png "Select D4ps_v6 from the D-Series v6 family")

- For **Authentication type**, select **SSH public key**.

{{% notice Note %}}
Azure can generate an SSH key pair for you and lets you save it for future use.
{{% /notice %}}

- Fill in the **Administrator username** for your VM.
- Select **Generate new key pair**, and select **RSA SSH Format** as the SSH Key Type.

{{% notice Note %}}
RSA offers better security with keys longer than 3072 bits.
{{% /notice %}}

- Give your SSH key a key pair name.
- In the **Inbound port rules**, select **HTTP (80)** and **SSH (22)** as the inbound ports, as shown below:

![Azure Portal showing inbound port rules with HTTP (80) and SSH (22) selected#center](images/instance1.png "Configure inbound port rules for HTTP and SSH access")

- Now select the **Review + Create** tab and review the configuration for your virtual machine. It should look like the following:

![Azure Portal Review + Create tab showing VM configuration summary ready for deployment#center](images/ubuntu-pro.png "Review VM configuration before creation")

- When you're happy with your selection, select the **Create** button and then **Download Private key and Create Resource** button.

![Azure Portal showing Create button and SSH key download dialog#center](images/instance4.png "Download SSH key and create the virtual machine")

Your virtual machine should be ready and running in a few minutes. You can SSH into the virtual machine using the private key, along with the public IP details.

![Azure Portal showing successful VM deployment with confirmation details#center](images/final-vm.png "Successful VM deployment confirmation")

{{% notice Note %}}To learn more about Arm-based virtual machines in Azure, see "Getting Started with Microsoft Azure" in [Get started with Arm-based cloud instances](/learning-paths/servers-and-cloud-computing/csp/azure/).{{% /notice %}}

## What you've learned and what's next

You've created an Azure Cobalt 100 Arm64 virtual machine running Ubuntu 24.04 LTS with SSH authentication configured. The virtual machine is now ready for compiling and installing OpenJDK with PAC/BTI support.

Next, you'll download and compile OpenJDK on the VM, register the resulting JVM runtime, and run validation checks for PAC/BTI support.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: Compile the OpenJDK JVM source
weight: 4

### FIXED, DO NOT MODIFY
layout: learningpathall
---

### Install build prerequisites

Install these prerequisites in an SSH shell on your Cobalt 100 VM. Also install a bootstrap JVM to build the PAC/BTI-enabled JVM:

```bash
sudo apt update
sudo apt install -y zip git build-essential wget curl autoconf
sudo apt install -y libcups2-dev libasound2-dev libfontconfig1-dev alsa-ucm-conf ubuntu-drivers-common
sudo apt install -y libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev
sudo apt install -y openjdk-25-jdk
```

### Download the OpenJDK source

Download OpenJDK. Since the bootstrap JVM is v25, build v26 with PAC/BTI support enabled:

```bash
cd $HOME
git clone https://github.com/openjdk/jdk
cd jdk
git checkout jdk-26+35
```

### Configure the OpenJDK source build

Configure the OpenJDK source build and enable branch protection support:

```bash
bash configure --enable-branch-protection
```

### Build the JVM

Run the build to create the JVM. This process can take more than 30 minutes:

```bash
make images
```

### Register the JVM with the system

Run the following commands to register the newly created JDK/JVM with the system:

```bash
cd $HOME/jdk
WD=$(pwd)/build/linux-aarch64-server-release
cd /usr/lib/jvm
sudo ln -s ${WD}/jdk ./java-26-openjdk-arm64
sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-26-openjdk-arm64/bin/java 3000
cd
```

Confirm the newly installed JVM:

```bash
java --version
```

Output should be similar to:

```output
openjdk 26-internal 2026-03-17
OpenJDK Runtime Environment (build 26-internal-adhoc.ubuntu.jdk)
OpenJDK 64-Bit Server VM (build 26-internal-adhoc.ubuntu.jdk, mixed mode)
```

Next, run a script to confirm PAC/BTI readiness in the JVM you just built and installed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: Test the installed JVM for PAC/BTI enablement
weight: 5

### FIXED, DO NOT MODIFY
layout: learningpathall
---


### Setup the test script

Clone this repo and set execute permissions for the downloaded test script:

```bash
git clone https://github.com/DougAnsonAustinTx/pac-bti-jdk-assets
cd pac-bti-jdk-assets
chmod 755 ./test-pacbti.sh
```

### Run the test script

Run the test script to confirm PAC/BTI enablement:

```bash
./test-pacbti.sh --java /usr/bin/java
```

Output should resemble:

```output
== JVM PAC/BTI check ==
java executable : /home/ubuntu/jdk/build/linux-aarch64-server-release/jdk/bin/java
libjvm : /home/ubuntu/jdk/build/linux-aarch64-server-release/jdk/lib/server/libjvm.so

-- Host support (auxv/hwcaps) --
PAC APIA/generic support : yes (PACA=yes PACG=yes)
BTI support : yes

-- JVM support/config --
UseBranchProtection flag : yes
JVM default flag value : {default}

-- Binary instruction scan --
java contains PAC instr : yes
java contains BTI instr : yes
libjvm contains PAC instr: no
libjvm contains BTI instr: no

-- Verdict --
PAC status : possible-but-not-proven
BTI status : yes

Interpretation:
PAC-capable build detected, but no running JVM cmdline was checked.
BTI is likely enabled in the runtime binaries.
```

### What you've learned

Some OpenJDK builds are not distributed with PAC/BTI enabled by default because they must remain compatible with older Arm platforms. When you need these protections, you can build and register your own JVM with branch protection support.

When a PAC/BTI-enabled JVM runs on a platform that supports these features, Java workloads gain additional control-flow protection.
Loading