feat: report SELinux labels

This will be useful for debugging SELinux implementation. Make API report other xattrs for further development like IMA/EVM

Signed-off-by: Dmitry Sharshakov <dmitry.sharshakov@siderolabs.com>
This commit is contained in:
Dmitry Sharshakov 2024-04-07 18:02:09 +03:00
parent 8fe39eacba
commit 4834a61a8e
No known key found for this signature in database
GPG Key ID: 9866BBFAF691F3AF
8 changed files with 2523 additions and 2101 deletions

View File

@ -452,6 +452,8 @@ message ListRequest {
// Types indicates what file type should be returned. If not indicated,
// all files will be returned.
repeated Type types = 4;
// Report xattrs
bool report_xattrs = 5;
}
// DiskUsageRequest describes a request to list disk usage of directories and regular files
@ -492,6 +494,13 @@ message FileInfo {
uint32 uid = 10;
// Owner gid
uint32 gid = 11;
// Extended attributes (if present and requested)
repeated Xattr xattrs = 12;
}
message Xattr {
string name = 1;
bytes data = 2;
}
// DiskUsageInfo describes a file or directory's information for du command

View File

@ -85,6 +85,7 @@ var lsCmd = &cobra.Command{
Recurse: recursionDepth > 1 || recurse,
RecursionDepth: recursionDepth,
Types: reqTypes,
ReportXattrs: long,
})
if err != nil {
return fmt.Errorf("error fetching logs: %s", err)
@ -117,7 +118,7 @@ var lsCmd = &cobra.Command{
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
defer w.Flush() //nolint:errcheck
fmt.Fprintln(w, "NODE\tMODE\tUID\tGID\tSIZE(B)\tLASTMOD\tNAME")
fmt.Fprintln(w, "NODE\tMODE\tUID\tGID\tSIZE(B)\tLASTMOD\tLABEL\tNAME")
return helpers.ReadGRPCStream(stream, func(info *machineapi.FileInfo, node string, multipleNodes bool) error {
if info.Error != "" {
@ -148,13 +149,25 @@ var lsCmd = &cobra.Command{
}
}
fmt.Fprintf(w, "%s\t%s\t%d\t%d\t%s\t%s\t%s\n",
label := ""
if info.Xattrs != nil {
for _, l := range info.Xattrs {
if l.Name == "security.selinux" {
label = string(l.Data)
break
}
}
}
fmt.Fprintf(w, "%s\t%s\t%d\t%d\t%s\t%s\t%s\t%s\n",
node,
os.FileMode(info.Mode).String(),
info.Uid,
info.Gid,
size,
timestampFormatted,
label,
display,
)

1
go.mod
View File

@ -117,6 +117,7 @@ require (
github.com/packethost/packngo v0.31.0
github.com/pelletier/go-toml/v2 v2.2.2
github.com/pin/tftp/v3 v3.1.0
github.com/pkg/xattr v0.4.9
github.com/pmorjan/kmod v1.1.1
github.com/prometheus/procfs v0.15.1
github.com/rivo/tview v0.0.0-20240807095714-a8dd8799d63b

3
go.sum
View File

@ -526,6 +526,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA=
github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -871,6 +873,7 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -31,6 +31,7 @@ import (
"github.com/gopacket/gopacket/afpacket"
multierror "github.com/hashicorp/go-multierror"
"github.com/nberlee/go-netstat/netstat"
"github.com/pkg/xattr"
"github.com/prometheus/procfs"
"github.com/rs/xid"
"github.com/siderolabs/gen/xslices"
@ -831,11 +832,24 @@ func (s *Server) List(req *machine.ListRequest, obj machine.MachineService_ListS
}
for fi := range files {
xattrs := []*machine.Xattr{}
if req.ReportXattrs {
if list, err := xattr.List(fi.FullPath); err == nil {
for _, attr := range list {
if data, err := xattr.Get(fi.FullPath, attr); err == nil {
xattrs = append(xattrs, &machine.Xattr{Name: attr, Data: data})
}
}
}
}
if fi.Error != nil {
err = obj.Send(&machine.FileInfo{
Name: fi.FullPath,
RelativeName: fi.RelPath,
Error: fi.Error.Error(),
Xattrs: xattrs,
})
} else {
err = obj.Send(&machine.FileInfo{
@ -848,6 +862,7 @@ func (s *Server) List(req *machine.ListRequest, obj machine.MachineService_ListS
Link: fi.Link,
Uid: fi.FileInfo.Sys().(*syscall.Stat_t).Uid,
Gid: fi.FileInfo.Sys().(*syscall.Stat_t).Gid,
Xattrs: xattrs,
})
}

File diff suppressed because it is too large Load Diff

View File

@ -2623,6 +2623,16 @@ func (m *ListRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.ReportXattrs {
i--
if m.ReportXattrs {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x28
}
if len(m.Types) > 0 {
var pksize2 int
for _, num := range m.Types {
@ -2761,6 +2771,18 @@ func (m *FileInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Xattrs) > 0 {
for iNdEx := len(m.Xattrs) - 1; iNdEx >= 0; iNdEx-- {
size, err := m.Xattrs[iNdEx].MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0x62
}
}
if m.Gid != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Gid))
i--
@ -2849,6 +2871,53 @@ func (m *FileInfo) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *Xattr) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Xattr) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *Xattr) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Data) > 0 {
i -= len(m.Data)
copy(dAtA[i:], m.Data)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Data)))
i--
dAtA[i] = 0x12
}
if len(m.Name) > 0 {
i -= len(m.Name)
copy(dAtA[i:], m.Name)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Name)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *DiskUsageInfo) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
@ -11137,6 +11206,9 @@ func (m *ListRequest) SizeVT() (n int) {
}
n += 1 + protohelpers.SizeOfVarint(uint64(l)) + l
}
if m.ReportXattrs {
n += 2
}
n += len(m.unknownFields)
return n
}
@ -11216,6 +11288,30 @@ func (m *FileInfo) SizeVT() (n int) {
if m.Gid != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.Gid))
}
if len(m.Xattrs) > 0 {
for _, e := range m.Xattrs {
l = e.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
}
n += len(m.unknownFields)
return n
}
func (m *Xattr) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Data)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
@ -19735,6 +19831,26 @@ func (m *ListRequest) UnmarshalVT(dAtA []byte) error {
} else {
return fmt.Errorf("proto: wrong wireType = %d for field Types", wireType)
}
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ReportXattrs", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.ReportXattrs = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
@ -20214,6 +20330,157 @@ func (m *FileInfo) UnmarshalVT(dAtA []byte) error {
break
}
}
case 12:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Xattrs", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Xattrs = append(m.Xattrs, &Xattr{})
if err := m.Xattrs[len(m.Xattrs)-1].UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Xattr) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Xattr: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Xattr: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
if m.Data == nil {
m.Data = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])

View File

@ -445,6 +445,7 @@ description: Talos gRPC API reference.
- [Version](#machine.Version)
- [VersionInfo](#machine.VersionInfo)
- [VersionResponse](#machine.VersionResponse)
- [Xattr](#machine.Xattr)
- [ApplyConfigurationRequest.Mode](#machine.ApplyConfigurationRequest.Mode)
- [ConnectRecord.State](#machine.ConnectRecord.State)
@ -5973,6 +5974,7 @@ FileInfo describes a file or directory's information
| relative_name | [string](#string) | | RelativeName is the name of the file or directory relative to the RootPath |
| uid | [uint32](#uint32) | | Owner uid |
| gid | [uint32](#uint32) | | Owner gid |
| xattrs | [Xattr](#machine.Xattr) | repeated | Extended attributes (if present and requested) |
@ -6219,6 +6221,7 @@ ListRequest describes a request to list the contents of a directory.
| recurse | [bool](#bool) | | Recurse indicates that subdirectories should be recursed. |
| recursion_depth | [int32](#int32) | | RecursionDepth indicates how many levels of subdirectories should be recursed. The default (0) indicates that no limit should be enforced. |
| types | [ListRequest.Type](#machine.ListRequest.Type) | repeated | Types indicates what file type should be returned. If not indicated, all files will be returned. |
| report_xattrs | [bool](#bool) | | Report xattrs |
@ -7734,6 +7737,22 @@ rpc upgrade
<a name="machine.Xattr"></a>
### Xattr
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| name | [string](#string) | | |
| data | [bytes](#bytes) | | |
<!-- end messages -->