1
+ package org.utbot.instrumentation.process
2
+
3
+ import sun.security.provider.PolicyFile
4
+ import java.lang.reflect.ReflectPermission
5
+ import java.net.URI
6
+ import java.nio.file.Files
7
+ import java.nio.file.Paths
8
+ import java.security.AccessControlContext
9
+ import java.security.AccessController
10
+ import java.security.CodeSource
11
+ import java.security.Permission
12
+ import java.security.PermissionCollection
13
+ import java.security.Permissions
14
+ import java.security.Policy
15
+ import java.security.PrivilegedAction
16
+ import java.security.ProtectionDomain
17
+ import java.security.cert.Certificate
18
+
19
+ internal fun permissions (block : SimplePolicy .() -> Unit ) {
20
+ val policy = Policy .getPolicy()
21
+ if (policy !is SimplePolicy ) {
22
+ Policy .setPolicy(SimplePolicy (block))
23
+ System .setSecurityManager(SecurityManager ())
24
+ } else {
25
+ policy.block()
26
+ }
27
+ }
28
+
29
+ /* *
30
+ * Run [block] in sandbox mode.
31
+ *
32
+ * When running in sandbox by default only necessary to instrumentation permissions are enabled.
33
+ * Other options are not enabled by default and rises [java.security.AccessControlException].
34
+ *
35
+ * To add new permissions create and/or edit file "{user.home}/.utbot/sandbox.policy".
36
+ *
37
+ * For example to enable property reading (`System.getProperty("user.home")`):
38
+ *
39
+ * ```
40
+ * grant {
41
+ * permission java.util.PropertyPermission "user.home", "read";
42
+ * };
43
+ * ```
44
+ * Read more [about policy file and syntax](https://docs.oracle.com/javase/7/docs/technotes/guides/security/PolicyFiles.html#Examples)
45
+ */
46
+ internal fun <T > sandbox (block : () -> T ): T {
47
+ val policyPath = Paths .get(System .getProperty(" user.home" ), " .utbot" , " sandbox.policy" )
48
+ return sandbox(policyPath.toUri()) { block() }
49
+ }
50
+
51
+ internal fun <T > sandbox (file : URI , block : () -> T ): T {
52
+ val path = Paths .get(file)
53
+ val perms = mutableListOf<Permission >(
54
+ RuntimePermission (" accessDeclaredMembers" ),
55
+ RuntimePermission (" getProtectionDomain" ),
56
+ RuntimePermission (" accessClassInPackage.*" ),
57
+ ReflectPermission (" *" ),
58
+ )
59
+ if (Files .exists(path)) {
60
+ val policyFile = PolicyFile (file.toURL())
61
+ val collection = policyFile.getPermissions(CodeSource (null , emptyArray<Certificate >()))
62
+ perms + = collection.elements().toList()
63
+ }
64
+ return sandbox(perms) { block() }
65
+ }
66
+
67
+ internal fun <T > sandbox (permission : List <Permission >, block : () -> T ): T {
68
+ val perms = permission.fold(Permissions ()) { acc, p -> acc.add(p); acc }
69
+ return sandbox(perms) { block() }
70
+ }
71
+
72
+ internal fun <T > sandbox (perms : PermissionCollection , block : () -> T ): T {
73
+ val acc = AccessControlContext (arrayOf(ProtectionDomain (null , perms)))
74
+ return AccessController .doPrivileged(
75
+ PrivilegedAction {
76
+ block()
77
+ },
78
+ acc
79
+ )
80
+ }
81
+
82
+ /* *
83
+ * This policy can add grant or denial rules for permissions.
84
+ *
85
+ * To add a grant permission use like this in any place:
86
+ *
87
+ * ```
88
+ * permissions {
89
+ * + java.security.PropertyPolicy("user.home", "read,write")
90
+ * }
91
+ * ```
92
+ *
93
+ * After first call [SecurityManager] is set with this policy
94
+ *
95
+ * To deny a permission:
96
+ *
97
+ * ```
98
+ * permissions {
99
+ * - java.security.PropertyPolicy("user.home", "read,write")
100
+ * }
101
+ * ```
102
+ *
103
+ * To delete all concrete permissions (if it was added before):
104
+ *
105
+ * ```
106
+ * permissions {
107
+ * ! java.security.PropertyPolicy("user.home", "read,write")
108
+ * }
109
+ * ```
110
+ *
111
+ * The last permission has priority. Enable all property read for "user.*", but forbid to read only "user.home":
112
+ *
113
+ * ```
114
+ * permissions {
115
+ * + java.security.PropertyPolicy("user.*", "read,write")
116
+ * - java.security.PropertyPolicy("user.home", "read,write")
117
+ * }
118
+ * ```
119
+ */
120
+ internal class SimplePolicy (init : SimplePolicy .() -> Unit = {}) : Policy() {
121
+ sealed class Access (val permission : Permission ) {
122
+ class Allow (permission : Permission ) : Access(permission)
123
+ class Deny (permission : Permission ) : Access(permission)
124
+ }
125
+ private var permissions = mutableListOf<Access >()
126
+
127
+ init { apply (init ) }
128
+
129
+ operator fun Permission.unaryPlus () = permissions.add(Access .Allow (this ))
130
+
131
+ operator fun Permission.unaryMinus () = permissions.add(Access .Deny (this ))
132
+
133
+ operator fun Permission.not () = permissions.removeAll { it.permission == this }
134
+
135
+ override fun getPermissions (codesource : CodeSource ) = UNSUPPORTED_EMPTY_COLLECTION !!
136
+ override fun getPermissions (domain : ProtectionDomain ) = UNSUPPORTED_EMPTY_COLLECTION !!
137
+ override fun implies (domain : ProtectionDomain , permission : Permission ): Boolean {
138
+ // 0 means no info, < 0 is denied and > 0 is allowed
139
+ val result = permissions.lastOrNull { it.permission.implies(permission) }?.let {
140
+ when (it) {
141
+ is Access .Allow -> 1
142
+ is Access .Deny -> - 1
143
+ }
144
+ } ? : 0
145
+ return result > 0
146
+ }
147
+ }
0 commit comments