1 | /****************************************************************************** |
---|
2 | * acm_ops.c |
---|
3 | * |
---|
4 | * Copyright (C) 2005 IBM Corporation |
---|
5 | * |
---|
6 | * Author: |
---|
7 | * Reiner Sailer <sailer@watson.ibm.com> |
---|
8 | * |
---|
9 | * This program is free software; you can redistribute it and/or |
---|
10 | * modify it under the terms of the GNU General Public License as |
---|
11 | * published by the Free Software Foundation, version 2 of the |
---|
12 | * License. |
---|
13 | * |
---|
14 | * Process acm command requests from guest OS. |
---|
15 | */ |
---|
16 | |
---|
17 | #include <xen/config.h> |
---|
18 | #include <xen/types.h> |
---|
19 | #include <xen/lib.h> |
---|
20 | #include <xen/mm.h> |
---|
21 | #include <public/acm.h> |
---|
22 | #include <public/acm_ops.h> |
---|
23 | #include <xen/sched.h> |
---|
24 | #include <xen/event.h> |
---|
25 | #include <xen/trace.h> |
---|
26 | #include <xen/console.h> |
---|
27 | #include <xen/guest_access.h> |
---|
28 | #include <acm/acm_hooks.h> |
---|
29 | |
---|
30 | #ifndef ACM_SECURITY |
---|
31 | |
---|
32 | long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg) |
---|
33 | { |
---|
34 | return -ENOSYS; |
---|
35 | } |
---|
36 | |
---|
37 | #else |
---|
38 | |
---|
39 | int acm_authorize_acm_ops(struct domain *d) |
---|
40 | { |
---|
41 | return (IS_PRIV(d) ? 0 : -EPERM); |
---|
42 | } |
---|
43 | |
---|
44 | long do_acm_op(int cmd, XEN_GUEST_HANDLE(void) arg) |
---|
45 | { |
---|
46 | long rc = -EFAULT; |
---|
47 | |
---|
48 | if ( acm_authorize_acm_ops(current->domain) ) |
---|
49 | return -EPERM; |
---|
50 | |
---|
51 | switch ( cmd ) |
---|
52 | { |
---|
53 | |
---|
54 | case ACMOP_setpolicy: { |
---|
55 | struct acm_setpolicy setpolicy; |
---|
56 | if (copy_from_guest(&setpolicy, arg, 1) != 0) |
---|
57 | return -EFAULT; |
---|
58 | if (setpolicy.interface_version != ACM_INTERFACE_VERSION) |
---|
59 | return -EACCES; |
---|
60 | |
---|
61 | rc = acm_set_policy(setpolicy.pushcache, |
---|
62 | setpolicy.pushcache_size); |
---|
63 | break; |
---|
64 | } |
---|
65 | |
---|
66 | case ACMOP_getpolicy: { |
---|
67 | struct acm_getpolicy getpolicy; |
---|
68 | if (copy_from_guest(&getpolicy, arg, 1) != 0) |
---|
69 | return -EFAULT; |
---|
70 | if (getpolicy.interface_version != ACM_INTERFACE_VERSION) |
---|
71 | return -EACCES; |
---|
72 | |
---|
73 | rc = acm_get_policy(getpolicy.pullcache, |
---|
74 | getpolicy.pullcache_size); |
---|
75 | break; |
---|
76 | } |
---|
77 | |
---|
78 | case ACMOP_dumpstats: { |
---|
79 | struct acm_dumpstats dumpstats; |
---|
80 | if (copy_from_guest(&dumpstats, arg, 1) != 0) |
---|
81 | return -EFAULT; |
---|
82 | if (dumpstats.interface_version != ACM_INTERFACE_VERSION) |
---|
83 | return -EACCES; |
---|
84 | |
---|
85 | rc = acm_dump_statistics(dumpstats.pullcache, |
---|
86 | dumpstats.pullcache_size); |
---|
87 | break; |
---|
88 | } |
---|
89 | |
---|
90 | case ACMOP_getssid: { |
---|
91 | struct acm_getssid getssid; |
---|
92 | ssidref_t ssidref; |
---|
93 | |
---|
94 | if (copy_from_guest(&getssid, arg, 1) != 0) |
---|
95 | return -EFAULT; |
---|
96 | if (getssid.interface_version != ACM_INTERFACE_VERSION) |
---|
97 | return -EACCES; |
---|
98 | |
---|
99 | if (getssid.get_ssid_by == ACM_GETBY_ssidref) |
---|
100 | ssidref = getssid.id.ssidref; |
---|
101 | else if (getssid.get_ssid_by == ACM_GETBY_domainid) |
---|
102 | { |
---|
103 | struct domain *subj = rcu_lock_domain_by_id(getssid.id.domainid); |
---|
104 | if (!subj) |
---|
105 | { |
---|
106 | rc = -ESRCH; /* domain not found */ |
---|
107 | break; |
---|
108 | } |
---|
109 | if (subj->ssid == NULL) |
---|
110 | { |
---|
111 | rcu_unlock_domain(subj); |
---|
112 | rc = -ESRCH; |
---|
113 | break; |
---|
114 | } |
---|
115 | ssidref = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; |
---|
116 | rcu_unlock_domain(subj); |
---|
117 | } |
---|
118 | else |
---|
119 | { |
---|
120 | rc = -ESRCH; |
---|
121 | break; |
---|
122 | } |
---|
123 | rc = acm_get_ssid(ssidref, getssid.ssidbuf, getssid.ssidbuf_size); |
---|
124 | break; |
---|
125 | } |
---|
126 | |
---|
127 | case ACMOP_getdecision: { |
---|
128 | struct acm_getdecision getdecision; |
---|
129 | ssidref_t ssidref1, ssidref2; |
---|
130 | |
---|
131 | if (copy_from_guest(&getdecision, arg, 1) != 0) |
---|
132 | return -EFAULT; |
---|
133 | if (getdecision.interface_version != ACM_INTERFACE_VERSION) |
---|
134 | return -EACCES; |
---|
135 | |
---|
136 | if (getdecision.get_decision_by1 == ACM_GETBY_ssidref) |
---|
137 | ssidref1 = getdecision.id1.ssidref; |
---|
138 | else if (getdecision.get_decision_by1 == ACM_GETBY_domainid) |
---|
139 | { |
---|
140 | struct domain *subj = rcu_lock_domain_by_id(getdecision.id1.domainid); |
---|
141 | if (!subj) |
---|
142 | { |
---|
143 | rc = -ESRCH; /* domain not found */ |
---|
144 | break; |
---|
145 | } |
---|
146 | if (subj->ssid == NULL) |
---|
147 | { |
---|
148 | rcu_unlock_domain(subj); |
---|
149 | rc = -ESRCH; |
---|
150 | break; |
---|
151 | } |
---|
152 | ssidref1 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; |
---|
153 | rcu_unlock_domain(subj); |
---|
154 | } |
---|
155 | else |
---|
156 | { |
---|
157 | rc = -ESRCH; |
---|
158 | break; |
---|
159 | } |
---|
160 | if (getdecision.get_decision_by2 == ACM_GETBY_ssidref) |
---|
161 | ssidref2 = getdecision.id2.ssidref; |
---|
162 | else if (getdecision.get_decision_by2 == ACM_GETBY_domainid) |
---|
163 | { |
---|
164 | struct domain *subj = rcu_lock_domain_by_id(getdecision.id2.domainid); |
---|
165 | if (!subj) |
---|
166 | { |
---|
167 | rc = -ESRCH; /* domain not found */ |
---|
168 | break;; |
---|
169 | } |
---|
170 | if (subj->ssid == NULL) |
---|
171 | { |
---|
172 | rcu_unlock_domain(subj); |
---|
173 | rc = -ESRCH; |
---|
174 | break; |
---|
175 | } |
---|
176 | ssidref2 = ((struct acm_ssid_domain *)(subj->ssid))->ssidref; |
---|
177 | rcu_unlock_domain(subj); |
---|
178 | } |
---|
179 | else |
---|
180 | { |
---|
181 | rc = -ESRCH; |
---|
182 | break; |
---|
183 | } |
---|
184 | rc = acm_get_decision(ssidref1, ssidref2, getdecision.hook); |
---|
185 | |
---|
186 | if (rc == ACM_ACCESS_PERMITTED) |
---|
187 | { |
---|
188 | getdecision.acm_decision = ACM_ACCESS_PERMITTED; |
---|
189 | rc = 0; |
---|
190 | } |
---|
191 | else if (rc == ACM_ACCESS_DENIED) |
---|
192 | { |
---|
193 | getdecision.acm_decision = ACM_ACCESS_DENIED; |
---|
194 | rc = 0; |
---|
195 | } |
---|
196 | else |
---|
197 | rc = -ESRCH; |
---|
198 | |
---|
199 | if ( (rc == 0) && (copy_to_guest(arg, &getdecision, 1) != 0) ) |
---|
200 | rc = -EFAULT; |
---|
201 | break; |
---|
202 | } |
---|
203 | |
---|
204 | case ACMOP_chgpolicy: { |
---|
205 | struct acm_change_policy chgpolicy; |
---|
206 | |
---|
207 | if (copy_from_guest(&chgpolicy, arg, 1) != 0) |
---|
208 | return -EFAULT; |
---|
209 | if (chgpolicy.interface_version != ACM_INTERFACE_VERSION) |
---|
210 | return -EACCES; |
---|
211 | |
---|
212 | rc = acm_change_policy(&chgpolicy); |
---|
213 | |
---|
214 | if (rc == 0) |
---|
215 | if (copy_to_guest(arg, &chgpolicy, 1) != 0) |
---|
216 | rc = -EFAULT; |
---|
217 | break; |
---|
218 | } |
---|
219 | |
---|
220 | case ACMOP_relabeldoms: { |
---|
221 | struct acm_relabel_doms relabeldoms; |
---|
222 | |
---|
223 | if (copy_from_guest(&relabeldoms, arg, 1) != 0) |
---|
224 | return -EFAULT; |
---|
225 | if (relabeldoms.interface_version != ACM_INTERFACE_VERSION) |
---|
226 | return -EACCES; |
---|
227 | |
---|
228 | rc = acm_relabel_domains(&relabeldoms); |
---|
229 | |
---|
230 | if (rc == 0) |
---|
231 | if (copy_to_guest(arg, &relabeldoms, 1) != 0) |
---|
232 | rc = -EFAULT; |
---|
233 | break; |
---|
234 | } |
---|
235 | |
---|
236 | default: |
---|
237 | rc = -ENOSYS; |
---|
238 | break; |
---|
239 | } |
---|
240 | |
---|
241 | return rc; |
---|
242 | } |
---|
243 | |
---|
244 | #endif /* defined(ACM_SECURITY) */ |
---|
245 | |
---|
246 | /* |
---|
247 | * Local variables: |
---|
248 | * mode: C |
---|
249 | * c-set-style: "BSD" |
---|
250 | * c-basic-offset: 4 |
---|
251 | * tab-width: 4 |
---|
252 | * indent-tabs-mode: nil |
---|
253 | * End: |
---|
254 | */ |
---|