From patchwork Tue Apr 24 12:06:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 134069 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp2150993lji; Tue, 24 Apr 2018 05:07:53 -0700 (PDT) X-Google-Smtp-Source: AB8JxZo5DlCGbX7QvPew9ILtbUl3XMYppOl5+K61Is0zIz7k3vizrtllU17+GfbnYnpM9Q2/uUnx X-Received: by 2002:a17:902:b90c:: with SMTP id bf12-v6mr3325232plb.37.1524571673735; Tue, 24 Apr 2018 05:07:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524571673; cv=none; d=google.com; s=arc-20160816; b=KFIowtan+2exq/0vA1OjXl/TqmLN7X0Mx//7VdU1LlaY2VbhS046pwHWXSs84dTyOF q6ObUNn8iiG2EdgvpgucV52Yh6zI79UVByc2VfvxP/DejkGQKIRZKKSBGhY5soN8nhrh 9DPh1Ikk7tsN0O9rDVok0l97oiTaYL77v1jqn2E6wXJG6mfDHJFBviUydQchFsFHHeyF Wiu2U7Y0pFQGueG6PoFUx+/MpkM6BfkfTSWe2gIi169u/jukYob+uNfFl6pIxwSxZsVX mmI0tStpK/3X227/SdaSazh79Re5PUs8cWohbfGTs+hR8MxAUSVG8Uynx60eej6SxgNa G9Gw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=OCmcHsSbvhGshM6zLlIP6iy81qjhmrSbYVIsx/7mHWc=; b=jp3JPbUpUK+FTsH7IDTQdTtPpihkZIphY3gkNQqWsRlmC8M/PMhz2GaNEVvpeFOKWk HZR9ivuQQHGN6SGW/dy5sMw7wgSP6INE1vmDXdco2i9G5KHSMlv/hKrcSu30MOgqybUh OpVU3npKLTNERXJHmXc5Byfl85j5SgSe2ki2OPCM98vYRFwUx/db8IWbNHzeOgIaxsgU 7VgOGIy94BCAJtbSesCI5FOqCFNepQenGFvB/bew4cmqcf9WWHbmRS5U23jNejhwkZdC zzixXMwVC15cgaUx28NOQFPvwuLU3TAe6r3zGShgz7Ontb1gj9kuZiB9OJifHRrh5pnJ Qr6w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=HwxU8pFg; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 68si11746716pgd.511.2018.04.24.05.07.53; Tue, 24 Apr 2018 05:07:53 -0700 (PDT) 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; dkim=pass header.i=@linaro.org header.s=google header.b=HwxU8pFg; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757022AbeDXMHu (ORCPT + 29 others); Tue, 24 Apr 2018 08:07:50 -0400 Received: from mail-pf0-f194.google.com ([209.85.192.194]:43570 "EHLO mail-pf0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756101AbeDXMHo (ORCPT ); Tue, 24 Apr 2018 08:07:44 -0400 Received: by mail-pf0-f194.google.com with SMTP id j11so12081421pff.10 for ; Tue, 24 Apr 2018 05:07:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=OCmcHsSbvhGshM6zLlIP6iy81qjhmrSbYVIsx/7mHWc=; b=HwxU8pFgqbCfJEXG9Pz7eS6Rg7dAM6tJlFjT0SNeNXQnKtSl4Vn2HMhftTbBKp28GQ zTtQGV0xm6eYI8/mpqHofc7LxHt9QtS0Amp4ztB44cNxAf7JUmuVqDYnuR7bxNFwUZjv bD7eLBZQRElClrmZ2XNA/41lZQKxiZI8uTuOI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=OCmcHsSbvhGshM6zLlIP6iy81qjhmrSbYVIsx/7mHWc=; b=NHGpDONLEkEAi9BEI2ptBnQ4p1BomYn5jEYu/AY3dBk6IHCSe0SCKVE4fZEWHuKoH3 D5wT2k16fIu7apnXY2pP03Q0oYMJJG8tMrAlAtz3RWEkfYJaXvKmKbRTSX2BUYvgL1ui 4Ic1SpMtS49S7gpSNy13otKS5dUB3j4Lhn3BbJpK7AN5aqIJgHFKb+hVha0fClWTxU/v lare5WH+Rer5gCMEM7Kge9PjrWCi5ym/fzsK4FqdsNiqTavezOV9QxLCmML6ZmWiHp2K 20ZNK6MPZvjcSUSnwagvJeWCLfV3MlAwV/psBNbq8EU93+RekuFIbxrqmAGOQ9z5vIgy KNrA== X-Gm-Message-State: ALQs6tBkt6YgJk9vznPwjlrVqjqStcWC6sFDFxrkkRtyocELD5QHrLFj IypX3j3AXHluiaBbVA48JSU+Ew== X-Received: by 2002:a17:902:d807:: with SMTP id a7-v6mr25503985plz.314.1524571664109; Tue, 24 Apr 2018 05:07:44 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([117.18.48.82]) by smtp.gmail.com with ESMTPSA id c7sm46350567pfg.81.2018.04.24.05.07.39 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 24 Apr 2018 05:07:43 -0700 (PDT) From: Baolin Wang To: perex@perex.cz, tiwai@suse.com, arnd@arndb.de Cc: baolin.wang@linaro.org, lgirdwood@gmail.com, broonie@kernel.org, o-takashi@sakamocchi.jp, mingo@kernel.org, elfring@users.sourceforge.net, dan.carpenter@oracle.com, jeeja.kp@intel.com, vinod.koul@intel.com, guneshwor.o.singh@intel.com, subhransu.s.prusty@intel.com, bhumirks@gmail.com, gudishax.kranthikumar@intel.com, naveen.m@intel.com, hardik.t.shah@intel.com, arvind.yadav.cs@gmail.com, fabf@skynet.be, alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org Subject: [PATCH 6/8] ALSA: Avoid using timespec for struct snd_timer_tread Date: Tue, 24 Apr 2018 20:06:13 +0800 Message-Id: X-Mailer: git-send-email 1.7.9.5 In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The struct snd_timer_tread will use 'timespec' type variables to record timestamp, which is not year 2038 safe on 32bits system. Since the struct snd_timer_tread is passed through read() rather than ioctl(), and the read syscall has no command number that lets us pick between the 32-bit or 64-bit version of this structure. Thus we introduced one new command SNDRV_TIMER_IOCTL_TREAD64 and new struct snd_timer_tread64 replacing timespec with s64 type to handle 64bit time_t. That means we will set tu->tread = TREAD_FORMAT_64BIT when user space has a 64bit time_t, then we will copy to user with struct snd_timer_tread64. Otherwise we will use 32bit time_t variables when copying to user. Moreover this patch replaces timespec type with timespec64 type and related y2038 safe APIs. Signed-off-by: Baolin Wang --- include/uapi/sound/asound.h | 13 +++- sound/core/timer.c | 144 ++++++++++++++++++++++++++++++++----------- sound/core/timer_compat.c | 2 +- 3 files changed, 121 insertions(+), 38 deletions(-) -- 1.7.9.5 diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index fad66ad..f368e80 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -773,7 +773,7 @@ struct snd_timer_status { #define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) #define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) -#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) #define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) #define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) #define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) @@ -786,6 +786,15 @@ struct snd_timer_status { #define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) #define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) #define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) +#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) + +#if __BITS_PER_LONG == 64 +#define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD +#else +#define SNDRV_TIMER_IOCTL_TREAD ((sizeof(__kernel_long_t) >= sizeof(time_t)) ? \ + SNDRV_TIMER_IOCTL_TREAD_OLD : \ + SNDRV_TIMER_IOCTL_TREAD64) +#endif struct snd_timer_read { unsigned int resolution; @@ -813,8 +822,10 @@ enum { struct snd_timer_tread { int event; + __u8 pad1[sizeof(time_t) - sizeof(int)]; struct timespec tstamp; unsigned int val; + __u8 pad2[sizeof(time_t) - sizeof(unsigned int)]; }; /**************************************************************************** diff --git a/sound/core/timer.c b/sound/core/timer.c index c9d7ddb..729a643 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -58,6 +58,21 @@ MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER); MODULE_ALIAS("devname:snd/timer"); +enum timer_tread_format { + TREAD_FORMAT_NONE = 0, + TREAD_FORMAT_TIME64, + TREAD_FORMAT_TIME32, +}; + +struct snd_timer_tread64 { + int event; + u8 pad1[sizeof(time_t) - sizeof(int)]; + s64 tstamp_sec; + s64 tstamp_nsec; + unsigned int val; + u32 pad2; +}; + struct snd_timer_user { struct snd_timer_instance *timeri; int tread; /* enhanced read with timestamps and events */ @@ -69,7 +84,7 @@ struct snd_timer_user { int queue_size; bool disconnected; struct snd_timer_read *queue; - struct snd_timer_tread *tqueue; + struct snd_timer_tread64 *tqueue; spinlock_t qlock; unsigned long last_resolution; unsigned int filter; @@ -1306,7 +1321,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri, } static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu, - struct snd_timer_tread *tread) + struct snd_timer_tread64 *tread) { if (tu->qused >= tu->queue_size) { tu->overrun++; @@ -1323,7 +1338,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, unsigned long resolution) { struct snd_timer_user *tu = timeri->callback_data; - struct snd_timer_tread r1; + struct snd_timer_tread64 r1; unsigned long flags; if (event >= SNDRV_TIMER_EVENT_START && @@ -1333,7 +1348,8 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, return; memset(&r1, 0, sizeof(r1)); r1.event = event; - r1.tstamp = timespec64_to_timespec(*tstamp); + r1.tstamp_sec = tstamp->tv_sec; + r1.tstamp_nsec = tstamp->tv_nsec; r1.val = resolution; spin_lock_irqsave(&tu->qlock, flags); snd_timer_user_append_to_tqueue(tu, &r1); @@ -1355,7 +1371,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, unsigned long ticks) { struct snd_timer_user *tu = timeri->callback_data; - struct snd_timer_tread *r, r1; + struct snd_timer_tread64 *r, r1; struct timespec64 tstamp; int prev, append = 0; @@ -1376,7 +1392,8 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { r1.event = SNDRV_TIMER_EVENT_RESOLUTION; - r1.tstamp = timespec64_to_timespec(tstamp); + r1.tstamp_sec = tstamp.tv_sec; + r1.tstamp_nsec = tstamp.tv_nsec; r1.val = resolution; snd_timer_user_append_to_tqueue(tu, &r1); tu->last_resolution = resolution; @@ -1390,14 +1407,16 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; r = &tu->tqueue[prev]; if (r->event == SNDRV_TIMER_EVENT_TICK) { - r->tstamp = timespec64_to_timespec(tstamp); + r->tstamp_sec = tstamp.tv_sec; + r->tstamp_nsec = tstamp.tv_nsec; r->val += ticks; append++; goto __wake; } } r1.event = SNDRV_TIMER_EVENT_TICK; - r1.tstamp = timespec64_to_timespec(tstamp); + r1.tstamp_sec = tstamp.tv_sec; + r1.tstamp_nsec = tstamp.tv_nsec; r1.val = ticks; snd_timer_user_append_to_tqueue(tu, &r1); append++; @@ -1412,7 +1431,7 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, static int realloc_user_queue(struct snd_timer_user *tu, int size) { struct snd_timer_read *queue = NULL; - struct snd_timer_tread *tqueue = NULL; + struct snd_timer_tread64 *tqueue = NULL; if (tu->tread) { tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); @@ -1841,11 +1860,11 @@ static int snd_timer_user_params(struct file *file, tu->qhead = tu->qtail = tu->qused = 0; if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->tread) { - struct snd_timer_tread tread; + struct snd_timer_tread64 tread; memset(&tread, 0, sizeof(tread)); tread.event = SNDRV_TIMER_EVENT_EARLY; - tread.tstamp.tv_sec = 0; - tread.tstamp.tv_nsec = 0; + tread.tstamp_sec = 0; + tread.tstamp_nsec = 0; tread.val = 0; snd_timer_user_append_to_tqueue(tu, &tread); } else { @@ -1963,6 +1982,36 @@ static int snd_timer_user_pause(struct file *file) return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; } +static int snd_timer_user_tread(void __user *argp, struct snd_timer_user *tu, + unsigned int cmd, bool compat) +{ + int __user *p = argp; + int xarg, old_tread; + + if (tu->timeri) /* too late */ + return -EBUSY; + if (get_user(xarg, p)) + return -EFAULT; + + old_tread = tu->tread; + + if (!xarg) + tu->tread = TREAD_FORMAT_NONE; + else if (cmd == SNDRV_TIMER_IOCTL_TREAD64 || + (IS_ENABLED(CONFIG_64BITS) && !compat)) + tu->tread = TREAD_FORMAT_TIME64; + else + tu->tread = TREAD_FORMAT_TIME32; + + if (tu->tread != old_tread && + realloc_user_queue(tu, tu->queue_size) < 0) { + tu->tread = old_tread; + return -ENOMEM; + } + + return 0; +} + enum { SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), @@ -1971,7 +2020,7 @@ enum { }; static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg, bool compat) { struct snd_timer_user *tu; void __user *argp = (void __user *)arg; @@ -1983,23 +2032,9 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0; case SNDRV_TIMER_IOCTL_NEXT_DEVICE: return snd_timer_user_next_device(argp); - case SNDRV_TIMER_IOCTL_TREAD: - { - int xarg, old_tread; - - if (tu->timeri) /* too late */ - return -EBUSY; - if (get_user(xarg, p)) - return -EFAULT; - old_tread = tu->tread; - tu->tread = xarg ? 1 : 0; - if (tu->tread != old_tread && - realloc_user_queue(tu, tu->queue_size) < 0) { - tu->tread = old_tread; - return -ENOMEM; - } - return 0; - } + case SNDRV_TIMER_IOCTL_TREAD_OLD: + case SNDRV_TIMER_IOCTL_TREAD64: + return snd_timer_user_tread(argp, tu, cmd, compat); case SNDRV_TIMER_IOCTL_GINFO: return snd_timer_user_ginfo(file, argp); case SNDRV_TIMER_IOCTL_GPARAMS: @@ -2039,7 +2074,7 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, long ret; mutex_lock(&tu->ioctl_lock); - ret = __snd_timer_user_ioctl(file, cmd, arg); + ret = __snd_timer_user_ioctl(file, cmd, arg, false); mutex_unlock(&tu->ioctl_lock); return ret; } @@ -2055,13 +2090,28 @@ static int snd_timer_user_fasync(int fd, struct file * file, int on) static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) { + struct snd_timer_tread64 *tread; + struct snd_timer_tread tread32; struct snd_timer_user *tu; long result = 0, unit; int qhead; int err = 0; tu = file->private_data; - unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); + switch (tu->tread) { + case TREAD_FORMAT_TIME64: + unit = sizeof(struct snd_timer_tread64); + break; + case TREAD_FORMAT_TIME32: + unit = sizeof(struct snd_timer_tread); + break; + case TREAD_FORMAT_NONE: + unit = sizeof(struct snd_timer_read); + break; + default: + return -ENOTSUPP; + } + mutex_lock(&tu->ioctl_lock); spin_lock_irq(&tu->qlock); while ((long)count - result >= unit) { @@ -2100,14 +2150,36 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, tu->qused--; spin_unlock_irq(&tu->qlock); - if (tu->tread) { - if (copy_to_user(buffer, &tu->tqueue[qhead], - sizeof(struct snd_timer_tread))) + tread = &tu->tqueue[qhead]; + + switch (tu->tread) { + case TREAD_FORMAT_TIME64: + if (copy_to_user(buffer, tread, + sizeof(struct snd_timer_tread64))) err = -EFAULT; - } else { + break; + case TREAD_FORMAT_TIME32: + memset(&tread32, 0, sizeof(tread32)); + tread32 = (struct snd_timer_tread) { + .event = tread->event, + .tstamp = { + .tv_sec = tread->tstamp_sec, + .tv_nsec = tread->tstamp_nsec, + }, + .val = tread->val, + }; + + if (copy_to_user(buffer, &tread32, sizeof(tread32))) + err = -EFAULT; + break; + case TREAD_FORMAT_NONE: if (copy_to_user(buffer, &tu->queue[qhead], sizeof(struct snd_timer_read))) err = -EFAULT; + break; + default: + err = -ENOTSUPP; + break; } spin_lock_irq(&tu->qlock); diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 0495ede..bef7f87 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -111,7 +111,7 @@ static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, case SNDRV_TIMER_IOCTL_PAUSE: case SNDRV_TIMER_IOCTL_PAUSE_OLD: case SNDRV_TIMER_IOCTL_NEXT_DEVICE: - return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp); + return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp, true); case SNDRV_TIMER_IOCTL_GPARAMS32: return snd_timer_user_gparams_compat(file, argp); case SNDRV_TIMER_IOCTL_INFO32: