Commit e400cfa3 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Paolo Abeni

af_unix: Fix wrong ioctl(SIOCATMARK) when consumed OOB skb is at the head.

Even if OOB data is recv()ed, ioctl(SIOCATMARK) must return 1 when the
OOB skb is at the head of the receive queue and no new OOB data is queued.

Without fix:

  #  RUN           msg_oob.no_peek.oob ...
  # msg_oob.c:305:oob:Expected answ[0] (0) == oob_head (1)
  # oob: Test terminated by assertion
  #          FAIL  msg_oob.no_peek.oob
  not ok 2 msg_oob.no_peek.oob

With fix:

  #  RUN           msg_oob.no_peek.oob ...
  #            OK  msg_oob.no_peek.oob
  ok 2 msg_oob.no_peek.oob

Fixes: 314001f0 ("af_unix: Add OOB support")
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 48a99837
...@@ -3107,12 +3107,23 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -3107,12 +3107,23 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
#if IS_ENABLED(CONFIG_AF_UNIX_OOB) #if IS_ENABLED(CONFIG_AF_UNIX_OOB)
case SIOCATMARK: case SIOCATMARK:
{ {
struct unix_sock *u = unix_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
int answ = 0; int answ = 0;
mutex_lock(&u->iolock);
skb = skb_peek(&sk->sk_receive_queue); skb = skb_peek(&sk->sk_receive_queue);
if (skb && skb == READ_ONCE(unix_sk(sk)->oob_skb)) if (skb) {
answ = 1; struct sk_buff *oob_skb = READ_ONCE(u->oob_skb);
if (skb == oob_skb ||
(!oob_skb && !unix_skb_len(skb)))
answ = 1;
}
mutex_unlock(&u->iolock);
err = put_user(answ, (int __user *)arg); err = put_user(answ, (int __user *)arg);
} }
break; break;
......
...@@ -288,6 +288,26 @@ static void __setinlinepair(struct __test_metadata *_metadata, ...@@ -288,6 +288,26 @@ static void __setinlinepair(struct __test_metadata *_metadata,
} }
} }
static void __siocatmarkpair(struct __test_metadata *_metadata,
FIXTURE_DATA(msg_oob) *self,
bool oob_head)
{
int answ[2] = {};
int i;
for (i = 0; i < 2; i++) {
int ret;
ret = ioctl(self->fd[i * 2 + 1], SIOCATMARK, &answ[i]);
ASSERT_EQ(ret, 0);
}
ASSERT_EQ(answ[0], oob_head);
if (self->tcp_compliant)
ASSERT_EQ(answ[0], answ[1]);
}
#define sendpair(buf, len, flags) \ #define sendpair(buf, len, flags) \
__sendpair(_metadata, self, buf, len, flags) __sendpair(_metadata, self, buf, len, flags)
...@@ -304,6 +324,9 @@ static void __setinlinepair(struct __test_metadata *_metadata, ...@@ -304,6 +324,9 @@ static void __setinlinepair(struct __test_metadata *_metadata,
#define epollpair(oob_remaining) \ #define epollpair(oob_remaining) \
__epollpair(_metadata, self, oob_remaining) __epollpair(_metadata, self, oob_remaining)
#define siocatmarkpair(oob_head) \
__siocatmarkpair(_metadata, self, oob_head)
#define setinlinepair() \ #define setinlinepair() \
__setinlinepair(_metadata, self) __setinlinepair(_metadata, self)
...@@ -325,9 +348,11 @@ TEST_F(msg_oob, oob) ...@@ -325,9 +348,11 @@ TEST_F(msg_oob, oob)
{ {
sendpair("x", 1, MSG_OOB); sendpair("x", 1, MSG_OOB);
epollpair(true); epollpair(true);
siocatmarkpair(true);
recvpair("x", 1, 1, MSG_OOB); recvpair("x", 1, 1, MSG_OOB);
epollpair(false); epollpair(false);
siocatmarkpair(true);
} }
TEST_F(msg_oob, oob_drop) TEST_F(msg_oob, oob_drop)
...@@ -481,18 +506,40 @@ TEST_F(msg_oob, ex_oob_ahead_break) ...@@ -481,18 +506,40 @@ TEST_F(msg_oob, ex_oob_ahead_break)
epollpair(false); epollpair(false);
} }
TEST_F(msg_oob, ex_oob_siocatmark)
{
sendpair("hello", 5, MSG_OOB);
epollpair(true);
siocatmarkpair(false);
recvpair("o", 1, 1, MSG_OOB);
epollpair(false);
siocatmarkpair(false);
sendpair("world", 5, MSG_OOB);
epollpair(true);
siocatmarkpair(false);
recvpair("hell", 4, 4, 0); /* Intentionally stop at ex-OOB. */
epollpair(true);
siocatmarkpair(false);
}
TEST_F(msg_oob, inline_oob) TEST_F(msg_oob, inline_oob)
{ {
setinlinepair(); setinlinepair();
sendpair("x", 1, MSG_OOB); sendpair("x", 1, MSG_OOB);
epollpair(true); epollpair(true);
siocatmarkpair(true);
recvpair("", -EINVAL, 1, MSG_OOB); recvpair("", -EINVAL, 1, MSG_OOB);
epollpair(true); epollpair(true);
siocatmarkpair(true);
recvpair("x", 1, 1, 0); recvpair("x", 1, 1, 0);
epollpair(false); epollpair(false);
siocatmarkpair(false);
} }
TEST_F(msg_oob, inline_oob_break) TEST_F(msg_oob, inline_oob_break)
...@@ -591,4 +638,25 @@ TEST_F(msg_oob, inline_ex_oob_drop) ...@@ -591,4 +638,25 @@ TEST_F(msg_oob, inline_ex_oob_drop)
} }
} }
TEST_F(msg_oob, inline_ex_oob_siocatmark)
{
sendpair("hello", 5, MSG_OOB);
epollpair(true);
siocatmarkpair(false);
recvpair("o", 1, 1, MSG_OOB);
epollpair(false);
siocatmarkpair(false);
setinlinepair();
sendpair("world", 5, MSG_OOB);
epollpair(true);
siocatmarkpair(false);
recvpair("hell", 4, 4, 0); /* Intentionally stop at ex-OOB. */
epollpair(true);
siocatmarkpair(false);
}
TEST_HARNESS_MAIN TEST_HARNESS_MAIN
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment