Skip to content

Commit eeba90f

Browse files
authored
Merge pull request #13 from rmohr/xattrs
Add a command to bazeldnf which allow setting capabilities and selinux labels on existing tar streams
2 parents 75fd5e0 + 9ac9982 commit eeba90f

File tree

15 files changed

+315
-33
lines changed

15 files changed

+315
-33
lines changed

cmd/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ go_library(
1717
"sandbox.go",
1818
"tar2files.go",
1919
"verify.go",
20+
"xattr.go",
2021
],
2122
importpath = "github.com/rmohr/bazeldnf/cmd",
2223
visibility = ["//visibility:private"],
@@ -31,6 +32,7 @@ go_library(
3132
"//pkg/repo",
3233
"//pkg/rpm",
3334
"//pkg/sat",
35+
"//pkg/xattr",
3436
"@com_github_sassoftware_go_rpmutils//:go_default_library",
3537
"@com_github_sirupsen_logrus//:go_default_library",
3638
"@com_github_spf13_cobra//:go_default_library",

cmd/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var rootCmd = &cobra.Command{
1616
}
1717

1818
func Execute() {
19+
rootCmd.AddCommand(NewXATTRCmd())
1920
rootCmd.AddCommand(NewSandboxCmd())
2021
rootCmd.AddCommand(NewFetchCmd())
2122
rootCmd.AddCommand(NewInitCmd())

cmd/rpm2tar.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import (
1212
)
1313

1414
type rpm2tarOpts struct {
15-
output string
16-
input []string
17-
symlinks map[string]string
18-
capabilities map[string]string
15+
output string
16+
input []string
17+
symlinks map[string]string
18+
capabilities map[string]string
19+
selinuxLabels map[string]string
1920
}
2021

2122
var rpm2taropts = rpm2tarOpts{}
@@ -79,13 +80,13 @@ func NewRpm2TarCmd() *cobra.Command {
7980
return fmt.Errorf("could not open rpm at %s: %v", i, err)
8081
}
8182
defer rpmStream.Close()
82-
err = rpm.RPMToTar(rpmStream, tarWriter, true, cap)
83+
err = rpm.RPMToTar(rpmStream, tarWriter, true, cap, rpm2taropts.selinuxLabels)
8384
if err != nil {
8485
return fmt.Errorf("could not convert rpm at %s: %v", i, err)
8586
}
8687
}
8788
} else {
88-
err := rpm.RPMToTar(rpmStream, tarWriter, false, cap)
89+
err := rpm.RPMToTar(rpmStream, tarWriter, false, cap, rpm2taropts.selinuxLabels)
8990
if err != nil {
9091
return fmt.Errorf("could not convert rpm : %v", err)
9192
}
@@ -98,6 +99,7 @@ func NewRpm2TarCmd() *cobra.Command {
9899
rpm2tarCmd.Flags().StringArrayVarP(&rpm2taropts.input, "input", "i", []string{}, "location from where to read the rpm file (defaults to stdin)")
99100
rpm2tarCmd.Flags().StringToStringVarP(&rpm2taropts.symlinks, "symlinks", "s", map[string]string{}, "symlinks to add. Relative or absolute.")
100101
rpm2tarCmd.Flags().StringToStringVarP(&rpm2taropts.capabilities, "capabilities", "c", map[string]string{}, "capabilities of files (--capabilities=/bin/ls=cap_net_bind_service)")
102+
rpm2tarCmd.Flags().StringToStringVar(&rpm2taropts.selinuxLabels, "selinux-labels", map[string]string{}, "selinux labels of files (--selinux-labels=/bin/ls=unconfined_u:object_r:default_t:s0)")
101103
// deprecated options
102104
rpm2tarCmd.Flags().StringToStringVar(&rpm2taropts.capabilities, "capabilties", map[string]string{}, "capabilities of files (-c=/bin/ls=cap_net_bind_service)")
103105
rpm2tarCmd.Flags().MarkDeprecated("capabilties", "use --capabilities instead")

cmd/xattr.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package main
2+
3+
import (
4+
"archive/tar"
5+
"os"
6+
"strings"
7+
8+
"github.com/rmohr/bazeldnf/pkg/xattr"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
type xattrOpts struct {
13+
filePrefix string
14+
tarFileInput string
15+
tarFileOutput string
16+
capabilities map[string]string
17+
selinuxLabels map[string]string
18+
}
19+
20+
var xattropts = xattrOpts{}
21+
22+
func NewXATTRCmd() *cobra.Command {
23+
xattrCmd := &cobra.Command{
24+
Use: "xattr",
25+
Short: "Modify xattrs on tar file members",
26+
Args: cobra.ExactArgs(0),
27+
RunE: func(cmd *cobra.Command, args []string) (err error) {
28+
capabilityMap := map[string][]string{}
29+
for file, caps := range xattropts.capabilities {
30+
split := strings.Split(caps, ":")
31+
if len(split) > 0 {
32+
capabilityMap["./"+strings.TrimPrefix(file, "/")] = split
33+
}
34+
}
35+
labelMap := map[string]string{}
36+
for file, label := range xattropts.selinuxLabels {
37+
labelMap["./"+strings.TrimPrefix(file, "/")] = label
38+
}
39+
40+
streamInput := os.Stdin
41+
if xattropts.tarFileInput != "" {
42+
streamInput, err = os.Open(xattropts.tarFileInput)
43+
if err != nil {
44+
return err
45+
}
46+
defer streamInput.Close()
47+
}
48+
49+
streamOutput := os.Stdout
50+
if xattropts.tarFileOutput != "" {
51+
streamOutput, err = os.OpenFile(xattropts.tarFileOutput, os.O_WRONLY|os.O_CREATE, os.ModePerm)
52+
if err != nil {
53+
return err
54+
}
55+
}
56+
tarWriter := tar.NewWriter(streamOutput)
57+
defer tarWriter.Close()
58+
return xattr.Apply(tar.NewReader(streamInput), tarWriter , capabilityMap, labelMap)
59+
},
60+
}
61+
62+
xattrCmd.Flags().StringVarP(&xattropts.tarFileInput, "input", "i", "", "location from where to read the tar file (defaults to stdin)")
63+
xattrCmd.Flags().StringVarP(&xattropts.tarFileOutput, "output", "o", "", "where to write the file to (defaults to stdout)")
64+
xattrCmd.Flags().StringToStringVarP(&xattropts.capabilities, "capabilities", "c", map[string]string{}, "capabilities of files (--capabilities=/bin/ls=cap_net_bind_service)")
65+
xattrCmd.Flags().StringToStringVar(&xattropts.selinuxLabels, "selinux-labels", map[string]string{}, "selinux labels of files (--selinux-labels=/bin/ls=unconfined_u:object_r:default_t:s0)")
66+
return xattrCmd
67+
}

deps.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ load(
1414
"@bazeldnf//internal:rpmtree.bzl",
1515
_tar2files = "tar2files",
1616
)
17+
load(
18+
"@bazeldnf//internal:xattrs.bzl",
19+
_xattrs = "xattrs",
20+
)
1721

1822
rpm = _rpm
1923
rpmtree = _rpmtree
2024
tar2files = _tar2files
25+
xattrs = _xattrs
2126

2227
def bazeldnf_dependencies():
2328
_maybe(

internal/rpmtree.bzl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ def _rpm2tar_impl(ctx):
3030
capabilities = []
3131
for k, v in ctx.attr.capabilities.items():
3232
capabilities += [k + "=" + ":".join(v)]
33-
args += ["-c", ",".join(capabilities)]
33+
args += ["--capabilities", ",".join(capabilities)]
34+
35+
if ctx.attr.selinux_labels:
36+
selinux_labels = []
37+
for k, v in ctx.attr.selinux_labels.items():
38+
selinux_labels += [k + "=" + v]
39+
args += ["--selinux-labels", ",".join(selinux_labels)]
3440

3541
args += rpms
3642

@@ -71,6 +77,7 @@ _rpm2tar_attrs = {
7177
),
7278
"symlinks": attr.string_dict(),
7379
"capabilities": attr.string_list_dict(),
80+
"selinux_labels": attr.string_list_dict(),
7481
"out": attr.output(mandatory = True),
7582
}
7683

internal/xattrs.bzl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright 2014 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
def _xattrs_impl(ctx):
16+
out = ctx.outputs.out
17+
args = ["xattr", "-i", ctx.files.tar[0].path, "-o", out.path]
18+
19+
if ctx.attr.capabilities:
20+
capabilities = []
21+
for k, v in ctx.attr.capabilities.items():
22+
capabilities += [k + "=" + ":".join(v)]
23+
args += ["--capabilities", ",".join(capabilities)]
24+
25+
if ctx.attr.selinux_labels:
26+
selinux_labels = []
27+
for k, v in ctx.attr.selinux_labels.items():
28+
selinux_labels += [k + "=" + v]
29+
args += ["--selinux-labels", ",".join(selinux_labels)]
30+
31+
ctx.actions.run(
32+
inputs = ctx.files.tar,
33+
outputs = [out],
34+
arguments = args,
35+
progress_message = "Enriching %s with xattrs" % ctx.label.name,
36+
executable = ctx.executable._bazeldnf,
37+
)
38+
39+
return [DefaultInfo(files = depset([ctx.outputs.out]))]
40+
41+
_xattrs_attrs = {
42+
"tar": attr.label(allow_single_file = True),
43+
"_bazeldnf": attr.label(
44+
executable = True,
45+
cfg = "exec",
46+
allow_files = True,
47+
default = Label("//cmd:cmd"),
48+
),
49+
"capabilities": attr.string_list_dict(),
50+
"selinux_labels": attr.string_dict(),
51+
"out": attr.output(mandatory = True),
52+
}
53+
54+
_xattrs = rule(
55+
implementation = _xattrs_impl,
56+
attrs = _xattrs_attrs,
57+
)
58+
59+
def xattrs(**kwargs):
60+
basename = kwargs["name"]
61+
tarname = basename + ".tar"
62+
_xattrs(
63+
out = tarname,
64+
**kwargs
65+
)

pkg/rpm/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ go_library(
1111
visibility = ["//visibility:public"],
1212
deps = [
1313
"//pkg/api",
14+
"//pkg/xattr",
1415
"@com_github_sassoftware_go_rpmutils//:go_default_library",
1516
"@com_github_sassoftware_go_rpmutils//cpio:go_default_library",
1617
"@com_github_sirupsen_logrus//:go_default_library",

pkg/rpm/cpio2tar.go

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,12 @@ import (
2323
"io/ioutil"
2424
"time"
2525

26+
"github.com/rmohr/bazeldnf/pkg/xattr"
2627
"github.com/sassoftware/go-rpmutils/cpio"
2728
)
2829

29-
const (
30-
capabilities_header = "SCHILY.xattr.security.capability"
31-
)
32-
33-
var cap_empty_bitmask = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
34-
var supported_capabilities = map[string][]byte{
35-
"cap_net_bind_service": {1, 0, 0, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
36-
}
37-
3830
// Extract the contents of a cpio stream from and writes it as a tar file into the provided writer
39-
func Tar(rs io.Reader, tarfile *tar.Writer, noSymlinksAndDirs bool, capabilities map[string][]string) error {
31+
func Tar(rs io.Reader, tarfile *tar.Writer, noSymlinksAndDirs bool, capabilities map[string][]string, selinuxLabels map[string]string) error {
4032
hardLinks := map[int][]*tar.Header{}
4133
inodes := map[int]string{}
4234

@@ -54,18 +46,13 @@ func Tar(rs io.Reader, tarfile *tar.Writer, noSymlinksAndDirs bool, capabilities
5446

5547
pax := map[string]string{}
5648
if caps, exists := capabilities[entry.Header.Filename()]; exists {
57-
for _, cap := range caps {
58-
if _, supported := supported_capabilities[cap]; !supported {
59-
return fmt.Errorf("Requested capability '%s' for file '%s' is not supported", cap, entry.Header.Filename())
60-
}
61-
if _, exists := pax[capabilities_header]; !exists {
62-
pax[capabilities_header] = string(cap_empty_bitmask)
63-
}
64-
val := []byte(pax[capabilities_header])
65-
for i, b := range supported_capabilities[cap] {
66-
val[i] = val[i] | b
67-
}
68-
pax[capabilities_header] = string(val)
49+
if err := xattr.AddCapabilities(pax, caps); err != nil {
50+
return fmt.Errorf("failed setting capabilities on %s: %v", entry.Header.Filename(), err)
51+
}
52+
}
53+
if label, exists := selinuxLabels[entry.Header.Filename()]; exists {
54+
if err := xattr.SetSELinuxLabel(pax, label); err != nil {
55+
return fmt.Errorf("failed setting selinux label on %s: %v", entry.Header.Filename(), err)
6956
}
7057
}
7158

pkg/rpm/tar.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
log "github.com/sirupsen/logrus"
1616
)
1717

18-
func RPMToTar(rpmReader io.Reader, tarWriter *tar.Writer, noSymlinksAndDirs bool, capabilities map[string][]string) error {
18+
func RPMToTar(rpmReader io.Reader, tarWriter *tar.Writer, noSymlinksAndDirs bool, capabilities map[string][]string, selinuxLabels map[string]string) error {
1919
rpm, err := rpmutils.ReadRpm(rpmReader)
2020
if err != nil {
2121
return fmt.Errorf("failed to read rpm: %s", err)
@@ -24,7 +24,7 @@ func RPMToTar(rpmReader io.Reader, tarWriter *tar.Writer, noSymlinksAndDirs bool
2424
if err != nil {
2525
return fmt.Errorf("failed to open the payload reader: %s", err)
2626
}
27-
return Tar(payloadReader, tarWriter, noSymlinksAndDirs, capabilities)
27+
return Tar(payloadReader, tarWriter, noSymlinksAndDirs, capabilities, selinuxLabels)
2828
}
2929

3030
func RPMToCPIO(rpmReader io.Reader) (*cpio.CpioStream, error) {

0 commit comments

Comments
 (0)