Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 683080 | Differences between
and this patch

Collapse All | Expand All

(-)a/libgnome-desktop/gnome-desktop-thumbnail-script.c (-626 / +39 lines)
Lines 33-73 Link Here
33
#include <sys/stat.h>
33
#include <sys/stat.h>
34
#include <fcntl.h>
34
#include <fcntl.h>
35
35
36
#ifdef ENABLE_SECCOMP
37
#include <errno.h>
38
#include <sys/socket.h>
39
#include <sys/ioctl.h>
40
#include <sys/utsname.h>
41
#include <seccomp.h>
42
#endif
43
44
#include "gnome-desktop-thumbnail-script.h"
36
#include "gnome-desktop-thumbnail-script.h"
45
37
46
typedef struct {
38
typedef struct {
47
  gboolean sandbox;
48
  char *thumbnailer_name;
49
  GArray *fd_array;
50
  /* Input/output file paths outside the sandbox */
51
  char *infile;
39
  char *infile;
52
  char *infile_tmp; /* the host version of /tmp/gnome-desktop-file-to-thumbnail.* */
53
  char *outfile;
40
  char *outfile;
54
  char *outdir; /* outdir is outfile's parent dir, if it needs to be deleted */
55
  /* I/O file paths inside the sandbox */
56
  char *s_infile;
57
  char *s_outfile;
58
} ScriptExec;
41
} ScriptExec;
59
42
60
static char *
43
static char *
61
expand_thumbnailing_elem (const char *elem,
44
expand_thumbnailing_elem (const char *elem,
62
			  const int   size,
45
			  const int   size,
63
			  const char *infile,
46
			  const char *inuri,
64
			  const char *outfile,
47
			  const char *outfile,
65
			  gboolean   *got_input,
48
			  gboolean   *got_input,
66
			  gboolean   *got_output)
49
			  gboolean   *got_output)
67
{
50
{
68
  GString *str;
51
  GString *str;
69
  const char *p, *last;
52
  const char *p, *last;
70
  char *inuri;
53
  char *localfile;
71
54
72
  str = g_string_new (NULL);
55
  str = g_string_new (NULL);
73
56
Lines 79-96 expand_thumbnailing_elem (const char *elem, Link Here
79
62
80
      switch (*p) {
63
      switch (*p) {
81
      case 'u':
64
      case 'u':
82
        inuri = g_filename_to_uri (infile, NULL, NULL);
65
	g_string_append (str, inuri);
83
        if (inuri)
66
	*got_input = TRUE;
84
	  {
85
	    g_string_append (str, inuri);
86
	    *got_input = TRUE;
87
	    g_free (inuri);
88
	  }
89
	p++;
67
	p++;
90
	break;
68
	break;
91
      case 'i':
69
      case 'i':
92
	g_string_append (str, infile);
70
	localfile = g_filename_from_uri (inuri, NULL, NULL);
93
	*got_input = TRUE;
71
	if (localfile)
72
	  {
73
	    g_string_append (str, localfile);
74
	    *got_input = TRUE;
75
	    g_free (localfile);
76
	  }
94
	p++;
77
	p++;
95
	break;
78
	break;
96
      case 'o':
79
      case 'o':
Lines 117-610 expand_thumbnailing_elem (const char *elem, Link Here
117
  return g_string_free (str, FALSE);
100
  return g_string_free (str, FALSE);
118
}
101
}
119
102
120
/* From https://github.com/flatpak/flatpak/blob/master/common/flatpak-run.c */
121
G_GNUC_NULL_TERMINATED
122
static void
123
add_args (GPtrArray *argv_array, ...)
124
{
125
  va_list args;
126
  const gchar *arg;
127
128
  va_start (args, argv_array);
129
  while ((arg = va_arg (args, const gchar *)))
130
    g_ptr_array_add (argv_array, g_strdup (arg));
131
  va_end (args);
132
}
133
134
static void
135
add_env (GPtrArray  *array,
136
         const char *envvar)
137
{
138
  if (g_getenv (envvar) != NULL)
139
    add_args (array,
140
              "--setenv", envvar, g_getenv (envvar),
141
              NULL);
142
}
143
144
static char *
145
get_extension (const char *path)
146
{
147
  g_autofree char *basename = NULL;
148
  char *p;
149
150
  basename = g_path_get_basename (path);
151
  p = strrchr (basename, '.');
152
  if (p == NULL)
153
    return NULL;
154
  return g_strdup (p + 1);
155
}
156
157
#ifdef ENABLE_SECCOMP
158
static gboolean
159
flatpak_fail (GError     **error,
160
	      const char  *msg,
161
	      ...)
162
{
163
  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, msg);
164
  return FALSE;
165
}
166
167
/* From https://github.com/flatpak/flatpak/blob/master/common/flatpak-utils.c */
168
#if !defined(__i386__) && !defined(__x86_64__) && !defined(__aarch64__) && !defined(__arm__)
169
static const char *
170
flatpak_get_kernel_arch (void)
171
{
172
  static struct utsname buf;
173
  static char *arch = NULL;
174
  char *m;
175
176
  if (arch != NULL)
177
    return arch;
178
179
  if (uname (&buf))
180
    {
181
      arch = "unknown";
182
      return arch;
183
    }
184
185
  /* By default, just pass on machine, good enough for most arches */
186
  arch = buf.machine;
187
188
  /* Override for some arches */
189
190
  m = buf.machine;
191
  /* i?86 */
192
  if (strlen (m) == 4 && m[0] == 'i' && m[2] == '8'  && m[3] == '6')
193
    {
194
      arch = "i386";
195
    }
196
  else if (g_str_has_prefix (m, "arm"))
197
    {
198
      if (g_str_has_suffix (m, "b"))
199
        arch = "armeb";
200
      else
201
        arch = "arm";
202
    }
203
  else if (strcmp (m, "mips") == 0)
204
    {
205
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
206
      arch = "mipsel";
207
#endif
208
    }
209
  else if (strcmp (m, "mips64") == 0)
210
    {
211
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
212
      arch = "mips64el";
213
#endif
214
    }
215
216
  return arch;
217
}
218
#endif
219
220
/* This maps the kernel-reported uname to a single string representing
221
 * the cpu family, in the sense that all members of this family would
222
 * be able to understand and link to a binary file with such cpu
223
 * opcodes. That doesn't necessarily mean that all members of the
224
 * family can run all opcodes, for instance for modern 32bit intel we
225
 * report "i386", even though they support instructions that the
226
 * original i386 cpu cannot run. Still, such an executable would
227
 * at least try to execute a 386, whereas an arm binary would not.
228
 */
229
static const char *
230
flatpak_get_arch (void)
231
{
232
  /* Avoid using uname on multiarch machines, because uname reports the kernels
233
   * arch, and that may be different from userspace. If e.g. the kernel is 64bit and
234
   * the userspace is 32bit we want to use 32bit by default. So, we take the current build
235
   * arch as the default. */
236
#if defined(__i386__)
237
  return "i386";
238
#elif defined(__x86_64__)
239
  return "x86_64";
240
#elif defined(__aarch64__)
241
  return "aarch64";
242
#elif defined(__arm__)
243
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
244
  return "arm";
245
#else
246
  return "armeb";
247
#endif
248
#else
249
  return flatpak_get_kernel_arch ();
250
#endif
251
}
252
253
/* From https://github.com/flatpak/flatpak/blob/master/common/flatpak-run.c */
254
static const uint32_t seccomp_x86_64_extra_arches[] = { SCMP_ARCH_X86, 0, };
255
256
#ifdef SCMP_ARCH_AARCH64
257
static const uint32_t seccomp_aarch64_extra_arches[] = { SCMP_ARCH_ARM, 0 };
258
#endif
259
260
static inline void
261
cleanup_seccomp (void *p)
262
{
263
  scmp_filter_ctx *pp = (scmp_filter_ctx *) p;
264
265
  if (*pp)
266
    seccomp_release (*pp);
267
}
268
269
static gboolean
270
setup_seccomp (GPtrArray  *argv_array,
271
               GArray     *fd_array,
272
               const char *arch,
273
               gboolean    multiarch,
274
               gboolean    devel,
275
               GError    **error)
276
{
277
  __attribute__((cleanup (cleanup_seccomp))) scmp_filter_ctx seccomp = NULL;
278
279
  /**** BEGIN NOTE ON CODE SHARING
280
   *
281
   * There are today a number of different Linux container
282
   * implementations.  That will likely continue for long into the
283
   * future.  But we can still try to share code, and it's important
284
   * to do so because it affects what library and application writers
285
   * can do, and we should support code portability between different
286
   * container tools.
287
   *
288
   * This syscall blacklist is copied from linux-user-chroot, which was in turn
289
   * clearly influenced by the Sandstorm.io blacklist.
290
   *
291
   * If you make any changes here, I suggest sending the changes along
292
   * to other sandbox maintainers.  Using the libseccomp list is also
293
   * an appropriate venue:
294
   * https://groups.google.com/forum/#!topic/libseccomp
295
   *
296
   * A non-exhaustive list of links to container tooling that might
297
   * want to share this blacklist:
298
   *
299
   *  https://github.com/sandstorm-io/sandstorm
300
   *    in src/sandstorm/supervisor.c++
301
   *  http://cgit.freedesktop.org/xdg-app/xdg-app/
302
   *    in common/flatpak-run.c
303
   *  https://git.gnome.org/browse/linux-user-chroot
304
   *    in src/setup-seccomp.c
305
   *
306
   **** END NOTE ON CODE SHARING
307
   */
308
  struct
309
  {
310
    int                  scall;
311
    struct scmp_arg_cmp *arg;
312
  } syscall_blacklist[] = {
313
    /* Block dmesg */
314
    {SCMP_SYS (syslog)},
315
    /* Useless old syscall */
316
    {SCMP_SYS (uselib)},
317
    /* Don't allow you to switch to bsd emulation or whatnot */
318
    {SCMP_SYS (personality)},
319
    /* Don't allow disabling accounting */
320
    {SCMP_SYS (acct)},
321
    /* 16-bit code is unnecessary in the sandbox, and modify_ldt is a
322
       historic source of interesting information leaks. */
323
    {SCMP_SYS (modify_ldt)},
324
    /* Don't allow reading current quota use */
325
    {SCMP_SYS (quotactl)},
326
327
    /* Don't allow access to the kernel keyring */
328
    {SCMP_SYS (add_key)},
329
    {SCMP_SYS (keyctl)},
330
    {SCMP_SYS (request_key)},
331
332
    /* Scary VM/NUMA ops */
333
    {SCMP_SYS (move_pages)},
334
    {SCMP_SYS (mbind)},
335
    {SCMP_SYS (get_mempolicy)},
336
    {SCMP_SYS (set_mempolicy)},
337
    {SCMP_SYS (migrate_pages)},
338
339
    /* Don't allow subnamespace setups: */
340
    {SCMP_SYS (unshare)},
341
    {SCMP_SYS (mount)},
342
    {SCMP_SYS (pivot_root)},
343
    {SCMP_SYS (clone), &SCMP_A0 (SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)},
344
345
    /* Don't allow faking input to the controlling tty (CVE-2017-5226) */
346
    {SCMP_SYS (ioctl), &SCMP_A1(SCMP_CMP_EQ, (int)TIOCSTI)},
347
  };
348
349
  struct
350
  {
351
    int                  scall;
352
    struct scmp_arg_cmp *arg;
353
  } syscall_nondevel_blacklist[] = {
354
    /* Profiling operations; we expect these to be done by tools from outside
355
     * the sandbox.  In particular perf has been the source of many CVEs.
356
     */
357
    {SCMP_SYS (perf_event_open)},
358
    {SCMP_SYS (ptrace)}
359
  };
360
  /* Blacklist all but unix, inet, inet6 and netlink */
361
  int socket_family_blacklist[] = {
362
    AF_AX25,
363
    AF_IPX,
364
    AF_APPLETALK,
365
    AF_NETROM,
366
    AF_BRIDGE,
367
    AF_ATMPVC,
368
    AF_X25,
369
    AF_ROSE,
370
    AF_DECnet,
371
    AF_NETBEUI,
372
    AF_SECURITY,
373
    AF_KEY,
374
    AF_NETLINK + 1, /* Last gets CMP_GE, so order is important */
375
  };
376
  guint i;
377
  int r;
378
  int fd = -1;
379
  g_autofree char *fd_str = NULL;
380
  g_autofree char *path = NULL;
381
382
  seccomp = seccomp_init (SCMP_ACT_ALLOW);
383
  if (!seccomp)
384
    return flatpak_fail (error, "Initialize seccomp failed");
385
386
  if (arch != NULL)
387
    {
388
      uint32_t arch_id = 0;
389
      const uint32_t *extra_arches = NULL;
390
391
      if (strcmp (arch, "i386") == 0)
392
        {
393
          arch_id = SCMP_ARCH_X86;
394
        }
395
      else if (strcmp (arch, "x86_64") == 0)
396
        {
397
          arch_id = SCMP_ARCH_X86_64;
398
          extra_arches = seccomp_x86_64_extra_arches;
399
        }
400
      else if (strcmp (arch, "arm") == 0)
401
        {
402
          arch_id = SCMP_ARCH_ARM;
403
        }
404
#ifdef SCMP_ARCH_AARCH64
405
      else if (strcmp (arch, "aarch64") == 0)
406
        {
407
          arch_id = SCMP_ARCH_AARCH64;
408
          extra_arches = seccomp_aarch64_extra_arches;
409
        }
410
#endif
411
412
      /* We only really need to handle arches on multiarch systems.
413
       * If only one arch is supported the default is fine */
414
      if (arch_id != 0)
415
        {
416
          /* This *adds* the target arch, instead of replacing the
417
             native one. This is not ideal, because we'd like to only
418
             allow the target arch, but we can't really disallow the
419
             native arch at this point, because then bubblewrap
420
             couldn't continue running. */
421
          r = seccomp_arch_add (seccomp, arch_id);
422
          if (r < 0 && r != -EEXIST)
423
            return flatpak_fail (error, "Failed to add architecture to seccomp filter");
424
425
          if (multiarch && extra_arches != NULL)
426
            {
427
              for (i = 0; extra_arches[i] != 0; i++)
428
                {
429
                  r = seccomp_arch_add (seccomp, extra_arches[i]);
430
                  if (r < 0 && r != -EEXIST)
431
                    return flatpak_fail (error, "Failed to add multiarch architecture to seccomp filter");
432
                }
433
            }
434
        }
435
    }
436
437
  /* TODO: Should we filter the kernel keyring syscalls in some way?
438
   * We do want them to be used by desktop apps, but they could also perhaps
439
   * leak system stuff or secrets from other apps.
440
   */
441
442
  for (i = 0; i < G_N_ELEMENTS (syscall_blacklist); i++)
443
    {
444
      int scall = syscall_blacklist[i].scall;
445
      if (syscall_blacklist[i].arg)
446
        r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 1, *syscall_blacklist[i].arg);
447
      else
448
        r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 0);
449
      if (r < 0 && r == -EFAULT /* unknown syscall */)
450
        return flatpak_fail (error, "Failed to block syscall %d", scall);
451
    }
452
453
  if (!devel)
454
    {
455
      for (i = 0; i < G_N_ELEMENTS (syscall_nondevel_blacklist); i++)
456
        {
457
          int scall = syscall_nondevel_blacklist[i].scall;
458
          if (syscall_nondevel_blacklist[i].arg)
459
            r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 1, *syscall_nondevel_blacklist[i].arg);
460
          else
461
            r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 0);
462
463
          if (r < 0 && r == -EFAULT /* unknown syscall */)
464
            return flatpak_fail (error, "Failed to block syscall %d", scall);
465
        }
466
    }
467
468
  /* Socket filtering doesn't work on e.g. i386, so ignore failures here
469
   * However, we need to user seccomp_rule_add_exact to avoid libseccomp doing
470
   * something else: https://github.com/seccomp/libseccomp/issues/8 */
471
  for (i = 0; i < G_N_ELEMENTS (socket_family_blacklist); i++)
472
    {
473
      int family = socket_family_blacklist[i];
474
      if (i == G_N_ELEMENTS (socket_family_blacklist) - 1)
475
        seccomp_rule_add_exact (seccomp, SCMP_ACT_ERRNO (EAFNOSUPPORT), SCMP_SYS (socket), 1, SCMP_A0 (SCMP_CMP_GE, family));
476
      else
477
        seccomp_rule_add_exact (seccomp, SCMP_ACT_ERRNO (EAFNOSUPPORT), SCMP_SYS (socket), 1, SCMP_A0 (SCMP_CMP_EQ, family));
478
    }
479
480
  fd = g_file_open_tmp ("flatpak-seccomp-XXXXXX", &path, error);
481
  if (fd == -1)
482
    return FALSE;
483
484
  unlink (path);
485
486
  if (seccomp_export_bpf (seccomp, fd) != 0)
487
    {
488
      close (fd);
489
      return flatpak_fail (error, "Failed to export bpf");
490
    }
491
492
  lseek (fd, 0, SEEK_SET);
493
494
  fd_str = g_strdup_printf ("%d", fd);
495
  if (fd_array)
496
    g_array_append_val (fd_array, fd);
497
498
  add_args (argv_array,
499
            "--seccomp", fd_str,
500
            NULL);
501
502
  fd = -1; /* Don't close on success */
503
504
  return TRUE;
505
}
506
#endif
507
508
#ifdef HAVE_BWRAP
509
static gboolean
510
add_bwrap (GPtrArray   *array,
511
	   ScriptExec  *script)
512
{
513
  g_return_val_if_fail (script->outdir != NULL, FALSE);
514
  g_return_val_if_fail (script->s_infile != NULL, FALSE);
515
516
  add_args (array,
517
	    "bwrap",
518
	    "--ro-bind", "/usr", "/usr",
519
	    "--ro-bind", "/lib", "/lib",
520
	    "--ro-bind", "/lib64", "/lib64",
521
	    "--proc", "/proc",
522
	    "--dev", "/dev",
523
	    "--symlink", "usr/bin", "/bin",
524
	    "--symlink", "usr/sbin", "/sbin",
525
	    "--chdir", "/",
526
	    "--setenv", "GIO_USE_VFS", "local",
527
	    "--unshare-all",
528
	    "--die-with-parent",
529
	    NULL);
530
531
  add_env (array, "G_MESSAGES_DEBUG");
532
  add_env (array, "G_MESSAGES_PREFIXED");
533
534
  /* Add gnome-desktop's install prefix if needed */
535
  if (g_strcmp0 (INSTALL_PREFIX, "") != 0 &&
536
      g_strcmp0 (INSTALL_PREFIX, "/usr") != 0 &&
537
      g_strcmp0 (INSTALL_PREFIX, "/usr/") != 0)
538
    {
539
      add_args (array,
540
                "--ro-bind", INSTALL_PREFIX, INSTALL_PREFIX,
541
                NULL);
542
    }
543
544
  g_ptr_array_add (array, g_strdup ("--bind"));
545
  g_ptr_array_add (array, g_strdup (script->outdir));
546
  g_ptr_array_add (array, g_strdup ("/tmp"));
547
548
  /* We make sure to also re-use the original file's original
549
   * extension in case it's useful for the thumbnailer to
550
   * identify the file type */
551
  g_ptr_array_add (array, g_strdup ("--ro-bind"));
552
  g_ptr_array_add (array, g_strdup (script->infile));
553
  g_ptr_array_add (array, g_strdup (script->s_infile));
554
555
  return TRUE;
556
}
557
#endif /* HAVE_BWRAP */
558
559
static char **
103
static char **
560
expand_thumbnailing_cmd (const char  *cmd,
104
expand_thumbnailing_script (const char  *cmd,
561
			 ScriptExec  *script,
105
			    ScriptExec  *script,
562
			 int          size,
106
			    int          size,
563
			 GError     **error)
107
			    GError     **error)
564
{
108
{
565
  GPtrArray *array;
109
  GPtrArray *array;
566
  g_auto(GStrv) cmd_elems = NULL;
110
  g_auto(GStrv) cmd_elems = NULL;
567
  guint i;
111
  guint i;
568
  gboolean got_in, got_out;
112
  gboolean got_in, got_out;
113
  g_autofree char *sandboxed_path = NULL;
569
114
570
  if (!g_shell_parse_argv (cmd, NULL, &cmd_elems, error))
115
  if (!g_shell_parse_argv (cmd, NULL, &cmd_elems, error))
571
    return NULL;
116
    return NULL;
572
117
573
  script->thumbnailer_name = g_strdup (cmd_elems[0]);
574
575
  array = g_ptr_array_new_with_free_func (g_free);
118
  array = g_ptr_array_new_with_free_func (g_free);
576
119
577
#ifdef HAVE_BWRAP
578
  if (script->sandbox)
579
    {
580
      if (!add_bwrap (array, script))
581
        {
582
          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
583
			       "Bubblewrap setup failed");
584
	  goto bail;
585
	}
586
    }
587
#endif
588
589
#ifdef ENABLE_SECCOMP
590
  if (script->sandbox)
591
    {
592
      const char *arch;
593
594
      arch = flatpak_get_arch ();
595
      g_assert (arch);
596
      if (!setup_seccomp (array,
597
                          script->fd_array,
598
                          arch,
599
                          FALSE,
600
                          FALSE,
601
                          error))
602
        {
603
          goto bail;
604
        }
605
    }
606
#endif
607
608
  got_in = got_out = FALSE;
120
  got_in = got_out = FALSE;
609
  for (i = 0; cmd_elems[i] != NULL; i++)
121
  for (i = 0; cmd_elems[i] != NULL; i++)
610
    {
122
    {
Lines 612-619 expand_thumbnailing_cmd (const char *cmd, Link Here
612
124
613
      expanded = expand_thumbnailing_elem (cmd_elems[i],
125
      expanded = expand_thumbnailing_elem (cmd_elems[i],
614
					   size,
126
					   size,
615
					   script->s_infile ? script->s_infile : script->infile,
127
					   script->infile,
616
					   script->s_outfile ? script->s_outfile : script->outfile,
128
					   script->outfile,
617
					   &got_in,
129
					   &got_in,
618
					   &got_out);
130
					   &got_out);
619
131
Lines 642-768 bail: Link Here
642
  return NULL;
154
  return NULL;
643
}
155
}
644
156
645
static void
646
child_setup (gpointer user_data)
647
{
648
  GArray *fd_array = user_data;
649
  guint i;
650
651
  /* If no fd_array was specified, don't care. */
652
  if (fd_array == NULL)
653
    return;
654
655
  /* Otherwise, mark not - close-on-exec all the fds in the array */
656
  for (i = 0; i < fd_array->len; i++)
657
    fcntl (g_array_index (fd_array, int, i), F_SETFD, 0);
658
}
659
660
static void
157
static void
661
script_exec_free (ScriptExec *exec)
158
script_exec_free (ScriptExec *exec)
662
{
159
{
663
  if (exec == NULL)
664
    return;
665
666
  g_free (exec->thumbnailer_name);
667
  g_free (exec->infile);
160
  g_free (exec->infile);
668
  if (exec->infile_tmp)
669
    {
670
      g_unlink (exec->infile_tmp);
671
      g_free (exec->infile_tmp);
672
    }
673
  if (exec->outfile)
161
  if (exec->outfile)
674
    {
162
    {
675
      g_unlink (exec->outfile);
163
      g_unlink (exec->outfile);
676
      g_free (exec->outfile);
164
      g_free (exec->outfile);
677
    }
165
    }
678
  if (exec->outdir)
679
    {
680
      if (g_rmdir (exec->outdir) < 0)
681
        {
682
          g_warning ("Could not remove %s, thumbnailer %s left files in directory",
683
                     exec->outdir, exec->thumbnailer_name);
684
        }
685
      g_free (exec->outdir);
686
    }
687
  g_free (exec->s_infile);
688
  g_free (exec->s_outfile);
689
  if (exec->fd_array)
690
    g_array_free (exec->fd_array, TRUE);
691
  g_free (exec);
166
  g_free (exec);
692
}
167
}
693
168
694
static void
695
clear_fd (gpointer data)
696
{
697
  int *fd_p = data;
698
  if (fd_p != NULL && *fd_p != -1)
699
    close (*fd_p);
700
}
701
702
static ScriptExec *
169
static ScriptExec *
703
script_exec_new (const char  *uri,
170
script_exec_new (const char *uri)
704
		 GError     **error)
705
{
171
{
706
  ScriptExec *exec;
172
  ScriptExec *exec;
707
  g_autoptr(GFile) file = NULL;
173
  g_autoptr(GFile) file = NULL;
174
  int fd;
175
  g_autofree char *tmpname = NULL;
708
176
709
  exec = g_new0 (ScriptExec, 1);
177
  exec = g_new0 (ScriptExec, 1);
710
#ifdef HAVE_BWRAP
711
  /* Bubblewrap is not used if the application is already sandboxed in
712
   * Flatpak as all privileges to create a new namespace are dropped when
713
   * the initial one is created. */
714
  if (!g_file_test ("/.flatpak-info", G_FILE_TEST_IS_REGULAR))
715
    exec->sandbox = TRUE;
716
#endif
717
718
  file = g_file_new_for_uri (uri);
178
  file = g_file_new_for_uri (uri);
719
179
720
  exec->infile = g_file_get_path (file);
180
  exec->infile = g_file_get_path (file);
721
  if (!exec->infile)
181
  if (!exec->infile)
722
    {
182
    goto bail;
723
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
724
                   "Could not get path for URI '%s'", uri);
725
      goto bail;
726
    }
727
183
728
#ifdef HAVE_BWRAP
184
  fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, NULL);
729
  if (exec->sandbox)
185
  if (fd == -1)
730
    {
186
    goto bail;
731
      char *tmpl;
187
  close (fd);
732
      g_autofree char *ext = NULL;
188
  exec->outfile = g_steal_pointer (&tmpname);
733
      g_autofree char *infile = NULL;
734
735
      exec->fd_array = g_array_new (FALSE, TRUE, sizeof (int));
736
      g_array_set_clear_func (exec->fd_array, clear_fd);
737
738
      tmpl = g_strdup ("/tmp/gnome-desktop-thumbnailer-XXXXXX");
739
      exec->outdir = g_mkdtemp (tmpl);
740
      if (!exec->outdir)
741
        {
742
          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
743
                               "Could not create temporary sandbox directory");
744
          goto bail;
745
        }
746
      exec->outfile = g_build_filename (exec->outdir, "gnome-desktop-thumbnailer.png", NULL);
747
      ext = get_extension (exec->infile);
748
      infile = g_strdup_printf ("gnome-desktop-file-to-thumbnail.%s", ext);
749
      exec->infile_tmp = g_build_filename (exec->outdir, infile, NULL);
750
751
      exec->s_infile = g_build_filename ("/tmp/", infile, NULL);
752
      exec->s_outfile = g_build_filename ("/tmp/", "gnome-desktop-thumbnailer.png", NULL);
753
    }
754
  else
755
#endif
756
    {
757
      int fd;
758
      g_autofree char *tmpname = NULL;
759
760
      fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, error);
761
      if (fd == -1)
762
        goto bail;
763
      close (fd);
764
      exec->outfile = g_steal_pointer (&tmpname);
765
    }
766
189
767
  return exec;
190
  return exec;
768
191
Lines 771-792 bail: Link Here
771
  return NULL;
194
  return NULL;
772
}
195
}
773
196
774
static void
775
print_script_debug (GStrv expanded_script)
776
{
777
  GString *out;
778
  guint i;
779
780
  out = g_string_new (NULL);
781
782
  for (i = 0; expanded_script[i]; i++)
783
    g_string_append_printf (out, "%s ", expanded_script[i]);
784
  g_string_append_printf (out, "\n");
785
786
  g_debug ("About to launch script: %s", out->str);
787
  g_string_free (out, TRUE);
788
}
789
790
GBytes *
197
GBytes *
791
gnome_desktop_thumbnail_script_exec (const char  *cmd,
198
gnome_desktop_thumbnail_script_exec (const char  *cmd,
792
				     int          size,
199
				     int          size,
Lines 800-816 gnome_desktop_thumbnail_script_exec (const char *cmd, Link Here
800
  GBytes *image = NULL;
207
  GBytes *image = NULL;
801
  ScriptExec *exec;
208
  ScriptExec *exec;
802
209
803
  exec = script_exec_new (uri, error);
210
  exec = script_exec_new (uri);
804
  if (!exec)
211
  expanded_script = expand_thumbnailing_script (cmd, exec, size, error);
805
    goto out;
806
  expanded_script = expand_thumbnailing_cmd (cmd, exec, size, error);
807
  if (expanded_script == NULL)
212
  if (expanded_script == NULL)
808
    goto out;
213
    goto out;
809
214
810
  print_script_debug (expanded_script);
215
#if 0
216
  guint i;
217
218
  g_print ("About to launch script: ");
219
  for (i = 0; expanded_script[i]; i++)
220
    g_print ("%s ", expanded_script[i]);
221
  g_print ("\n");
222
#endif
811
223
812
  ret = g_spawn_sync (NULL, expanded_script, NULL, G_SPAWN_SEARCH_PATH,
224
  ret = g_spawn_sync (NULL, expanded_script, NULL, G_SPAWN_SEARCH_PATH,
813
		      child_setup, exec->fd_array, NULL, &error_out,
225
		      NULL, NULL, NULL, &error_out,
814
		      &exit_status, error);
226
		      &exit_status, error);
815
  if (ret && g_spawn_check_exit_status (exit_status, error))
227
  if (ret && g_spawn_check_exit_status (exit_status, error))
816
    {
228
    {
Lines 830-832 out: Link Here
830
  return image;
242
  return image;
831
}
243
}
832
244
245

Return to bug 683080