|
| 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 |
0 commit comments