Run a Dynamically Linked Executable

Introduction

Most applications are dynamically linked. This means that the application uses shared libraries that are loaded at runtime. This is in contrast to statically linked applications, which include all the necessary libraries in the executable itself. In this guide, we will show you how to run a dynamically linked executable on a Ginger OS virtual machine (VM).

This How To guide will use nginx as an example. Nginx is a popular web server that is dynamically linked. The steps in this guide can be applied to other dynamically linked executables.

The code for this guide can be found at https://github.com/gingercybersecurity/ginger-nginx.

Chroot

Building a Ginger VM and testing it is an acceptable path to take. However, building and starting virtual machines takes more time compared to starting a process. For this reason, you may want to consider using chroot to decrease the amount of time spent trying to identify all the required resources of a program.

A chroot environment is a way to isolate a process from the rest of the system by changing its root directory. This means that the process cannot access files outside the specified directory, effectively creating a sandboxed environment. The chroot command is used to set up and enter a chroot environment. See the man page for chroot for more information.

Identify Dependent Libraries

Before running a dynamically linked executable, you must identify the shared libraries that the executable depends on. You can use the ldd command to list the shared libraries that an executable depends on. For example, to list the shared libraries that the nginx executable depends on, you can run the following command:

ubuntu@ubuntu:~$ ldd /usr/sbin/nginx
        linux-vdso.so.1 (0x00007fff407a1000)
        libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x0000714ec7c88000)
        libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x0000714ec7bee000)
        libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x0000714ec7b44000)
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x0000714ec7600000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x0000714ec7b28000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000714ec7200000)
        /lib64/ld-linux-x86-64.so.2 (0x0000714ec7e2e000)

Please note that the shared libraries that an executable depends on may vary depending on the OS and executable version.

In the output above, you can see the shared libraries that the nginx executable depends on. You must ensure that these shared libraries are available inside your Ginger OS VM. Edit the image version configuration file (typically image.yaml) to include the shared libraries that the executable depends on. The dirs and files sections should have the following entries:

dirs:
- path: '/lib'
  uid: 10
  permissions: 0o700
  label: 'nginx_lib'
- path: '/lib/x86_64-linux-gnu'
  uid: 10
  permissions: 0o700
  label: 'nginx_lib'
- path: '/lib64'
  uid: 10
  permissions: 0o700
  label: 'nginx_lib'
files:
- source: '/usr/sbin/nginx'
  destination: '/sbin/nginx'
  uid: 10
  permissions: 0o500
  label: 'nginx_exec'
- source: '/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2'
  destination: '/lib64/ld-linux-x86-64.so.2'
  uid: 10
  permissions: 0o500
  label: 'nginx_lib'
- source: '/lib/x86_64-linux-gnu/libc.so.6'
  destination: '/lib/x86_64-linux-gnu/libc.so.6'
  uid: 10
  permissions: 0o500
  label: 'nginx_lib'
- source: '/lib/x86_64-linux-gnu/libcrypt.so.1.1.0'
  destination: '/lib/x86_64-linux-gnu/libcrypt.so.1'
  uid: 10
  permissions: 0o500
  label: 'nginx_lib'
- source: '/lib/x86_64-linux-gnu/libcrypto.so.3'
  destination: '/lib/x86_64-linux-gnu/libcrypto.so.3'
  uid: 10
  permissions: 0o500
  label: 'nginx_lib'
- source: '/lib/x86_64-linux-gnu/libpcre2-8.so.0.11.2'
  destination: '/lib/x86_64-linux-gnu/libpcre2-8.so.0'
  uid: 10
  permissions: 0o500
  label: 'nginx_lib'
- source: '/lib/x86_64-linux-gnu/libssl.so.3'
  destination: '/lib/x86_64-linux-gnu/libssl.so.3'
  uid: 10
  permissions: 0o500
  label: 'nginx_lib'
- source: '/lib/x86_64-linux-gnu/libz.so.1.3'
  destination: '/lib/x86_64-linux-gnu/libz.so.1'
  uid: 10
  permissions: 0o500
  label: 'nginx_lib'

Please note that the source and destination names may differ. This is because many of the dependent libraries use symbolic links. You can use the ls -l command to find the actual files that are linked into the executable. The source will be the actual file linked into the executable while the destination will be the dependent name as identified by the ldd command.

The linux-vdso dependent library is automatically provided by the kernel. You do not need to include this library in the image.yaml file.

Identify Dependent Resources

A program may depend upon more than just shared libraries. It may also depend on other files. All the dependent files must be identified and copied into the VM via the gingervm configuration files for the image version, server deployment, and data disk. This is the same requirement for all programs executed in a Ginger OS VM. The sections below are specific to nginx, but the process will be the same for other programs.

Passwd and Group

The nginx program will try to look up and switch the uid and gid for the process. The default user and group are nobody and nogroup. The values can be specified in the configuration file main section using the user directive.

The nginx program will try to query the user and group using getpwent. This function will open and parse /etc/passwd and /etc/group. Both of these files must be provided with an entry for the user to use.

nobody:x:10:10:nobody:/nonexistent:/usr/sbin/nologin
nogroup:x:10:

Make sure the UID and GID in the files match what is expected in the Ginger OS init.yaml file.

Logging and Data Storage

The /var/log/nginx directory must be created so nginx will store the log files there. The /var/lib/nginx directory must be created so nginx can write data there.

Configuration File

An nginx.conf configuration file must be provided. See the Nginx documentation for details on how to configure nginx.

Web Files

The nginx.conf file will specify the files to distribute. Create the appropriate directories and copy the files to those directories.

Build and Deploy

The final step is to build and deploy the disk images and the VM. The steps are the same as for any other program. See the Run a Rust Application guide for more information.

The code for this guide can be found at https://github.com/gingercybersecurity/ginger-nginx.

Copyright © 2026 | Ginger Cybersecurity LLC | All Rights Reserved

Privacy Policy / Cookie Policy / Terms and Conditions