summaryrefslogtreecommitdiffstats
path: root/net/compat.c
diff options
context:
space:
mode:
authorDeepa Dinamani <deepa.kernel@gmail.com>2018-12-27 21:55:09 -0500
committerDavid S. Miller <davem@davemloft.net>2019-01-01 12:47:59 -0500
commit3a0ed3e9619738067214871e9cb826fa23b2ddb9 (patch)
treef27788a1eb07823c642631cb4d27aa0c052e3095 /net/compat.c
parent756af9c642329d54f048bac2a62f829b391f6944 (diff)
sock: Make sock->sk_stamp thread-safe
Al Viro mentioned (Message-ID <20170626041334.GZ10672@ZenIV.linux.org.uk>) that there is probably a race condition lurking in accesses of sk_stamp on 32-bit machines. sock->sk_stamp is of type ktime_t which is always an s64. On a 32 bit architecture, we might run into situations of unsafe access as the access to the field becomes non atomic. Use seqlocks for synchronization. This allows us to avoid using spinlocks for readers as readers do not need mutual exclusion. Another approach to solve this is to require sk_lock for all modifications of the timestamps. The current approach allows for timestamps to have their own lock: sk_stamp_lock. This allows for the patch to not compete with already existing critical sections, and side effects are limited to the paths in the patch. The addition of the new field maintains the data locality optimizations from commit 9115e8cd2a0c ("net: reorganize struct sock for better data locality") Note that all the instances of the sk_stamp accesses are either through the ioctl or the syscall recvmsg. Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/compat.c')
-rw-r--r--net/compat.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/net/compat.c b/net/compat.c
index 47a614b370cd..d1f3a8a0b3ef 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -467,12 +467,14 @@ int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
467 ctv = (struct compat_timeval __user *) userstamp; 467 ctv = (struct compat_timeval __user *) userstamp;
468 err = -ENOENT; 468 err = -ENOENT;
469 sock_enable_timestamp(sk, SOCK_TIMESTAMP); 469 sock_enable_timestamp(sk, SOCK_TIMESTAMP);
470 tv = ktime_to_timeval(sk->sk_stamp); 470 tv = ktime_to_timeval(sock_read_timestamp(sk));
471
471 if (tv.tv_sec == -1) 472 if (tv.tv_sec == -1)
472 return err; 473 return err;
473 if (tv.tv_sec == 0) { 474 if (tv.tv_sec == 0) {
474 sk->sk_stamp = ktime_get_real(); 475 ktime_t kt = ktime_get_real();
475 tv = ktime_to_timeval(sk->sk_stamp); 476 sock_write_timestamp(sk, kt);
477 tv = ktime_to_timeval(kt);
476 } 478 }
477 err = 0; 479 err = 0;
478 if (put_user(tv.tv_sec, &ctv->tv_sec) || 480 if (put_user(tv.tv_sec, &ctv->tv_sec) ||
@@ -494,12 +496,13 @@ int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *usersta
494 ctv = (struct compat_timespec __user *) userstamp; 496 ctv = (struct compat_timespec __user *) userstamp;
495 err = -ENOENT; 497 err = -ENOENT;
496 sock_enable_timestamp(sk, SOCK_TIMESTAMP); 498 sock_enable_timestamp(sk, SOCK_TIMESTAMP);
497 ts = ktime_to_timespec(sk->sk_stamp); 499 ts = ktime_to_timespec(sock_read_timestamp(sk));
498 if (ts.tv_sec == -1) 500 if (ts.tv_sec == -1)
499 return err; 501 return err;
500 if (ts.tv_sec == 0) { 502 if (ts.tv_sec == 0) {
501 sk->sk_stamp = ktime_get_real(); 503 ktime_t kt = ktime_get_real();
502 ts = ktime_to_timespec(sk->sk_stamp); 504 sock_write_timestamp(sk, kt);
505 ts = ktime_to_timespec(kt);
503 } 506 }
504 err = 0; 507 err = 0;
505 if (put_user(ts.tv_sec, &ctv->tv_sec) || 508 if (put_user(ts.tv_sec, &ctv->tv_sec) ||