1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
// SPDX-License-Identifier: MPL-2.0
/*
* libpathrs: safe path resolution on Linux
* Copyright (C) 2019-2025 Aleksa Sarai <cyphar@cyphar.com>
* Copyright (C) 2019-2025 SUSE LLC
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
/*
* File: examples/c/cat.c
*
* An example program which opens a file inside a root and outputs its contents
* using libpathrs.
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "../../include/pathrs.h"
#define bail(fmt, ...) \
do { fprintf(stderr, fmt "\n", #__VA_ARGS__); exit(1); } while (0)
/* Helper to output a pathrs_error_t in a readable format. */
void print_error(pathrs_error_t *error)
{
int saved_errno = error->saved_errno;
if (saved_errno)
printf("ERROR[%s]: %s\n", strerror(saved_errno), error->description);
else
printf("ERROR: %s\n", error->description);
errno = saved_errno;
}
int open_in_root(const char *root_path, const char *unsafe_path)
{
int liberr = 0;
int rootfd = -EBADF, fd = -EBADF;
rootfd = pathrs_open_root(root_path);
if (IS_PATHRS_ERR(rootfd)) {
liberr = rootfd;
goto err;
}
fd = pathrs_inroot_open(rootfd, unsafe_path, O_RDONLY);
if (IS_PATHRS_ERR(fd)) {
liberr = fd;
goto err;
}
err:
close(rootfd);
if (IS_PATHRS_ERR(liberr)) {
pathrs_error_t *error = pathrs_errorinfo(liberr);
print_error(error);
pathrs_errorinfo_free(error);
}
return fd;
}
void usage(void) {
printf("usage: cat <root> <unsafe-path>\n");
exit(1);
}
int main(int argc, char **argv)
{
int fd;
char *root, *path;
if (argc != 3)
usage();
root = argv[1];
path = argv[2];
/*
* Safely open the file descriptor. Normally applications would create a
* root handle and persist it for longer periods of time, but this is such
* a trivial example it's not necessary.
*/
fd = open_in_root(root, path);
if (fd < 0)
bail("open_in_root failed: %m");
/* Pipe the contents to stdout. */
for (;;) {
ssize_t copied, written;
char buffer[1024];
copied = read(fd, buffer, sizeof(buffer));
if (copied < 0)
bail("read failed: %m");
else if (copied == 0)
break;
written = write(STDOUT_FILENO, buffer, copied);
if (written < 0)
bail("write failed: %m");
if (written != copied)
bail("write was short (read %dB, wrote %dB)", copied, written);
}
close(fd);
return 0;
}
|