1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.seccomp.cts.app;
18 
19 import android.content.pm.ApplicationInfo;
20 import android.os.Process;
21 import android.os.UserHandle;
22 import android.util.Log;
23 
24 public class ZygotePreload implements android.app.ZygotePreload {
25     static final String TAG = "SeccompDeviceTest";
26 
27     static volatile boolean sResult = false;
28     static volatile int sStartOfIsolatedRange = -1;
29 
testSetResUidGidBlocked(int rid, int eid, int sid, boolean expectBlocked, boolean log)30     static private boolean testSetResUidGidBlocked(int rid, int eid, int sid,
31             boolean expectBlocked, boolean log) {
32         boolean blocked = SeccompDeviceTest.testSetresuidBlocked(rid, eid, sid);
33         if (blocked != expectBlocked) {
34             if (log) {
35                 Log.e(TAG, "setresuid( " + Integer.toString(rid) + ","
36                         + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
37                         + " is wrongly " + (expectBlocked ? "allowed." : "blocked."));
38             }
39             return false;
40         }
41 
42         blocked = SeccompDeviceTest.testSetresgidBlocked(rid, eid, sid);
43         if (blocked != expectBlocked) {
44             if (log) {
45                 Log.e(TAG, "setresguid( " + Integer.toString(rid) + ","
46                         + Integer.toString(eid) + "," + Integer.toString(sid) + ")"
47                         + " is wrongly " + (expectBlocked ? "allowed." : "blocked."));
48             }
49             return false;
50         }
51 
52         return true;
53     }
54 
testSetResUidGidBlocked(int rid, int eid, int sid)55     static private boolean testSetResUidGidBlocked(int rid, int eid, int sid) {
56         return testSetResUidGidBlocked(rid, eid, sid, true /*expectBlocked */, true /* log */);
57     }
58 
testSetResUidGidAllowed(int rid, int eid, int sid)59     static private boolean testSetResUidGidAllowed(int rid, int eid, int sid) {
60         return testSetResUidGidBlocked(rid, eid, sid, false /*expectBlocked */, true /* log */);
61     }
62 
testSetResUidGidAllowedNoLog(int rid, int eid, int sid)63     static private boolean testSetResUidGidAllowedNoLog(int rid, int eid, int sid) {
64         return testSetResUidGidBlocked(rid, eid, sid, false /*expectBlocked */, false /* log */);
65     }
66 
getSeccomptestResult()67     static synchronized public boolean getSeccomptestResult() {
68         return sResult;
69     }
70 
getStartOfIsolatedRange()71     static synchronized public int getStartOfIsolatedRange() {
72         return sStartOfIsolatedRange;
73     }
74 
75     /*
76      * This is called from the app_zygote security context, which has two seccomp
77      * filters in place:
78      * 1) The regular app seccomp filter (which allows setresuid/setresgid)
79      * 2) A setresuid/setresgid limiting filter, which restricts the calls to
80      *    setresuid/setresgid to be in a particular range.
81      *
82      * This test enforces 2) is in place.
83      */
84     @Override
doPreload(ApplicationInfo appInfo)85     synchronized public void doPreload(ApplicationInfo appInfo) {
86         boolean result = true;
87 
88         // root uid
89         result &= testSetResUidGidBlocked(0, 0, 0);
90         // system uid
91         result &= testSetResUidGidBlocked(Process.SYSTEM_UID, Process.SYSTEM_UID,
92                 Process.SYSTEM_UID);
93         // mix of uids
94         result &= testSetResUidGidBlocked(0, Process.SYSTEM_UID,
95                 Process.SYSTEM_UID);
96 
97         // an app uid for the current user, and another user
98         for (int userId = UserHandle.myUserId(); userId <= UserHandle.myUserId() + 1; userId++) {
99             int appStart = UserHandle.getUid(userId, Process.FIRST_APPLICATION_UID);
100             result &= testSetResUidGidBlocked(appStart, appStart, appStart);
101             int appEnd = UserHandle.getUid(userId, Process.LAST_APPLICATION_UID);
102             result &= testSetResUidGidBlocked(appEnd, appEnd, appEnd);
103         }
104 
105         // an isolated process uid for the current user, and another user
106         for (int userId = UserHandle.myUserId(); userId <= UserHandle.myUserId() + 1; userId++) {
107             int regularIsolatedStart = UserHandle.getUid(userId, Process.FIRST_ISOLATED_UID);
108             result &= testSetResUidGidBlocked(regularIsolatedStart, regularIsolatedStart,
109                     regularIsolatedStart);
110             int regularIsolatedEnd = UserHandle.getUid(userId, Process.LAST_ISOLATED_UID);
111             result &= testSetResUidGidBlocked(regularIsolatedEnd, regularIsolatedEnd,
112                     regularIsolatedEnd);
113         }
114 
115         // Test all ranges of app zygote UIDs; we don't know here which
116         // isolated UID is assigned to our process, so we will test all ranges,
117         // and verify only one is allowed; then have the caller verify that
118         // this was indeed our allowed range.
119         int isolatedUserStart = UserHandle.getUid(UserHandle.myUserId(),
120                 Process.FIRST_APP_ZYGOTE_ISOLATED_UID);
121         int isolatedUserEnd = UserHandle.getUid(UserHandle.myUserId(),
122                 Process.LAST_APP_ZYGOTE_ISOLATED_UID);
123 
124         for (int i = isolatedUserStart; i < isolatedUserEnd; i += Process.NUM_UIDS_PER_APP_ZYGOTE) {
125             boolean rangeAllowed = testSetResUidGidAllowedNoLog(i, i, i);
126             if (rangeAllowed) {
127                 if (sStartOfIsolatedRange != -1) {
128                     Log.e(TAG, "Found more than one allowed isolated UID range: "
129                             + sStartOfIsolatedRange + ", " + i);
130                     result = false;
131                     break;
132                 }
133                 sStartOfIsolatedRange = i;
134 
135                 // off-by-one and some variants
136                 result &= testSetResUidGidBlocked(i - 1, i - 1, i - 1);
137                 result &= testSetResUidGidBlocked(i, i - 1, i);
138                 result &= testSetResUidGidBlocked(i, i, i - 1);
139                 int overEndOfRange = i + Process.NUM_UIDS_PER_APP_ZYGOTE;
140                 result &= testSetResUidGidBlocked(overEndOfRange, overEndOfRange, overEndOfRange);
141                 result &= testSetResUidGidBlocked(overEndOfRange, i, i);
142                 result &= testSetResUidGidBlocked(i, overEndOfRange, overEndOfRange);
143 
144                 // mixed allowed rgid with dis-allowed euid and suid (and variants)
145                 result &= testSetResUidGidBlocked(i, 0, 0);
146                 result &= testSetResUidGidBlocked(i, 0, i);
147                 result &= testSetResUidGidBlocked(i, i, 0);
148                 result &= testSetResUidGidBlocked(0, i, 0);
149                 result &= testSetResUidGidBlocked(0, i, i);
150                 result &= testSetResUidGidBlocked(0, 0, i);
151             }
152         }
153 
154         result &= testSetResUidGidBlocked(Process.LAST_APP_ZYGOTE_ISOLATED_UID + 1,
155                 Process.LAST_APP_ZYGOTE_ISOLATED_UID + 1, Process.LAST_APP_ZYGOTE_ISOLATED_UID + 1);
156 
157         // Store result
158         sResult = result;
159     }
160 }
161