1 /*
2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.jfr;
27 
28 import java.util.Collections;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Objects;
32 
33 import jdk.jfr.internal.PlatformEventType;
34 import jdk.jfr.internal.PlatformRecorder;
35 import jdk.jfr.internal.PlatformRecording;
36 import jdk.jfr.internal.PrivateAccess;
37 import jdk.jfr.internal.Type;
38 import jdk.jfr.internal.Utils;
39 
40 /**
41  * Permission for controlling access to Flight Recorder.
42  * <p>
43  * The following table provides a summary of what the permission
44  * allows, and the risks of granting code the permission.
45  *
46  * <table class="striped">
47  * <caption style="display:none">Table shows permission target name,
48  *      what the permission allows, and associated risks</caption>
49  * <thead>
50  * <tr>
51  * <th scope="col">Permission Target Name</th>
52  * <th scope="col">What the Permission Allows</th>
53  * <th scope="col">Risks of Allowing this Permission</th>
54  * </tr>
55  * </thead>
56  *
57  * <tbody>
58  * <tr>
59  * <th scope="row">{@code accessFlightRecorder}</th>
60  * <td>Ability to create a Flight Recorder instance, register callbacks to
61  * monitor the Flight Recorder life cycle, and control an existing instance
62  * of Flight Recorder, which can record and dump runtime information, such as
63  * stack traces, class names, and data in user defined events.</td>
64  * <td>A malicious user may be able to extract sensitive information that is stored in
65  * events and interrupt Flight Recorder by installing listeners or hooks that
66  * never finish.</td>
67  * </tr>
68  * <tr>
69  * <th scope="row">{@code registerEvent}</th>
70  * <td>Ability to register events, write data to the Flight Recorder buffers,
71  * and execute code in a callback function for periodic events.
72  *
73  * <td>A malicious user may be able to write sensitive information to Flight
74  * Recorder buffers.</td>
75  * </tr>
76  * </tbody>
77  * </table>
78  *
79  * <p>
80  * Typically, programmers do not create {@code FlightRecorderPermission} objects
81  * directly. Instead the objects are created by the security policy code that is based on
82  * reading the security policy file.
83  *
84  * @since 9
85  *
86  * @see java.security.BasicPermission
87  * @see java.security.Permission
88  * @see java.security.Permissions
89  * @see java.security.PermissionCollection
90  * @see java.lang.SecurityManager
91  *
92  */
93 @SuppressWarnings("serial")
94 public final class FlightRecorderPermission extends java.security.BasicPermission {
95 
96     // Purpose of InternalAccess is to give classes in jdk.jfr.internal
97     // access to package private methods in this package (jdk.jfr).
98     //
99     // The initialization could be done in any class in this package,
100     // but this one was chosen because it is light weight and
101     // lacks dependencies on other public classes.
102     static {
PrivateAccess.setPrivateAccess(new InternalAccess())103         PrivateAccess.setPrivateAccess(new InternalAccess());
104     }
105 
106     private final static class InternalAccess extends PrivateAccess {
107 
108         @Override
getType(Object o)109         public Type getType(Object o) {
110             if (o instanceof AnnotationElement) {
111                 return ((AnnotationElement) o).getType();
112             }
113             if (o instanceof EventType) {
114                 return ((EventType) o).getType();
115             }
116             if (o instanceof ValueDescriptor) {
117                 return ((ValueDescriptor) o).getType();
118             }
119             if (o instanceof SettingDescriptor) {
120                 return ((SettingDescriptor) o).getType();
121             }
122             throw new Error("Unknown type " + o.getClass());
123         }
124 
125         @Override
newConfiguration(String name, String label, String description, String provider, Map<String, String> settings, String contents)126         public Configuration newConfiguration(String name, String label, String description, String provider, Map<String, String> settings, String contents) {
127             return new Configuration(name, label, description, provider, settings, contents);
128         }
129 
130         @Override
newEventType(PlatformEventType platformEventType)131         public EventType newEventType(PlatformEventType platformEventType) {
132             return new EventType(platformEventType);
133         }
134 
135         @Override
newAnnotation(Type annotationType, List<Object> values, boolean boot)136         public AnnotationElement newAnnotation(Type annotationType, List<Object> values, boolean boot) {
137             return new AnnotationElement(annotationType, values, boot);
138         }
139 
140         @Override
newValueDescriptor(String name, Type fieldType, List<AnnotationElement> annos, int dimension, boolean constantPool, String fieldName)141         public ValueDescriptor newValueDescriptor(String name, Type fieldType, List<AnnotationElement> annos, int dimension, boolean constantPool, String fieldName) {
142             return new ValueDescriptor(fieldType, name, annos, dimension, constantPool, fieldName);
143         }
144 
145         @Override
getPlatformRecording(Recording r)146         public PlatformRecording getPlatformRecording(Recording r) {
147             return r.getInternal();
148         }
149 
150         @Override
getPlatformEventType(EventType eventType)151         public PlatformEventType getPlatformEventType(EventType eventType) {
152             return eventType.getPlatformEventType();
153         }
154 
155         @Override
isConstantPool(ValueDescriptor v)156         public boolean isConstantPool(ValueDescriptor v) {
157             return v.isConstantPool();
158         }
159 
160         @Override
setAnnotations(ValueDescriptor v, List<AnnotationElement> a)161         public void setAnnotations(ValueDescriptor v, List<AnnotationElement> a) {
162             v.setAnnotations(a);
163         }
164 
165         @Override
setAnnotations(SettingDescriptor s, List<AnnotationElement> a)166         public void setAnnotations(SettingDescriptor s, List<AnnotationElement> a) {
167            s.setAnnotations(a);
168         }
169 
170         @Override
getFieldName(ValueDescriptor v)171         public String getFieldName(ValueDescriptor v) {
172             return v.getJavaFieldName();
173         }
174 
175         @Override
newValueDescriptor(Class<?> type, String name)176         public ValueDescriptor newValueDescriptor(Class<?> type, String name) {
177             return new ValueDescriptor(type, name, Collections.emptyList(), true);
178         }
179 
180         @Override
newSettingDescriptor(Type type, String name, String defaultValue, List<AnnotationElement> annotations)181         public SettingDescriptor newSettingDescriptor(Type type, String name, String defaultValue, List<AnnotationElement> annotations) {
182             return new SettingDescriptor(type, name, defaultValue, annotations);
183         }
184 
185         @Override
isUnsigned(ValueDescriptor v)186         public boolean isUnsigned(ValueDescriptor v) {
187             return v.isUnsigned();
188         }
189 
190         @Override
getPlatformRecorder()191         public PlatformRecorder getPlatformRecorder() {
192             return FlightRecorder.getFlightRecorder().getInternal();
193         }
194     }
195 
196     /**
197      * Constructs a {@code FlightRecorderPermission} with the specified name.
198      *
199      * @param name the permission name, must be either
200      *        {@code "accessFlightRecorder"} or {@code "registerEvent"}, not
201      *        {@code null}
202      *
203      * @throws IllegalArgumentException if {@code name} is empty or not valid
204      */
FlightRecorderPermission(String name)205     public FlightRecorderPermission(String name) {
206         super(Objects.requireNonNull(name));
207         if (!name.equals(Utils.ACCESS_FLIGHT_RECORDER) && !name.equals(Utils.REGISTER_EVENT)) {
208             throw new IllegalArgumentException("name: " + name);
209         }
210     }
211 }
212