Skip to content

Commit 226a33d

Browse files
Compare pointers that are not valid LLVM pointers. (#1141)
Comparing the offsets as unsigned bitvectors is not sound, because of overflow (e.g. `base - 1` is less than `base`, but -1 is not less than 0 when compared as unsigned). It is safe to allow a small negative offset, because each pointer base is mapped to an address that is not in the first page, which is never mapped on X86_64 Linux.
1 parent 1af3c78 commit 226a33d

File tree

2 files changed

+58
-5
lines changed

2 files changed

+58
-5
lines changed

src/SAWScript/Crucible/LLVM/X86.hs

+57-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Stability : provisional
1818
{-# Language TypeApplications #-}
1919
{-# Language GADTs #-}
2020
{-# Language DataKinds #-}
21+
{-# Language RankNTypes #-}
2122
{-# Language ConstraintKinds #-}
2223
{-# Language GeneralizedNewtypeDeriving #-}
2324
{-# Language TemplateHaskell #-}
@@ -226,6 +227,50 @@ cryptolUninterpreted env nm sc xs =
226227
]
227228
Right t -> liftIO $ scApplyAll sc t xs
228229

230+
llvmPointerBlock :: C.LLVM.LLVMPtr sym w -> W4.SymNat sym
231+
llvmPointerBlock = fst . C.LLVM.llvmPointerView
232+
llvmPointerOffset :: C.LLVM.LLVMPtr sym w -> W4.SymBV sym w
233+
llvmPointerOffset = snd . C.LLVM.llvmPointerView
234+
235+
-- | Compare pointers that are not valid LLVM pointers. Comparing the offsets
236+
-- as unsigned bitvectors is not sound, because of overflow (e.g. `base - 1` is
237+
-- less than `base`, but -1 is not less than 0 when compared as unsigned). It
238+
-- is safe to allow a small negative offset, because each pointer base is
239+
-- mapped to an address that is not in the first page (4K), which is never
240+
-- mapped on X86_64 Linux. Specifically, assume pointer1 = (base1, offset1) and
241+
-- pointer2 = (base2, offset2), and size1 is the size of the allocation of
242+
-- base1 and size2 is the size of the allocation of base2. If offset1 is in the
243+
-- interval [-4096, size1], and offset2 is in the interval [-4096, size2], then
244+
-- the unsigned comparison between pointer1 and pointer2 is equivalent with the
245+
-- unsigned comparison between offset1 + 4096 and offset2 + 4096.
246+
doPtrCmp ::
247+
(sym -> W4.SymBV sym w -> W4.SymBV sym w -> IO (W4.Pred sym)) ->
248+
Macaw.PtrOp sym w (C.RegValue sym C.BoolType)
249+
doPtrCmp f = Macaw.ptrOp $ \sym mem w xPtr xBits yPtr yBits x y -> do
250+
let ptr_as_bv_for_cmp ptr = do
251+
page_size <- W4.bvLit sym (W4.bvWidth $ llvmPointerOffset ptr) $
252+
BV.mkBV (W4.bvWidth $ llvmPointerOffset ptr) 4096
253+
ptr_as_bv <- W4.bvAdd sym (llvmPointerOffset ptr) page_size
254+
is_valid <- Macaw.isValidPtr sym mem w ptr
255+
is_negative_offset <- W4.bvIsNeg sym (llvmPointerOffset ptr)
256+
is_not_overflow <- W4.notPred sym =<< W4.bvIsNeg sym ptr_as_bv
257+
ok <- W4.orPred sym is_valid
258+
=<< W4.andPred sym is_negative_offset is_not_overflow
259+
return (ptr_as_bv, ok)
260+
both_bits <- W4.andPred sym xBits yBits
261+
both_ptrs <- W4.andPred sym xPtr yPtr
262+
same_region <- W4.natEq sym (llvmPointerBlock x) (llvmPointerBlock y)
263+
(x_ptr_as_bv, ok_x) <- ptr_as_bv_for_cmp x
264+
(y_ptr_as_bv, ok_y) <- ptr_as_bv_for_cmp y
265+
ok_both_ptrs <- W4.andPred sym both_ptrs
266+
=<< W4.andPred sym same_region
267+
=<< W4.andPred sym ok_x ok_y
268+
res_both_bits <- f sym (llvmPointerOffset x) (llvmPointerOffset y)
269+
res_both_ptrs <- f sym x_ptr_as_bv y_ptr_as_bv
270+
undef <- Macaw.mkUndefinedBool sym "ptr_cmp"
271+
W4.itePred sym both_bits res_both_bits
272+
=<< W4.itePred sym ok_both_ptrs res_both_ptrs undef
273+
229274
-------------------------------------------------------------------------------
230275
-- ** Entrypoint
231276

@@ -329,17 +374,25 @@ llvm_verify_x86 (Some (llvmModule :: LLVMModule x)) path nm globsyms checkSat se
329374
, show $ W4.ppExpr off
330375
]
331376
noExtraValidityPred _ _ _ _ = return Nothing
377+
defaultMacawExtensions_x86_64 = Macaw.macawExtensions
378+
(Macaw.x86_64MacawEvalFn sfs) mvar
379+
(mkGlobalMap . Map.singleton 0 $ preState ^. x86GlobalBase)
380+
funcLookup
381+
noExtraValidityPred
382+
sawMacawExtensions = defaultMacawExtensions_x86_64
383+
{ C.extensionExec = \s0 st -> case s0 of
384+
Macaw.PtrLt w x y -> doPtrCmp W4.bvUlt st mvar w x y
385+
Macaw.PtrLeq w x y -> doPtrCmp W4.bvUle st mvar w x y
386+
_ -> (C.extensionExec defaultMacawExtensions_x86_64) s0 st
387+
}
332388
ctx :: C.SimContext (Macaw.MacawSimulatorState Sym) Sym (Macaw.MacawExt Macaw.X86_64)
333389
ctx = C.SimContext
334390
{ C._ctxSymInterface = sym
335391
, C.ctxSolverProof = id
336392
, C.ctxIntrinsicTypes = C.LLVM.llvmIntrinsicTypes
337393
, C.simHandleAllocator = halloc
338394
, C.printHandle = stdout
339-
, C.extensionImpl =
340-
Macaw.macawExtensions (Macaw.x86_64MacawEvalFn sfs) mvar
341-
(mkGlobalMap . Map.singleton 0 $ preState ^. x86GlobalBase)
342-
funcLookup noExtraValidityPred
395+
, C.extensionImpl = sawMacawExtensions
343396
, C._functionBindings = C.FnBindings $ C.insertHandleMap (C.cfgHandle cfg) (C.UseCFG cfg $ C.postdomInfo cfg) C.emptyHandleMap
344397
, C._cruciblePersonality = Macaw.MacawSimulatorState
345398
, C._profilingMetrics = Map.empty

0 commit comments

Comments
 (0)