示例#1
0
文件: prctl_caps.c 项目: khuey/rr
int main(int argc, char* argv[]) {
  if (argc > 1) {
    if (strcmp(argv[1], "verify_only_admin") == 0) {
      verify_caps(((uint32_t)1) << CAP_SYS_ADMIN);
      return 0;
    } else if (strcmp(argv[1], "verify_no_caps") == 0) {
      verify_caps(0);
      return 0;
    } else {
      return 1;
    }
  }

  if (-1 == try_setup_ns_no_root(CLONE_NEWUSER)) {
    atomic_puts("EXIT-SUCCESS");
    return 0;
  }

  test_assert(1 == prctl(PR_CAPBSET_READ, CAP_SYS_ADMIN));

  int err = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
  if (err == -1) {
    // This is a rather new option, may not be available in all kernels
    // we want to run on
    test_assert(errno == EINVAL);
  } else {
    fork_exec_self("verify_no_caps");
    test_assert(
        0 == prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_SYS_ADMIN, 0, 0));
    raise_in_inheritable_set((uint32_t)1 << CAP_SYS_ADMIN);
    test_assert(
        0 == prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_SYS_ADMIN, 0, 0));
    test_assert(
        1 == prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_SYS_ADMIN, 0, 0));
    fork_exec_self("verify_only_admin");
    test_assert(
        0 == prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, CAP_SYS_ADMIN, 0, 0));
    fork_exec_self("verify_no_caps");
  }

  test_assert(0 == prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN));
  test_assert(0 == prctl(PR_CAPBSET_READ, CAP_SYS_ADMIN));

  test_assert(0 == try_setup_ns(CLONE_NEWUSER));

  test_assert(1 == prctl(PR_CAPBSET_READ, CAP_SYS_ADMIN));

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
示例#2
0
文件: pivot_root.c 项目: orbea/rr
int main(void) {
  if (-1 == try_setup_ns(CLONE_NEWNS)) {
    atomic_puts("EXIT-SUCCESS");
    return 0;
  }

  /* Set up a directory structure for testing */
  test_assert(0 == mkdir("old_root", 0700));
  test_assert(0 == mount("", "old_root", "tmpfs", 0, NULL));

  test_assert(0 == mkdir("old_root/new_root", 0700));
  test_assert(0 == mount("", "old_root/new_root", "tmpfs", 0, NULL));

  test_assert(0 == mkdir("old_root/new_root/new_old_root", 0700));

  /* Write some files so we can identify directories */
  int fd = open("old_root/old_root.txt", O_WRONLY | O_CREAT);
  test_assert(fd != -1);
  test_assert(0 == close(fd));

  fd = open("old_root/new_root/new_root.txt", O_WRONLY | O_CREAT);
  test_assert(fd != -1);
  test_assert(0 == close(fd));

  /* The actual test */
  test_assert(0 == chdir("old_root"));
  test_assert(0 == chroot("."));

  test_assert(0 ==
              syscall(SYS_pivot_root, "new_root", "new_root/new_old_root"));

  /* Verify that directory structure looks as expected */
  struct stat buf;
  test_assert(0 == stat("new_root.txt", &buf));
  test_assert(0 == stat("new_old_root/old_root.txt", &buf));

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
示例#3
0
int main(void) {
  if (!try_setup_ns(CLONE_NEWNET)) {
    atomic_printf("EXIT-SUCCESS");
    return 0;
  }

  /*
   * For this test, we'll be manually doing the following:
   * iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j MASQUERADE
   */

  int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  struct ipt_getinfo info;
  memset(&info, 0, sizeof(info));
  strcpy(info.name, "nat");
  uint32_t getinfo_size = sizeof(info);
  test_assert(
      0 == getsockopt(sock_fd, SOL_IP, IPT_SO_GET_INFO, &info, &getinfo_size));
  test_assert(getinfo_size == sizeof(info));

  atomic_printf("%d existing entries in nat table\n", info.num_entries);

  struct ipt_get_entries* entries =
      malloc(sizeof(struct ipt_get_entries) + info.size);
  strcpy(entries->name, "nat");
  entries->size = info.size;
  uint32_t getentries_size = sizeof(struct ipt_get_entries) + entries->size;
  test_assert(0 == getsockopt(sock_fd, SOL_IP, IPT_SO_GET_ENTRIES, entries,
                              &getentries_size));
  test_assert(getentries_size == sizeof(struct ipt_get_entries) + info.size);

  // matches will be empty
  struct xt_entry_target target;
  const char* target_name = "MASQUERADE";
  target.u.user.target_size = strlen(target_name) - 1;
  memcpy(target.u.user.name, target_name, strlen(target_name) - 1);

  struct ipt_entry entry;
  memset(&entry, 0, sizeof(struct ipt_entry));
  entry.ip.src.s_addr = 0x10;
  entry.ip.smsk.s_addr = 0xffffff;
  entry.target_offset = 0x70;
  entry.next_offset = 0x98;

  // Allocate space to receive counters
  struct xt_counters* counters =
      malloc(sizeof(struct xt_counters) * info.num_entries);
  // We will check for at least some of these bytes being replaced by the kernel
  memset(counters, 0xff, sizeof(struct xt_counters) * info.num_entries);

  struct ipt_replace repl;
  strcpy(repl.name, "nat");
  repl.num_entries = info.num_entries + 1;
  repl.size = info.size + entry.next_offset;
  memcpy(repl.hook_entry, info.hook_entry, sizeof(repl.hook_entry));
  memcpy(repl.underflow, info.underflow, sizeof(repl.underflow));
  repl.num_counters = info.num_entries;
  repl.counters = counters;

  size_t final_size = sizeof(struct ipt_replace) + repl.size;
  char* final = malloc(final_size);

  // Assemble structure
  memcpy(final, &repl, sizeof(struct ipt_replace));

  // Copy over original entries and insert our new one as the second-to-last one
  char* src_ptr = (char*)entries->entrytable;
  char* dest_ptr = (char*)((struct ipt_replace*)final)->entries;
  for (size_t i = 0; i < info.num_entries; ++i) {
    if (i == info.num_entries - 2) {
      memcpy(dest_ptr, &entry, sizeof(struct ipt_entry));
      dest_ptr += sizeof(struct ipt_entry);
      memcpy(dest_ptr, &target, sizeof(struct xt_entry_target));
      dest_ptr += sizeof(struct xt_entry_target);
      size_t npad = entry.next_offset - sizeof(struct xt_entry_target);
      memset(dest_ptr, 0, npad);
      dest_ptr += npad;
    }
    struct ipt_entry* cur_entry = (struct ipt_entry*)src_ptr;
    memcpy(dest_ptr, src_ptr, cur_entry->next_offset);
    dest_ptr += cur_entry->next_offset;
    src_ptr += cur_entry->next_offset;
  }

  // Finally pass this off to the kernel
  test_assert(
      setsockopt(sock_fd, SOL_IP, IPT_SO_SET_REPLACE, final, final_size));

  // Verify that the counters array was overwritten. Since we don't know the
  // exact value here, just make sure some bytes were written. After every byte
  // comparison we also call getuid if they were not the same, which should
  // catch any replay divergence, just from tick mismatch.
  int any_changed = 0;
  for (size_t i = 0; i < sizeof(struct xt_counters) * info.num_entries; ++i) {
    if (((uint8_t*)entries)[i] != 0xff) {
      any_changed = 1;
      (void)getuid();
    }
  }

  test_assert(any_changed);
  atomic_printf("EXIT-SUCCESS");
}