Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added simple chroot support instead of dropping privilages #108

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 109 additions & 12 deletions src/install.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#define _GNU_SOURCE

Check warning on line 1 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:1:9 [bugprone-reserved-identifier]

declaration uses identifier '_GNU_SOURCE', which is a reserved identifier

#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>

// Include necessary headers
#include "libspm.h"
Expand Down Expand Up @@ -40,7 +41,7 @@
- 0: Package installed successfully.
- -1: Installation failed.
*/
int f_install_package_source(const char* spm_path, int as_dep, char* repo) {

Check warning on line 44 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:44:5 [readability-function-cognitive-complexity]

function 'f_install_package_source' has cognitive complexity of 78 (threshold 25)
// Check if spm_path is NULL

if (spm_path == NULL) {
Expand Down Expand Up @@ -82,21 +83,21 @@
{
dbg(1, "Getting environment variables...");
char* env_path = calloc(MAX_PATH, 1);
sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg.environment);

Check warning on line 86 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:86:9 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]

Call to function 'sprintf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11

readConfig(env_path, 1);
}

// Set global environment variables

if (pkg.exports != NULL && pkg.exportsCount > 0 && strlen(pkg.exports[0]) > 0)

Check warning on line 93 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:93:9 [clang-analyzer-unix.Malloc]

Potential leak of memory pointed to by 'env_path'
{
dbg(1, "Setting environment variables...");
char* env_path = calloc(MAX_PATH, 1);
sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg.name);

Check warning on line 97 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:97:9 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]

Call to function 'sprintf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11

FILE *env_file;

Check warning on line 99 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:99:15 [cppcoreguidelines-init-variables]

variable 'env_file' is not initialized
env_file = fopen(env_path, "w");

Check warning on line 100 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:100:18 [clang-analyzer-unix.Malloc]

Potential leak of memory pointed to by 'env_path'

for (int i = 0; i < pkg.exportsCount; i++)
{
Expand All @@ -115,7 +116,7 @@
dbg(2, "Key: %s Value: %s", key, value);

// Set environment variables based on the key-value pairs in the config file
setenv(key, value, 1);

Check warning on line 119 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:119:17 [clang-analyzer-core.NonNullParamChecker]

Null pointer passed to 2nd parameter expecting 'nonnull'
}
}

Expand Down Expand Up @@ -156,11 +157,113 @@
}

// Check if a package is a collection
if(strcmp(pkg.type, "con") != 0)

Check warning on line 160 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:160:8 [clang-analyzer-core.NonNullParamChecker]

Null pointer passed to 1st parameter expecting 'nonnull'
{
// Parse the files
for (int i = 0; i < pkg.filesCount; i++)
{
int download_attempts = 3;
int download_success = 0;

struct stat st_source = {0};
struct stat st_source_loc = {0};

char* location = calloc(MAX_PATH, 1);
char* source_location = calloc(MAX_PATH, 1);
char* source_file_location = calloc(MAX_PATH, 1);

// This seems stupid, but should work
char* file_name = strtok(pkg.files[i], " ");
parse_env(&file_name);
char* file_url = strtok(NULL, " ");
parse_env(&file_url);
char* file_sha256 = strtok(NULL, " ");

sprintf(location, "%s/%s", getenv("SOVIET_MAKE_DIR"), file_name);

Check warning on line 182 in src/install.c

View workflow job for this annotation

GitHub Actions / c-linter

src/install.c:182:13 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]

Call to function 'sprintf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
sprintf(source_location, "%s/%s-%s", getenv("SOVIET_SOURCE_DIR"), getenv("NAME"), getenv("VERSION"));
sprintf(source_file_location, "%s/%s-%s/%s", getenv("SOVIET_SOURCE_DIR"), getenv("NAME"), getenv("VERSION"), file_name);

dbg(1, "Downloading %s", file_name);

if (stat(source_location, &st_source_loc) == -1)
{
mkdir(source_location, 0755);
chown(source_location, getuid(), getgid());
chmod(source_location, 0755);
}


if (stat(source_file_location, &st_source) == -1)
{
FILE* fp = fopen(location, "wb");
download(file_url, fp);
fclose(fp);

// Check if the checksum shall be bypassed

if (INSECURE) {
msg(WARNING, "The Checksum is being skipped");
goto skip_checksum;
}

// Check the hash, abort if mismatch
unsigned char hash[SHA256_DIGEST_LENGTH];
char* hash_str = calloc(SHA256_DIGEST_LENGTH, 8);

struct stat st;
stat(location, &st);
int size = st.st_size;

char* buffer = malloc(size);
FILE *ptr;
ptr = fopen(location,"r");
fread(buffer, sizeof(char), size, ptr);

if (buffer == NULL) {
msg(FATAL, "Could not verify the file's hash");
return -1;
}

SHA256((unsigned char*) buffer, size, hash);

if (hash[0] == 0) {
msg(FATAL, "Could not verify the file's hash");
return -1;
}

dbg(1, "Hash is %s", file_sha256);
for(int k = 0; k < SHA256_DIGEST_LENGTH; k++) {
char* temp = calloc(8, 1);
sprintf(temp, "%02x", hash[k]);
strcat(hash_str, temp);
}

dbg(1, "Got %s", hash_str);
if(strcmp(hash_str, file_sha256) != 0) {
msg(FATAL, "Hash mismatch, aborting");
}
free(hash_str);
free(buffer);

skip_checksum:

dbg(1, "Download finished");

loadFile(location, source_file_location);
}
else {
dbg(1, "Loading form %s", source_location);
loadFile(source_file_location, location);
}

free(location);
free(source_location);
free(source_file_location);
}

// Legacy directory path for compatibility
char legacy_dir[MAX_PATH];
sprintf(legacy_dir, "%s/%s-%s", getenv("SOVIET_MAKE_DIR"), pkg.name, pkg.version);
sprintf(legacy_dir, "/make/%s-%s", pkg.name, pkg.version);

// ...
chmod(getenv("SOVIET_MAKE_DIR"), 0777);
Expand All @@ -170,19 +273,13 @@
int status = 0;
if ( p == 0)
{

if (getuid() == 0)
chdir(getenv("SOVIET_WORK_DIR"));
if (chroot(getenv("SOVIET_WORK_DIR")) != 0)
{
/* process is running as root, drop privileges */
if (setgid(1000) != 0)
{
msg(ERROR, "setgid: Unable to drop group privileges");
}
if (setuid(1000) != 0)
{
msg(ERROR, "setuid: Unable to drop user privileges");
}
msg(ERROR, "Failed to chroot into %s", getenv("SOVIET_WORK_DIR"));
exit(1);
}

// Build the package
dbg(1, "Making %s", pkg.name);
if (make(legacy_dir, &pkg) != 0) {
Expand Down
107 changes: 2 additions & 105 deletions src/make.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "string.h"
#include <sys/stat.h>
#include <unistd.h>
#include <openssl/sha.h>

// Include necessary headers
#include "libspm.h"
Expand All @@ -24,8 +23,8 @@
- -3: No install command found.
*/
int make(char* package_dir, struct package* pkg) {
char* build_dir = getenv("SOVIET_BUILD_DIR");
char* make_dir = getenv("SOVIET_MAKE_DIR");
char* build_dir = "/build";
char* make_dir = "/make";

char* cmd_params;
if (QUIET) {
Expand All @@ -44,108 +43,6 @@ int make(char* package_dir, struct package* pkg) {
// If so, it will just copy the dir from /usr/src/$NAME-$VERSION
// Instead of executing the following:
//
// Parse the files
for (int i = 0; i < pkg->filesCount; i++)
{
int download_attempts = 3;
int download_success = 0;

struct stat st_source = {0};
struct stat st_source_loc = {0};

char* location = calloc(MAX_PATH, 1);
char* source_location = calloc(MAX_PATH, 1);
char* source_file_location = calloc(MAX_PATH, 1);

// This seems stupid, but should work
char* file_name = strtok(pkg->files[i], " ");
parse_env(&file_name);
char* file_url = strtok(NULL, " ");
parse_env(&file_url);
char* file_sha256 = strtok(NULL, " ");

sprintf(location, "%s/%s", getenv("SOVIET_MAKE_DIR"), file_name);
sprintf(source_location, "%s/%s-%s", getenv("SOVIET_SOURCE_DIR"), getenv("NAME"), getenv("VERSION"));
sprintf(source_file_location, "%s/%s-%s/%s", getenv("SOVIET_SOURCE_DIR"), getenv("NAME"), getenv("VERSION"), file_name);

dbg(1, "Downloading %s", file_name);

if (stat(source_location, &st_source_loc) == -1)
{
mkdir(source_location, 0755);
chown(source_location, getuid(), getgid());
chmod(source_location, 0755);
}


if (stat(source_file_location, &st_source) == -1)
{
FILE* fp = fopen(location, "wb");
download(file_url, fp);
fclose(fp);

// Check if the checksum shall be bypassed

if (INSECURE) {
msg(WARNING, "The Checksum is being skipped");
goto skip_checksum;
}

// Check the hash, abort if mismatch
unsigned char hash[SHA256_DIGEST_LENGTH];
char* hash_str = calloc(SHA256_DIGEST_LENGTH, 8);

struct stat st;
stat(location, &st);
int size = st.st_size;

char* buffer = malloc(size);
FILE *ptr;
ptr = fopen(location,"r");
fread(buffer, sizeof(char), size, ptr);

if (buffer == NULL) {
msg(FATAL, "Could not verify the file's hash");
return -1;
}

SHA256((unsigned char*) buffer, size, hash);

if (hash[0] == 0) {
msg(FATAL, "Could not verify the file's hash");
return -1;
}

dbg(1, "Hash is %s", file_sha256);
for(int k = 0; k < SHA256_DIGEST_LENGTH; k++) {
char* temp = calloc(8, 1);
sprintf(temp, "%02x", hash[k]);
strcat(hash_str, temp);
}

dbg(1, "Got %s", hash_str);
if(strcmp(hash_str, file_sha256) != 0) {
msg(FATAL, "Hash mismatch, aborting");
}
free(hash_str);
free(buffer);

skip_checksum:

dbg(1, "Download finished");

loadFile(location, source_file_location);
}
else {
dbg(1, "Loading form %s", source_location);
loadFile(source_file_location, location);
}

free(location);
free(source_location);
free(source_file_location);
}

// Download package sources
if (pkg->info.download != NULL && strlen(pkg->info.download) > 0) {
char sources_cmd[64 + strlen(make_dir) + strlen(pkg->info.download)];
Expand Down
Loading