-
Notifications
You must be signed in to change notification settings - Fork 0
/
copy.go
134 lines (110 loc) · 3.67 KB
/
copy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package container
import (
"io"
"os"
"path/filepath"
"golang.org/x/net/context"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/system"
"github.com/maliceio/malice/malice/docker/client"
er "github.com/maliceio/malice/malice/errors"
"github.com/maliceio/malice/malice/maldirs"
"github.com/maliceio/malice/malice/persist"
)
// CopyToVolume copies samples into Malice volume
func CopyToVolume(docker *client.Docker, file persist.File) {
name := "copy2volume"
image := "busybox"
cmd := strslice.StrSlice{"sh", "-c", "while true; do echo 'Waiting...'; sleep 1; done"}
binds := []string{"malice:/malice:rw"}
volSavePath := filepath.Join("/malice", file.SHA256)
if docker.Ping() {
cont, err := Start(docker, cmd, name, image, false, binds, nil, nil, nil)
er.CheckError(err)
defer func() {
er.CheckError(Remove(docker, cont.ID, true, false, true))
}()
// Get an absolute source path.
srcPath, err := resolveLocalPath(file.Path)
er.CheckError(err)
// Prepare destination copy info by stat-ing the container path.
dstInfo := archive.CopyInfo{Path: volSavePath}
dstStat, err := statContainerPath(docker, cont.Name, volSavePath)
log.WithFields(log.Fields{
"dstInfo": dstInfo,
"dstStat": dstStat,
"container.Name": cont.Name,
"file.Path": file.Path,
"volSavePath": volSavePath,
"SampledsDir": maldirs.GetSampledsDir(),
}).Debug("First statContainerPath call.")
// er.CheckError(err)
// Check if file already exists in volume
if dstStat.Size > 0 {
log.Debug("Sample ", file.Name, " already in malice volume.")
return
}
// If the destination is a symbolic link, we should evaluate it.
if err == nil && dstStat.Mode&os.ModeSymlink != 0 {
linkTarget := dstStat.LinkTarget
if !system.IsAbs(linkTarget) {
// Join with the parent directory.
dstParent, _ := archive.SplitPathDirEntry(volSavePath)
linkTarget = filepath.Join(dstParent, linkTarget)
}
dstInfo.Path = linkTarget
dstStat, err = statContainerPath(docker, cont.Name, linkTarget)
log.WithFields(log.Fields{
"dstInfo": dstInfo,
"dstStat": dstStat,
"container.Name": cont.Name,
"file.Path": file.Path,
"linkTarget": linkTarget,
"SampledsDir": maldirs.GetSampledsDir(),
}).Debug("Second statContainerPath call.")
er.CheckError(err)
}
if err == nil {
dstInfo.Exists = true
dstInfo.IsDir = dstStat.Mode.IsDir()
}
var (
content io.Reader
resolvedDstPath string
)
// Prepare source copy info.
srcInfo, err := archive.CopyInfoSourcePath(srcPath, false)
er.CheckError(err)
srcArchive, err := archive.TarResource(srcInfo)
er.CheckError(err)
defer srcArchive.Close()
dstDir, preparedArchive, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, dstInfo)
er.CheckError(err)
defer preparedArchive.Close()
resolvedDstPath = dstDir
content = preparedArchive
copyOptions := types.CopyToContainerOptions{
AllowOverwriteDirWithFile: true,
}
// Copy sample to malice volume
er.CheckError(docker.Client.CopyToContainer(
context.Background(),
cont.ID,
resolvedDstPath,
content,
copyOptions,
))
}
}
func resolveLocalPath(localPath string) (absPath string, err error) {
if absPath, err = filepath.Abs(localPath); err != nil {
return
}
return archive.PreserveTrailingDotOrSeparator(absPath, localPath), nil
}
func statContainerPath(docker *client.Docker, containerName, path string) (types.ContainerPathStat, error) {
return docker.Client.ContainerStatPath(context.Background(), containerName, path)
}