third_party/cap: initialize

This adds libcap which is needed for any chance at running chrony as non-root.

Upstream contains a multi-stage codegen based on various external utilities
which has been replaced by a clean Go script. Upstream is capable of also
using gperf to generate hash tables for faster lookups, but due to the
extremely low amount of items (~40) and the additional complexity this is
not enabled.

This is not tested standalone, but it has been tested with chrony.

Change-Id: I638f6aea98158cd2e2838531a5a6125e724838f5
Reviewed-on: https://review.monogon.dev/c/monogon/+/317
Reviewed-by: Sergiusz Bazanski <serge@monogon.tech>
diff --git a/WORKSPACE b/WORKSPACE
index 5bd45f7..4ccbb9e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -202,6 +202,13 @@
     name = "chrony",
 )
 
+load("//third_party/cap:external.bzl", "cap_external")
+
+cap_external(
+    name = "cap",
+    version = "1.2.55",
+)
+
 register_toolchains("//:host_python")
 
 # python dependencies. Currently we don't use Python, but some of our deps (ie. gvisor) do expect @pydeps// to exist, even
diff --git a/third_party/cap/BUILD.bazel b/third_party/cap/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/cap/BUILD.bazel
diff --git a/third_party/cap/cap.bzl b/third_party/cap/cap.bzl
new file mode 100644
index 0000000..459c89b
--- /dev/null
+++ b/third_party/cap/cap.bzl
@@ -0,0 +1,52 @@
+#  Copyright 2021 The Monogon Project Authors.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+load("@rules_cc//cc:defs.bzl", "cc_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_binary")
+
+cc_library(
+    name = "cap",
+    srcs = [
+        "cap_alloc.c",
+        "cap_extint.c",
+        "cap_file.c",
+        "cap_flag.c",
+        "cap_proc.c",
+        "cap_text.c",
+    ] + glob(["include/sys/*.h"]),  # UAPI is intentionally excluded as we want it from our own kernel headers
+    hdrs = ["libcap.h", ":cap_names.h"],
+    visibility = ["//visibility:public"],
+    includes = [".", "include"],
+)
+
+go_binary(
+    name = "makenames",
+    srcs = ["makenames.go"],
+)
+
+genrule(
+    name = "cap_names_hdr",
+    srcs = [
+        "include/uapi/linux/capability.h",
+    ],
+    outs = [
+        "cap_names.h",
+    ],
+    cmd = "$(location :makenames) \"$(location include/uapi/linux/capability.h)\" \"$@\"",
+    tools = [
+        ":makenames",
+    ],
+)
diff --git a/third_party/cap/external.bzl b/third_party/cap/external.bzl
new file mode 100644
index 0000000..075851b
--- /dev/null
+++ b/third_party/cap/external.bzl
@@ -0,0 +1,34 @@
+#  Copyright 2021 The Monogon Project Authors.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+def cap_external(name, version):
+    sums = {
+        "1.2.55": "e29322032ea94e90696ae2d17530edc914c71765232ee8fd4fde38ba639cb256",
+    }
+
+    http_archive(
+        name = name,
+        sha256 = sums[version],
+        build_file = "@//third_party/cap:cap.bzl",
+        strip_prefix = "libcap-cap/v%s/libcap" % version,
+        patch_args = ["-p1"],
+        patches = [
+            "//third_party/cap/patches:add_go_codegen.patch",
+        ],
+        urls = ["https://git.kernel.org/pub/scm/libs/libcap/libcap.git/snapshot/libcap-cap/v%s.tar.gz" % version],
+    )
diff --git a/third_party/cap/patches/BUILD b/third_party/cap/patches/BUILD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/cap/patches/BUILD
diff --git a/third_party/cap/patches/add_go_codegen.patch b/third_party/cap/patches/add_go_codegen.patch
new file mode 100644
index 0000000..2572367
--- /dev/null
+++ b/third_party/cap/patches/add_go_codegen.patch
@@ -0,0 +1,78 @@
+--- /dev/null
++++ b/makenames.go
+@@ -0,0 +1,73 @@
++// makenames replaces the built-in array generation consisting of Perl incantations being
++// consumed by C code with a single implementation that's shorter anyways.
++package main
++
++import (
++   "io/ioutil"
++	"log"
++	"os"
++	"regexp"
++	"strconv"
++	"strings"
++	"text/template"
++)
++
++type tmplParams struct {
++	Bits     int
++	NameSize int
++	Caps     []string
++}
++
++var capNamesTmpl = template.Must(template.New("cap_names").Parse(`/*
++ * DO NOT EDIT: this file is generated automatically from
++ *
++ *     <uapi/linux/capability.h>
++ */
++
++#define __CAP_BITS       {{ .Bits }}
++#define __CAP_NAME_SIZE  {{ .NameSize }}
++
++#ifdef LIBCAP_PLEASE_INCLUDE_ARRAY
++#define LIBCAP_CAP_NAMES { \
++{{ range $i, $name := .Caps }}      /* {{ $i }} */	{{ if $name }}"{{ $name }}"{{else}}NULL,		/* - presently unused */{{end}}, \
++{{end}}  }
++#endif /* LIBCAP_PLEASE_INCLUDE_ARRAY */
++
++/* END OF FILE */
++`))
++
++var capRe = regexp.MustCompile(`(?m)^#define[ \t](CAP[_A-Z]+)[ \t]+([0-9]+)\s+$`)
++
++func main() {
++	sourceFile, err := ioutil.ReadFile(os.Args[1])
++	if err != nil {
++		log.Fatalln(err)
++	}
++
++	matches := capRe.FindAllStringSubmatch(string(sourceFile), -1)
++	out := tmplParams{
++		Caps: make([]string, 1024),
++	}
++	for _, m := range matches {
++		i, err := strconv.Atoi(m[2])
++		if err != nil {
++			log.Fatalln(err)
++		}
++		if i+1 > out.Bits {
++			out.Bits = i + 1
++		}
++		if len(m[1])+1 > out.NameSize {
++			out.NameSize = len(m[1]) + 1
++		}
++		out.Caps[i] = strings.ToLower(m[1])
++	}
++	out.Caps = out.Caps[:out.Bits]
++	outFile, err := os.Create(os.Args[2])
++	if err != nil {
++		log.Fatalln(err)
++	}
++	if err := capNamesTmpl.ExecuteTemplate(outFile, "cap_names", &out); err != nil {
++		log.Fatalln(err)
++	}
++	outFile.Close()
++}
+--
+2.25.1