qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a)
@ 2009-04-21  8:24 Arnaud Patard
  2009-04-21  8:36 ` Laurent Desnogues
  2009-04-21 12:34 ` Riku Voipio
  0 siblings, 2 replies; 7+ messages in thread
From: Arnaud Patard @ 2009-04-21  8:24 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 369 bytes --]



Don't use the glibc function for utimensat because glibc returns -EINVAL
if the path is null which is a different behaviour with the syscall.
path can be null because internally the glibc is using utimensat with
path null (for instance, see __futimes in
sysdeps/unix/sysv/linux/futimes.c in glibc tree).


Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>
---

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: utimensat.patch --]
[-- Type: text/x-diff, Size: 1025 bytes --]

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b6dc6cc..6959da0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -412,13 +412,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags)
   return (unlinkat(dirfd, pathname, flags));
 }
 #endif
-#ifdef TARGET_NR_utimensat
-static int sys_utimensat(int dirfd, const char *pathname,
-    const struct timespec times[2], int flags)
-{
-  return (utimensat(dirfd, pathname, times, flags));
-}
-#endif
 #else /* !CONFIG_ATFILE */
 
 /*
@@ -478,12 +471,12 @@ _syscall3(int,sys_symlinkat,const char *,oldpath,
 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
 #endif
+#endif /* CONFIG_ATFILE */
 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
           const struct timespec *,tsp,int,flags)
 #endif
 
-#endif /* CONFIG_ATFILE */
 
 #ifdef CONFIG_INOTIFY
 #include <sys/inotify.h>


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a)
  2009-04-21  8:24 [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a) Arnaud Patard
@ 2009-04-21  8:36 ` Laurent Desnogues
  2009-04-21 12:34 ` Riku Voipio
  1 sibling, 0 replies; 7+ messages in thread
From: Laurent Desnogues @ 2009-04-21  8:36 UTC (permalink / raw)
  To: Arnaud Patard; +Cc: qemu-devel

On Tue, Apr 21, 2009 at 10:24 AM, Arnaud Patard
<arnaud.patard@rtp-net.org> wrote:
>
>
> Don't use the glibc function for utimensat because glibc returns -EINVAL
> if the path is null which is a different behaviour with the syscall.
> path can be null because internally the glibc is using utimensat with
> path null (for instance, see __futimes in
> sysdeps/unix/sysv/linux/futimes.c in glibc tree).
>
>
> Signed-off-by: Arnaud Patard <arnaud.patard@rtp-net.org>

Acked-by: Laurent Desnogues <laurent.desnogues@gmail.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a)
  2009-04-21  8:24 [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a) Arnaud Patard
  2009-04-21  8:36 ` Laurent Desnogues
@ 2009-04-21 12:34 ` Riku Voipio
  2009-04-21 14:42   ` Jamie Lokier
  2009-04-21 16:09   ` Martin Mohring
  1 sibling, 2 replies; 7+ messages in thread
From: Riku Voipio @ 2009-04-21 12:34 UTC (permalink / raw)
  To: Arnaud Patard; +Cc: laurent.desnogues, qemu-devel

On Tue, Apr 21, 2009 at 10:24:03AM +0200, Arnaud Patard wrote:
> Don't use the glibc function for utimensat because glibc returns -EINVAL
> if the path is null which is a different behaviour with the syscall.
> path can be null because internally the glibc is using utimensat with
> path null (for instance, see __futimes in
> sysdeps/unix/sysv/linux/futimes.c in glibc tree).

Soo.. glibc uses utimensat to implement futimens, but doesn't allow
applications to use utimensat in the same way. What a mess.

But if we are to go towards using libc calls, your patch is a step
backwards. In case pathname is null, we can use futimens.


commit 0f34ff059fb9ad6e8c8fa5161d9d17265286bb62
Author: Riku Voipio <riku.voipio@iki.fi>
Date:   Tue Apr 21 15:01:51 2009 +0300

    linux-user: fix utimensat when used as futimens
    
    The glibc function for utimensat glibc returns -EINVAL when the path is null
    which is a different behaviour with the syscall.
    
    path can be null because internally the glibc is using utimensat with
    path null when implmenting futimens. If path is null, call futimes
    instead.

diff --git a/configure b/configure
index 08df436..fc980a4 100755
--- a/configure
+++ b/configure
@@ -1208,6 +1208,25 @@ EOF
   fi
 fi
 
+# check if utimensat and futimens are supported
+utimens=no
+cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <fcntl.h>
+
+int main(void)
+{
+    utimensat(AT_FDCWD, "foo", NULL, 0);
+    futimens(0, NULL);
+    return 0;
+}
+EOF
+if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+  utimens=yes
+fi
+
 # Check if tools are available to build documentation.
 if [ -x "`which texi2html 2>/dev/null`" ] && \
    [ -x "`which pod2man 2>/dev/null`" ]; then
@@ -1604,6 +1623,9 @@ fi
 if test "$atfile" = "yes" ; then
   echo "#define CONFIG_ATFILE 1" >> $config_h
 fi
+if test "$utimens" = "yes" ; then
+  echo "#define CONFIG_UTIMENSAT 1" >> $config_h
+fi
 if test "$inotify" = "yes" ; then
   echo "#define CONFIG_INOTIFY 1" >> $config_h
 fi
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 408ccc6..4dad5c1 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -406,13 +406,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags)
   return (unlinkat(dirfd, pathname, flags));
 }
 #endif
-#ifdef TARGET_NR_utimensat
-static int sys_utimensat(int dirfd, const char *pathname,
-    const struct timespec times[2], int flags)
-{
-  return (utimensat(dirfd, pathname, times, flags));
-}
-#endif
 #else /* !CONFIG_ATFILE */
 
 /*
@@ -476,12 +469,24 @@ _syscall3(int,sys_symlinkat,const char *,oldpath,
 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
 #endif
+
+#endif /* CONFIG_ATFILE */
+
+#ifdef CONFIG_UTIMENSAT
+static int sys_utimensat(int dirfd, const char *pathname,
+    const struct timespec times[2], int flags)
+{
+    if (pathname == NULL)
+        return futimens(dirfd, times);
+    else
+        return utimensat(dirfd, pathname, times, flags);
+}
+#else
 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
           const struct timespec *,tsp,int,flags)
 #endif
-
-#endif /* CONFIG_ATFILE */
+#endif /* CONFIG_UTIMENSAT  */
 
 #ifdef CONFIG_INOTIFY
 #include <sys/inotify.h>

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a)
  2009-04-21 12:34 ` Riku Voipio
@ 2009-04-21 14:42   ` Jamie Lokier
  2009-04-21 16:09   ` Martin Mohring
  1 sibling, 0 replies; 7+ messages in thread
From: Jamie Lokier @ 2009-04-21 14:42 UTC (permalink / raw)
  To: Riku Voipio; +Cc: laurent.desnogues, qemu-devel, Arnaud Patard

Riku Voipio wrote:
> Soo.. glibc uses utimensat to implement futimens, but doesn't allow
> applications to use utimensat in the same way. What a mess.

It protects against apps passing in NULL path due to a bug and
touching the directory by accident.  A minor bit of protection indeed.

> But if we are to go towards using libc calls, your patch is a step
> backwards. In case pathname is null, we can use futimens.

I agree, good idea.

-- Jamie

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a)
  2009-04-21 12:34 ` Riku Voipio
  2009-04-21 14:42   ` Jamie Lokier
@ 2009-04-21 16:09   ` Martin Mohring
  2009-04-21 16:38     ` Martin Mohring
  1 sibling, 1 reply; 7+ messages in thread
From: Martin Mohring @ 2009-04-21 16:09 UTC (permalink / raw)
  To: Riku Voipio; +Cc: laurent.desnogues, qemu-devel, Arnaud Patard

i found another related case it seems:

when i call in a chroot under arm with qemu user mode:

$ touch /var/log/wtmp

the resulting file has a date/time of 1.1.1970, although the clock is
correct in the system.

calling

$ touch /var/log/wtmp /var/run/utmp /var/log/btmp
/bin/touch: setting times of `/var/run/utmp': Invalid argument
/bin/touch: setting times of `/var/log/btmp': Invalid argument

results in the invalid argutment error. I ll currently check which
syscalls are involved here.
the time of 1.1.1970 looks to me like a wrongly passed argument (of ==0).

Riku Voipio wrote:
> On Tue, Apr 21, 2009 at 10:24:03AM +0200, Arnaud Patard wrote:
>   
>> Don't use the glibc function for utimensat because glibc returns -EINVAL
>> if the path is null which is a different behaviour with the syscall.
>> path can be null because internally the glibc is using utimensat with
>> path null (for instance, see __futimes in
>> sysdeps/unix/sysv/linux/futimes.c in glibc tree).
>>     
>
> Soo.. glibc uses utimensat to implement futimens, but doesn't allow
> applications to use utimensat in the same way. What a mess.
>
> But if we are to go towards using libc calls, your patch is a step
> backwards. In case pathname is null, we can use futimens.
>
>
> commit 0f34ff059fb9ad6e8c8fa5161d9d17265286bb62
> Author: Riku Voipio <riku.voipio@iki.fi>
> Date:   Tue Apr 21 15:01:51 2009 +0300
>
>     linux-user: fix utimensat when used as futimens
>     
>     The glibc function for utimensat glibc returns -EINVAL when the path is null
>     which is a different behaviour with the syscall.
>     
>     path can be null because internally the glibc is using utimensat with
>     path null when implmenting futimens. If path is null, call futimes
>     instead.
>
> diff --git a/configure b/configure
> index 08df436..fc980a4 100755
> --- a/configure
> +++ b/configure
> @@ -1208,6 +1208,25 @@ EOF
>    fi
>  fi
>  
> +# check if utimensat and futimens are supported
> +utimens=no
> +cat > $TMPC << EOF
> +#define _ATFILE_SOURCE
> +#define _GNU_SOURCE
> +#include <stddef.h>
> +#include <fcntl.h>
> +
> +int main(void)
> +{
> +    utimensat(AT_FDCWD, "foo", NULL, 0);
> +    futimens(0, NULL);
> +    return 0;
> +}
> +EOF
> +if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
> +  utimens=yes
> +fi
> +
>  # Check if tools are available to build documentation.
>  if [ -x "`which texi2html 2>/dev/null`" ] && \
>     [ -x "`which pod2man 2>/dev/null`" ]; then
> @@ -1604,6 +1623,9 @@ fi
>  if test "$atfile" = "yes" ; then
>    echo "#define CONFIG_ATFILE 1" >> $config_h
>  fi
> +if test "$utimens" = "yes" ; then
> +  echo "#define CONFIG_UTIMENSAT 1" >> $config_h
> +fi
>  if test "$inotify" = "yes" ; then
>    echo "#define CONFIG_INOTIFY 1" >> $config_h
>  fi
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 408ccc6..4dad5c1 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -406,13 +406,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags)
>    return (unlinkat(dirfd, pathname, flags));
>  }
>  #endif
> -#ifdef TARGET_NR_utimensat
> -static int sys_utimensat(int dirfd, const char *pathname,
> -    const struct timespec times[2], int flags)
> -{
> -  return (utimensat(dirfd, pathname, times, flags));
> -}
> -#endif
>  #else /* !CONFIG_ATFILE */
>  
>  /*
> @@ -476,12 +469,24 @@ _syscall3(int,sys_symlinkat,const char *,oldpath,
>  #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
>  _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
>  #endif
> +
> +#endif /* CONFIG_ATFILE */
> +
> +#ifdef CONFIG_UTIMENSAT
> +static int sys_utimensat(int dirfd, const char *pathname,
> +    const struct timespec times[2], int flags)
> +{
> +    if (pathname == NULL)
> +        return futimens(dirfd, times);
> +    else
> +        return utimensat(dirfd, pathname, times, flags);
> +}
> +#else
>  #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
>  _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
>            const struct timespec *,tsp,int,flags)
>  #endif
> -
> -#endif /* CONFIG_ATFILE */
> +#endif /* CONFIG_UTIMENSAT  */
>  
>  #ifdef CONFIG_INOTIFY
>  #include <sys/inotify.h>
>
>
>   

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a)
  2009-04-21 16:09   ` Martin Mohring
@ 2009-04-21 16:38     ` Martin Mohring
  2009-04-21 18:18       ` Riku Voipio
  0 siblings, 1 reply; 7+ messages in thread
From: Martin Mohring @ 2009-04-21 16:38 UTC (permalink / raw)
  To: Martin Mohring; +Cc: laurent.desnogues, Riku Voipio, qemu-devel, Arnaud Patard

Martin Mohring wrote:
> i found another related case it seems:
>
> when i call in a chroot under arm with qemu user mode:
>
> $ touch /var/log/wtmp
>
> the resulting file has a date/time of 1.1.1970, although the clock is
> correct in the system.
>
> calling
>
> $ touch /var/log/wtmp /var/run/utmp /var/log/btmp
> /bin/touch: setting times of `/var/run/utmp': Invalid argument
> /bin/touch: setting times of `/var/log/btmp': Invalid argument
>
> results in the invalid argutment error. I ll currently check which
> syscalls are involved here.
> the time of 1.1.1970 looks to me like a wrongly passed argument (of ==0).
>   
a trace of this:

27374 open("/var/log/wtmp",0x20941,0666) = 3
27374 dup2(3,0,3,0,0,1109324328) = 0
27374 close(3) = 0
27374 utimensat(0,"(null)",(nil),0) = 0
27374 close(0) = 0
27374 open("/var/run/utmp",0x20941,0666) = 0
27374 utimensat(0,"(null)",(nil),0) = -1 errno=22 (Invalid argument)
27374 close(0) = 0
27374 write(2,0x4007d430,12)/bin/touch:  = 12
27374 write(2,0x4007d408,32)setting times of `/var/run/utmp' = 32
27374 write(2,0x4007cfd0,18): Invalid argument = 18
27374 write(2,0x4007d3d8,1) = 1
27374 open("/var/log/btmp",0x20941,0666) = 0
27374 utimensat(0,"(null)",(nil),0) = -1 errno=22 (Invalid argument)
27374 close(0) = 0
27374 write(2,0x4007d430,12)/bin/touch:  = 12
27374 write(2,0x4007d408,32)setting times of `/var/log/btmp' = 32
27374 write(2,0x4007cfd0,18): Invalid argument = 18
27374 write(2,0x4007d3d8,1) = 1
27374 close(1) = 0
27374 close(2)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a)
  2009-04-21 16:38     ` Martin Mohring
@ 2009-04-21 18:18       ` Riku Voipio
  0 siblings, 0 replies; 7+ messages in thread
From: Riku Voipio @ 2009-04-21 18:18 UTC (permalink / raw)
  To: Martin Mohring; +Cc: laurent.desnogues, qemu-devel, Arnaud Patard

On Tue, Apr 21, 2009 at 06:38:17PM +0200, Martin Mohring wrote:
> > results in the invalid argutment error. I ll currently check which
> > syscalls are involved here.
> > the time of 1.1.1970 looks to me like a wrongly passed argument (of ==0).

no, NULL is what is supposed to be passed. try stracing a normal host
/bin/touch.

> 27374 open("/var/log/wtmp",0x20941,0666) = 3
> 27374 dup2(3,0,3,0,0,1109324328) = 0
> 27374 close(3) = 0
> 27374 utimensat(0,"(null)",(nil),0) = 0
> 27374 close(0) = 0
> 27374 open("/var/run/utmp",0x20941,0666) = 0
> 27374 utimensat(0,"(null)",(nil),0) = -1 errno=22 (Invalid argument)

It is unclear what svn revision you are using qemu, and/or if you are using
any of the patches in this thread. The patch I sent earlier, should fix
the invalid arg issue. As for the 1970 issue, try this patch.

commit 7f7e93aabde6b8f0e4a1a05537145efa9ed0156b
Author: Riku Voipio <riku.voipio@iki.fi>
Date:   Tue Apr 21 20:37:01 2009 +0300

    linux-user: fix utimensat with NULL timespec
    
    Don't try to copy timespec from user if it is NULL.

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e19e289..0049840 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6674,17 +6674,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
     case TARGET_NR_utimensat:
         {
-            struct timespec ts[2];
-            target_to_host_timespec(ts, arg3);
-            target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+            struct timespec *tsp, ts[2];
+            if (!arg3) {
+                tsp = NULL;
+            } else {
+                target_to_host_timespec(ts, arg3);
+                target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+                tsp = ts;
+            }
             if (!arg2)
-                ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
+                ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
             else {
                 if (!(p = lock_user_string(arg2))) {
                     ret = -TARGET_EFAULT;
                     goto fail;
                 }
-                ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
+                ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
                 unlock_user(p, arg2, 0);
             }
         }

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-04-21 18:18 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-21  8:24 [Qemu-devel] [PATCH] Fix utimensat (aka unbreak cp -a) Arnaud Patard
2009-04-21  8:36 ` Laurent Desnogues
2009-04-21 12:34 ` Riku Voipio
2009-04-21 14:42   ` Jamie Lokier
2009-04-21 16:09   ` Martin Mohring
2009-04-21 16:38     ` Martin Mohring
2009-04-21 18:18       ` Riku Voipio

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).