Skip to content

Commit a98032f

Browse files
manninglucasgvisor-bot
authored andcommitted
Add locking around ringbuffer fields and reserve in packetmmap endpoint.
Reported-by: syzbot+740f3fdf0245dde5e8cc@syzkaller.appspotmail.com Reported-by: syzbot+f22c4f574091579bcc79@syzkaller.appspotmail.com PiperOrigin-RevId: 759230496
1 parent 498360c commit a98032f

File tree

4 files changed

+58
-24
lines changed

4 files changed

+58
-24
lines changed

pkg/sentry/socket/netstack/packetmmap/endpoint.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,11 @@ func (m *Endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
188188
}
189189

190190
// HandlePacket implements stack.PacketMMapEndpoint.HandlePacket.
191-
func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
191+
func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) bool {
192+
if !m.Mapped() {
193+
return false
194+
}
195+
192196
const minMacLen = 16
193197
var (
194198
status = uint32(linux.TP_STATUS_USER)
@@ -200,11 +204,12 @@ func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtoco
200204
cooked := m.cooked
201205
stats := m.stack.Stats()
202206
hdrLen := m.headerLen
207+
reserve := m.reserve
203208
if !m.rxRingBuffer.hasRoom() {
204209
m.mu.Unlock()
205210
stats.DroppedPackets.Increment()
206211
m.dropped.Add(1)
207-
return
212+
return true
208213
}
209214
m.mu.Unlock()
210215

@@ -220,14 +225,14 @@ func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtoco
220225
pktBuf.TrimFront(int64(len(pkt.LinkHeader().Slice()) + len(pkt.VirtioNetHeader().Slice())))
221226
// Cooked packet endpoints don't include the link-headers in received
222227
// packets.
223-
netOffset = linux.TPacketAlign(hdrLen+minMacLen) + m.reserve
228+
netOffset = linux.TPacketAlign(hdrLen+minMacLen) + reserve
224229
macOffset = netOffset
225230
} else {
226231
virtioNetHdrLen := uint32(len(pkt.VirtioNetHeader().Slice()))
227232
macLen := uint32(len(pkt.LinkHeader().Slice())) + virtioNetHdrLen
228-
netOffset = linux.TPacketAlign(hdrLen+macLen) + m.reserve
233+
netOffset = linux.TPacketAlign(hdrLen+macLen) + reserve
229234
if macLen < minMacLen {
230-
netOffset = linux.TPacketAlign(hdrLen+minMacLen) + m.reserve
235+
netOffset = linux.TPacketAlign(hdrLen+minMacLen) + reserve
231236
}
232237
if virtioNetHdrLen > 0 {
233238
netOffset += virtioNetHdrLen
@@ -237,16 +242,16 @@ func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtoco
237242
if netOffset > uint32(^uint16(0)) {
238243
stats.DroppedPackets.Increment()
239244
m.dropped.Add(1)
240-
return
245+
return true
241246
}
242247
dataLength = uint32(pktBuf.Size())
243248

244249
// If the packet is too large to fit in the ring buffer, copy it to the
245250
// receive queue.
246-
if macOffset+dataLength > m.rxRingBuffer.frameSize {
251+
if macOffset+dataLength > m.rxRingBuffer.FrameSize() {
247252
clone = pkt.Clone()
248253
defer clone.DecRef()
249-
dataLength = m.rxRingBuffer.frameSize - macOffset
254+
dataLength = m.rxRingBuffer.FrameSize() - macOffset
250255
if int(dataLength) < 0 {
251256
dataLength = 0
252257
}
@@ -258,15 +263,15 @@ func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtoco
258263
m.mu.Unlock()
259264
stats.DroppedPackets.Increment()
260265
m.dropped.Add(1)
261-
return
266+
return true
262267
}
263268

264269
slot, ok := m.rxRingBuffer.testAndMarkHead()
265270
if !ok {
266271
m.mu.Unlock()
267272
stats.DroppedPackets.Increment()
268273
m.dropped.Add(1)
269-
return
274+
return true
270275
}
271276
m.rxRingBuffer.incHead()
272277

@@ -288,18 +293,19 @@ func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtoco
288293
if err := m.rxRingBuffer.writeFrame(slot, hdrView, pktBuf); err != nil {
289294
stats.DroppedPackets.Increment()
290295
m.dropped.Add(1)
291-
return
296+
return true
292297
}
293298

294299
m.mu.Lock()
295300
defer m.mu.Unlock()
296301
if err := m.rxRingBuffer.writeStatus(slot, status); err != nil {
297302
stats.DroppedPackets.Increment()
298303
m.dropped.Add(1)
299-
return
304+
return true
300305
}
301306
m.received.Add(1)
302307
m.wq.Notify(waiter.ReadableEvents)
308+
return true
303309
}
304310

305311
// AddMapping implements memmap.Mappable.AddMapping.

pkg/sentry/socket/netstack/packetmmap/ring_buffer.go

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,22 @@ import (
3131
"gvisor.dev/gvisor/pkg/tcpip"
3232
)
3333

34+
// Lock order for the mutexes in ringBuffer:
35+
//
36+
// mu
37+
// dataMu
38+
//
3439
// +stateify savable
3540
type ringBuffer struct {
41+
mu sync.Mutex `state:"nosave"`
42+
// +checklocks:mu
3643
framesPerBlock uint32
37-
frameSize uint32
38-
frameMax uint32
39-
blockSize uint32
40-
numBlocks uint32
41-
version int
44+
// +checklocks:mu
45+
frameSize uint32
46+
// +checklocks:mu
47+
frameMax uint32
48+
// +checklocks:mu
49+
blockSize uint32
4250

4351
// The following fields are protected by the owning endpoint's mutex.
4452
head uint32
@@ -59,11 +67,12 @@ type ringBuffer struct {
5967
//
6068
// The owning endpoint must be locked when calling this function.
6169
func (rb *ringBuffer) init(ctx context.Context, req *tcpip.TpacketReq) error {
70+
rb.mu.Lock()
71+
defer rb.mu.Unlock()
6272
rb.blockSize = req.TpBlockSize
6373
rb.framesPerBlock = req.TpBlockSize / req.TpFrameSize
6474
rb.frameMax = req.TpFrameNr - 1
6575
rb.frameSize = req.TpFrameSize
66-
rb.numBlocks = req.TpBlockNr
6776

6877
rb.rxOwnerMap = bitmap.New(req.TpFrameNr)
6978
rb.head = 0
@@ -92,7 +101,6 @@ func (rb *ringBuffer) destroy() {
92101
rb.dataMu.Lock()
93102
rb.mf.DecRef(rb.data)
94103
rb.dataMu.Unlock()
95-
*rb = ringBuffer{}
96104
}
97105

98106
// AppendTranslation essentially implements memmap.Mappable.Translate, with the
@@ -125,6 +133,12 @@ func (rb *ringBuffer) AppendTranslation(ctx context.Context, required, optional
125133
return ts, nil
126134
}
127135

136+
func (rb *ringBuffer) FrameSize() uint32 {
137+
rb.mu.Lock()
138+
defer rb.mu.Unlock()
139+
return rb.frameSize
140+
}
141+
128142
// writeStatus writes the status of a frame to the ring buffer's internal
129143
// mappings at the provided frame number. It also clears the owner map for the
130144
// frame number if setting it to TP_STATUS_USER.
@@ -134,6 +148,8 @@ func (rb *ringBuffer) writeStatus(frameNum uint32, status uint32) error {
134148
if status&linux.TP_STATUS_USER != 0 {
135149
rb.rxOwnerMap.Remove(frameNum)
136150
}
151+
rb.mu.Lock()
152+
defer rb.mu.Unlock()
137153
ims, err := rb.internalMappingsForFrame(frameNum, hostarch.Write)
138154
if err != nil {
139155
return err
@@ -148,6 +164,8 @@ func (rb *ringBuffer) writeStatus(frameNum uint32, status uint32) error {
148164
// writeFrame writes a frame to the ring buffer's internal mappings at the
149165
// provided frame number.
150166
func (rb *ringBuffer) writeFrame(frameNum uint32, hdrView *buffer.View, pkt buffer.Buffer) error {
167+
rb.mu.Lock()
168+
defer rb.mu.Unlock()
151169
ims, err := rb.internalMappingsForFrame(frameNum, hostarch.Write)
152170
if err != nil {
153171
return err
@@ -168,6 +186,8 @@ func (rb *ringBuffer) writeFrame(frameNum uint32, hdrView *buffer.View, pkt buff
168186
//
169187
// The owning endpoint must be locked when calling this method.
170188
func (rb *ringBuffer) incHead() {
189+
rb.mu.Lock()
190+
defer rb.mu.Unlock()
171191
if rb.head == rb.frameMax {
172192
rb.head = 0
173193
} else {
@@ -179,6 +199,8 @@ func (rb *ringBuffer) incHead() {
179199
//
180200
// The owning endpoint must be locked when calling this method.
181201
func (rb *ringBuffer) currFrameStatus() (uint32, error) {
202+
rb.mu.Lock()
203+
defer rb.mu.Unlock()
182204
return rb.frameStatus(rb.head)
183205
}
184206

@@ -187,6 +209,8 @@ func (rb *ringBuffer) currFrameStatus() (uint32, error) {
187209
//
188210
// The owning endpoint must be locked when calling this method.
189211
func (rb *ringBuffer) prevFrameStatus() (uint32, error) {
212+
rb.mu.Lock()
213+
defer rb.mu.Unlock()
190214
prev := rb.head - 1
191215
if rb.head == 0 {
192216
prev = rb.frameMax
@@ -225,6 +249,7 @@ func (rb *ringBuffer) bufferSize() uint64 {
225249
return rb.size
226250
}
227251

252+
// +checklocks:rb.mu
228253
func (rb *ringBuffer) internalMappingsForFrame(frameNum uint32, at hostarch.AccessType) (safemem.BlockSeq, error) {
229254
rb.dataMu.RLock()
230255
defer rb.dataMu.RUnlock()
@@ -239,6 +264,7 @@ func (rb *ringBuffer) internalMappingsForFrame(frameNum uint32, at hostarch.Acce
239264
return rb.mf.MapInternal(frameFR, at)
240265
}
241266

267+
// +checklocks:rb.mu
242268
func (rb *ringBuffer) frameStatus(frameNum uint32) (uint32, error) {
243269
ims, err := rb.internalMappingsForFrame(frameNum, hostarch.Read)
244270
if err != nil {

pkg/tcpip/stack/registration.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ type PacketMMapOpts struct {
217217
// mapped packets over the packet transport protocol (PACKET_MMAP).
218218
type PacketMMapEndpoint interface {
219219
// HandlePacket is called by the stack when new packets arrive that
220-
// match the endpoint.
220+
// match the endpoint. It returns true if the packet was handled by the
221+
// endpoint and false otherwise.
221222
//
222223
// Implementers should treat packet as immutable and should copy it
223224
// before modification.
@@ -226,7 +227,7 @@ type PacketMMapEndpoint interface {
226227
// should construct its own ethernet header for applications.
227228
//
228229
// HandlePacket may modify pkt.
229-
HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *PacketBuffer)
230+
HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *PacketBuffer) bool
230231

231232
// Close releases any resources associated with the endpoint.
232233
Close()

pkg/tcpip/transport/packet/endpoint.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,10 @@ func (ep *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) {
492492
func (ep *endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
493493
ep.packetMmapMu.RLock()
494494
if ep.packetMMapEp != nil {
495-
ep.packetMMapEp.HandlePacket(nicID, netProto, pkt)
496-
ep.packetMmapMu.RUnlock()
497-
return
495+
if handled := ep.packetMMapEp.HandlePacket(nicID, netProto, pkt); handled {
496+
ep.packetMmapMu.RUnlock()
497+
return
498+
}
498499
}
499500
ep.packetMmapMu.RUnlock()
500501

0 commit comments

Comments
 (0)