execregs.c revision 1.1 1 /* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2025 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $");
31
32 #include "execregs.h"
33
34 #include <errno.h>
35 #include <spawn.h>
36 #include <stddef.h>
37 #include <unistd.h>
38
39 extern char **environ;
40
41 static unsigned long
42 nonnull(unsigned long x)
43 {
44
45 x |= x << 8;
46 x |= x << 16;
47 x |= x << 32;
48 return x;
49 }
50
51 int
52 execregschild(char *path)
53 {
54 /* rdi: used to pass exec arg0, nonnull anyway (path) */
55 /* rsi: used to pass exec arg1, nonnull anyway (argv) */
56 /* rdx: used to pass exec arg2, nonnull anyway (environ) */
57 register long r10 __asm("r10") = nonnull(10);
58 register long r8 __asm("r8") = nonnull(8);
59 register long r9 __asm("r9") = nonnull(9);
60 register long rcx __asm("rcx") = nonnull('c');
61 register long r11 __asm("r11") = nonnull(11);
62 register long r12 __asm("r12") = nonnull(12);
63 register long r13 __asm("r13") = nonnull(13);
64 register long r14 __asm("r14") = nonnull(14);
65 register long r15 __asm("r15") = nonnull(15);
66 /* rbp: frame pointer, can't touch that here, but it'll be nonnull */
67 /* rbx: ps_strings, passed to child */
68 register long rax __asm("rax") = nonnull('a');
69
70 char *argv[] = {path, NULL};
71 char **envp = environ;
72
73 /*
74 * Not perfect -- compiler might use some registers for
75 * stack/argument transfers, but all the arguments are nonnull
76 * so this is probably a good test anyway.
77 */
78 __asm volatile("" :
79 "+r"(r10),
80 "+r"(r8),
81 "+r"(r9),
82 "+r"(rcx),
83 "+r"(r11),
84 "+r"(r12),
85 "+r"(r13),
86 "+r"(r14),
87 "+r"(r15),
88 "+r"(rax)
89 :: "memory");
90
91 return execve(path, argv, envp);
92 }
93
94 pid_t
95 spawnregschild(char *path, int fd)
96 {
97 /* rdi: used to pass posix_spawn arg0, nonnull anyway (&pid) */
98 /* rsi: used to pass posix_spawn arg1, nonnull anyway (path) */
99 /* rdx: used to pass posix_spawn arg2, nonnull anyway (&fileacts) */
100 register long r10 __asm("r10") = nonnull(10);
101 /* r8: used to pass posix_spawn arg4, nonnull anyway (argv) */
102 /* r9: used to pass posix_spawn arg5, nonnull anyway (environ) */
103 /* rcx: used to pass posix_spawn arg3, nonnull anyway (&attr) */
104 register long r11 __asm("r11") = nonnull(11);
105 register long r12 __asm("r12") = nonnull(12);
106 register long r13 __asm("r13") = nonnull(13);
107 register long r14 __asm("r14") = nonnull(14);
108 register long r15 __asm("r15") = nonnull(15);
109 /* rbp: frame pointer, can't touch that here, but it'll be nonnull */
110 /* rbx: ps_strings, passed to child */
111 register long rax __asm("rax") = nonnull('a');
112
113 char *argv[] = {path, NULL};
114 char **envp = environ;
115 posix_spawn_file_actions_t fileacts;
116 posix_spawnattr_t attr;
117 pid_t pid;
118 int error;
119
120 error = posix_spawn_file_actions_init(&fileacts);
121 if (error)
122 goto out;
123 error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO);
124 if (error)
125 goto out;
126 error = posix_spawnattr_init(&attr);
127 if (error)
128 goto out;
129
130 /*
131 * Not perfect -- compiler might use some registers for
132 * stack/argument transfers, but all the arguments are nonnull
133 * so this is probably a good test anyway.
134 */
135 __asm volatile("" :
136 "+r"(r10),
137 "+r"(r11),
138 "+r"(r12),
139 "+r"(r13),
140 "+r"(r14),
141 "+r"(r15),
142 "+r"(rax)
143 :: "memory");
144
145 error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp);
146 if (error)
147 goto out;
148
149 out: posix_spawnattr_destroy(&attr);
150 posix_spawn_file_actions_destroy(&fileacts);
151 if (error) {
152 errno = error;
153 return -1;
154 }
155 return 0;
156 }
157