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