Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Test triggering of loading of firmware from different mount
0003  * namespaces. Expect firmware to be always loaded from the mount
0004  * namespace of PID 1. */
0005 #define _GNU_SOURCE
0006 #include <errno.h>
0007 #include <fcntl.h>
0008 #include <sched.h>
0009 #include <stdarg.h>
0010 #include <stdbool.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <string.h>
0014 #include <sys/mount.h>
0015 #include <sys/stat.h>
0016 #include <sys/types.h>
0017 #include <sys/wait.h>
0018 #include <unistd.h>
0019 
0020 #ifndef CLONE_NEWNS
0021 # define CLONE_NEWNS 0x00020000
0022 #endif
0023 
0024 static char *fw_path = NULL;
0025 
0026 static void die(char *fmt, ...)
0027 {
0028     va_list ap;
0029 
0030     va_start(ap, fmt);
0031     vfprintf(stderr, fmt, ap);
0032     va_end(ap);
0033     if (fw_path)
0034         unlink(fw_path);
0035     umount("/lib/firmware");
0036     exit(EXIT_FAILURE);
0037 }
0038 
0039 static void trigger_fw(const char *fw_name, const char *sys_path)
0040 {
0041     int fd;
0042 
0043     fd = open(sys_path, O_WRONLY);
0044     if (fd < 0)
0045         die("open failed: %s\n",
0046             strerror(errno));
0047     if (write(fd, fw_name, strlen(fw_name)) != strlen(fw_name))
0048         exit(EXIT_FAILURE);
0049     close(fd);
0050 }
0051 
0052 static void setup_fw(const char *fw_path)
0053 {
0054     int fd;
0055     const char fw[] = "ABCD0123";
0056 
0057     fd = open(fw_path, O_WRONLY | O_CREAT, 0600);
0058     if (fd < 0)
0059         die("open failed: %s\n",
0060             strerror(errno));
0061     if (write(fd, fw, sizeof(fw) -1) != sizeof(fw) -1)
0062         die("write failed: %s\n",
0063             strerror(errno));
0064     close(fd);
0065 }
0066 
0067 static bool test_fw_in_ns(const char *fw_name, const char *sys_path, bool block_fw_in_parent_ns)
0068 {
0069     pid_t child;
0070 
0071     if (block_fw_in_parent_ns)
0072         if (mount("test", "/lib/firmware", "tmpfs", MS_RDONLY, NULL) == -1)
0073             die("blocking firmware in parent ns failed\n");
0074 
0075     child = fork();
0076     if (child == -1) {
0077         die("fork failed: %s\n",
0078             strerror(errno));
0079     }
0080     if (child != 0) { /* parent */
0081         pid_t pid;
0082         int status;
0083 
0084         pid = waitpid(child, &status, 0);
0085         if (pid == -1) {
0086             die("waitpid failed: %s\n",
0087                 strerror(errno));
0088         }
0089         if (pid != child) {
0090             die("waited for %d got %d\n",
0091                 child, pid);
0092         }
0093         if (!WIFEXITED(status)) {
0094             die("child did not terminate cleanly\n");
0095         }
0096         if (block_fw_in_parent_ns)
0097             umount("/lib/firmware");
0098         return WEXITSTATUS(status) == EXIT_SUCCESS;
0099     }
0100 
0101     if (unshare(CLONE_NEWNS) != 0) {
0102         die("unshare(CLONE_NEWNS) failed: %s\n",
0103             strerror(errno));
0104     }
0105     if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) == -1)
0106         die("remount root in child ns failed\n");
0107 
0108     if (!block_fw_in_parent_ns) {
0109         if (mount("test", "/lib/firmware", "tmpfs", MS_RDONLY, NULL) == -1)
0110             die("blocking firmware in child ns failed\n");
0111     } else
0112         umount("/lib/firmware");
0113 
0114     trigger_fw(fw_name, sys_path);
0115 
0116     exit(EXIT_SUCCESS);
0117 }
0118 
0119 int main(int argc, char **argv)
0120 {
0121     const char *fw_name = "test-firmware.bin";
0122     char *sys_path;
0123     if (argc != 2)
0124         die("usage: %s sys_path\n", argv[0]);
0125 
0126     /* Mount tmpfs to /lib/firmware so we don't have to assume
0127        that it is writable for us.*/
0128     if (mount("test", "/lib/firmware", "tmpfs", 0, NULL) == -1)
0129         die("mounting tmpfs to /lib/firmware failed\n");
0130 
0131     sys_path = argv[1];
0132     if (asprintf(&fw_path, "/lib/firmware/%s", fw_name) < 0)
0133         die("error: failed to build full fw_path\n");
0134 
0135     setup_fw(fw_path);
0136 
0137     setvbuf(stdout, NULL, _IONBF, 0);
0138     /* Positive case: firmware in PID1 mount namespace */
0139     printf("Testing with firmware in parent namespace (assumed to be same file system as PID1)\n");
0140     if (!test_fw_in_ns(fw_name, sys_path, false))
0141         die("error: failed to access firmware\n");
0142 
0143     /* Negative case: firmware in child mount namespace, expected to fail */
0144     printf("Testing with firmware in child namespace\n");
0145     if (test_fw_in_ns(fw_name, sys_path, true))
0146         die("error: firmware access did not fail\n");
0147 
0148     unlink(fw_path);
0149     free(fw_path);
0150     umount("/lib/firmware");
0151     exit(EXIT_SUCCESS);
0152 }