From 2e55270c6153a451ed50986513b743778c30a5b4 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 12 Feb 2014 14:53:21 -0600 Subject: [PATCH] Added rename()/renameat() testcase and prevent more syscall nesting. * testsuite/systemtap.syscall/rename.c: New testcase for rename() and renameat(). * tapset/linux/syscalls2.stp: Prevent syscall nesting in syscall.open, and syscall.renameat. * tapset/linux/nd_syscalls2.stp: Ditto. * tapset/linux/syscalls.stp: Prevent syscall nesting in syscall.mkdirat. * tapset/linux/nd_syscalls.stp: Ditto. * runtime/linux/compat_unistd.h: Add __NR_compat defines. --- runtime/linux/compat_unistd.h | 15 +++++ tapset/linux/nd_syscalls.stp | 2 + tapset/linux/nd_syscalls2.stp | 4 ++ tapset/linux/syscalls.stp | 2 + tapset/linux/syscalls2.stp | 4 ++ testsuite/systemtap.syscall/rename.c | 86 ++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+) create mode 100644 testsuite/systemtap.syscall/rename.c diff --git a/runtime/linux/compat_unistd.h b/runtime/linux/compat_unistd.h index bfb3e6fc6..2fc7c7aba 100644 --- a/runtime/linux/compat_unistd.h +++ b/runtime/linux/compat_unistd.h @@ -39,12 +39,21 @@ #ifndef __NR_ia32_linkat #define __NR_ia32_linkat 303 #endif +#ifndef __NR_ia32_mkdirat +#define __NR_ia32_mkdirat 296 +#endif +#ifndef __NR_ia32_open +#define __NR_ia32_open 5 +#endif #ifndef __NR_ia32_pipe2 #define __NR_ia32_pipe2 331 #endif #ifndef __NR_ia32_readlinkat #define __NR_ia32_readlinkat 305 #endif +#ifndef __NR_ia32_renameat +#define __NR_ia32_renameat 302 +#endif #ifndef __NR_ia32_rt_sigprocmask #define __NR_ia32_rt_sigprocmask 175 #endif @@ -63,8 +72,11 @@ #define __NR_compat_getpgid __NR_ia32_getpgid #define __NR_compat_inotify_init1 __NR_ia32_inotify_init1 #define __NR_compat_linkat __NR_ia32_linkat +#define __NR_compat_mkdirat __NR_ia32_mkdirat +#define __NR_compat_open __NR_ia32_open #define __NR_compat_pipe2 __NR_ia32_pipe2 #define __NR_compat_readlinkat __NR_ia32_readlinkat +#define __NR_compat_renameat __NR_ia32_renameat #define __NR_compat_rt_sigprocmask __NR_ia32_rt_sigprocmask #define __NR_compat_symlinkat __NR_ia32_symlinkat #define __NR_compat_umount2 __NR_ia32_umount2 @@ -84,8 +96,11 @@ #define __NR_compat_getpgid __NR_getpgid #define __NR_compat_inotify_init1 __NR_inotify_init1 #define __NR_compat_linkat __NR_linkat +#define __NR_compat_mkdirat __NR_mkdirat +#define __NR_compat_open __NR_open #define __NR_compat_pipe2 __NR_pipe2 #define __NR_compat_readlinkat __NR_readlinkat +#define __NR_compat_renameat __NR_renameat #define __NR_compat_rt_sigprocmask __NR_rt_sigprocmask #define __NR_compat_symlinkat __NR_symlinkat #define __NR_compat_umount2 __NR_umount2 diff --git a/tapset/linux/nd_syscalls.stp b/tapset/linux/nd_syscalls.stp index 19813facc..bfd7d2001 100644 --- a/tapset/linux/nd_syscalls.stp +++ b/tapset/linux/nd_syscalls.stp @@ -3447,6 +3447,7 @@ probe nd_syscall.mkdir.return = kprobe.function("sys_mkdir").return ? # long sys_mkdirat(int dfd, const char __user *pathname, int mode) probe nd_syscall.mkdirat = kprobe.function("sys_mkdirat") ? { + @__syscall_compat_gate(%{ __NR_mkdirat %}, %{ __NR_compat_mkdirat %}) name = "mkdirat" // dirfd = $dfd // pathname = user_string($pathname) @@ -3460,6 +3461,7 @@ probe nd_syscall.mkdirat = kprobe.function("sys_mkdirat") ? } probe nd_syscall.mkdirat.return = kprobe.function("sys_mkdirat").return ? { + @__syscall_compat_gate(%{ __NR_mkdirat %}, %{ __NR_compat_mkdirat %}) name = "mkdirat" retstr = returnstr(1) } diff --git a/tapset/linux/nd_syscalls2.stp b/tapset/linux/nd_syscalls2.stp index 9a5322c63..019ed365d 100644 --- a/tapset/linux/nd_syscalls2.stp +++ b/tapset/linux/nd_syscalls2.stp @@ -132,6 +132,7 @@ probe nd_syscall.open = kprobe.function("compat_sys_open") ?, kprobe.function("sys32_open") ?, kprobe.function("sys_open") ? { + @__syscall_compat_gate(%{ __NR_open %}, %{ __NR_compat_open %}) name = "open" // filename = user_string($filename) // flags = $flags @@ -157,6 +158,7 @@ probe nd_syscall.open.return = kprobe.function("compat_sys_open").return ?, kprobe.function("sys32_open").return ?, kprobe.function("sys_open").return ? { + @__syscall_compat_gate(%{ __NR_open %}, %{ __NR_compat_open %}) name = "open" retstr = returnstr(1) } @@ -1266,6 +1268,7 @@ probe nd_syscall.rename.return = kprobe.function("sys_rename").return ? # int newdfd, const char __user *newname) probe nd_syscall.renameat = kprobe.function("sys_renameat") ? { + @__syscall_compat_gate(%{ __NR_renameat %}, %{ __NR_compat_renameat %}) name = "renameat" // olddfd = $olddfd // olddfd_str = _dfd_str($olddfd) @@ -1293,6 +1296,7 @@ probe nd_syscall.renameat = kprobe.function("sys_renameat") ? } probe nd_syscall.renameat.return = kprobe.function("sys_renameat").return ? { + @__syscall_compat_gate(%{ __NR_renameat %}, %{ __NR_compat_renameat %}) name = "renameat" retstr = returnstr(1) } diff --git a/tapset/linux/syscalls.stp b/tapset/linux/syscalls.stp index 99e4579df..38a00b479 100644 --- a/tapset/linux/syscalls.stp +++ b/tapset/linux/syscalls.stp @@ -2750,6 +2750,7 @@ probe syscall.mkdir.return = kernel.function("sys_mkdir").return # long sys_mkdirat(int dfd, const char __user *pathname, int mode) probe syscall.mkdirat = kernel.function("sys_mkdirat").call ? { + @__syscall_compat_gate(%{ __NR_mkdirat %}, %{ __NR_compat_mkdirat %}) name = "mkdirat" dirfd = $dfd pathname = user_string_quoted($pathname) @@ -2758,6 +2759,7 @@ probe syscall.mkdirat = kernel.function("sys_mkdirat").call ? } probe syscall.mkdirat.return = kernel.function("sys_mkdirat").return ? { + @__syscall_compat_gate(%{ __NR_mkdirat %}, %{ __NR_compat_mkdirat %}) name = "mkdirat" retstr = return_str(1, $return) } diff --git a/tapset/linux/syscalls2.stp b/tapset/linux/syscalls2.stp index 1686d98df..fee448bef 100644 --- a/tapset/linux/syscalls2.stp +++ b/tapset/linux/syscalls2.stp @@ -122,6 +122,7 @@ probe syscall.ni_syscall.return = kernel.function("sys_ni_syscall").return # probe syscall.open = __syscall.compat_open ?, __syscall.open { + @__syscall_compat_gate(%{ __NR_open %}, %{ __NR_compat_open %}) name = "open" flags = $flags if ($flags & 64) @@ -148,6 +149,7 @@ probe syscall.open.return = kernel.function("compat_sys_open").return ?, kernel.function("sys32_open").return ?, kernel.function("sys_open").return ? { + @__syscall_compat_gate(%{ __NR_open %}, %{ __NR_compat_open %}) name = "open" retstr = return_str(1, $return) } @@ -1157,6 +1159,7 @@ probe syscall.rename.return = kernel.function("sys_rename").return # int newdfd, const char __user *newname) probe syscall.renameat = kernel.function("sys_renameat").call ? { + @__syscall_compat_gate(%{ __NR_renameat %}, %{ __NR_compat_renameat %}) name = "renameat" olddfd = $olddfd olddfd_str = _dfd_str($olddfd) @@ -1172,6 +1175,7 @@ probe syscall.renameat = kernel.function("sys_renameat").call ? } probe syscall.renameat.return = kernel.function("sys_renameat").return ? { + @__syscall_compat_gate(%{ __NR_renameat %}, %{ __NR_compat_renameat %}) name = "renameat" retstr = return_str(1, $return) } diff --git a/testsuite/systemtap.syscall/rename.c b/testsuite/systemtap.syscall/rename.c new file mode 100644 index 000000000..e6cbb44f1 --- /dev/null +++ b/testsuite/systemtap.syscall/rename.c @@ -0,0 +1,86 @@ +/* COVERAGE: rename renameat */ + +#include +#include +#include +#include +#include + +// To test for glibc support for renameat(): +// +// Since glibc 2.10: +// _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L +// Before glibc 2.10: +// _ATFILE_SOURCE + +#define GLIBC_SUPPORT \ + (_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L \ + || defined(_ATFILE_SOURCE)) + +int main() +{ + int fd1; + + fd1 = creat("file1", S_IREAD|S_IWRITE); + close (fd1); + + mkdir("dir1", S_IREAD|S_IWRITE|S_IEXEC); + mkdir("dir3", S_IREAD|S_IWRITE|S_IEXEC); + + fd1 = creat("dir3/file", S_IREAD|S_IWRITE); + close (fd1); + + rename("file1", "file2"); + //staptest// rename ("file1", "file2") = 0 + + rename("dir1", "dir2"); + //staptest// rename ("dir1", "dir2") = 0 + + // This will fail since the target isn't empty. + rename("dir2", "dir3"); + //staptest// rename ("dir2", "dir3") = -NNNN (ENOTEMPTY!!!!EEXIST) + + // This will fail since you can't rename a file to a directory. + rename("file2", "dir2"); + //staptest// rename ("file2", "dir2") = -NNNN (EISDIR) + + // You can't rename a directory to a subdirectory of itself. + rename("dir2", "dir2/dir4"); + //staptest// rename ("dir2", "dir2/dir4") = -NNNN (EINVAL) + + // You can't rename a directory to a file. + rename("dir2", "file2"); + //staptest// rename ("dir2", "file2") = -NNNN (ENOTDIR) + + rename("file2", (char *)-1); + //staptest// rename ("file2", XXXX) = -NNNN (EFAULT) + +#if GLIBC_SUPPORT + renameat(AT_FDCWD, "file2", AT_FDCWD, "file1"); + //staptest// renameat (AT_FDCWD, "file2", AT_FDCWD, "file1") = 0 + + renameat(AT_FDCWD, "dir2", AT_FDCWD, "dir1"); + //staptest// renameat (AT_FDCWD, "dir2", AT_FDCWD, "dir1") = 0 + + // This will fail since the target isn't empty. + renameat(AT_FDCWD, "dir1", AT_FDCWD, "dir3"); + //staptest// rename (AT_FDCWD, "dir1", AT_FDCWD, "dir3") = -NNNN (ENOTEMPTY!!!!EEXIST) + + // This will fail since you can't rename a file to a directory. + renameat(AT_FDCWD, "file1", AT_FDCWD, "dir1"); + //staptest// renameat (AT_FDCWD, "file1", AT_FDCWD, "dir1") = -NNNN (EISDIR) + + // You can't rename a directory to a subdirectory of itself. + renameat(AT_FDCWD, "dir1", AT_FDCWD, "dir1/dir4"); + //staptest// renameat (AT_FDCWD, "dir1", AT_FDCWD, "dir1/dir4") = -NNNN (EINVAL) + + // You can't rename a directory to a file. + renameat(AT_FDCWD, "dir1", AT_FDCWD, "file1"); + //staptest// renameat (AT_FDCWD, "dir1", AT_FDCWD, "file1") = -NNNN (ENOTDIR) + + renameat(AT_FDCWD, "file1", AT_FDCWD, (char *)-1); + //staptest// renameat (AT_FDCWD, "file1", AT_FDCWD, XXXX) = -NNNN (EFAULT) + +#endif + return 0; +} -- 2.43.5