Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 314001f0bf92 ("af_unix: Add OOB support")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Kuniyuki Iwashima and committed by
Paolo Abeni
e400cfa3 48a99837

+81 -2
+13 -2
net/unix/af_unix.c
··· 3107 3107 #if IS_ENABLED(CONFIG_AF_UNIX_OOB) 3108 3108 case SIOCATMARK: 3109 3109 { 3110 + struct unix_sock *u = unix_sk(sk); 3110 3111 struct sk_buff *skb; 3111 3112 int answ = 0; 3112 3113 3114 + mutex_lock(&u->iolock); 3115 + 3113 3116 skb = skb_peek(&sk->sk_receive_queue); 3114 - if (skb && skb == READ_ONCE(unix_sk(sk)->oob_skb)) 3115 - answ = 1; 3117 + if (skb) { 3118 + struct sk_buff *oob_skb = READ_ONCE(u->oob_skb); 3119 + 3120 + if (skb == oob_skb || 3121 + (!oob_skb && !unix_skb_len(skb))) 3122 + answ = 1; 3123 + } 3124 + 3125 + mutex_unlock(&u->iolock); 3126 + 3116 3127 err = put_user(answ, (int __user *)arg); 3117 3128 } 3118 3129 break;
+68
tools/testing/selftests/net/af_unix/msg_oob.c
··· 288 288 } 289 289 } 290 290 291 + static void __siocatmarkpair(struct __test_metadata *_metadata, 292 + FIXTURE_DATA(msg_oob) *self, 293 + bool oob_head) 294 + { 295 + int answ[2] = {}; 296 + int i; 297 + 298 + for (i = 0; i < 2; i++) { 299 + int ret; 300 + 301 + ret = ioctl(self->fd[i * 2 + 1], SIOCATMARK, &answ[i]); 302 + ASSERT_EQ(ret, 0); 303 + } 304 + 305 + ASSERT_EQ(answ[0], oob_head); 306 + 307 + if (self->tcp_compliant) 308 + ASSERT_EQ(answ[0], answ[1]); 309 + } 310 + 291 311 #define sendpair(buf, len, flags) \ 292 312 __sendpair(_metadata, self, buf, len, flags) 293 313 ··· 323 303 324 304 #define epollpair(oob_remaining) \ 325 305 __epollpair(_metadata, self, oob_remaining) 306 + 307 + #define siocatmarkpair(oob_head) \ 308 + __siocatmarkpair(_metadata, self, oob_head) 326 309 327 310 #define setinlinepair() \ 328 311 __setinlinepair(_metadata, self) ··· 348 325 { 349 326 sendpair("x", 1, MSG_OOB); 350 327 epollpair(true); 328 + siocatmarkpair(true); 351 329 352 330 recvpair("x", 1, 1, MSG_OOB); 353 331 epollpair(false); 332 + siocatmarkpair(true); 354 333 } 355 334 356 335 TEST_F(msg_oob, oob_drop) ··· 506 481 epollpair(false); 507 482 } 508 483 484 + TEST_F(msg_oob, ex_oob_siocatmark) 485 + { 486 + sendpair("hello", 5, MSG_OOB); 487 + epollpair(true); 488 + siocatmarkpair(false); 489 + 490 + recvpair("o", 1, 1, MSG_OOB); 491 + epollpair(false); 492 + siocatmarkpair(false); 493 + 494 + sendpair("world", 5, MSG_OOB); 495 + epollpair(true); 496 + siocatmarkpair(false); 497 + 498 + recvpair("hell", 4, 4, 0); /* Intentionally stop at ex-OOB. */ 499 + epollpair(true); 500 + siocatmarkpair(false); 501 + } 502 + 509 503 TEST_F(msg_oob, inline_oob) 510 504 { 511 505 setinlinepair(); 512 506 513 507 sendpair("x", 1, MSG_OOB); 514 508 epollpair(true); 509 + siocatmarkpair(true); 515 510 516 511 recvpair("", -EINVAL, 1, MSG_OOB); 517 512 epollpair(true); 513 + siocatmarkpair(true); 518 514 519 515 recvpair("x", 1, 1, 0); 520 516 epollpair(false); 517 + siocatmarkpair(false); 521 518 } 522 519 523 520 TEST_F(msg_oob, inline_oob_break) ··· 636 589 recvpair("y", 1, 1, 0); /* TCP returns -EAGAIN. */ 637 590 epollpair(false); 638 591 } 592 + } 593 + 594 + TEST_F(msg_oob, inline_ex_oob_siocatmark) 595 + { 596 + sendpair("hello", 5, MSG_OOB); 597 + epollpair(true); 598 + siocatmarkpair(false); 599 + 600 + recvpair("o", 1, 1, MSG_OOB); 601 + epollpair(false); 602 + siocatmarkpair(false); 603 + 604 + setinlinepair(); 605 + 606 + sendpair("world", 5, MSG_OOB); 607 + epollpair(true); 608 + siocatmarkpair(false); 609 + 610 + recvpair("hell", 4, 4, 0); /* Intentionally stop at ex-OOB. */ 611 + epollpair(true); 612 + siocatmarkpair(false); 639 613 } 640 614 641 615 TEST_HARNESS_MAIN