// want to store the terminating '\0'. The readlink system call doesn't add
// terminating null, but our initialization of buf handles this for us.
char buf[PATH_MAX + 1] = { 0 };
- if (readlink("/proc/self/exe", buf, sizeof buf) < 0) {
+ if (readlink("/proc/self/exe", buf, sizeof(buf) - 1) < 0) {
die("cannot readlink /proc/self/exe");
}
if (buf[0] != '/') { // this shouldn't happen, but make sure have absolute path
die("readlink /proc/self/exe returned relative path");
}
+ // as we are looking up other tools relative to our own path, check
+ // we are located where we think we should be - otherwise we
+ // may have been hardlink'd elsewhere and then may execute the
+ // wrong tool as a result
+ if (!sc_is_expected_path(buf)) {
+ die("running from unexpected location: %s", buf);
+ }
char *dir_name = dirname(buf);
- int dir_fd SC_CLEANUP(sc_cleanup_close) = 1;
+ int dir_fd SC_CLEANUP(sc_cleanup_close) = -1;
dir_fd = open(dir_name, O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
if (dir_fd < 0) {
die("cannot open path %s", dir_name);
g_assert_cmpint(errno, ==, EFAULT);
}
+static void test_sc_is_expected_path(void)
+{
+ struct {
+ const char *path;
+ bool expected;
+ } test_cases[] = {
+ {"/tmp/snap-confine", false},
+ {"/tmp/foo", false},
+ {"/home/ ", false},
+ {"/usr/lib/snapd/snap-confine1", false},
+ {"/usr/lib/snapd/snap—confine", false},
+ {"/snap/core/usr/lib/snapd/snap-confine", false},
+ {"/snap/core/x1x/usr/lib/snapd/snap-confine", false},
+ {"/snap/core/z1/usr/lib/snapd/snap-confine", false},
+ {"/snap/cꓳre/1/usr/lib/snapd/snap-confine", false},
+ {"/snap/snapd1/1/usr/lib/snapd/snap-confine", false},
+ {"/snap/core/current/usr/lib/snapd/snap-confine", false},
+ {"/usr/lib/snapd/snap-confine", true},
+ {"/usr/libexec/snapd/snap-confine", true},
+ {"/snap/core/1/usr/lib/snapd/snap-confine", true},
+ {"/snap/core/x1/usr/lib/snapd/snap-confine", true},
+ {"/snap/snapd/1/usr/lib/snapd/snap-confine", true},
+ {"/snap/snapd/1/usr/libexec/snapd/snap-confine", false},
+ };
+ size_t i;
+ for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) {
+ bool result = sc_is_expected_path(test_cases[i].path);
+ g_assert_cmpint(result, ==, test_cases[i].expected);
+ }
+}
+
static void test_die(void)
{
if (g_test_subprocess()) {
static void __attribute__ ((constructor)) init(void)
{
g_test_add_func("/utils/parse_bool", test_parse_bool);
+ g_test_add_func("/utils/sc_is_expected_path", test_sc_is_expected_path);
g_test_add_func("/utils/die", test_die);
g_test_add_func("/utils/die_with_errno", test_die_with_errno);
g_test_add_func("/utils/sc_nonfatal_mkpath/relative",
*/
#include <errno.h>
#include <fcntl.h>
+#include <regex.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
}
return 0;
}
+
+bool sc_is_expected_path(const char *path)
+{
+ const char *expected_path_re =
+ "^(/snap/(snapd|core)/x?[0-9]+/usr/lib|/usr/lib(exec)?)/snapd/snap-confine$";
+ regex_t re;
+ if (regcomp(&re, expected_path_re, REG_EXTENDED | REG_NOSUB) != 0)
+ die("can not compile regex %s", expected_path_re);
+ int status = regexec(&re, path, 0, NULL, 0);
+ regfree(&re);
+ return status == 0;
+}