Skip to content

Commit 8cec05e

Browse files
authored
Add files via upload
1 parent 84fcb99 commit 8cec05e

6 files changed

Lines changed: 604 additions & 73 deletions

File tree

Makefile

Lines changed: 8 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,8 @@
1-
# Generic Makefile for project automation
2-
# Customize these targets based on your technology stack
3-
4-
.PHONY: help setup run test lint build clean install
5-
6-
# Default target shows help
7-
.DEFAULT_GOAL := help
8-
9-
help: ## Show this help message
10-
@echo "Available targets:"
11-
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
12-
13-
setup: ## Install dependencies and pre-commit hooks
14-
@echo "Setting up project..."
15-
@echo "TODO: Add your setup commands here"
16-
@echo "Examples:"
17-
@echo " - Python: pip install -r requirements.txt && pre-commit install"
18-
@echo " - Node.js: npm install && npm run prepare"
19-
@echo " - Go: go mod download"
20-
@echo " - Java: mvn install"
21-
22-
run: ## Run the application
23-
@echo "Running application..."
24-
@echo "TODO: Add your run command here"
25-
@echo "Examples:"
26-
@echo " - Python: python src/main.py"
27-
@echo " - Node.js: node src/index.js"
28-
@echo " - Go: go run src/main.go"
29-
@echo " - Java: java -jar target/app.jar"
30-
31-
test: ## Run tests
32-
@echo "Running tests..."
33-
@echo "TODO: Add your test command here"
34-
@echo "Examples:"
35-
@echo " - Python: pytest tests/"
36-
@echo " - Node.js: npm test"
37-
@echo " - Go: go test ./..."
38-
@echo " - Java: mvn test"
39-
40-
lint: ## Run code linter
41-
@echo "Running linter..."
42-
@echo "TODO: Add your linting command here"
43-
@echo "Examples:"
44-
@echo " - Python: pylint src/ or flake8 src/"
45-
@echo " - Node.js: npm run lint or eslint src/"
46-
@echo " - Go: golangci-lint run"
47-
@echo " - Java: mvn checkstyle:check"
48-
49-
build: ## Build the project
50-
@echo "Building project..."
51-
@echo "TODO: Add your build command here"
52-
@echo "Examples:"
53-
@echo " - Python: pip install -e ."
54-
@echo " - Node.js: npm run build"
55-
@echo " - Go: go build -o bin/app"
56-
@echo " - Java: mvn package"
57-
58-
clean: ## Clean build artifacts
59-
@echo "Cleaning build artifacts..."
60-
@echo "TODO: Add cleanup commands here"
61-
@echo "Examples:"
62-
@echo " - rm -rf build/ dist/ *.egg-info __pycache__"
63-
@echo " - rm -rf node_modules/.cache"
64-
@echo " - go clean"
65-
66-
install: ## Install dependencies
67-
@echo "Installing dependencies..."
68-
@echo "TODO: Add your install command here"
69-
@echo "Examples:"
70-
@echo " - Python: pip install -r requirements.txt"
71-
@echo " - Node.js: npm install"
72-
@echo " - Go: go mod download"
73-
@echo " - Java: mvn install"
1+
obj-m := message_slot.o
2+
KDIR := /lib/modules/$(shell uname -r)/build
3+
PWD := $(shell pwd)
4+
all:
5+
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
6+
7+
clean:
8+
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

instructions_kernel.txt

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
OperatingSystems(0368216208)
2+
MessageSlotKernelModuleAssignment
3+
Duedate(viamoodle):December28th,23:59
4+
Individualworkpolicy
5+
Theworkyousubmitinthiscourseisrequiredtobetheresultofyourindividualeffort
6+
only.Youmaydiscussconceptsandideaswithothers,butyoumustprogramindividually.
7+
Youshouldneverobserveanotherstudent’scode, fromthisorprevioussemesters.
8+
Studentsviolatingthispolicywill receiveacoursegradeof 250(“didnot completecourse
9+
requirements”).
10+
AIUsagePolicy
11+
AI tools(ChatGPT,Claude,Copilot, etc.)maybeusedfor learningconceptsand
12+
understandingsystemcalls,butthecoursematerial isyourprimaryresource.
13+
Youmustunderstandandbeabletoexplaineverylineofcodeyousubmit.Submittingcodeyou
14+
don’tunderstandviolatestheindividualworkpolicy.
15+
Requireddocumentation:IfyouuseAItools,addacommentattheendofyourmessage_slot.c
16+
filewithalinktoyourconversation(e.g.,//AIchat:https://...).
17+
1 Introduction
18+
Note:Wehighlyrecommendreviewingtheexamplesfromtherecitationsregarding
19+
loadablekernelmodulesbeforebeginningthisassignment.
20+
Thegoalofthisassignment istogainexperiencewithkernelprogrammingand,particularly,
21+
abetterunderstandingonthedesignandimplementationof inter-processcommunication(IPC),
22+
kernelmodules,anddrivers.
23+
Inthisassignment,youwill implementakernelmodulethatprovidesanewIPCmechanism,
24+
calledamessageslot.Amessageslotisacharacterdevicefilethroughwhichprocessescommunicate.
25+
Amessageslotdevicehasmultiplemessagechannelsactiveconcurrently,whichcanbeusedby
26+
multipleprocesses.Afteropeningamessageslotdevicefile,aprocessusesioctl()tospecifythe
27+
idof themessagechannel itwantstouse. Itsubsequentlyusesread()/write()toreceive/send
28+
messagesonthechannel. Incontrasttopipes,amessagechannelpreservesamessageuntil it
29+
isoverwritten,sothesamemessagecanbereadmultipletimes.
30+
2 Messageslotspecification
31+
Amessageslotappearsinthesystemasacharacterdevicefile.Thisdevicefileismanagedbythe
32+
messageslotdevicedriver,whichyouwill implement.Amessageslot isapseudodevice: itdoesn’t
33+
1
34+
correspond to a physical hardware device, and therefore all its functionality is provided by the
35+
device driver.
36+
Message slot device files. A device file has a major number and a minor number. The major
37+
number tells the kernel which driver is associated with the device file. The minor number is used
38+
internally by the driver for its own purposes.
39+
In our case: There can be several message slot files, which correspond to different message slots.
40+
All of these files are managed by your driver, i.e., they all have the same major number, which
41+
is hard-coded to 235. However, different message slot files will have different minor numbers,
42+
allowing your driver to distinguish between them.
43+
Device files are created with the mknod command, which takes as arguments the file’s major and
44+
minor numbers. For example:
45+
mknod /dev/slot0 c 235 0
46+
The above command creates a character device file /dev/slot0 with major number 235 (i.e., a
47+
message slot) and minor number 0. Then, a subsequent command creates another message slot file:
48+
mknod /dev/slot1 c 235 1
49+
2.1 Semantics of message slot file operations
50+
The message slot driver has special semantics for the ioctl, write, and read file operations, as
51+
described below. Note that the description is given in the style of a manual page, and specifies the
52+
behavior from the perspective of the processes using the driver. One of your tasks is to figure out
53+
how to implement the module so that it provides the specified behavior.
54+
2.1.1 ioctl()
55+
A message slot supports two ioctl commands:
56+
1. MSG_SLOT_CHANNEL: Takes a single unsigned int parameter that specifies a non-zero channel
57+
id. Invoking this ioctl() sets the file descriptor’s channel id. Subsequent reads/writes on this
58+
f
59+
ile descriptor will receive/send messages on the specified channel.
60+
2. MSG_SLOT_SET_CEN: Takes a single unsigned int parameter that specifies the censorship mode
61+
(0 for disabled, 1 for enabled). When censorship is enabled, messages written to the channel will
62+
be censored using a simple algorithm: every 4th character in the message is replaced with ’#’.
63+
The censorship state is maintained per file descriptor.
64+
Note: The default state is uncensored (mode 0). You can write to the channel immediately after
65+
setting the channel ID; invoking MSG_SLOT_SET_CEN is only required if you wish to change this
66+
default behavior.
67+
Error cases:
68+
• If the passed command is not MSG_SLOT_CHANNEL or MSG_SLOT_SET_CEN, the ioctl() returns-1
69+
and errno is set to EINVAL.
70+
• If the passed channel id is 0 (for MSG_SLOT_CHANNEL), the ioctl() returns-1 and errno is set
71+
to EINVAL.
72+
2
73+
2.1.2 write()
74+
Writes a non-empty message of up to 128 bytes from the user’s buffer to the channel. Returns the
75+
number of bytes written, unless an error occurs. (Note that the message can contain any sequence
76+
of bytes, it is not necessarily a C string.)
77+
Error cases:
78+
• If no channel has been set on the file descriptor, returns-1 and errno is set to EINVAL.
79+
• If the passed message length is 0 or more than 128, returns-1 and errno is set to EMSGSIZE.
80+
• In any other error case (for example, failing to allocate memory), returns-1 and errno is set
81+
appropriately (you are free to choose the exact value).
82+
Censorship: When censorship is enabled for the file descriptor (set via MSG_SLOT_SET_CEN), the
83+
message is censored before being stored in the channel. The censorship algorithm replaces every 4th
84+
character (e.g., positions 3, 7, 11, etc., using 0-based indexing) with ’#’. The censored message is
85+
what gets stored and will be returned by subsequent reads.
86+
2.1.3 read()
87+
Reads the last message written on the channel into the user’s buffer. Returns the number of bytes
88+
read, unless an error occurs:
89+
Error cases:
90+
• If no channel has been set on the file descriptor, returns-1 and errno is set to EINVAL.
91+
• If no message exists on the channel, returns-1 and errno is set to EWOULDBLOCK.
92+
• If the provided buffer length is too small to hold the last message written on the channel, returns-1 and errno is set to ENOSPC.
93+
• In any other error case (for example, failing to allocate memory), returns-1 and errno is set
94+
appropriately (you are free to choose the exact value).
95+
Censorship: Reading from a channel always returns the stored message exactly as it was written.
96+
If a message was written with censorship enabled, read() will return the censored version (with ’#’
97+
characters). If a message was written without censorship, read() will return the original message.
98+
IMPORTANT: Message slot reads/write should be atomic: they should always read/write the
99+
entire passed message and not parts of it. So a successful write() always returns the number of
100+
bytes in the supplied message and a successful read() returns the number of bytes in the last
101+
message written on the channel.
102+
3 Assignment description
103+
Implement the following:
104+
1. message_slot: A kernel module implementing the message slot IPC mechanism.
105+
2. message_sender: A user space program to send a message.
106+
3. message_reader: A user space program to read a message.
107+
3
108+
3.1 Message slot kernel module (device driver)
109+
Implement the module in files named message_slot.c and message_slot.h:
110+
1. The module should use the hard-coded major number 235. (The proper way to implement a
111+
character device driver is to dynamically allocate a major number, as seen in the recitation, but
112+
we will use a hard-coded major number for simplicity.)
113+
2. If module initialization fails, print an error message using printk(KERN_ERR ...).
114+
3. The module should implement the file operations needed to provide the message slot interface:
115+
device_open, device_ioctl, device_read, and device_write. Implement these operations
116+
any way you like, as long as the module provides the message slot interface specified above. You
117+
might find these suggestions useful:
118+
• You’ll need a data structure to describe individual message slots (device files with different
119+
minor numbers). In device_open(), the module can check if it has already created a data
120+
structure for the file being opened, and create one if not. You can get the opened file’s minor
121+
number using the iminor() kernel function (applied to the struct inode* argument of
122+
device_open()).
123+
• device_ioctl() needs to associate the passed channel id with the file descriptor it was
124+
invoked on. You can use the void* private_data field in the file structure parameter
125+
for this purpose. For example: file->private_data = (void*) 3. Check <linux/fs.h>
126+
for the details on struct file.
127+
4. Bounds on number of messages channels and message slots:
128+
• For each message slot file, assume that no more than 220 message channels will be used.
129+
This does not mean that the channel ids will be smaller than 220, just that you need to
130+
support at most 220 different ids.
131+
• If you use register_chrdev() to register your device, you can assume that minor numbers
132+
are in the range [0,255] (i.e., there can be at most 256 different message slots device files).
133+
(This occurs because register_chrdev() limits the registered device to 256 minor number.)
134+
Otherwise, you can assume that minor numbers do not exceed 220, because Linux uses 20
135+
bits to represent minor numbers.
136+
5. In the module’s struct file_operations, include the initialization
137+
.owner = THIS_MODULE,
138+
This will prevent the module from being unloaded while it is being used.
139+
6. You need to define both MSG_SLOT_CHANNEL and MSG_SLOT_SET_CEN ioctl commands using the
140+
appropriate macros (e.g., _IOW).
141+
7. Thecensorship state should be maintained per file descriptor (you can store it in file->private_data
142+
along with the channel id).
143+
8. Censorship only affects write operations. Read operations always return the stored message as-is,
144+
regardless of the current censorship setting of the file descriptor.
145+
9. You are responsible for defining the driver’s ioctl command, as shown in the recitation.
146+
10. Allocate memory using kmalloc() with GFP_KERNEL flag. (It is declared in <linux/slab.h>.)
147+
4
148+
11. While your module runs, the total amount of memory allocated by it should be O(C ·M +N),
149+
where C is the total number of channels that were used (across all device files), M is the size
150+
of the largest message held and N is the number of times MSG_SLOT_SET_CEN ioctl command is
151+
called.
152+
12. When unloaded, the module should free all memory that it allocated.
153+
13. Remember that processes aren’t trusted. Verify arguments to file operations and return-1 with
154+
errno set to EINVAL if the arguments are invalid. In particular, check the validity of user space
155+
buffers.
156+
14. You can assume that any invocation of the module’s operations (including loading/unloading)
157+
will run alone; i.e., there will not be concurrent system call invocations. This does not mean
158+
that there can’t be several processes that have the same message slot open or using the same
159+
channel; it just means that they won’t access the device concurrently.
160+
3.2 Message sender
161+
Implement the program in a file named message_sender.c.
162+
Command line arguments:
163+
• argv[1]: message slot file path.
164+
• argv[2]: the target message channel id. Assume a non-negative integer.
165+
• argv[3]: censorship mode (0 for disabled, 1 for enabled).
166+
• argv[4]: the message to pass.
167+
You should validate that the correct number of command line arguments is passed.
168+
The flow:
169+
1. Open the specified message slot device file.
170+
2. Set the censorship mode to the value specified on the command line (0 to disable censorship, 1
171+
to enable censorship).
172+
3. Set the channel id to the id specified on the command line.
173+
4. Write the specified message to the message slot file. Don’t include the terminating null character
174+
of the C string as part of the message.
175+
5. Close the device.
176+
6. Exit the program with exit value 0.
177+
If an error occurs in any of the above steps, print an appropriate error message (using strerror()
178+
or perror()) and exit the program with exit value 1.
179+
3.3 Message reader
180+
Implement the program in a file named message_reader.c.
181+
5
182+
Command line arguments:
183+
• argv[1]: message slot file path.
184+
• argv[2]: the target message channel id. Assume a non-negative integer.
185+
You should validate that the correct number of command line arguments is passed.
186+
The flow:
187+
1. Open the specified message slot device file.
188+
2. Set the channel id to the id specified on the command line.
189+
3. Read a message from the message slot file to a buffer.
190+
4. Close the device.
191+
5. Print the message to standard output (using the write() system call). Print only the message,
192+
without any additional text.
193+
6. Exit the program with exit value 0.
194+
If an error occurs in any of the above steps, print an appropriate error message (using strerror()
195+
or perror()) and exit the program with exit value 1.
196+
3.4 Example session
197+
1. As root (e.g., with sudo): Load (insmod) the message_slot.ko module.
198+
2. As root: Create a message slot file using mknod.
199+
3. As root: Change the message slot file’s permissions to make it readable and writable by your user.
200+
4. Invoke message_sender to send a message on some channel without censorship.
201+
5. Invoke message_reader to read the message on the same channel.
202+
6. Invoke message_sender to send a message on some channel with censorship.
203+
7. Invoke message_reader to read the message on the same channel.
204+
8. Execute steps #4 to #7 several times, for different channels, in different sequences.
205+
4 General guidelines
206+
1. Because your message sender takes the messages from the command line, it will only be able to
207+
send a C string as a message. This does not mean that the kernel module or message reader
208+
should only work with C string messages. The kernel module provides the general interface
209+
specified in Section 2, and any program—not necessarily yours—can use it.
210+
2. There’s no requirement for the message sender/reader to exit “cleanly” on error. These programs
211+
may terminate without freeing memory and closing file descriptors.
212+
6
213+
5 Submission instructions
214+
1. Submit a ZIP file containing five files: message_slot.c, message_slot.h, message_sender.c,
215+
message_reader.c, and a Makefile that builds the module. The ZIP file should be named
216+
ex4_XXXXXXXXX.zip, where XXXXXXXXX is your ID #.
217+
2. The message sender and reader programs must compile cleanly on the course VM (no errors
218+
or warnings) when the following command is run in a directory containing the source code file
219+
and the message_slot.h file:
220+
gcc-O3-Wall-std=c11 message_sender.c (or message_reader.c)
221+
Appendix: Troubleshooting for ARM Users
222+
If you encounter the following error during compilation on an ARM architecture (e.g., Apple Silicon
223+
M1/M2/M3 via VM):
224+
make[1]: * /lib/modules/5.10.0-18-arm64/build: No such file or directory. Stop.
225+
make: * [Makefile:7: all] Error 2
226+
This error indicates that the kernel headers for your specific kernel version are missing. To
227+
resolve this, please execute the following commands in order:
228+
1. Update and upgrade your system repositories:
229+
sudo apt-get update
230+
sudo apt-get upgrade
231+
sudo apt-get dist-upgrade
232+
2. Reboot the system: This step is crucial to ensure that any kernel updates are applied
233+
correctly before installing headers.
234+
reboot
235+
3. Install the Linux headers: This command installs the headers specifically matching your
236+
currently running kernel.
237+
sudo apt-get install linux-headers-$(uname-r)
238+
For additional information, you may refer to this discussion: https://stackoverflow.com/
239+
questions/22165929/install-linux-headers-on-debian-unable-to-locate-package
240+
7

message_reader.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <fcntl.h>
2+
#include <unistd.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <sys/ioctl.h>
6+
#include "message_slot.h"
7+
8+
int main(int argc, char *argv[]) {
9+
int fd;
10+
unsigned int channel;
11+
char buf[MAX_MESSAGE_LEN];
12+
ssize_t n;
13+
14+
if (argc != 3) /*You should validate that the correct number of command line arguments is passed.*/
15+
{
16+
perror("Incorrect number of arguments. should be: <device_file> <channel_id>");
17+
exit(1);
18+
}
19+
20+
channel = atoi(argv[2]);
21+
22+
fd = open(argv[1], O_RDONLY);
23+
if (fd < 0) {
24+
perror("Failed to open device file");
25+
exit(1);
26+
}
27+
28+
if (ioctl(fd, MSG_SLOT_CHANNEL, channel) < 0) {
29+
perror("Failed to set the channel id");
30+
exit(1);
31+
}
32+
33+
n = read(fd, buf, MAX_MESSAGE_LEN);
34+
if (n < 0) {
35+
perror("Failed to read from the message slot");
36+
exit(1);
37+
}
38+
39+
if (write(STDOUT_FILENO, buf, n) != n) {
40+
perror("Failed to write to standard output");
41+
close(fd);
42+
exit(1);
43+
}
44+
close(fd);
45+
exit(0);
46+
}

0 commit comments

Comments
 (0)