Skip to content

Commit ee2f0fa

Browse files
committed
Add support for SELinux relabeling on bind mounts
Add supprt for SELinux relabeling for bind mounts in the RUN instruction. See also: https://github.com/containers/common/blob/crio-1.31/docs/Containerfile.5.md?plain=1#L134C1-L136C72 related-to: hadolint/hadolint#1101 Signed-off-by: Moritz Röhrich <[email protected]>
1 parent 3275c5b commit ee2f0fa

File tree

6 files changed

+54
-9
lines changed

6 files changed

+54
-9
lines changed

src/Language/Docker/Parser/Run.hs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ data RunMountArg
3131
| MountArgType MountType
3232
| MountArgUid Text
3333
| MountArgGid Text
34+
| MountArgRelabel Relabel
3435
deriving (Show)
3536

3637
data MountType
@@ -114,13 +115,14 @@ bindMount args =
114115
Left e -> customError e
115116
Right as -> return $ foldr bindOpts def as
116117
where
117-
allowed = Set.fromList ["target", "source", "from", "ro"]
118+
allowed = Set.fromList ["target", "source", "from", "ro", "relabel"]
118119
required = Set.singleton "target"
119120
bindOpts :: RunMountArg -> BindOpts -> BindOpts
120121
bindOpts (MountArgTarget path) bo = bo {bTarget = path}
121122
bindOpts (MountArgSource path) bo = bo {bSource = Just path}
122123
bindOpts (MountArgFromImage img) bo = bo {bFromImage = Just img}
123124
bindOpts (MountArgReadOnly ro) bo = bo {bReadOnly = Just ro}
125+
bindOpts (MountArgRelabel re) bo = bo {bRelabel = Just re}
124126
bindOpts invalid _ = error $ "unhandled " <> show invalid <> " please report this bug"
125127

126128
cacheMount :: [RunMountArg] -> Parser CacheOpts
@@ -204,6 +206,7 @@ mountArgs =
204206
mountArgId,
205207
mountArgMode,
206208
mountArgReadOnly,
209+
mountArgRelabel,
207210
mountArgRequired,
208211
mountArgSharing,
209212
mountArgSource,
@@ -318,6 +321,12 @@ mountType =
318321
mountArgUid :: (?esc :: Char) => Parser RunMountArg
319322
mountArgUid = MountArgUid <$> key "uid" stringArg
320323

324+
mountArgRelabel :: Parser RunMountArg
325+
mountArgRelabel = MountArgRelabel <$> key "relabel" relabel
326+
327+
relabel :: Parser Relabel
328+
relabel = choice [RelabelShared <$ string "shared", RelabelPrivate <$ string "private"]
329+
321330
toArgName :: RunMountArg -> Text
322331
toArgName (MountArgEnv _) = "env"
323332
toArgName (MountArgFromImage _) = "from"
@@ -331,3 +340,4 @@ toArgName (MountArgSource _) = "source"
331340
toArgName (MountArgTarget _) = "target"
332341
toArgName (MountArgType _) = "type"
333342
toArgName (MountArgUid _) = "uid"
343+
toArgName (MountArgRelabel _) = "relabel"

src/Language/Docker/PrettyPrint.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ prettyPrintRunMount set =
188188
<> maybe mempty printSource bSource
189189
<> maybe mempty printFromImage bFromImage
190190
<> maybe mempty printReadOnly bReadOnly
191+
<> maybe mempty printRelabel bRelabel
191192
CacheMount CacheOpts {..} ->
192193
"type=cache"
193194
<> printTarget cTarget
@@ -237,6 +238,10 @@ prettyPrintRunMount set =
237238
printReadOnly False = ",rw"
238239
printRequired True = ",required"
239240
printRequired False = mempty
241+
printRelabel r = ",relabel="
242+
<> case r of
243+
RelabelShared -> printQuotable "shared"
244+
RelabelPrivate -> printQuotable "private"
240245

241246
prettyPrintRunNetwork :: Maybe RunNetwork -> Doc ann
242247
prettyPrintRunNetwork Nothing = mempty

src/Language/Docker/Syntax.hs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ newtype TargetPath
119119
}
120120
deriving (Show, Eq, Ord, IsString)
121121

122+
data Relabel
123+
= RelabelShared
124+
| RelabelPrivate
125+
deriving (Show, Eq, Ord)
126+
122127
data Checksum
123128
= Checksum !Text
124129
| NoChecksum
@@ -271,12 +276,13 @@ data BindOpts
271276
{ bTarget :: !TargetPath,
272277
bSource :: !(Maybe SourcePath),
273278
bFromImage :: !(Maybe Text),
274-
bReadOnly :: !(Maybe Bool)
279+
bReadOnly :: !(Maybe Bool),
280+
bRelabel :: !(Maybe Relabel)
275281
}
276282
deriving (Show, Eq, Ord)
277283

278284
instance Default BindOpts where
279-
def = BindOpts "" Nothing Nothing Nothing
285+
def = BindOpts "" Nothing Nothing Nothing Nothing
280286

281287
data CacheOpts
282288
= CacheOpts

test/Language/Docker/ParseExposeSpec.hs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
module Language.Docker.ParseExposeSpec where
22

3-
import Data.Default.Class (def)
4-
import qualified Data.Text as Text
53
import Language.Docker.Syntax
64
import TestHelper
75
import Test.Hspec

test/Language/Docker/ParseHealthcheckSpec.hs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
module Language.Docker.ParseHealthcheckSpec where
22

3-
import Data.Default.Class (def)
43
import Language.Docker.Syntax
54
import Test.Hspec
65
import TestHelper
7-
import qualified Data.Set as Set
86
import qualified Data.Text as Text
97

108

test/Language/Docker/ParseRunSpec.hs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ spec = do
5050
[ Run $ RunArgs (ArgumentsText "echo foo") flags
5151
]
5252
it "--mount=type=bind all modifiers" $
53-
let file = Text.unlines ["RUN --mount=type=bind,target=/foo,source=/bar,from=ubuntu,ro echo foo"]
54-
flags = def {mount = Set.singleton $ BindMount (BindOpts {bTarget = "/foo", bSource = Just "/bar", bFromImage = Just "ubuntu", bReadOnly = Just True})}
53+
let file = Text.unlines ["RUN --mount=type=bind,target=/foo,source=/bar,from=ubuntu,ro,relabel=shared echo foo"]
54+
flags = def {mount = Set.singleton $ BindMount (BindOpts {bTarget = "/foo", bSource = Just "/bar", bFromImage = Just "ubuntu", bReadOnly = Just True, bRelabel = Just RelabelShared})}
5555
in assertAst
5656
file
5757
[ Run $ RunArgs (ArgumentsText "echo foo") flags
@@ -706,3 +706,31 @@ spec = do
706706
it "fail because of multiple types in --mount" $
707707
let line = "RUN --mount=type=cache,type=tmpfs,target=/foo foo bar"
708708
in expectFail line
709+
710+
describe "Parse RUN instructions - SELinux relabeling" $ do
711+
let flagsRelabelShared =
712+
def { mount = Set.singleton $
713+
BindMount
714+
( def
715+
{ bTarget = "/bar",
716+
bRelabel = Just RelabelShared
717+
}
718+
)
719+
}
720+
flagsRelabelPrivate =
721+
def { mount = Set.singleton $
722+
BindMount
723+
( def
724+
{ bTarget = "/bar",
725+
bRelabel = Just RelabelPrivate
726+
}
727+
)
728+
}
729+
it "RUN with --relabel=shared" $
730+
let file = Text.unlines
731+
["RUN --mount=type=bind,target=/bar,relabel=shared echo foo"]
732+
in assertAst file [ Run $ RunArgs (ArgumentsText "echo foo") flagsRelabelShared ]
733+
it "RUN with --relabel=private" $
734+
let file = Text.unlines
735+
["RUN --mount=type=bind,target=/bar,relabel=private echo foo"]
736+
in assertAst file [ Run $ RunArgs (ArgumentsText "echo foo") flagsRelabelPrivate ]

0 commit comments

Comments
 (0)