@@ -30,6 +30,56 @@ import (
30
30
"github.com/kinvolk/seccompagent/pkg/registry"
31
31
)
32
32
33
+ func closeStateFds (recvFds []int ) {
34
+ // If performance becomes an issue, we can fallback to the new syscall closerange().
35
+ for i := range recvFds {
36
+ // Ignore the return code. There isn't anything better to do.
37
+ unix .Close (i )
38
+ }
39
+ }
40
+
41
+ // parseContainerProcessState returns the seccomp-fd and closes the rest of the fds in recvFds.
42
+ // In case of error, no fd is closed.
43
+ // StateFds is assumed to be formated as specs.ContainerProcessState.Fds and
44
+ // recvFds the corresponding list of received fds in the same SCM_RIGHT message.
45
+ func parseStateFds (stateFds []string , recvFds []int ) (uintptr , error ) {
46
+ // Lets find the index in stateFds of the seccomp-fd.
47
+ idx := - 1
48
+ err := false
49
+
50
+ for i , name := range stateFds {
51
+ if name == specs .SeccompFdName && idx == - 1 {
52
+ idx = i
53
+ continue
54
+ }
55
+
56
+ // We found the seccompFdName two times. Error out!
57
+ if name == specs .SeccompFdName && idx != - 1 {
58
+ err = true
59
+ }
60
+ }
61
+
62
+ if idx == - 1 || err {
63
+ return 0 , fmt .Errorf ("seccomp fd not found or malformed containerProcessState.Fds" )
64
+ }
65
+
66
+ if idx >= len (recvFds ) || idx < 0 {
67
+ return 0 , fmt .Errorf ("seccomp fd index out of range" )
68
+ }
69
+
70
+ fd := uintptr (recvFds [idx ])
71
+
72
+ for i := range recvFds {
73
+ if i == idx {
74
+ continue
75
+ }
76
+
77
+ unix .Close (recvFds [i ])
78
+ }
79
+
80
+ return fd , nil
81
+ }
82
+
33
83
func receiveNewSeccompFile (resolver registry.ResolverFunc , sockfd int ) (* registry.Registry , * os.File , error ) {
34
84
MaxNameLen := 4096
35
85
@@ -56,16 +106,6 @@ func receiveNewSeccompFile(resolver registry.ResolverFunc, sockfd int) (*registr
56
106
stateBuf = stateBuf [:n ]
57
107
oob = oob [:oobn ]
58
108
59
- containerProcessState := & specs.ContainerProcessState {}
60
- err = json .Unmarshal (stateBuf , containerProcessState )
61
- if err != nil {
62
- return nil , nil , fmt .Errorf ("cannot parse OCI state: %v\n " , err )
63
- }
64
- seccompFdIndex , ok := containerProcessState .FdIndexes ["seccompFd" ]
65
- if ! ok || seccompFdIndex < 0 {
66
- return nil , nil , fmt .Errorf ("recvfd: didn't receive seccomp fd" )
67
- }
68
-
69
109
scms , err := unix .ParseSocketControlMessage (oob )
70
110
if err != nil {
71
111
return nil , nil , err
@@ -75,14 +115,28 @@ func receiveNewSeccompFile(resolver registry.ResolverFunc, sockfd int) (*registr
75
115
}
76
116
scm := scms [0 ]
77
117
118
+ // The fds are added just after executing recvmsg(). So, since then
119
+ // until here, if we return, we are leaking fds.
120
+ // However, it is tricky to close the fds before we have a reference to
121
+ // the fds slice, that we create just here.
122
+ // TODO: Close fds if we return before this too.
78
123
fds , err := unix .ParseUnixRights (& scm )
79
124
if err != nil {
80
125
return nil , nil , err
81
126
}
82
- if seccompFdIndex >= len (fds ) {
83
- return nil , nil , fmt .Errorf ("recvfd: number of fds is %d and seccompFdIndex is %d" , len (fds ), seccompFdIndex )
127
+
128
+ containerProcessState := & specs.ContainerProcessState {}
129
+ err = json .Unmarshal (stateBuf , containerProcessState )
130
+ if err != nil {
131
+ closeStateFds (fds )
132
+ return nil , nil , fmt .Errorf ("cannot parse OCI state: %v\n " , err )
133
+ }
134
+
135
+ fd , err := parseStateFds (containerProcessState .Fds , fds )
136
+ if err != nil {
137
+ closeStateFds (fds )
138
+ return nil , nil , err
84
139
}
85
- fd := uintptr (fds [seccompFdIndex ])
86
140
87
141
log .WithFields (log.Fields {
88
142
"fd" : fd ,
@@ -92,12 +146,6 @@ func receiveNewSeccompFile(resolver registry.ResolverFunc, sockfd int) (*registr
92
146
"annotations" : containerProcessState .State .Annotations ,
93
147
}).Debug ("New seccomp fd received on socket" )
94
148
95
- for i := 0 ; i < len (fds ); i ++ {
96
- if i != seccompFdIndex {
97
- unix .Close (fds [i ])
98
- }
99
- }
100
-
101
149
var reg * registry.Registry
102
150
if resolver != nil {
103
151
reg = resolver (containerProcessState )
0 commit comments