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

ipv4: avoid undefined behavior in do_ip_setsockopt()

(1<<optname) is undefined behavior in C with a negative optname or
optname larger than 31. In those cases the result of the shift is
not necessarily zero (e.g., on x86).

This patch simplifies the code with a switch statement on optname.
It also allows the compiler to generate better code (e.g., using a
64-bit mask).

Signed-off-by: Xi Wang <xi.wang@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Xi Wang and committed by
David S. Miller
0c9f79be 77b67063

+22 -13
+22 -13
net/ipv4/ip_sockglue.c
··· 457 457 struct inet_sock *inet = inet_sk(sk); 458 458 int val = 0, err; 459 459 460 - if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | 461 - (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | 462 - (1<<IP_RETOPTS) | (1<<IP_TOS) | 463 - (1<<IP_TTL) | (1<<IP_HDRINCL) | 464 - (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 465 - (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | 466 - (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) | 467 - (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) || 468 - optname == IP_UNICAST_IF || 469 - optname == IP_MULTICAST_TTL || 470 - optname == IP_MULTICAST_ALL || 471 - optname == IP_MULTICAST_LOOP || 472 - optname == IP_RECVORIGDSTADDR) { 460 + switch (optname) { 461 + case IP_PKTINFO: 462 + case IP_RECVTTL: 463 + case IP_RECVOPTS: 464 + case IP_RECVTOS: 465 + case IP_RETOPTS: 466 + case IP_TOS: 467 + case IP_TTL: 468 + case IP_HDRINCL: 469 + case IP_MTU_DISCOVER: 470 + case IP_RECVERR: 471 + case IP_ROUTER_ALERT: 472 + case IP_FREEBIND: 473 + case IP_PASSSEC: 474 + case IP_TRANSPARENT: 475 + case IP_MINTTL: 476 + case IP_NODEFRAG: 477 + case IP_UNICAST_IF: 478 + case IP_MULTICAST_TTL: 479 + case IP_MULTICAST_ALL: 480 + case IP_MULTICAST_LOOP: 481 + case IP_RECVORIGDSTADDR: 473 482 if (optlen >= sizeof(int)) { 474 483 if (get_user(val, (int __user *) optval)) 475 484 return -EFAULT;