mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-08 08:07:10 +02:00
[BUG] stream_sock: BUF_INFINITE_FORWARD broke splice on 64-bit platforms
Yohan Tordjman at Dstorage found that upgrading haproxy to 1.4-dev4 caused truncated objects to be returned. An strace quickly exhibited the issue which was 100% reproducible : 4297 epoll_wait(0, {}, 10, 0) = 0 4297 epoll_wait(0, {{EPOLLIN, {u32=7, u64=7}}}, 10, 1000) = 1 4297 splice(0x7, 0, 0x5, 0, 0xffffffffffffffff, 0x3) = -1 EINVAL (Invalid argument) 4297 shutdown(7, 1 /* send */) = 0 4297 close(7) = 0 4297 shutdown(2, 1 /* send */) = 0 4297 close(2) = 0 This is caused by the fact that the forward length is taken from BUF_INFINITE_FORWARD, which is -1. The problem does not appear in 32-bit mode because this value is first cast to an unsigned long, truncating it to 32-bit (4 GB). Setting an upper bound fixes the issue. Also, a second error check has been added for splice. If EINVAL is returned, we fall back to recv().
This commit is contained in:
parent
655dce90d4
commit
a9de333aa5
@ -84,6 +84,10 @@ _syscall6(int, splice, int, fdin, loff_t *, off_in, int, fdout, loff_t *, off_ou
|
|||||||
*/
|
*/
|
||||||
#define SPLICE_FULL_HINT 16*1448
|
#define SPLICE_FULL_HINT 16*1448
|
||||||
|
|
||||||
|
/* how many data we attempt to splice at once when the buffer is configured for
|
||||||
|
* infinite forwarding */
|
||||||
|
#define MAX_SPLICE_AT_ONCE (1<<30)
|
||||||
|
|
||||||
/* Returns :
|
/* Returns :
|
||||||
* -1 if splice is not possible or not possible anymore and we must switch to
|
* -1 if splice is not possible or not possible anymore and we must switch to
|
||||||
* user-land copy (eg: to_forward reached)
|
* user-land copy (eg: to_forward reached)
|
||||||
@ -138,7 +142,11 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
|
|||||||
/* At this point, b->pipe is valid */
|
/* At this point, b->pipe is valid */
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
if (b->to_forward == BUF_INFINITE_FORWARD)
|
||||||
|
max = MAX_SPLICE_AT_ONCE;
|
||||||
|
else
|
||||||
max = b->to_forward;
|
max = b->to_forward;
|
||||||
|
|
||||||
if (!max) {
|
if (!max) {
|
||||||
/* It looks like the buffer + the pipe already contain
|
/* It looks like the buffer + the pipe already contain
|
||||||
* the maximum amount of data to be transferred. Try to
|
* the maximum amount of data to be transferred. Try to
|
||||||
@ -188,7 +196,7 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errno == ENOSYS) {
|
if (errno == ENOSYS || errno == EINVAL) {
|
||||||
/* splice not supported on this end, disable it */
|
/* splice not supported on this end, disable it */
|
||||||
b->flags &= ~BF_KERN_SPLICING;
|
b->flags &= ~BF_KERN_SPLICING;
|
||||||
si->flags &= ~SI_FL_CAP_SPLICE;
|
si->flags &= ~SI_FL_CAP_SPLICE;
|
||||||
|
Loading…
Reference in New Issue
Block a user