Re: [TOMOYO #5 18/18] LSM expansion for TOMOYO Linux.

Tetsuo Handa
2007-11-19T14:30:15Z

Hello.

Paul Moore wrote:
> If that is the case then the second call to
> skb_peek() will return a different skb then the one you passed to
> security_post_recv_datagram().
Yes. The second call to skb_peek() might return a different skb than the one
I passed to security_post_recv_datagram().

skb_peek() itself doesn't modify reference count nor queue.
| static inline struct sk_buff *skb_peek(struct sk_buff_head *list_)
| {
| struct sk_buff *list = ((struct sk_buff *)list_)->next;
| if (list == (struct sk_buff *)list_)
| list = NULL;
| return list;
| }

> This is significant because you always throw
> away this second skb without first consulting the LSM via
> security_post_recv_datagram().
I just dequeue skb returned by *first* call to skb_peek().
I'm not handling skb returned by *second* call to skb_peek().
The skb returned by *second* call to skb_peek() is later handled by
somebody else's *first* call to skb_peek().

All skb returned by *first* call to skb_peek() are passed to security_post_recv_datagram().
Only skb returned by *first* call to skb_peek() can become candidate for that skb_recv_datagram() call.
No skb returned by *second* call to skb_peek() can become candidate for that skb_recv_datagram() call,
but can become candidate for subsequent skb_recv_datagram() call if the skb is returned by
*first* call to skb_peek().

Let's consider with named packets.

Suppose a socket has n packets in it's receive queue.
---------------
P0 P1 P2 ... Pn
---------------

Case 1:

Thread T0 picks up P0 with MSG_PEEK flag and then calls security_post_recv_datagram().

While T0 is in security_post_recv_datagram(),
another thread T1 picks up P0 without MSG_PEEK flag and then calls security_post_recv_datagram().

security_post_recv_datagram(P0) from T0 returns -EAGAIN (which means "Don't deliver this packet to caller."),
T0 checks whether P0 is still in socket queue.
T0 finds that P0 is already dequeued, and just drop reference count of P0.

security_post_recv_datagram(P0) from T1 returns -EAGAIN,
T1 drops reference count of P0.

Case 2:

Thread T0 picks up P0 with MSG_PEEK flag and then calls security_post_recv_datagram().

While T0 is in security_post_recv_datagram(),
T1 picks up P0 with MSG_PEEK flag and then calls security_post_recv_datagram().

security_post_recv_datagram(P0) from T0 returns -EAGAIN,
T0 checks whether P0 is still in socket queue.
T0 finds that P0 is still in queue, and dequeues P0 and drop reference count of P0.

security_post_recv_datagram(P0) from T1 returns -EAGAIN,
T1 checks whether P0 is still in socket queue,
T1 finds that P0 is already dequeued, and just drop reference count of P0.

Case 3:

Thread T0 picks up P0 with MSG_PEEK flag and then calls security_post_recv_datagram().

While T0 is in security_post_recv_datagram(),
T1 picks up P0 with MSG_PEEK flag and then calls security_post_recv_datagram().

security_post_recv_datagram(P0) from T1 returns -EAGAIN,
T1 checks whether P0 is still in socket queue.
T1 finds that P0 is still in queue, and dequeues P0 and drop reference count of P0.

security_post_recv_datagram(P0) from T0 returns -EAGAIN,
T0 checks whether P0 is still in socket queue,
T0 finds that P0 is already dequeued, and just drop reference count of P0.

In which case did you find racy condition that P0 is passed to userland without LSM check?

Regards.