google / gvisor

Application Kernel for Containers

Home Page:https://gvisor.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

setsockopt on raw IPv6 socket ignores opt_len on Linux

ghananigans opened this issue · comments

It seems like linux does not check the passed length of an option in calls to setsockopt on a raw IPv6 socket before copying an "int" from userspace:

TEST(RawIPv6SocketTest, IPv6Checksum) {
  int fd;
  ASSERT_GE(fd = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP), 0) << strerror(errno);

  // Even though we specify a smaller than int value, Linux seems to read
  // the full int.
  int intV = std::numeric_limits<int>::max();
  if (intV & 1) {
    intV--;
  }
  ASSERT_EQ(
      setsockopt(fd, SOL_IPV6, IPV6_CHECKSUM, &intV, sizeof(intV) - 1),
      0) << strerror(errno);
  {
    int got;
    socklen_t got_len = sizeof(got);
    ASSERT_EQ(getsockopt(fd, SOL_IPV6, IPV6_CHECKSUM, &got, &got_len),
                0) <<strerror(errno);
    ASSERT_EQ(got_len, sizeof(got));
    EXPECT_EQ(got, intV);
  }

  // If we have pass a pointer that points to memory less than the size of an
  // int, we get a bad address error.
  std::unique_ptr<uint8_t> u8V;
  // Linux seems to assume a full int but doesn't check the passed length.
  //
  // https://github.com/torvalds/linux/blob/a52a8e9eaf4a12dd58953fc622bb2bc08fd1d32c/net/ipv6/raw.c#L1023
  // shows that Linux copies optVal to an int without first checking optLen.
  ASSERT_EQ(
      setsockopt(fd, SOL_IPV6, IPV6_CHECKSUM, u8V.get(), sizeof(*u8V)), -1);
  EXPECT_THAT(errno, EFAULT) << strerror(errno);
}

Should we match this behaviour?

A friendly reminder that this issue had no activity for 120 days.

This issue has been closed due to lack of activity.