@@ -208,7 +208,13 @@ static int qubes_connect(int s, const char *connect_path, const size_t total_pat
208
208
Returns 0 on success, -1 if the file is definitely absent in all of the
209
209
paths, and -2 on error (broken symlink, I/O error, path too long, out
210
210
of memory, etc).
211
- On success, fills buffer and statbuf (unless statbuf is NULL).
211
+ On success, fills buffer and statbuf (unless statbuf is NULL). buffer
212
+ will contain the path to the file, while statbuf will contain metadata
213
+ about the file as reported by stat(2).
214
+ If statbuf is not NULL, buffer may be filled with string starting
215
+ with "/dev/tcp/", which corresponds to the target of the symbolic link.
216
+ In this case, statbuf will contain the metadata for the symlink itself,
217
+ not its (hopefully nonexistent) target.
212
218
*/
213
219
static int find_file (
214
220
const char * path_list ,
@@ -220,13 +226,22 @@ static int find_file(
220
226
struct stat dummy_buf ;
221
227
const char * path_start = path_list ;
222
228
size_t name_length = strlen (name );
229
+ char * buf = NULL ;
223
230
int res ;
231
+ int rc ;
224
232
225
233
if (name_length > NAME_MAX )
226
234
return -1 ; /* cannot possibly exist */
227
235
228
- if (!statbuf )
236
+ if (!statbuf ) {
229
237
statbuf = & dummy_buf ;
238
+ } else {
239
+ buf = malloc (buffer_size );
240
+ if (buf == NULL ) {
241
+ LOG (ERROR , "Cannot allocate %zu bytes" , buffer_size );
242
+ return -2 ;
243
+ }
244
+ }
230
245
231
246
while (* path_start ) {
232
247
/* Find next path (up to ':') */
@@ -235,7 +250,8 @@ static int find_file(
235
250
236
251
if (path_length + name_length + 1 >= buffer_size ) {
237
252
LOG (ERROR , "find_qrexec_service_file: buffer too small for file path" );
238
- return -2 ;
253
+ rc = -2 ;
254
+ goto done ;
239
255
}
240
256
241
257
memcpy (buffer , path_start , path_length );
@@ -244,24 +260,53 @@ static int find_file(
244
260
//LOG(INFO, "stat(%s)", buffer);
245
261
res = lstat (buffer , statbuf );
246
262
if (res == 0 && S_ISLNK (statbuf -> st_mode )) {
263
+ if (buf != NULL ) {
264
+ ssize_t res = readlink (buffer , buf , buffer_size );
265
+ if (res < 0 ) {
266
+ /* readlink(2) failed */
267
+ LOG (ERROR , "readlink(2) failed: %m" );
268
+ rc = -2 ;
269
+ goto done ;
270
+ }
271
+ size_t target_len = (size_t )res ;
272
+ if ((target_len >= sizeof ("/dev/tcp" ) && memcmp (buf , "/dev/tcp/" , sizeof ("/dev/tcp" )) == 0 ) ||
273
+ (target_len == sizeof ("/dev/tcp" ) - 1 && memcmp (buf , "/dev/tcp/" , sizeof ("/dev/tcp" ) - 1 ) == 0 ))
274
+ {
275
+ if (target_len >= buffer_size ) {
276
+ /* buffer too small */
277
+ rc = -2 ;
278
+ } else {
279
+ memcpy (buffer , buf , target_len );
280
+ buffer [target_len ] = '\0' ;
281
+ rc = 0 ;
282
+ }
283
+ goto done ;
284
+ }
285
+ }
247
286
/* check if the symlink is valid */
248
287
res = stat (buffer , statbuf );
249
288
assert (res == -1 || !S_ISLNK (statbuf -> st_mode ));
250
289
}
251
290
if (res == 0 ) {
252
- return 0 ;
291
+ rc = 0 ;
292
+ goto done ;
253
293
} else {
254
294
assert (res == -1 );
255
295
if (errno != ENOENT ) {
256
- return -2 ;
296
+ LOG (ERROR , "stat/lstat(%s): %m" , buffer );
297
+ rc = -2 ;
298
+ goto done ;
257
299
}
258
300
}
259
301
260
302
path_start = path_end ;
261
303
while (* path_start == ':' )
262
304
path_start ++ ;
263
305
}
264
- return -1 ;
306
+ rc = -1 ;
307
+ done :
308
+ free (buf );
309
+ return rc ;
265
310
}
266
311
267
312
static int load_service_config_raw (struct qrexec_parsed_command * cmd ,
0 commit comments