Skip to content

Commit

Permalink
Merge pull request #120 from Galfurian/develop
Browse files Browse the repository at this point in the history
Monitor VFS and ET2 files. Fix memory leack.
  • Loading branch information
Galfurian authored Dec 6, 2024
2 parents c786ec4 + 4e2314f commit b276e03
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 92 deletions.
69 changes: 50 additions & 19 deletions libc/src/shadow.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
#include "ctype.h"
#include "limits.h"

/// Defines the buffer size for reading lines from the shadow file.
#define LINE_LIM 256

/// @brief Converts a string to a long integer.
///
/// @details Parses a string into a long integer and advances the string pointer.
Expand Down Expand Up @@ -83,57 +80,91 @@ int __parsespent(char *s, struct spwd *sp)
struct spwd *getspnam(const char *name)
{
static struct spwd spwd_buf;
static char *line;
struct spwd *result;
char buffer[BUFSIZ];
int e;
int orig_errno = errno;

if (!line) line = malloc(LINE_LIM);
if (!line) return 0;
e = getspnam_r(name, &spwd_buf, line, LINE_LIM, &result);
// Call the reentrant function to get the shadow password entry.
e = getspnam_r(name, &spwd_buf, buffer, BUFSIZ, &result);

// Propagate error from getspnam_r if it fails.
errno = e ? e : orig_errno;

return result;
}

int getspnam_r(const char *name, struct spwd *spwd_buf, char *buf, size_t buflen, struct spwd **result)
{
char path[20 + NAME_MAX];
int rv = 0;
int fd;
size_t k, l = strlen(name);
int skip = 0;
int cs;
int orig_errno = errno;
int rv = 0; // Return value to track errors (e.g., ERANGE).
int fd; // File descriptor for the shadow file.
size_t k; // Length of the current line read from the file.
size_t l = strlen(name); // Length of the username to search for.
int skip = 0; // Flag to indicate whether the current line should be skipped.
int orig_errno = errno; // Preserve the original errno value for later restoration.

if (!spwd_buf) {
fprintf(stderr, "spwd_buf is NULL in getspnam_r.\n");
return errno = EINVAL;
}
if (!result) {
fprintf(stderr, "result is NULL in getspnam_r.\n");
return errno = EINVAL;
}

// Initialize the result to NULL, indicating no match found yet.
*result = 0;

/* Disallow potentially-malicious user names */
if (*name == '.' || strchr(name, '/') || !l)
// Validate the user name for security:
// - Disallow names starting with '.' or containing '/' (to prevent path traversal attacks).
// - Disallow empty names.
if (*name == '.' || strchr(name, '/') || !l) {
return errno = EINVAL;
}

/* Buffer size must at least be able to hold name, plus some.. */
if (buflen < l + 100)
// Ensure the buffer is large enough to hold the username and additional data.
if (buflen < l + 100) {
return errno = ERANGE;
}

// Open the shadow file for reading.
fd = open(SHADOW, O_RDONLY, 0);
if (fd < 0) {
return errno;
}

// Read lines from the shadow file.
while (fgets(buf, buflen, fd) && (k = strlen(buf)) > 0) {
// If skipping the line (due to being too long), or if the line does not match the user name:
if (skip || strncmp(name, buf, l) || buf[l] != ':') {
// Set skip if the line does not end with a newline.
skip = buf[k - 1] != '\n';
continue;
}

// If the line does not end with a newline, the buffer is too small.
if (buf[k - 1] != '\n') {
// Buffer overflow risk; set return value to ERANGE.
rv = ERANGE;
break;
}

if (__parsespent(buf, spwd_buf) < 0) continue;
// Parse the shadow entry from the line.
// If parsing fails, continue to the next line.
if (__parsespent(buf, spwd_buf) < 0) {
continue;
}

// Set the result to the parsed shadow entry.
*result = spwd_buf;
// Exit the loop after finding the match.
break;
}

// Close the file descriptor.
close(fd);
// Restore errno to its original value unless an error occurred.
errno = rv ? rv : orig_errno;
// Return 0 on success or an error code.
return rv;
}
8 changes: 8 additions & 0 deletions mentos/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ set(BOOTLOADER_NAME bootloader)
# Enables memory allocation tracing.
option(ENABLE_KMEM_TRACE "Enables kmalloc tracing." OFF)
option(ENABLE_PAGE_TRACE "Enables page allocation tracing." OFF)
option(ENABLE_EXT2_TRACE "Enables EXT2 allocation tracing." OFF)
option(ENABLE_FILE_TRACE "Enables vfs_file allocation tracing." OFF)
# Enables scheduling feedback on terminal.
option(ENABLE_SCHEDULER_FEEDBACK "Enables scheduling feedback on terminal." OFF)

Expand Down Expand Up @@ -144,6 +146,12 @@ endif(ENABLE_KMEM_TRACE)
if(ENABLE_PAGE_TRACE)
target_compile_definitions(${KERNEL_NAME} PUBLIC ENABLE_PAGE_TRACE)
endif(ENABLE_PAGE_TRACE)
if(ENABLE_EXT2_TRACE)
target_compile_definitions(${KERNEL_NAME} PUBLIC ENABLE_EXT2_TRACE)
endif(ENABLE_EXT2_TRACE)
if(ENABLE_FILE_TRACE)
target_compile_definitions(${KERNEL_NAME} PUBLIC ENABLE_FILE_TRACE)
endif(ENABLE_FILE_TRACE)

# =============================================================================
# Enables scheduling feedback on terminal.
Expand Down
24 changes: 21 additions & 3 deletions mentos/inc/fs/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
#pragma once

#include "fs/vfs_types.h"
#include "os_root_path.h"
#include "mem/slab.h"

/// Maximum number of opened file.
#define MAX_OPEN_FD 16

/// Cache for file structures in the VFS.
extern kmem_cache_t *vfs_file_cache;

/// @brief Forward declaration of task_struct.
/// Used for task management in the VFS.
struct task_struct;
Expand All @@ -23,6 +21,26 @@ struct task_struct;
/// must be called before any other VFS functions.
void vfs_init(void);

/// @brief Allocates a VFS file structure from the cache.
/// @param file Source file where the allocation is requested (for logging).
/// @param fun Function name where the allocation is requested (for logging).
/// @param line Line number where the allocation is requested (for logging).
/// @return Pointer to the allocated VFS file structure, or NULL if allocation fails.
vfs_file_t *pr_vfs_alloc_file(const char *file, const char *fun, int line);

/// @brief Frees a VFS file structure back to the cache.
/// @param file Source file where the deallocation is requested (for logging).
/// @param fun Function name where the deallocation is requested (for logging).
/// @param line Line number where the deallocation is requested (for logging).
/// @param vfs_file Pointer to the VFS file structure to free.
void pr_vfs_dealloc_file(const char *file, const char *fun, int line, vfs_file_t *vfs_file);

/// Wrapper that provides the filename, the function and line where the alloc is happening.
#define vfs_alloc_file(...) pr_vfs_alloc_file(__RELATIVE_PATH__, __func__, __LINE__)

/// Wrapper that provides the filename, the function and line where the free is happening.
#define vfs_dealloc_file(...) pr_vfs_dealloc_file(__RELATIVE_PATH__, __func__, __LINE__, __VA_ARGS__)

/// @brief Register a new filesystem.
/// @param fs A pointer to the information concerning the new filesystem.
/// @return The outcome of the operation, 0 if fails.
Expand Down
6 changes: 3 additions & 3 deletions mentos/src/drivers/ata.c
Original file line number Diff line number Diff line change
Expand Up @@ -1300,7 +1300,7 @@ static int ata_close(vfs_file_t *file)
pr_debug("ata_close: Removed file `%s` from the opened file list.\n", file->name);

// Free the file from cache.
kmem_cache_free(file);
vfs_dealloc_file(file);
pr_debug("ata_close: Freed memory for file `%s`.\n", file->name);
}

Expand Down Expand Up @@ -1552,7 +1552,7 @@ static vfs_file_operations_t ata_fs_operations = {
static vfs_file_t *ata_device_create(ata_device_t *dev)
{
// Create the file.
vfs_file_t *file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL);
vfs_file_t *file = vfs_alloc_file();
if (file == NULL) {
pr_err("Failed to create ATA device.\n");
return NULL;
Expand Down Expand Up @@ -1613,7 +1613,7 @@ static ata_device_type_t ata_device_detect(ata_device_t *dev)
if (!vfs_register_superblock(dev->fs_root->name, dev->path, &ata_file_system_type, dev->fs_root)) {
pr_alert("Failed to mount ata device!\n");
// Free the memory.
kmem_cache_free(dev->fs_root);
vfs_dealloc_file(dev->fs_root);
return ata_dev_type_unknown;
}
// Increment the drive letter.
Expand Down
4 changes: 2 additions & 2 deletions mentos/src/drivers/mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static struct memdev *null_device_create(const char *name)
dev->next = NULL;

// Allocate memory for the associated file structure.
dev->file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL);
dev->file = vfs_alloc_file();
if (dev->file == NULL) {
pr_err("null_device_create: Failed to allocate memory for file\n");
kfree(dev); // Free the previously allocated device memory.
Expand Down Expand Up @@ -287,7 +287,7 @@ static int null_close(vfs_file_t *file)
pr_debug("null_close: Removed file `%s` from the opened file list.\n", file->name);

// Free the file from cache.
kmem_cache_free(file);
vfs_dealloc_file(file);
pr_debug("null_close: Freed memory for file `%s`.\n", file->name);
}

Expand Down
Loading

0 comments on commit b276e03

Please sign in to comment.