1010#include <errno.h>
1111#include <stdio.h>
1212#include <string.h>
13+ #include <sys/stat.h>
1314
1415#include "kbox/mount.h"
1516#include "lkl-wrap.h"
17+ #include "syscall-nr.h"
1618
1719/* MS_BIND from <linux/mount.h> without pulling the full header. */
1820#define KBOX_MS_BIND 0x1000
1921
22+ /* asm-generic O_* values for LKL openat (same on x86_64 and aarch64). */
23+ #define LKL_O_CREAT 0100
24+ #define LKL_O_EXCL 0200
25+
2026/* Bind-mount spec parser. */
2127
2228int kbox_parse_bind_spec (const char * spec , struct kbox_bind_spec * out )
@@ -118,7 +124,84 @@ int kbox_apply_recommended_mounts(const struct kbox_sysnrs *s,
118124 return 0 ;
119125}
120126
121- /* Bind mounts. */
127+ /* Bind mounts.
128+ *
129+ * The source is a host path; stat it to determine whether the bind-mount
130+ * target inside LKL should be a directory or a regular file. Anything
131+ * other than a regular file or directory is rejected up front.
132+ */
133+
134+ /* Verify that the existing inode at target has the expected type. */
135+ static int verify_existing_target (const struct kbox_sysnrs * s ,
136+ const char * target ,
137+ unsigned int expected_mode_type )
138+ {
139+ struct kbox_lkl_stat lkl_st ;
140+ long ret ;
141+
142+ ret = kbox_lkl_newfstatat (s , AT_FDCWD_LINUX , target , & lkl_st , 0 );
143+ if (ret < 0 ) {
144+ fprintf (stderr , "stat(%s): %s\n" , target , kbox_err_text (ret ));
145+ return -1 ;
146+ }
147+ if ((lkl_st .st_mode & S_IFMT ) != expected_mode_type ) {
148+ fprintf (stderr ,
149+ "bind mount: target %s exists but has wrong type "
150+ "(expected 0%o, got 0%o)\n" ,
151+ target , expected_mode_type , lkl_st .st_mode & S_IFMT );
152+ return -1 ;
153+ }
154+ return 0 ;
155+ }
156+
157+ static int create_bind_target (const struct kbox_sysnrs * s ,
158+ const char * source ,
159+ const char * target )
160+ {
161+ struct stat st ;
162+ long ret ;
163+
164+ if (stat (source , & st ) < 0 ) {
165+ fprintf (stderr , "bind mount: cannot stat source %s: %s\n" , source ,
166+ strerror (errno ));
167+ return -1 ;
168+ }
169+
170+ if (S_ISDIR (st .st_mode )) {
171+ ret = kbox_lkl_mkdir (s , target , 0755 );
172+ if (ret == - EEXIST )
173+ return verify_existing_target (s , target , S_IFDIR );
174+ if (ret < 0 ) {
175+ fprintf (stderr , "mkdir(%s): %s\n" , target , kbox_err_text (ret ));
176+ return -1 ;
177+ }
178+ return 0 ;
179+ }
180+
181+ if (S_ISREG (st .st_mode )) {
182+ long cret ;
183+
184+ ret = kbox_lkl_openat (s , AT_FDCWD_LINUX , target ,
185+ LKL_O_CREAT | LKL_O_EXCL , 0644 );
186+ if (ret == - EEXIST )
187+ return verify_existing_target (s , target , S_IFREG );
188+ if (ret < 0 ) {
189+ fprintf (stderr , "creat(%s): %s\n" , target , kbox_err_text (ret ));
190+ return -1 ;
191+ }
192+ cret = kbox_lkl_close (s , ret );
193+ if (cret < 0 ) {
194+ fprintf (stderr , "close(%s): %s\n" , target , kbox_err_text (cret ));
195+ return -1 ;
196+ }
197+ return 0 ;
198+ }
199+
200+ fprintf (stderr ,
201+ "bind mount: source %s is neither a regular file nor a directory\n" ,
202+ source );
203+ return -1 ;
204+ }
122205
123206int kbox_apply_bind_mounts (const struct kbox_sysnrs * s ,
124207 const struct kbox_bind_spec * specs ,
@@ -127,13 +210,12 @@ int kbox_apply_bind_mounts(const struct kbox_sysnrs *s,
127210 int i ;
128211 long ret ;
129212
213+ if (!s || (!specs && count > 0 ) || count < 0 )
214+ return -1 ;
215+
130216 for (i = 0 ; i < count ; i ++ ) {
131- ret = kbox_lkl_mkdir (s , specs [i ].target , 0755 );
132- if (ret < 0 && ret != - EEXIST ) {
133- fprintf (stderr , "mkdir(%s): %s\n" , specs [i ].target ,
134- kbox_err_text (ret ));
217+ if (create_bind_target (s , specs [i ].source , specs [i ].target ) < 0 )
135218 return -1 ;
136- }
137219
138220 ret = kbox_lkl_mount (s , specs [i ].source , specs [i ].target , NULL ,
139221 KBOX_MS_BIND , NULL );
0 commit comments