@@ -168,15 +168,15 @@ func (te *TarExtractor) restoreMetadata(path string, hdr *tar.Header) error {
168
168
// want, we first clear the set of xattrs from the file then apply the ones
169
169
// set in the tar.Header.
170
170
err := te .fsEval .Lclearxattrs (path , func (xattrName string ) bool {
171
- _ , ok := ignoreXattrs [ xattrName ]
172
- return ok
171
+ filter , isComplex := findComplexXattrFilter ( xattrName )
172
+ return isComplex && ! filter . UnpackShouldClear ( te . whiteoutMode , hdr . Name , xattrName )
173
173
})
174
174
if err != nil {
175
175
if ! errors .Is (err , unix .ENOTSUP ) {
176
176
return fmt .Errorf ("clear xattr metadata: %s: %w" , path , err )
177
177
}
178
178
if ! te .enotsupWarned {
179
- log .Warnf ("xattr{%s} ignoring ENOTSUP on clearxattrs" , path )
179
+ log .Warnf ("xattr{%s} ignoring ENOTSUP on clearxattrs" , hdr . Name )
180
180
log .Warnf ("xattr{%s} destination filesystem does not support xattrs, further warnings will be suppressed" , path )
181
181
te .enotsupWarned = true
182
182
} else {
@@ -187,26 +187,37 @@ func (te *TarExtractor) restoreMetadata(path string, hdr *tar.Header) error {
187
187
for name , value := range hdr .Xattrs {
188
188
value := []byte (value )
189
189
190
- // Forbidden xattrs should never be touched.
191
- if _ , skip := ignoreXattrs [name ]; skip {
192
- // If the xattr is already set to the requested value, don't bail.
193
- // The reason for this logic is kinda convoluted, but effectively
194
- // because restoreMetadata is called with the *on-disk* metadata we
195
- // run the risk of things like "security.selinux" being included in
196
- // that metadata (and thus tripping the forbidden xattr error). By
197
- // only touching xattrs that have a different value we are somewhat
198
- // more efficient and we don't have to special case parent restore.
199
- // Of course this will only ever impact ignoreXattrs.
200
- if oldValue , err := te .fsEval .Lgetxattr (path , name ); err == nil {
201
- if bytes .Equal (value , oldValue ) {
202
- log .Debugf ("restore xattr metadata: skipping already-set xattr %q: %s" , name , hdr .Name )
203
- continue
190
+ // Some xattrs need to be skipped for sanity reasons, such as
191
+ // security.selinux, because they are very much host-specific and
192
+ // extracting them from layers would be a really bad idea. Other xattrs
193
+ // need to be remapped (such as trusted.overlay.* xattrs when in
194
+ // overlayfs mode) to have correct values.
195
+ mappedName := name
196
+ if filter , isComplex := findComplexXattrFilter (name ); isComplex {
197
+ if newName := filter .UnpackEntry (te .whiteoutMode , hdr .Name , name ); newName == nil {
198
+ // If the xattr is already set to the requested value, skip it
199
+ // more silently. The reason for this logic is kinda
200
+ // convoluted, but effectively because restoreMetadata is
201
+ // called with the *on-disk* metadata we run the risk of things
202
+ // like "security.selinux" being included in that metadata (and
203
+ // thus tripping the forbidden xattr error). By only touching
204
+ // xattrs that have a different value we are somewhat more
205
+ // efficient and we don't have to special case parent restore.
206
+ // Of course this will only ever impact ignoreXattrs.
207
+ if oldValue , err := te .fsEval .Lgetxattr (path , name ); err == nil {
208
+ if bytes .Equal (value , oldValue ) {
209
+ log .Debugf ("xattr{%s} restore xattr metadata: skipping already-set xattr %q" , hdr .Name , name )
210
+ continue
211
+ }
204
212
}
213
+ log .Warnf ("xattr{%s} ignoring forbidden xattr: %q" , hdr .Name , name )
214
+ continue
215
+ } else if * newName != name {
216
+ mappedName = * newName
217
+ log .Debugf ("xattr{%s} remapping xattr %q to %q during extraction" , hdr .Name , name , mappedName )
205
218
}
206
- log .Warnf ("xattr{%s} ignoring forbidden xattr: %q" , hdr .Name , name )
207
- continue
208
219
}
209
- if err := te .fsEval .Lsetxattr (path , name , value , 0 ); err != nil {
220
+ if err := te .fsEval .Lsetxattr (path , mappedName , value , 0 ); err != nil {
210
221
// In rootless mode, some xattrs will fail (security.capability).
211
222
// This is _fine_ as long as we're not running as root (in which
212
223
// case we shouldn't be ignoring xattrs that we were told to set).
@@ -216,15 +227,15 @@ func (te *TarExtractor) restoreMetadata(path string, hdr *tar.Header) error {
216
227
// unprivileged users (we also would need to translate them
217
228
// back when creating archives).
218
229
if te .partialRootless && errors .Is (err , os .ErrPermission ) {
219
- log .Warnf ("rootless{%s} ignoring (usually) harmless EPERM on setxattr %q" , hdr .Name , name )
230
+ log .Warnf ("rootless{%s} ignoring (usually) harmless EPERM on setxattr %q" , hdr .Name , mappedName )
220
231
continue
221
232
}
222
233
// We cannot do much if we get an ENOTSUP -- this usually means
223
234
// that extended attributes are simply unsupported by the
224
235
// underlying filesystem (such as AUFS or NFS).
225
236
if errors .Is (err , unix .ENOTSUP ) {
226
237
if ! te .enotsupWarned {
227
- log .Warnf ("xattr{%s} ignoring ENOTSUP on setxattr %q" , hdr .Name , name )
238
+ log .Warnf ("xattr{%s} ignoring ENOTSUP on setxattr %q" , hdr .Name , mappedName )
228
239
log .Warnf ("xattr{%s} destination filesystem does not support xattrs, further warnings will be suppressed" , path )
229
240
te .enotsupWarned = true
230
241
} else {
@@ -555,7 +566,23 @@ func (te *TarExtractor) UnpackEntry(root string, hdr *tar.Header, r io.Reader) (
555
566
if err != nil {
556
567
return fmt .Errorf ("get xattr: %w" , err )
557
568
}
558
- dirHdr .Xattrs [xattr ] = string (value )
569
+ // Because restoreMetadata will re-apply these xattrs
570
+ // (potentially remapping them if we have complexXattrs
571
+ // filters) we need to map their names to match what we would
572
+ // get from an actual archive. If the xattr should be ignored
573
+ // we can safely skip it here because UnpackShouldClear will
574
+ // also stop them from being cleared.
575
+ mappedName := xattr
576
+ if filter , isComplex := findComplexXattrFilter (xattr ); isComplex {
577
+ if newName := filter .GenerateEntry (te .whiteoutMode , unsafeDir , xattr ); newName == nil {
578
+ log .Warnf ("xattr{%s} ignoring forbidden xattr: %q" , unsafeDir , xattr )
579
+ continue
580
+ } else if * newName != xattr {
581
+ mappedName = * newName
582
+ log .Debugf ("xattr{%s} remapping xattr %q to %q for later restoreMetadata" , unsafeDir , xattr , mappedName )
583
+ }
584
+ }
585
+ dirHdr .Xattrs [mappedName ] = string (value )
559
586
}
560
587
}
561
588
0 commit comments