Skip to content

Commit 6e90206

Browse files
committed
opkrun: Don't rely on external program for mounting
When calling the external mount program, the child process we create by the fork() system call may not have the right to mount devices or files, for instance in the case where capabilities are used. Signed-off-by: Paul Cercueil <[email protected]>
1 parent ed15530 commit 6e90206

File tree

1 file changed

+77
-4
lines changed

1 file changed

+77
-4
lines changed

opkrun.c

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "opk.h"
55

6+
#include <errno.h>
7+
#include <fcntl.h>
68
#include <getopt.h>
79
#include <limits.h>
810
#include <stdbool.h>
@@ -11,9 +13,12 @@
1113
#include <string.h>
1214
#include <sys/mount.h>
1315
#include <sys/stat.h>
16+
#include <sys/types.h>
1417
#include <sys/wait.h>
1518
#include <unistd.h>
1619

20+
#include <linux/loop.h>
21+
1722
#ifndef MY_NAME
1823
#define MY_NAME "opkrun"
1924
#endif
@@ -232,6 +237,61 @@ static char *get_url(const char *file)
232237
return tmp;
233238
}
234239

240+
static int logetfree(void)
241+
{
242+
int fd = open("/dev/loop-control", O_RDWR);
243+
if (fd < 0) {
244+
fprintf(stderr, "Failed to open '/dev/loop-control': %d\n", fd);
245+
return -1;
246+
}
247+
248+
int devnr = ioctl(fd, LOOP_CTL_GET_FREE, NULL);
249+
if (devnr < 0) {
250+
fprintf(stderr, "Failed to acquire free loop device: %d\n", devnr);
251+
}
252+
253+
close(fd);
254+
return devnr;
255+
}
256+
257+
static int losetup(const char *loop, const char *file)
258+
{
259+
unsigned int i;
260+
int filefd, loopfd, ret;
261+
262+
filefd = open(file, O_RDONLY);
263+
if (filefd < 0) {
264+
fprintf(stderr, "losetup: cannot open '%s': %d\n", file, filefd);
265+
return -1;
266+
}
267+
268+
/* We try to open the loop device just a bit after it was created.
269+
* Give some time to udev so that it can set the proper rights. */
270+
for (i = 0; i < 100; i++) {
271+
loopfd = open(loop, O_RDONLY);
272+
if (loopfd < 0 && errno == EACCES)
273+
usleep(10000);
274+
else
275+
break;
276+
}
277+
if (loopfd < 0) {
278+
fprintf(stderr, "losetup: cannot open '%s': %d\n", loop, loopfd);
279+
close(filefd);
280+
return loopfd;
281+
}
282+
283+
ret = ioctl(loopfd, LOOP_SET_FD, (void *)(intptr_t)filefd);
284+
if (ret < 0) {
285+
fprintf(stderr, "Cannot setup loop device '%s': %d\n", loop, ret);
286+
close(loopfd);
287+
close(filefd);
288+
return ret;
289+
}
290+
291+
close(filefd);
292+
return loopfd;
293+
}
294+
235295
int main(int argc, char **argv)
236296
{
237297
if (argc < 2) {
@@ -328,10 +388,20 @@ int main(int argc, char **argv)
328388
umount(params.mountpoint);
329389
mkdir(params.mountpoint, 0755);
330390

331-
char buf[256];
332-
sprintf(buf, "mount -o loop,nodev,nosuid,ro \'%s\' \'%s\' >/dev/null 2>&1",
333-
opk_name, params.mountpoint);
334-
ret = system(buf);
391+
int devnr = logetfree();
392+
if (devnr < 0)
393+
return devnr;
394+
395+
char loop_dev[9 + 10 + 1];
396+
sprintf(loop_dev, "/dev/loop%i", devnr);
397+
398+
int loopfd = losetup(loop_dev, opk_name);
399+
if (loopfd < 0) {
400+
perror("Failed to losetup");
401+
return loopfd;
402+
}
403+
404+
ret = mount(loop_dev, params.mountpoint, "squashfs", MS_NODEV | MS_NOSUID | MS_RDONLY, 0);
335405
if (ret < 0) {
336406
perror("Unable to mount OPK");
337407
free(params.mountpoint);
@@ -370,6 +440,9 @@ int main(int argc, char **argv)
370440
rmdir(params.mountpoint);
371441
free(params.mountpoint);
372442

443+
ioctl(loopfd, LOOP_CLR_FD, (void *)0);
444+
close(loopfd);
445+
373446
for (char **ptr = args; *ptr; ptr++)
374447
free(*ptr);
375448

0 commit comments

Comments
 (0)