From patchwork Mon Nov 27 11:29:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 119674 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp117076qgn; Mon, 27 Nov 2017 03:31:35 -0800 (PST) X-Google-Smtp-Source: AGs4zMYq8HaPOu62cHcKzD2FsLLaFMW0iJ4GESUC3pBo6frzX4WMsQV/lo/2obkMxvCkz8Vyhb/q X-Received: by 10.98.75.210 with SMTP id d79mr16303605pfj.230.1511782295871; Mon, 27 Nov 2017 03:31:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511782295; cv=none; d=google.com; s=arc-20160816; b=JFE068TTRm6lXwxndXG6pt5kRSH8+Wp8vUoQkHztii6319XvFGzlCbD+nJp8Y5uvZ3 kHesgqqp8+vdNAxWQOyCOo2OINAm2tW0/kPqB7g9mJ9k+4+urZZJtqVImYRl33yYCAru gGHIYOaL2MLjFTolD/f631O7JdeE5woGkTMn+NvrJjUUI0MwZubCKgH4/aRZgbVSIbQj cmhD5Qv/2jJ2k/PdmJJ5NKQfNHYriVgoe6DDU3VPi/jgjNAEoKgPhGbh8THPxsnKTo7S iuVlRUPeLu3c0Lfhe1Iiuu5P1JXxSejugSHqtEKn29C7WRsiw72WVGB38ARIHz4f8f1t kWXg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=qf1U5hEGCYEkTgZDFdHVt1lwtiduLb+fIfuL0xRhLLo=; b=cRpjSPwS3u0j53xoYbmMMGRELAen3YLIGjZHD5NxE28k0ic0yzSMBoXiTgnf5kPpM1 PNY3LJ2UvZVIrVc20RxlrxnnsN76GGJ3Mi2vWQylxKLADuwtbebZJjtfdLbFu1PRRvwo oXEhDOyGvtq13diJq8LQltZZuNZzBVID7rOrznoCdwiM1yYcNVO5PxDhjdc23Drab0ZW p7CoEshCbx/abppQxUd+g4v3noBDV8X9smh8pMigNpFgEJSbPFfVzz9ufehBfwlsL40A GHItm2yUQwHYaB6eQVc4+yO0nXCfgr4hmkBwF5wu3fQwlg6IJVFc1m1weacrtNm1D+y/ frkA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q15si25033354pfl.112.2017.11.27.03.31.35; Mon, 27 Nov 2017 03:31:35 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751706AbdK0Lbd (ORCPT + 28 others); Mon, 27 Nov 2017 06:31:33 -0500 Received: from mout.kundenserver.de ([217.72.192.73]:64798 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751350AbdK0Lbb (ORCPT ); Mon, 27 Nov 2017 06:31:31 -0500 Received: from wuerfel.lan ([109.193.157.232]) by mrelayeu.kundenserver.de (mreue101 [212.227.15.145]) with ESMTPA (Nemesis) id 0MYekE-1eebot1wVG-00VMbO; Mon, 27 Nov 2017 12:31:01 +0100 From: Arnd Bergmann To: Greg Kroah-Hartman Cc: y2038@lists.linaro.org, linux-api@vger.kernel.org, Arnd Bergmann , Bamvor Jian Zhang , Willy Tarreau , Thomas Gleixner , linux-kernel@vger.kernel.org Subject: [PATCH] lp: support 64-bit time_t user space Date: Mon, 27 Nov 2017 12:29:50 +0100 Message-Id: <20171127113058.2140606-1-arnd@arndb.de> X-Mailer: git-send-email 2.9.0 X-Provags-ID: V03:K0:xuww0wKc6wrk5OLKlKCXjsyVFiTRB88/+GmxSwzalY9WUaEya18 4t1ruPxE0VMB3F2cC8S9M4q9b74tZaxhsSgbpM2/jZHEw9Qvqu76sPgk/VNKeNbDOPqOo2+ cSmVShGbhNm4RiZHxpppz3oFnFzjOQ9JmXjaX4oVBgZemVj9/hubieCfKDR6SB2lXEJlXme 3j+UWWejcWp+lMxs+zduw== X-UI-Out-Filterresults: notjunk:1; V01:K0:O57h+keLG9c=:WH012Q64Sh7mGkwprYK40T CMKqbYYJHI0XIMpI683gcA/XjEN4vD/BuTYu3WtuEKqnHi4LDZLwHd+0R7yp7crs7oXPqLT7A 95O0gjXX/rnbemffNk527px5WBDn6sKoOhgqz+6qkmG/XEMT/bn6W+fv4TJ9Pci3ABrsKu/hQ HtS2SnGerQnRYrTwTYKNfjfmtYTdTM2HOpoT+Lre49LI4iz9Bhc/MAIHBN27pJ0CZoTPd7GQX TrC6CGNlGAFGZbiQsxprLHhmIqdcAPIgjmMERTUGWoVFcA726m0KXK5sEQuir3s3iJRQOs9fj HTADxdApdC6IqYGqMzmwxofQk1mJxGy2zAfAUmKp7C+GEIREWSmQPREDONa0g0WRhRbI9k+pt rHQK5l7+DURveb0NW82OfiDh64ON6X/dG9oyd58URUqBVs65LDHZ3JmmxhDASWMzNfiZ5NyAO 3izp4RBsS3zUUGp2R/U7A5Y9e66MH2eAHLgbzprFTLRi+LcbCQSHWW0V3JHHPUdPQKB0qsfYT mOx2ot6dXcbn4ucgSIJPonQIBsZHQiY4+nYqA0vpQjDX0B8ampY/l/hur8nFRut64phFIVvNt RNXNocdI6ZaApcOxWpZhaxLKPw+dFYQpoVRYE33DwjiB7NZeD+EqX1fWpj9/Lqj4uhPnze3ZN 8Fvz83soU0Iabn0ASnDTr0v37BsMxW+bc6z3bez24qRF3Adh4dj7FQWQeV7/yzW5sRfc+3a8t 2BELsgMUAI5ai2z0jpErU5ifhiPTqDmnDAYmzQ== Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Once we get a glibc with 64-bit time_t, the LPSETTIMEOUT ioctl stops working, since the command number and data structure no longer match. To work around that, this introduces a new command number LPSETTIMEOUT_NEW that is used whenever the modified user space evaluates the LPSETTIMEOUT macro. The trick we use is a bit convoluted but necessary: we cannot check for any macros set by the C library in linux/lp.h, because this particular header can be included before including sys/time.h. However, we can assume that by the time that LPSETTIMEOUT is seen in the code, the definition for 'timeval' and 'time_t' has been seen as well, so we can use the sizeof() operator to determine whether we should use the old or the new definition. We use the old one not only for traditional 32-bit user space with 32-bit time_t, but also for all 64-bit architectures and x32, which always use a 64-bit time_t, the new definition will be used only for 32-bit user space with 64-bit time_t, which also requires a newer kernel. The compat_ioctl() handler now implements both commands, but has to use a special case for existing x32 binaries. The native ioctl handler now implements both command numbers on both 32-bit and 64-bit, though the latter version use the same interpretation for both. This is based on an earlier patch from Bamvor. Cc: Bamvor Jian Zhang Link: http://www.spinics.net/lists/y2038/msg01162.html Signed-off-by: Arnd Bergmann --- drivers/char/lp.c | 67 +++++++++++++++++++++++++++++++++++++------------ include/uapi/linux/lp.h | 12 ++++++++- 2 files changed, 62 insertions(+), 17 deletions(-) -- 2.9.0 diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 8249762192d5..be14abf70da1 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -659,17 +659,31 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd, return retval; } -static int lp_set_timeout(unsigned int minor, struct timeval *par_timeout) +static int lp_set_timeout(unsigned int minor, s64 tv_sec, long tv_usec) { long to_jiffies; /* Convert to jiffies, place in lp_table */ - if ((par_timeout->tv_sec < 0) || - (par_timeout->tv_usec < 0)) { + if (tv_sec < 0 || tv_usec < 0) return -EINVAL; + + /* + * we used to not check, so let's not make this fatal, + * but deal with user space passing a 32-bit tv_nsec in + * a 64-bit field, capping the timeout to 1 second + * worth of microseconds, and capping the total at + * MAX_JIFFY_OFFSET. + */ + if (tv_usec > 999999) + tv_usec = 999999; + + if (tv_sec >= MAX_SEC_IN_JIFFIES - 1) { + to_jiffies = MAX_JIFFY_OFFSET; + } else { + to_jiffies = DIV_ROUND_UP(tv_usec, 1000000/HZ); + to_jiffies += tv_sec * (long) HZ; } - to_jiffies = DIV_ROUND_UP(par_timeout->tv_usec, 1000000/HZ); - to_jiffies += par_timeout->tv_sec * (long) HZ; + if (to_jiffies <= 0) { return -EINVAL; } @@ -677,23 +691,43 @@ static int lp_set_timeout(unsigned int minor, struct timeval *par_timeout) return 0; } +static int lp_set_timeout32(unsigned int minor, void __user *arg) +{ + s32 karg[2]; + + if (copy_from_user(karg, arg, sizeof(karg))) + return -EFAULT; + + return lp_set_timeout(minor, karg[0], karg[1]); +} + +static int lp_set_timeout64(unsigned int minor, void __user *arg) +{ + s64 karg[2]; + + if (copy_from_user(karg, arg, sizeof(karg))) + return -EFAULT; + + return lp_set_timeout(minor, karg[0], karg[1]); +} + static long lp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor; - struct timeval par_timeout; int ret; minor = iminor(file_inode(file)); mutex_lock(&lp_mutex); switch (cmd) { - case LPSETTIMEOUT: - if (copy_from_user(&par_timeout, (void __user *)arg, - sizeof (struct timeval))) { - ret = -EFAULT; + case LPSETTIMEOUT_OLD: + if (BITS_PER_LONG == 32) { + ret = lp_set_timeout32(minor, (void __user *)arg); break; } - ret = lp_set_timeout(minor, &par_timeout); + /* fallthrough for 64-bit */ + case LPSETTIMEOUT_NEW: + ret = lp_set_timeout64(minor, (void __user *)arg); break; default: ret = lp_do_ioctl(minor, cmd, arg, (void __user *)arg); @@ -709,18 +743,19 @@ static long lp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor; - struct timeval par_timeout; int ret; minor = iminor(file_inode(file)); mutex_lock(&lp_mutex); switch (cmd) { - case LPSETTIMEOUT: - if (compat_get_timeval(&par_timeout, compat_ptr(arg))) { - ret = -EFAULT; + case LPSETTIMEOUT_OLD: + if (!COMPAT_USE_64BIT_TIME) { + ret = lp_set_timeout32(minor, (void __user *)arg); break; } - ret = lp_set_timeout(minor, &par_timeout); + /* fallthrough for x32 mode */ + case LPSETTIMEOUT_NEW: + ret = lp_set_timeout64(minor, (void __user *)arg); break; #ifdef LP_STATS case LPGETSTATS: diff --git a/include/uapi/linux/lp.h b/include/uapi/linux/lp.h index dafcfe4e4834..8589a27037d7 100644 --- a/include/uapi/linux/lp.h +++ b/include/uapi/linux/lp.h @@ -8,6 +8,8 @@ #ifndef _UAPI_LINUX_LP_H #define _UAPI_LINUX_LP_H +#include +#include /* * Per POSIX guidelines, this module reserves the LP and lp prefixes @@ -88,7 +90,15 @@ #define LPGETSTATS 0x060d /* get statistics (struct lp_stats) */ #endif #define LPGETFLAGS 0x060e /* get status flags */ -#define LPSETTIMEOUT 0x060f /* set parport timeout */ +#define LPSETTIMEOUT_OLD 0x060f /* set parport timeout */ +#define LPSETTIMEOUT_NEW \ + _IOW(0x6, 0xf, __s64[2]) /* set parport timeout */ +#if __BITS_PER_LONG == 64 +#define LPSETTIMEOUT LPSETTIMEOUT_OLD +#else +#define LPSETTIMEOUT (sizeof(time_t) > sizeof(__kernel_long_t) ? \ + LPSETTIMEOUT_NEW : LPSETTIMEOUT_OLD) +#endif /* timeout for printk'ing a timeout, in jiffies (100ths of a second). This is also used for re-checking error conditions if LP_ABORT is