1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* Helpers shared by the binfmt_misc selftests. */ 3 #ifndef __SELFTESTS_EXEC_BINFMT_MISC_COMMON_H 4 #define __SELFTESTS_EXEC_BINFMT_MISC_COMMON_H 5 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <libgen.h> 9 #include <limits.h> 10 #include <stdbool.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <sys/mount.h> 14 #include <unistd.h> 15 16 #define BINFMT_DIR "/proc/sys/fs/binfmt_misc" 17 #define BINFMT_REG BINFMT_DIR "/register" 18 19 static inline int copy_file(const char *src, const char *dst) 20 { 21 char buf[4096]; 22 int in, out; 23 ssize_t n; 24 25 in = open(src, O_RDONLY); 26 if (in < 0) 27 return -1; 28 /* The tests share /tmp, so never write through a name they don't own. */ 29 unlink(dst); 30 out = open(dst, O_WRONLY | O_CREAT | O_EXCL, 0755); 31 if (out < 0) { 32 close(in); 33 return -1; 34 } 35 while ((n = read(in, buf, sizeof(buf))) > 0) { 36 if (write(out, buf, n) != n) { 37 close(in); 38 close(out); 39 return -1; 40 } 41 } 42 close(in); 43 close(out); 44 return n < 0 ? -1 : 0; 45 } 46 47 /* Write @rule to the register file, preserving the write's errno. */ 48 static inline int write_reg(const char *rule) 49 { 50 int fd, saved; 51 ssize_t n; 52 53 fd = open(BINFMT_REG, O_WRONLY); 54 if (fd < 0) 55 return -1; 56 n = write(fd, rule, strlen(rule)); 57 saved = errno; 58 close(fd); 59 errno = saved; 60 return n < 0 ? -1 : 0; 61 } 62 63 static inline void unregister(const char *name) 64 { 65 char path[PATH_MAX]; 66 int fd; 67 68 snprintf(path, sizeof(path), BINFMT_DIR "/%s", name); 69 fd = open(path, O_WRONLY); 70 if (fd >= 0) { 71 if (write(fd, "-1", 2) < 0) 72 ; /* best effort */ 73 close(fd); 74 } 75 } 76 77 /* Mount binfmt_misc unless it already is, and report whether it is usable. */ 78 static inline bool binfmt_misc_available(void) 79 { 80 if (access(BINFMT_REG, F_OK) < 0) 81 mount("binfmt_misc", BINFMT_DIR, "binfmt_misc", 0, NULL); 82 return access(BINFMT_REG, F_OK) == 0; 83 } 84 85 /* Absolute path of @name in the directory this test was built into. */ 86 static inline int artifact_path(char *out, size_t sz, const char *name) 87 { 88 char exe[PATH_MAX]; 89 ssize_t n; 90 91 n = readlink("/proc/self/exe", exe, sizeof(exe) - 1); 92 if (n < 0) 93 return -1; 94 exe[n] = '\0'; 95 if ((size_t)snprintf(out, sz, "%s/%s", dirname(exe), name) >= sz) 96 return -1; 97 return 0; 98 } 99 100 #endif /* __SELFTESTS_EXEC_BINFMT_MISC_COMMON_H */ 101