Hello,
I am still performing tests to fully understand the semantics of CIL,
here are three strange behaviours I have noticed, I would really
appreciate it if you can say if I am wrong and, in case I am not, if
they are coherent with the intended meaning of CIL constructs.
Please note again that I am currently using the version available on
Ubuntu 18.04.5 LTS via packet manager.
########################## Report ##########################
1)
Names defined inside the body of a macro are not checked before names
defined in the namespace in which the macro is defined. For example, in
the following
(block A
(type a)
(macro m ()
(type a)
(allow a a (file (read)))))
(block B
(call A.m))
I would expect "a" to be resolved as the type "a" in the body of the
macro, hence to "B.a" as the allow statement and type definition are
copied into block "B". Instead it is resolved as "A.a" (I get “allow A.a
A.a”).
Basically, it behaves like
(block A
(type a)
(macro m ()
(allow a a (file (read)))))
(block B
(call A.m))
and not like
(block A(macro m ()(type a)
(allow a a (file (read)))))
(block B
(call A.m))
as I expected.
I know that the documentation saying:
“Note that when resolving macros the callers namespace is not checked,
only the following places: - Items defined inside the macro
-Items passed into the macro as arguments- Items defined in the
same namespace of the macro- Items defined in the global namespace”
is outdated, and that it has been proposed to change it with:
"When resolving macros the following places are checked in this order:
- Items defined inside the macro
- Items passed into the macro as arguments
- Items defined in the same namespace of the macro
- Items defined in the callers namespace
- Items defined in the global namespace"
But the observed behaviour is not coherent with none of these descriptions.
Maybe this could work:
"When resolving macros the following places are checked in this order:
- Items passed into the macro as arguments
- Items defined in the same namespace of the macro
- Items defined inside the macro - Items defined in the callers namespace
- Items defined in the global namespace"
But I think it is not an intuitive way of resolving names.
2)
Usually, names inside a macro are resolved using the definitions in the
namespace in which the macro is defined before the ones in the caller
namespace.
I noticed that, in the following
(type a)
(macro m ()
(allow a a (file (read))))
(block A
(type a)
(call m))
the name "a" is resolved in "A", not as ".a" in the global namespace,
which is the namespace where "m" is defined.
Hence I assumed that the rule does not apply to macros defined in the
global namespace, can you confirm?
3)
I noticed that the types declared in a macro, being copied into the
caller namespace, can be used as parameters for the macro itself.
For example, in the following
(type a)
(block A
(macro m ((type x))
(type a)
(allow x x (file (read))))
)
(block B
(call A.m(a))
)
the resulting allow rule is (allow B.a B.a (file(read))), which in my
opinion is unexpected.
#############################################################
Thank you for your time.
Cheers,
Lorenzo Ceragioli