#245 'for' loop security concerns

Need_for_security
closed-fixed
7
2005-07-24
2005-07-18
Steve Jenson
No

FIXED
At
http://www.eros-os.org/pipermail/e-lang/2003-November/009232.html
:

Assuming an untrusted collection object, two potential
problems:

First: a collection can save the function it's passed
and call it later.
This is (at least to me) a rather surprising default
behavior which is
not obvious from inspection of the unexpanded source
(since no other
{block} in E's control structures behaves this way),
and it is awkward
to protect against.

Second: the 'for' expression's return value is that of
the collection's
iterate method. The 'break' expression can specify a
return value, but
there is no way to control what value is returned if
the collection is
empty (or acts as if it is). This is inconvenient (and
potentially
surprising) behavior because you can't rely on the
return value being
something chosen by your code (or null).

A revised Kernel-E expansion of the 'for' loop which
should avoid these
(I think) undesirable behaviors:

escape __break :any {
def [func :any, revoker :any] := makeRevoker.run(body)
try {
collection.iterate(func)
null
} finally {
revoker.revoke(OutOfScopeException)
}
}

('body' and 'collection' are the rest of the expansion,
'makeRevoker' is
<import:org.erights.e.facet.makeRevoker>,
OutOfScopeException is
whatever's appropriate)

Followups

Comment Date By
In line with the plans documented at
http://www.eros-os.org/pipermail/e-lang/2003-November/009234.html
http://www.eros-os.org/pipermail/e-lang/2003-December/009326.html

we change the for loop expansion as explained by the
pseudo-code:

escape __break {
var validFlag := true
try {
collExpr.iterate(def _(k, v) :any {
require(validFlag,
"For-loop body isn't valid after for-loop exits.")
if (k =~ kPattern && v =~ vPattern) {
escape __continue { mBody; null }
}
})
} finally {
validFlag := false
}
null
}

Actual session:

? interp.setExpand(true)
? for x in [1,2,3] {println(x)}
# expansion: escape __break {
# def var validFlag__1 := true
# try {
# __makeList.run(1, 2, 3).iterate(/**
# *For-loop body
# */
# def "__main$1" {
#
# /**
# * Invoke as a function
# */
# method run(key__3, value__5) :any {
# require.run(validFlag__1, "For-loop body isn't valid
after for-loop exits.")
# if ({
# if (key__3 =~ _) {
# if (value__5 =~ x) {
# __makeList.run(&x)
# } else {
# null
# }
# } else {
# null
# }
# } =~ [&x]) {
# escape __continue {
# println.run(x)
# null
# }
# } else {
# null
# }
# }
# })
# } finally {
# validFlag__1 := false
# }
# null
# }

1
2
3
? var capture := null
# expansion: def var capture := null

? def steal {
> to iterate(assocFunc) :any {
> capture := assocFunc
> assocFunc("k1", "v1")
> return 3 # to demonstrate that this is now ignored
> }
> }
# expansion: def steal := def "__main$steal__C" {
#
# method iterate(assocFunc) :any {
# escape __return {
# capture := assocFunc
# assocFunc.run("k1", "v1")
# __return.run(3)
# }
# }
# }

# value: <steal>

? interp.setExpand(false)
# expansion: interp.setExpand(false)

? for k => v in steal { println(`$k => $v`) }
k1 => v1
? capture(3,5)
# problem: For-loop body isn't valid after for-loop exits.
2004-Jul-03 19:34 markm
See
http://www.eros-os.org/pipermail/e-lang/2004-April/009758.html
2004-Apr-15 05:48 markm

Discussion

  • Steve Jenson
    Steve Jenson
    2005-07-18

    • status: open --> open-fixed
     
  • Steve Jenson
    Steve Jenson
    2005-07-18

    • status: open-fixed --> closed-fixed
     
    • assigned_to: nobody --> caplet