WORKSPACE: bump Linux to 5.15.2

This involves ripping out fsinfo because there now is quotactl_fd which
handles what we originally used fsinfo for. I also enabled a few new
interesting kernel features in the config like the Landlock LSM and
KFENCE.

Change-Id: Ic0a113893a437b2c8068d06984fdc386f34e6adb
Reviewed-on: https://review.monogon.dev/c/monogon/+/444
Reviewed-by: Sergiusz Bazanski <serge@monogon.tech>
diff --git a/metropolis/pkg/fsquota/BUILD.bazel b/metropolis/pkg/fsquota/BUILD.bazel
index dbeb19b..b25d812 100644
--- a/metropolis/pkg/fsquota/BUILD.bazel
+++ b/metropolis/pkg/fsquota/BUILD.bazel
@@ -3,10 +3,7 @@
 
 go_library(
     name = "go_default_library",
-    srcs = [
-        "fsinfo.go",
-        "fsquota.go",
-    ],
+    srcs = ["fsquota.go"],
     importpath = "source.monogon.dev/metropolis/pkg/fsquota",
     visibility = ["//metropolis:__subpackages__"],
     deps = [
diff --git a/metropolis/pkg/fsquota/fsinfo.go b/metropolis/pkg/fsquota/fsinfo.go
deleted file mode 100644
index ecbaecf..0000000
--- a/metropolis/pkg/fsquota/fsinfo.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2020 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.
-
-package fsquota
-
-import (
-	"fmt"
-	"os"
-	"unsafe"
-
-	"golang.org/x/sys/unix"
-)
-
-// This requires fsinfo() support, which is not yet in any stable kernel. Our
-// kernel has that syscall backported. This would otherwise be an extremely
-// expensive operation and also involve lots of logic from our side.
-
-// From syscall_64.tbl
-const sys_fsinfo = 441
-
-// From uapi/linux/fsinfo.h
-const fsinfo_attr_source = 0x09
-const fsinfo_flags_query_path = 0x0000
-const fsinfo_flags_query_fd = 0x0001
-
-type fsinfoParams struct {
-	resolveFlags uint64
-	atFlags      uint32
-	flags        uint32
-	request      uint32
-	nth          uint32
-	mth          uint32
-}
-
-func fsinfoGetSource(dir *os.File) (string, error) {
-	buf := make([]byte, 256)
-	params := fsinfoParams{
-		flags:   fsinfo_flags_query_fd,
-		request: fsinfo_attr_source,
-	}
-	n, _, err := unix.Syscall6(sys_fsinfo, dir.Fd(), 0, uintptr(unsafe.Pointer(&params)), unsafe.Sizeof(params), uintptr(unsafe.Pointer(&buf[0])), 256)
-	if err != unix.Errno(0) {
-		return "", fmt.Errorf("failed to call fsinfo: %w", err)
-	}
-	return string(buf[:n-1]), nil
-}
diff --git a/metropolis/pkg/fsquota/fsquota.go b/metropolis/pkg/fsquota/fsquota.go
index 263dd48..0d49592 100644
--- a/metropolis/pkg/fsquota/fsquota.go
+++ b/metropolis/pkg/fsquota/fsquota.go
@@ -43,10 +43,6 @@
 		return err
 	}
 	defer dir.Close()
-	source, err := fsinfoGetSource(dir)
-	if err != nil {
-		return err
-	}
 	var valid uint32
 	if maxBytes > 0 {
 		valid |= quotactl.FlagBLimitsValid
@@ -69,7 +65,7 @@
 		// kernels setquota interface. Due to the short time window and
 		// infrequent calls this should not be an immediate issue.
 		for {
-			quota, err := quotactl.GetNextQuota(source, quotactl.QuotaTypeProject, lastID)
+			quota, err := quotactl.GetNextQuota(dir, quotactl.QuotaTypeProject, lastID)
 			if err == unix.ENOENT || err == unix.ESRCH {
 				// We have enumerated all quotas, nothing exists here
 				break
@@ -102,7 +98,7 @@
 	// Always round up to the nearest block size
 	bytesLimitBlocks := uint64(math.Ceil(float64(maxBytes) / float64(1024)))
 
-	return quotactl.SetQuota(source, quotactl.QuotaTypeProject, lastID, &quotactl.Quota{
+	return quotactl.SetQuota(dir, quotactl.QuotaTypeProject, lastID, &quotactl.Quota{
 		BHardLimit: bytesLimitBlocks,
 		BSoftLimit: bytesLimitBlocks,
 		IHardLimit: maxInodes,
@@ -126,10 +122,6 @@
 		return nil, err
 	}
 	defer dir.Close()
-	source, err := fsinfoGetSource(dir)
-	if err != nil {
-		return nil, err
-	}
 	attrs, err := fsxattrs.Get(dir)
 	if err != nil {
 		return nil, err
@@ -137,7 +129,7 @@
 	if attrs.ProjectID == 0 {
 		return nil, os.ErrNotExist
 	}
-	quota, err := quotactl.GetQuota(source, quotactl.QuotaTypeProject, attrs.ProjectID)
+	quota, err := quotactl.GetQuota(dir, quotactl.QuotaTypeProject, attrs.ProjectID)
 	if err != nil {
 		return nil, err
 	}
diff --git a/metropolis/pkg/fsquota/quotactl/quotactl.go b/metropolis/pkg/fsquota/quotactl/quotactl.go
index 337daaa..08be6e0 100644
--- a/metropolis/pkg/fsquota/quotactl/quotactl.go
+++ b/metropolis/pkg/fsquota/quotactl/quotactl.go
@@ -21,6 +21,7 @@
 
 import (
 	"fmt"
+	"os"
 	"unsafe"
 
 	"golang.org/x/sys/unix"
@@ -101,16 +102,12 @@
 )
 
 // QuotaOn turns quota accounting and enforcement on
-func QuotaOn(device string, qtype QuotaType, quotaFormat QuotaFormat, quotaFilePath string) error {
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return err
-	}
+func QuotaOn(fd *os.File, qtype QuotaType, quotaFormat QuotaFormat, quotaFilePath string) error {
 	pathArg, err := unix.BytePtrFromString(quotaFilePath)
 	if err != nil {
 		return err
 	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_QUOTAON|uint(qtype)), uintptr(unsafe.Pointer(devArg)), uintptr(quotaFormat), uintptr(unsafe.Pointer(pathArg)), 0, 0)
+	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_QUOTAON|uint(qtype)), uintptr(quotaFormat), uintptr(unsafe.Pointer(pathArg)), 0, 0)
 	if err != unix.Errno(0) {
 		return err
 	}
@@ -118,12 +115,8 @@
 }
 
 // QuotaOff turns quotas off
-func QuotaOff(device string, qtype QuotaType) error {
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return err
-	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_QUOTAOFF|uint(qtype)), uintptr(unsafe.Pointer(devArg)), 0, 0, 0, 0)
+func QuotaOff(fd *os.File, qtype QuotaType) error {
+	_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_QUOTAOFF|uint(qtype)), 0, 0, 0, 0)
 	if err != unix.Errno(0) {
 		return err
 	}
@@ -131,13 +124,9 @@
 }
 
 // GetFmt gets the quota format used on given filesystem
-func GetFmt(device string, qtype QuotaType) (QuotaFormat, error) {
+func GetFmt(fd *os.File, qtype QuotaType) (QuotaFormat, error) {
 	var fmt uint32
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return 0, err
-	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_GETFMT|uint(qtype)), uintptr(unsafe.Pointer(devArg)), 0, uintptr(unsafe.Pointer(&fmt)), 0, 0)
+	_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_GETFMT|uint(qtype)), 0, uintptr(unsafe.Pointer(&fmt)), 0, 0)
 	if err != unix.Errno(0) {
 		return 0, err
 	}
@@ -145,13 +134,9 @@
 }
 
 // GetInfo gets information about quota files
-func GetInfo(device string, qtype QuotaType) (*DQInfo, error) {
+func GetInfo(fd *os.File, qtype QuotaType) (*DQInfo, error) {
 	var info DQInfo
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return nil, err
-	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_GETINFO|uint(qtype)), uintptr(unsafe.Pointer(devArg)), 0, uintptr(unsafe.Pointer(&info)), 0, 0)
+	_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_GETINFO|uint(qtype)), 0, uintptr(unsafe.Pointer(&info)), 0, 0)
 	if err != unix.Errno(0) {
 		return nil, err
 	}
@@ -159,12 +144,8 @@
 }
 
 // SetInfo sets information about quota files
-func SetInfo(device string, qtype QuotaType, info *DQInfo) error {
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return err
-	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_SETINFO|uint(qtype)), uintptr(unsafe.Pointer(devArg)), 0, uintptr(unsafe.Pointer(info)), 0, 0)
+func SetInfo(fd *os.File, qtype QuotaType, info *DQInfo) error {
+	_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_SETINFO|uint(qtype)), 0, uintptr(unsafe.Pointer(info)), 0, 0)
 	if err != unix.Errno(0) {
 		return err
 	}
@@ -172,13 +153,9 @@
 }
 
 // GetQuota gets user quota structure
-func GetQuota(device string, qtype QuotaType, id uint32) (*Quota, error) {
+func GetQuota(fd *os.File, qtype QuotaType, id uint32) (*Quota, error) {
 	var info Quota
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return nil, err
-	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_GETQUOTA|uint(qtype)), uintptr(unsafe.Pointer(devArg)), uintptr(id), uintptr(unsafe.Pointer(&info)), 0, 0)
+	_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_GETQUOTA|uint(qtype)), uintptr(id), uintptr(unsafe.Pointer(&info)), 0, 0)
 	if err != unix.Errno(0) {
 		return nil, err
 	}
@@ -186,13 +163,9 @@
 }
 
 // GetNextQuota gets disk limits and usage > ID
-func GetNextQuota(device string, qtype QuotaType, id uint32) (*NextDQBlk, error) {
+func GetNextQuota(fd *os.File, qtype QuotaType, id uint32) (*NextDQBlk, error) {
 	var info NextDQBlk
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return nil, err
-	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_GETNEXTQUOTA|uint(qtype)), uintptr(unsafe.Pointer(devArg)), uintptr(id), uintptr(unsafe.Pointer(&info)), 0, 0)
+	_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_GETNEXTQUOTA|uint(qtype)), uintptr(id), uintptr(unsafe.Pointer(&info)), 0, 0)
 	if err != unix.Errno(0) {
 		return nil, err
 	}
@@ -200,12 +173,8 @@
 }
 
 // SetQuota sets the given quota
-func SetQuota(device string, qtype QuotaType, id uint32, quota *Quota) error {
-	devArg, err := unix.BytePtrFromString(device)
-	if err != nil {
-		return err
-	}
-	_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_SETQUOTA|uint(qtype)), uintptr(unsafe.Pointer(devArg)), uintptr(id), uintptr(unsafe.Pointer(quota)), 0, 0)
+func SetQuota(fd *os.File, qtype QuotaType, id uint32, quota *Quota) error {
+	_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_SETQUOTA|uint(qtype)), uintptr(id), uintptr(unsafe.Pointer(quota)), 0, 0)
 	if err != unix.Errno(0) {
 		return fmt.Errorf("failed to set quota: %w", err)
 	}
@@ -214,13 +183,9 @@
 
 // Sync syncs disk copy of filesystems quotas. If device is empty it syncs all
 // filesystems.
-func Sync(device string) error {
-	if device != "" {
-		devArg, err := unix.BytePtrFromString(device)
-		if err != nil {
-			return err
-		}
-		_, _, err = unix.Syscall6(unix.SYS_QUOTACTL, uintptr(Q_SYNC), uintptr(unsafe.Pointer(devArg)), 0, 0, 0, 0)
+func Sync(fd *os.File) error {
+	if fd != nil {
+		_, _, err := unix.Syscall6(unix.SYS_QUOTACTL_FD, fd.Fd(), uintptr(Q_SYNC), 0, 0, 0, 0)
 		if err != unix.Errno(0) {
 			return err
 		}