34 Zones extend the isolation of processes beyond what is traditionally provided by UNIX and
35 UNIX-like systems, including OpenBSD. Traditionally, all processes running on an OpenBSD
36 are visible to all other processes. This can be demonstrated by running commands like top(1),
$ ps – ax
37 ps(1), and pgrep(1)/pkill(1), which can show all processes running in a system:
PID |
TT |
STAT |
TIME |
COMMAND |
|
1 |
?? |
I |
0:01.01 |
/ sbin / init |
|
35862 |
?? |
Ip |
0:00.01 |
/ sbin / slaacd |
|
9544 |
?? |
Ip |
0:00.01 |
slaacd : engine ( slaacd ) |
|
33073 |
?? |
IpU |
0:00.01 |
slaacd : frontend ( slaacd ) |
|
96644 |
?? |
IU |
0:00.01 |
/ sbin / dhcpleased |
|
82639 |
?? |
Ip |
0:00.01 |
dhcpleased : engine ( dhcpleased ) |
|
68436 |
?? |
IpU |
0:00.01 |
dhcpleased : frontend ( dhcpleased ) |
|
6881 |
?? |
IpU |
0:00.01 |
/ sbin / resolvd |
|
69588 |
?? |
IpU |
0:00.03 |
syslogd : [ priv ] ( syslogd ) |
|
54598 |
?? |
Spc |
0:00.03 |
/ usr/ sbin / syslogd |
|
14516 |
?? |
IU |
0:00.01 |
pflogd : [ priv ] ( pflogd ) |
|
15079 |
?? |
Spc |
0:00.12 |
pflogd : [ running ] -s 160 -i pflog 0 -f |
/ var/ log / |
pflog |
|||||
94692 |
?? |
S<pc |
0:00.12 |
ntpd : ntp engine ( ntpd ) |
|
37809 |
?? |
Sp |
0:00.26 |
ntpd : dns engine ( ntpd ) |
37682 |
?? |
Ipc |
0:00.02 |
smtpd : queue ( smtpd ) |
97246 |
?? |
Ipc |
0:00.02 |
smtpd : scheduler ( smtpd ) |
48848 |
?? |
IpU |
0:00.00 |
sndiod : helper ( sndiod ) |
47188 |
?? |
I<pc |
0:00.00 |
/ usr/ bin / sndiod |
96369 |
?? |
Ip |
0:00.02 |
/ usr/ sbin / cron |
45067 |
?? |
I |
0:00.07 |
sshd : dlg [ priv ] ( sshd ) |
32638 |
?? |
S |
0:00.03 |
sshd : dlg@ ttyp 0 ( sshd ) |
1730 |
p0 |
Sp |
0:00.02 |
– ksh ( ksh ) |
16990 |
p0 |
R+pU /2 |
0:00.00 |
ps – ax |
33428 |
00 |
I+pU |
0:00.01 |
/ usr/ libexec/ getty std .9600 |
tty00
$ ‘‘‘
38 While all processes are visible to each other, they are restricted from interacting with each
39 other based on the user that each process is running as. A non-root user can only signal their
40 own processes. Attempts to signal processes running as another user fails:
$ whoami dlg
$ ps -U _sndio PID TT STAT 47188 ?? I<pc
TIME COMMAND
0:00.00 / usr/ bin / sndiod
$ kill 47188
ksh : kill: 47188: Operation not permitted
$
41 However, the root user is allowed to signal any process:
$ doas kill 47188
doas ( dlg@ comp 3301 . eait. uq. edu . au) password :
$ ps -U _sndio
PID TT STAT TIME COMMAND
$
43 Zones are implemented for this assignment to add further isolation of processes. Processes
44 running within a zone can only see and interact with processes running within the same zone,
45 regardless of which user within the zone is running the commands. This implementation is
46 loosely modelled on the design of Solaris Zones as described in PSARC/2002/174.
47 The exception to this enhanced isolation is for processes running in the ”global” zone, which is
48 the default zone that is created and exists on boot. Processes running in the global zone can
49 see all other processes in the system, including those running in other (non-global) zones, and
50 the root user in the global zone can signal any of these processes too. However, non-root users
51 in the global zone cannot signal processes in other zones, even if they are running as the same
52 user.
zoneid_t zone_create ( const char * zonename );
58 zone_create() creates a new zone id for use in the system, with a unique name specified by
59 zonename.
60 zone_destroy()
int zone_destroy ( zoneid_t z);
61 zone_destroy() deletes the specified zone instance. The zone must have no running processes
62 inside it for the request to succeed.
63 zone_enter()
int zone_enter( zoneid_t z);
64 zone_enter() moves the current process into the specified zone.
65 zone_list()
int zone_list( zoneid_t * zs , size_t * nzs);
66 In the global zone zone_list() provides the list of zones in the running system as an array of
67 zoneid ts. If run in a non-global zone, the list will only contain the current zone.
68 zone_name()
int zone_name ( zoneid_t z, char * name , size_t namelen );
69 The zone_name() syscall provides the name of the zone identified by the z argument. If run
70 in a non-global zone the z id must be the identifier for the current zone. In the global zone it
71 can be any zone identifier.
72 zone_id()
zoneid_t zone_id ( const char * name);
73 zone_id() provides the id associated with the name zone. If run in a non-global zone, only the
74 current zone name may be specified. If name is a NULL pointer the zone id calling process is
75 running in is returned.
76 zone_stats()
int zone_stats( zoneid_t z, struct zstats * zstats);
77 zone_stats() provides an assortment of operating system statistics resulting from processes
78 in the zone associated with the id z.
83 This syscall will be necessary for you to implement the zone rename subcommand.
usage : |
zone |
create zonename |
1 |
|
zone |
destroy zonename |
2 |
|
zone |
exec zonename command … |
3 |
|
zone |
list |
4 |
|
zone |
id [ zonename ] |
5 |
|
zone |
name [ zid ] |
6 |
|
zone |
stats [- H] [- o property [ ,…] zone […] |
7 |
85 The zone(8) program uses the zone syscalls to allow systems administrators or operators to
86 use the zone subsystem in the kernel.
87 zone create
88 zone create uses the zone_create() syscall to create a zone with the specified name.
89 zone destroy
90 zone destroy uses the zone_destroy() syscall to create a zone with the specified name. If a
91 zone with the specified name does not exist, zone(8) will attempt to interpret the argument
92 as a numeric zone identifier.
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
zone exec
zone exec uses the zone_enter() syscall to move itself into the specified zone, and then executes the program. If a zone with the specified name does not exist, zone(8) will attempt to interpret the argument as a numeric zone identifier.
zone list
zone list uses the zone_list() syscall to fetch a list of ids for the currently running zones, and iterates over it calling the zone_name() syscall to print out the list of zone ids and names.
zone name / zone id
zone name and zone id use their associated syscalls zone_name() and zone_id() to return the name of a zone given its id, or the id of a zone given its name.
zone stats
zone stats uses the zone_stat() syscall to obtain and print out to the user a series of statis- tics from processes running in the current zone. See the manual page in zone(8) for more information.
3.3 Your Tasks
114
115
116
117
118
119
120
121
122
123
124
who are in that group to perform operations on the zone (regardless of whether they are the owner of the zone).
In short, where zones are now only controllable by root, your changes will allow the owner of a zone and a different group of users to control a zone.
The additional sub-commands you will be implementing are: zone rename, which will change the name of a zone; zone chown, which will change the owner of a zone in a manner similar to the existing chown(8); and zone chgrp, which will change the group of a zone in a manner similar to the existing chgrp(8).
-
Instructions
To complete the assignment, you will need to do the following.
-
Apply the diff
-
Fetch https: // stluc. manta. uqcloud. net/ comp3301 / public /2024/ a1 – zones – base. patch
-
Create an a1 branch
– ‘ git checkout -b a1 openbsd-7.5‘
-
Apply the base patch to the a1 branch
1
2
3
4
– ‘ git am / path / to/ a1 – zones – base . patch ‘ in / usr/ src 5
-
Build the kernel 6
-
‘ cd / usr/ src/ sys/ arch / amd64 / compile / GENERIC . MP ‘ 7
-
‘ make obj ‘ 8
-
‘ make config ‘ 9
– ‘ make -j 5 ‘ 10
-
‘ doas make install ‘ 11
-
-
Reboot into the kernel 12
-
‘ doas reboot ‘ 13
-
-
‘ make obj ‘ in / usr/ src 14
-
‘ doas make includes ‘ in / usr/ src/ include 15
-
Verify the zones syscalls are in / usr/ include / sys/ syscall. h 16
-
Verify / usr/ include / sys/ zones. h exists 17
-
-
Make and install libc 18
-
‘ cd / usr/ src/ lib / libc ‘ 19
– ‘ make -j 5 ‘ 20
-
‘ doas make install ‘ 21
-
-
Optional: make ps , and pkill/ pgrep 22
-
make zone (8) 23
-
‘ cd / usr/ src/ usr. sbin / zone ‘ 24
-
‘ make ‘ 25
-
‘ doas make install ‘ 26
-
-
Verify ‘ zone (8)‘ and the zones subsystem works: 27
$ zone list 28
125
126
127
128
$ zone list
ID NAME
0 global
42101 test
$ zone id
37
38
39
40
41
0
42
$ zone id test 42101
43
44
$ zone exec test ps – aux
45
zone : enter: Operation not permitted
46
$ doas zone exec test ps – aux
47
USER
PID % CPU % MEM VSZ
RSS TT
STAT STARTED
TIME
COMMAND
48
root
41705 0.0 0.1 628
580 p0
R+pU /0 3:37 PM
0:00.14
ps – aux
49
$ doas zone exec test zone id
50
42101
51
$ doas zone exec test zone id global
52
zone : id: No such process
53
$
54
As you add the functionality specified in the next sections, some of these steps will be repeated. eg, changing the kernel means rebuilding and installing the kernel. Adding a syscall means making the syscall stub as a function visible in the headers (make includes), and callable through libc.
129
130
131
132
133
134
135
136
137
138
139
A note on errors
We have over-specified the errors you should return from your syscalls – if you do not require an error code (for example, never returning ENOMEM on memory failures because you never allocate any memory) then you do not have to use it. The reverse is also true – if you find an error case that is not listed, choose an appropriate error from errno(2). We will not explicitly test all errors, but during your code interview, we will expect you to be able to explain the suitability of the error codes you use.
-
-
Zone Rename
The zone(8) commands should be extended to enable renaming of zones. Zones should only be able to be renamed by the owner, root, or members of the zone’s group. Additionally, the global zone cannot be renamed, and zone names must be unique.
$ zone usage :
zone
create zonename
1
2
zone
destroy zonename
3
zone
exec zonename command …
4
zone
list
5
zone
name [ id]
6
zone
id [ zonename ]
7
ID NAME
0 global
289 bar
$ doas zone rename 0 something zone : rename: Invalid Argument
$ doas zone rename 289 global zone : rename: File exists
16
17
18
19
20
21
22
140
141
142
143
144
145
146
147
148
149
150
-
Modifications to Existing Syscalls
zone_create() syscall
The zone_create() syscall should now ensure that the created zone is associated with the group of the user that created it, as well as the user themself. Additionally, this will mean ensuring that non-root users can create zones. The definition of zone_create() should not change – it should still take a single char *zonename as its argument.
All other syscalls
The full suite of zone_* syscalls should permit users with matching credentials (owner or group) to perform zone operations on them, not only the root user. The credentials may be changed
so appropriate synchronisation should be used. Namely, we expect that, unless credentials are being changed by another thread, authorisation should be non-blocking.
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
-
Zone name and zone list
zone_name() syscall
The zone_name() syscall should be renamed to zone_info(). Subsequently, it should return not only the name and namelen, but also the zone, user and group id, preferably all bundled in a struct format. However you may pass back one or more of these as individual parameters if that is easier. The zone(8) userland sub-command for zone name should also be modified in line with these changes – the name should be changed to zone info and the additional information should be provided to the user. Alternatively, you may also create zone info as an independent command.
zone list
The zone list subcommand should now take flags: -o and -g. If the -o flag is provided, the owner of the zone should be printed, and if the -g flag is provided, the zone’s group should be printed. If both flags are provided, print both. The extra fields should be printed as extra columns in the current table format. zone id and name must be displayed first. However, the order of the additional fields does not matter.
-
Zone chown and chgrp
-
The zone(8) commands and the kernel zones system should be extended to enable changing
171
172
173
174
175
176
177
178
4
zone exec zonename command … zone list
zone name [zoneid] zone id [ zonename ] zone chown zone user zone chgrp zone group
5
6
7
8
9
The two subcommands you are adding are zone chown and zone chgrp. zone chown takes the name of a zone and uses the zone_chown() syscall to change its owner to the user with the specified name. If a zone with the name zonename does not exist, zone(8) will attempt to interpret the argument as a numeric zone identifier.
zone chgrp behaves similarly, but instead, it uses the zone_chgrp() syscall to change the zone’s group to the specified group name.
To support these subcommands, you will need to implement the following system calls:
zone_chown() syscall
int zone_chown ( zoneid_t z, uid_t user);
179
180
181
182
The zone_chown() syscall alters the owner of the zone identified by the z argument. The new owner should be the owner identified by the user argument. If called from a non-global zone, then the z id must be the identifier for the current zone, but in the global zone, it can be any zone identifier. This means that to the user, a non-global zone should only be able to see itself.
183 Potential Errors:
184 • EPERM – the user does not have permission to alter the zone z
185 • ESRCH – the zone identified by z does not exist
186 • ENOMEM – the system was not able to allocate memory
187 • EINVAL – the zone to alter was the global zone
188 zone_chgrp() syscall
int zone_chgrp ( zoneid_t z, gid_t group );
189
190
191
192
193
194
195
196
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
The zone_chgrp() syscall alters the owner of the zone identified by the z argument. The new owner should be the group identified by the group argument. If called from a non-global zone, then the z id must be the identifier for the current zone, but in the global zone, it can be any zone identifier. This means that to the user, a non-global zone should only be able to see itself.
Potential Errors:
-
EPERM – the user does not have permission to alter the zone z
-
ESRCH – the zone identified by z does not exist
-
ENOMEM – the system was not able to allocate memory
Your code is to be written according to OpenBSD’s style guide, as per the style(9) man page. An automatic tool for checking for style violations is available at: https://stluc.manta.uqcloud.net/comp3301/public/2022/cstyle.pl
This tool will be used to calculate your style marks for this assignment.
-
-
Compilation
Your code for this assignment is to be built on an amd64 OpenBSD 7.5 system identical to your course-provided VM.
The following steps must succeed:
-
make obj; make config; make in src/sys/arch/amd64/compile/GENERIC.MP
-
make obj; make includes in src
-
make obj; make; make install in src/lib/libc
-
make obj; make; make install in src/usr.sbin/zone
The existing Makefiles in the provided code are functional as-is, but may need modification as part of your work for this assignment. Note that the existing Makefile ensures the -Wall flag is passed to the compiler, as well as a few other warning and error-related flags.
216
217
218
219
220
221
222
-
-
Provided code
-
The provided code, which forms the basis for this assignment, can be downloaded as a single patch file at:
https://stluc.manta.uqcloud.net/comp3301/public/2024/a1-zones-base.patch
You should create a new a1 branch in your repository based on the openbsd-7.5 tag using git checkout, and then apply this base patch using the git am command:
$ git checkout -b a1 openbsd -7.5
$ ftp https: // stluc. manta. uqcloud. net/ comp3301 / public /2024/ a1 – zones – base. patch
$ git am < a1 – zones – base . patch
$ git push origin a1
1
2
3
4
224 The following order will likely be the most reasonable way to complete this assignment:
225 1. Download, build, and install the zones patch.
226 2. Add the zone rename subcommand to zone(8).
231
232
233
234
235
236
237
238
239
240
-
Add the corresponding zone chown and zone chgrp commands to zone(8).
-
Fix up any tiny bugs and ensure it’s all working. But you did that as you were going… right?
Additionally, it is strongly recommended (and in some cases, required) that the following APIs be considered for use as part of your changes:
-
sys/ucred.h – provides necessary handlers for dealing with user and group credentials
-
copyin(9)/copyout(9) – provides the ability to copy data across the userspace boundary
-
user_from_uid(3) – conversions from group/user name to id and back
-
strtonum(3) – BSD style safe string to int conversions
-
Finally, you may wish to look at the header file sys/proc.h to see how user and group credentials are currently stored by threads.
-
241
242
243
244
245
246
247
248
249
250
251
252
253
-
Reflection
Provide a reflection on your implementation by briefly answering the following questions:
-
Describe the steps you took or draw a flowchart.
-
Describe an error that you encountered.
-
Describe how the error was debugged.
-
Describe how the bug was solved.
Upload your answers as a pdf to the Blackboard a1 reflection submission. Page length is a maximum 2 pages or less. Pdf name must be your STUDENT NUMBER a1.pdf. Note this is your XXXXXXXX ID number and not sXXXXXXX login.
-
-
Submission
Submission must be made electronically by committing to your course-provided Git repository on source.eait.uq.edu.au. In order to mark your assignment the markers will check out the a1 branch from your repository. Code checked into any other branch in your repository will
260
261
262
263
264
265
266
-
The openbsd-7.5 base commit
-
The A1 base patch commit
-
Your commit(s) for adding the required functionality
-
Your submission will be marked by course tutors and staff, during an in-person demo with you, at your lab session during the due week. You must attend your session, in-person, otherwise your submission will not be marked. Online attendence, e.g. zoom, is not permitted.
Reviews
There are no reviews yet.