#include #include #include #include #include #include #include "sock.h" #include "die.h" #include "str.h" #include "linktype.h" #include "built_in.h" #include "sysctl.h" int af_socket(int af) { int sock; if (unlikely(af != AF_INET && af != AF_INET6)) panic("Wrong AF socket type!\n"); sock = socket(af, SOCK_DGRAM, 0); if (unlikely(sock < 0)) panic("Creation AF socket failed: %s\n", strerror(errno)); return sock; } int pf_socket(void) { int sock = socket(PF_PACKET, SOCK_RAW, 0); if (unlikely(sock < 0)) panic("Creation of PF socket failed: %s\n", strerror(errno)); return sock; } static int pf_socket_dgram(void) { int sock = socket(PF_PACKET, SOCK_DGRAM, 0); if (unlikely(sock < 0)) panic("Creation of PF dgram socket failed: %s\n", strerror(errno)); return sock; } int pf_socket_type(uint32_t type) { switch (type) { case LINKTYPE_LINUX_SLL: return pf_socket_dgram(); default: return pf_socket(); } } /* Available in kernel >= 3.14 * in commit d346a3fae3 (packet: introduce PACKET_QDISC_BYPASS socket option) */ void set_sock_qdisc_bypass(int fd, bool verbose) { int ret, val = 1; ret = setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &val, sizeof(val)); if (ret < 0) { if (errno == ENOPROTOOPT) { if (verbose) printf("No kernel support for PACKET_QDISC_BYPASS" " (kernel < 3.14?)\n"); } else perror("Cannot set PACKET_QDISC_BYPASS"); } else if (verbose) printf("Enabled kernel qdisc bypass\n"); } void set_sock_prio(int fd, int prio) { int ret, val = prio; ret = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &val, sizeof(val)); if (unlikely(ret)) panic("Cannot set socket priority: %s\n", strerror(errno)); } void set_nonblocking(int fd) { int ret = fcntl(fd, F_SETFL, fcntl(fd, F_GETFD, 0) | O_NONBLOCK); if (unlikely(ret < 0)) panic("Cannot fcntl: %s\n", strerror(errno)); } int set_nonblocking_sloppy(int fd) { return fcntl(fd, F_SETFL, fcntl(fd, F_GETFD, 0) | O_NONBLOCK); } void set_socket_keepalive(int fd) { int ret, one = 1; ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)); if (unlikely(ret)) panic("Cannot set TCP keepalive: %s\n", strerror(errno)); } void set_tcp_nodelay(int fd) { int ret, one = 1; ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); if (unlikely(ret)) panic("Cannot set TCP nodelay: %s\n", strerror(errno)); } int set_ipv6_only(int fd) { int one = 1; return setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); } int set_reuseaddr(int fd) { int ret, one = 1; ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); if (unlikely(ret < 0)) panic("Cannot reuse addr: %s\n", strerror(errno)); return 0; } void set_mtu_disc_dont(int fd) { int mtu = IP_PMTUDISC_DONT, ret; ret = setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)); if (unlikely(ret)) panic("Cannot set MTU discovery options: %s\n", strerror(errno)); } enum { sock_rmem_max = 0, sock_rmem_def, sock_wmem_max, sock_wmem_def, }; #define SMEM_SUG_MAX 104857600 #define SMEM_SUG_DEF 4194304 static const char *const sock_mem[] = { [sock_rmem_max] = "net/core/rmem_max", [sock_rmem_def] = "net/core/rmem_default", [sock_wmem_max] = "net/core/wmem_max", [sock_wmem_def] = "net/core/wmem_default", }; static int get_system_socket_mem(int which) { int val; if (sysctl_get_int(sock_mem[which], &val)) return -1; return val; } static void set_system_socket_mem(int which, int val) { if (val > 0 && sysctl_set_int(sock_mem[which], val)) printf("Cannot set system socket memory in %s%s: %s\n", SYSCTL_PROC_PATH, sock_mem[which], strerror(errno)); } void set_system_socket_memory(int *vals, size_t len) { bug_on(len != 4); if ((vals[0] = get_system_socket_mem(sock_rmem_max)) < SMEM_SUG_MAX) set_system_socket_mem(sock_rmem_max, SMEM_SUG_MAX); if ((vals[1] = get_system_socket_mem(sock_rmem_def)) < SMEM_SUG_DEF) set_system_socket_mem(sock_rmem_def, SMEM_SUG_DEF); if ((vals[2] = get_system_socket_mem(sock_wmem_max)) < SMEM_SUG_MAX) set_system_socket_mem(sock_wmem_max, SMEM_SUG_MAX); if ((vals[3] = get_system_socket_mem(sock_wmem_def)) < SMEM_SUG_DEF) set_system_socket_mem(sock_wmem_def, SMEM_SUG_DEF); } void reset_system_socket_memory(int *vals, size_t len) { bug_on(len != 4); set_system_socket_mem(sock_rmem_max, vals[0]); set_system_socket_mem(sock_rmem_def, vals[1]); set_system_socket_mem(sock_wmem_max, vals[2]); set_system_socket_mem(sock_wmem_def, vals[3]); } lected'>includemode:
authorRalf Baechle <ralf@linux-mips.org>2016-07-01 15:01:01 +0200
committerRalf Baechle <ralf@linux-mips.org>2016-07-02 01:51:39 +0200
commit6d037de90a1fd7b4879b48d4dd5c4839b271be98 (patch)
tree38f96bf562d55edd65891d06aa3379c551dd6b5f /Documentation/input/gamepad.txt
parent4c2e07c6a29e0129e975727b9f57eede813eea85 (diff)
MIPS: Fix possible corruption of cache mode by mprotect.
The following testcase may result in a page table entries with a invalid CCA field being generated: static void *bindstack; static int sysrqfd; static void protect_low(int protect) { mprotect(bindstack, BINDSTACK_SIZE, protect); } static void sigbus_handler(int signal, siginfo_t * info, void *context) { void *addr = info->si_addr; write(sysrqfd, "x", 1); printf("sigbus, fault address %p (should not happen, but might)\n", addr); abort(); } static void run_bind_test(void) { unsigned int *p = bindstack; p[0] = 0xf001f001; write(sysrqfd, "x", 1); /* Set trap on access to p[0] */ protect_low(PROT_NONE); write(sysrqfd, "x", 1); /* Clear trap on access to p[0] */ protect_low(PROT_READ | PROT_WRITE | PROT_EXEC); write(sysrqfd, "x", 1); /* Check the contents of p[0] */ if (p[0] != 0xf001f001) { write(sysrqfd, "x", 1); /* Reached, but shouldn't be */ printf("badness, shouldn't happen but does\n"); abort(); } } int main(void) { struct sigaction sa; sysrqfd = open("/proc/sysrq-trigger", O_WRONLY); if (sigprocmask(SIG_BLOCK, NULL, &sa.sa_mask)) { perror("sigprocmask"); return 0; } sa.sa_sigaction = sigbus_handler; sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_RESTART; if (sigaction(SIGBUS, &sa, NULL)) { perror("sigaction"); return 0; } bindstack = mmap(NULL, BINDSTACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (bindstack == MAP_FAILED) { perror("mmap bindstack"); return 0; } printf("bindstack: %p\n", bindstack); run_bind_test(); printf("done\n"); return 0; } There are multiple ingredients for this: 1) PAGE_NONE is defined to _CACHE_CACHABLE_NONCOHERENT, which is CCA 3 on all platforms except SB1 where it's CCA 5. 2) _page_cachable_default must have bits set which are not set _CACHE_CACHABLE_NONCOHERENT. 3) Either the defective version of pte_modify for XPA or the standard version must be in used. However pte_modify for the 36 bit address space support is no affected. In that case additional bits in the final CCA mode may generate an invalid value for the CCA field. On the R10000 system where this was tracked down for example a CCA 7 has been observed, which is Uncached Accelerated. Fixed by: 1) Using the proper CCA mode for PAGE_NONE just like for all the other PAGE_* pte/pmd bits. 2) Fix the two affected variants of pte_modify. Further code inspection also shows the same issue to exist in pmd_modify which would affect huge page systems. Issue in pte_modify tracked down by Alastair Bridgewater, PAGE_NONE and pmd_modify issue found by me. The history of this goes back beyond Linus' git history. Chris Dearman's commit 351336929ccf222ae38ff0cb7a8dd5fd5c6236a0 ("[MIPS] Allow setting of the cache attribute at run time.") missed the opportunity to fix this but it was originally introduced in lmo commit d523832cf12007b3242e50bb77d0c9e63e0b6518 ("Missing from last commit.") and 32cc38229ac7538f2346918a09e75413e8861f87 ("New configuration option CONFIG_MIPS_UNCACHED.") Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Reported-by: Alastair Bridgewater <alastair.bridgewater@gmail.com>
Diffstat (limited to 'Documentation/input/gamepad.txt')