I created a script for this:, which almost does the work, but with 2 jars one besides another, one with the class to remove, and another without it.
#!/bin/bash
# tar needs find to package without ".". u for update, c for create
function pack_all_without_period() {
find $1 -printf "%P\n" -type f -o -type l -o -type d | sudo tar -$3vf $2 --no-recursion -C $1 -T -
}
if [ -z $1 ]; then
printf "Save the image as tar, extract, and enter each layer to remove the vulnerable classes(JMSAppender/SocketServer/SimpleSocketServer)\nPlease provide the image name. \n"
exit 1
fi
dir="log4j-1.x-fix"
image_tar=amq-image-to-fix.tar
if [ ! -d $dir ]; then
mkdir $dir
fi
# save image to tar
docker save $1 -o $image_tar
# extract tar
tar xf $image_tar -C $dir
# each layer is extracted to a folder, each folder has a "layer.tar".
# Go into each folder, extract `layer.tar`, and use `jar` to remove the classes
# and package them back to `layer.tar` (-a to append), and delete the extracted folders.
# at last, package all layers + manifest.json and so back into another tar, WITHOUT COMPRESSION
cd $dir
# enter layer and exit
for layer in */; do
echo Processing layer $layer
cd $layer
# tar does not support overwrite, as tape cannot be overwritten; so I wanted to remove the original jar from tar,
# then append it back with tar -u/-A/-r; but then I found tar --delete is extremely slow(by design)
# so at last I have to extract all files and package them back
mkdir temp
sudo tar --extract --directory=temp --file layer.tar --wildcards "*.jar" # file tree is preserved, so package them back is easy
pwd
if [[ $? -eq 0 ]]; then
for f in $(find . -mindepth 2 -name "*.jar" -not -type l -printf "%P\n"); do # exclude jolokia.jar(link)
sudo jar -tvf $f | grep -E "(*JMSAppender*.class|*SocketServer.class|*log4j*.class)"
if [[ $? -eq 0 ]]; then
echo Found classes in $f
read -p "Do you want to remove these classes? (Y/N) " option
if [[ $option == 'Y' || $option == 'y' ]]; then
echo Removing class file from $f
sudo zip -d $f "*JMSAppender.class" "*SocketServer.class" "*SimpleSocketServer.class"
######### here I need to delete the original jar with the classes I just deleted, but I don't know how ############
pack_all_without_period temp layer-new.tar u
mv layer-new.tar layer.tar -f
else continue
fi
else
continue
fi
done
# append folders to tar, without leading "."
# echo Appending modified folders to layer.tar anew
# findpack_all_without_period temp/ -type d -printf "%P\n" | sudo tar uvf layer.tar --no-recursion -C . -T -r
fi
sudo rm -r $(find . -maxdepth 1 -mindepth 1 -type d -print)
cd .. # back to $dir
done
cd ..
# tar will always include a folder "." as root. This function get rid of it, so the archive
# only contains the content of the folder
# compress will preserve ownership and group by default; and to extract while preserving the same info,
# we use '--same-owner', which is used by default when using sudo.
# again, append all layers and files to new tar, without leading "."
pwd
pack_all_without_period $dir amq-image-fixed.tar c
#sudo rm -Irv $dir
# tar needs find to package withoutecho ".".after uprocessing forall updatelayers, cwe forare create
functionat pack_all_without_period$(pwd) {
if [[ $3 == 'c' ]]; then
find $1 -printf "%P\n" -type f -o -type l -o -type d | sudo tar -cvf $2 --no-recursion -Cpack_all_without_period $dir amq-T image-
elif [[ $3 == 'u' ]];fixed.tar thenc
find $1 -printf "%P\n" -type f -o -type l -o -type d | sudo tar -uvf $2 --no-recursionrm -CIrv $dir -T -$image_tar
else exit 1
fi
}