Skip to content

Commit

Permalink
Add rename, renameat and renameat2 syscalls
Browse files Browse the repository at this point in the history
  • Loading branch information
qrilka committed Mar 26, 2019
1 parent cf82eb7 commit ade544c
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 0 deletions.
146 changes: 146 additions & 0 deletions src/System/Hatrace.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ module System.Hatrace
, SyscallExitDetails_write(..)
, SyscallEnterDetails_read(..)
, SyscallExitDetails_read(..)
, SyscallEnterDetails_rename(..)
, SyscallExitDetails_rename(..)
, SyscallEnterDetails_renameat(..)
, SyscallExitDetails_renameat(..)
, SyscallEnterDetails_renameat2(..)
, SyscallExitDetails_renameat2(..)
, SyscallEnterDetails_execve(..)
, SyscallExitDetails_execve(..)
, DetailedSyscallEnter(..)
Expand Down Expand Up @@ -392,6 +398,53 @@ data SyscallExitDetails_close = SyscallExitDetails_close
} deriving (Eq, Ord, Show)


data SyscallEnterDetails_rename = SyscallEnterDetails_rename
{ oldpath :: Ptr CChar
, newpath :: Ptr CChar
-- Peeked details
, oldpathBS :: ByteString
, newpathBS :: ByteString
} deriving (Eq, Ord, Show)


data SyscallExitDetails_rename = SyscallExitDetails_rename
{ enterDetail :: SyscallEnterDetails_rename
} deriving (Eq, Ord, Show)


data SyscallEnterDetails_renameat = SyscallEnterDetails_renameat
{ olddirfd :: CInt
, oldpath :: Ptr CChar
, newdirfd :: CInt
, newpath :: Ptr CChar
-- Peeked details
, oldpathBS :: ByteString
, newpathBS :: ByteString
} deriving (Eq, Ord, Show)


data SyscallExitDetails_renameat = SyscallExitDetails_renameat
{ enterDetail :: SyscallEnterDetails_renameat
} deriving (Eq, Ord, Show)


data SyscallEnterDetails_renameat2 = SyscallEnterDetails_renameat2
{ olddirfd :: CInt
, oldpath :: Ptr CChar
, newdirfd :: CInt
, newpath :: Ptr CChar
, flags :: CInt
-- Peeked details
, oldpathBS :: ByteString
, newpathBS :: ByteString
} deriving (Eq, Ord, Show)


data SyscallExitDetails_renameat2 = SyscallExitDetails_renameat2
{ enterDetail :: SyscallEnterDetails_renameat2
} deriving (Eq, Ord, Show)


data SyscallEnterDetails_execve = SyscallEnterDetails_execve
{ filename :: Ptr CChar
, argv :: Ptr (Ptr CChar)
Expand All @@ -417,6 +470,9 @@ data DetailedSyscallEnter
| DetailedSyscallEnter_read SyscallEnterDetails_read
| DetailedSyscallEnter_execve SyscallEnterDetails_execve
| DetailedSyscallEnter_close SyscallEnterDetails_close
| DetailedSyscallEnter_rename SyscallEnterDetails_rename
| DetailedSyscallEnter_renameat SyscallEnterDetails_renameat
| DetailedSyscallEnter_renameat2 SyscallEnterDetails_renameat2
| DetailedSyscallEnter_unimplemented Syscall SyscallArgs
deriving (Eq, Ord, Show)

Expand All @@ -429,6 +485,9 @@ data DetailedSyscallExit
| DetailedSyscallExit_read SyscallExitDetails_read
| DetailedSyscallExit_execve SyscallExitDetails_execve
| DetailedSyscallExit_close SyscallExitDetails_close
| DetailedSyscallExit_rename SyscallExitDetails_rename
| DetailedSyscallExit_renameat SyscallExitDetails_renameat
| DetailedSyscallExit_renameat2 SyscallExitDetails_renameat2
| DetailedSyscallExit_unimplemented Syscall SyscallArgs Word64
deriving (Eq, Ord, Show)

Expand Down Expand Up @@ -525,6 +584,48 @@ getSyscallEnterDetails syscall syscallArgs pid = let proc = TracedProcess pid in
pure $ DetailedSyscallEnter_close $ SyscallEnterDetails_close
{ fd = fromIntegral fd
}
Syscall_rename -> do
let SyscallArgs{ arg0 = oldpathAddr, arg1 = newpathAddr } = syscallArgs
let oldpathPtr = word64ToPtr oldpathAddr
let newpathPtr = word64ToPtr newpathAddr
oldpathBS <- peekNullTerminatedBytes proc oldpathPtr
newpathBS <- peekNullTerminatedBytes proc newpathPtr
pure $ DetailedSyscallEnter_rename $ SyscallEnterDetails_rename
{ oldpath = oldpathPtr
, newpath = newpathPtr
, oldpathBS
, newpathBS
}
Syscall_renameat -> do
let SyscallArgs{ arg0 = olddirfd, arg1 = oldpathAddr, arg2 =newdirfd, arg3 = newpathAddr } = syscallArgs
let oldpathPtr = word64ToPtr oldpathAddr
let newpathPtr = word64ToPtr newpathAddr
oldpathBS <- peekNullTerminatedBytes proc oldpathPtr
newpathBS <- peekNullTerminatedBytes proc newpathPtr
pure $ DetailedSyscallEnter_renameat $ SyscallEnterDetails_renameat
{ olddirfd = fromIntegral olddirfd
, oldpath = oldpathPtr
, newdirfd = fromIntegral newdirfd
, newpath = newpathPtr
, oldpathBS
, newpathBS
}
Syscall_renameat2 -> do
let SyscallArgs{ arg0 = olddirfd, arg1 = oldpathAddr
, arg2 =newdirfd, arg3 = newpathAddr, arg4 = flags } = syscallArgs
let oldpathPtr = word64ToPtr oldpathAddr
let newpathPtr = word64ToPtr newpathAddr
oldpathBS <- peekNullTerminatedBytes proc oldpathPtr
newpathBS <- peekNullTerminatedBytes proc newpathPtr
pure $ DetailedSyscallEnter_renameat2 $ SyscallEnterDetails_renameat2
{ olddirfd = fromIntegral olddirfd
, oldpath = oldpathPtr
, newdirfd = fromIntegral newdirfd
, newpath = newpathPtr
, oldpathBS
, newpathBS
, flags = fromIntegral flags
}
_ -> pure $
DetailedSyscallEnter_unimplemented (KnownSyscall syscall) syscallArgs

Expand Down Expand Up @@ -592,6 +693,21 @@ getSyscallExitDetails knownSyscall syscallArgs pid = do
pure $ DetailedSyscallExit_close $
SyscallExitDetails_close{ enterDetail }

DetailedSyscallEnter_rename
enterDetail@SyscallEnterDetails_rename{} -> do
pure $ DetailedSyscallExit_rename $
SyscallExitDetails_rename{ enterDetail }

DetailedSyscallEnter_renameat
enterDetail@SyscallEnterDetails_renameat{} -> do
pure $ DetailedSyscallExit_renameat $
SyscallExitDetails_renameat{ enterDetail }

DetailedSyscallEnter_renameat2
enterDetail@SyscallEnterDetails_renameat2{} -> do
pure $ DetailedSyscallExit_renameat2 $
SyscallExitDetails_renameat2{ enterDetail }

DetailedSyscallEnter_unimplemented syscall _syscallArgs ->
pure $ DetailedSyscallExit_unimplemented syscall syscallArgs result

Expand Down Expand Up @@ -639,6 +755,20 @@ formatDetailedSyscallEnter = \case
SyscallEnterDetails_close{ fd } ->
"close(" ++ show fd ++ ")"

DetailedSyscallEnter_rename
SyscallEnterDetails_rename{ oldpathBS, newpathBS } ->
"rename(" ++ show oldpathBS ++ ", " ++ show newpathBS ++ ")"

DetailedSyscallEnter_renameat
SyscallEnterDetails_renameat{ olddirfd, oldpathBS, newdirfd, newpathBS } ->
"renameat(" ++ show olddirfd ++ ", " ++ show oldpathBS ++
", " ++ show newdirfd ++ ", " ++ show newpathBS ++ ")"

DetailedSyscallEnter_renameat2
SyscallEnterDetails_renameat2{ olddirfd, oldpathBS, newdirfd, newpathBS, flags } ->
"renameat2(" ++ show olddirfd ++ ", " ++ show oldpathBS ++
", " ++ show newdirfd ++ ", " ++ show newpathBS ++ ", " ++ show flags ++ ")"

DetailedSyscallEnter_execve
SyscallEnterDetails_execve{ filenameBS, argvList, envpList } ->
"execve(" ++ show filenameBS ++ ", " ++ show argvList ++ ", " ++ show envpList ++ ")"
Expand Down Expand Up @@ -681,6 +811,22 @@ formatDetailedSyscallExit = \case
SyscallExitDetails_close{ enterDetail = SyscallEnterDetails_close{ fd } } ->
"close(" ++ show fd ++ ")"

DetailedSyscallExit_rename
SyscallExitDetails_rename{ enterDetail = SyscallEnterDetails_rename{ oldpathBS, newpathBS } } ->
"rename(" ++ show oldpathBS ++ ", " ++ show newpathBS ++ ")"

DetailedSyscallExit_renameat
SyscallExitDetails_renameat
{ enterDetail = SyscallEnterDetails_renameat{ olddirfd, oldpathBS, newdirfd, newpathBS } } ->
"renameat(" ++ show olddirfd ++ ", " ++ show oldpathBS ++
", " ++ show newdirfd ++ ", " ++ show newpathBS ++ ")"

DetailedSyscallExit_renameat2
SyscallExitDetails_renameat2
{ enterDetail = SyscallEnterDetails_renameat2{ olddirfd, oldpathBS, newdirfd, newpathBS, flags } } ->
"renameat2(" ++ show olddirfd ++ ", " ++ show oldpathBS ++
", " ++ show newdirfd ++ ", " ++ show newpathBS ++ ", " ++ show flags ++ ")"

DetailedSyscallExit_execve
SyscallExitDetails_execve{ optionalEnterDetail, execveResult } ->
-- TODO implement remembering arguments
Expand Down
20 changes: 20 additions & 0 deletions test/HatraceSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -445,3 +445,23 @@ spec = before_ assertNoChildren $ do
, pathnameBS == T.encodeUtf8 (T.pack tmpFile)
]
tmpFileOpenatEvents `shouldSatisfy` (not . null)

describe "rename" $ do
it "seen for a file we do an atomic write to" $ do
makeAtomicWriteExample
tmpFile <- emptySystemTempFile "test-output"
argv <- procToArgv "example-programs-build/atomic-write" ["atomic", "10", tmpFile]
(exitCode, events) <-
sourceTraceForkExecvFullPathWithSink argv $
syscallExitDetailsOnlyConduit .| CL.consume
exitCode `shouldBe` ExitSuccess
let renameToTmpFileEvents =
[ newpathBS
| (_pid
, Right (DetailedSyscallExit_rename
SyscallExitDetails_rename
{ enterDetail = SyscallEnterDetails_rename{ newpathBS }})
) <- events
, newpathBS == T.encodeUtf8 (T.pack tmpFile)
]
renameToTmpFileEvents `shouldSatisfy` (not . null)

0 comments on commit ade544c

Please sign in to comment.