summaryrefslogtreecommitdiffstats
path: root/sys/syscall_objdir.c
blob: 28eba688103060332babb5c2d88b91cb9c9f40b4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "arch/x86_64/hal/obj.h"
#include "proc/process.h"
#include "jove.h"
#include "lib/printf.h"
#include "sys/objdir.h"
#include "syscall.h"

int
s_syscall_objdir_objtype(
        jove_obj_t *objdir,
        jove_obj_t *target_dir,
        size_t payload_size,
        void *payload_data)
{
    size_t bytes_needed = 2;
    CHECK_TOOSMALL(bytes_needed, payload_size, "Message is too small for payload.");

    uint16_t local_idx = *((uint16_t*)payload_data);

    if(local_idx > OBJDIR_ENTRIES) {
        kprintf("%s: Object index is out of bounds (%i >= 512)\n", __func__, local_idx);
        return EOOB;
    }

    jove_obj_t local_obj = objdir_peeklocal(target_dir, local_idx);
    return obj_peektype(local_obj);
}

static int
s_syscall_objdir_swap(lockstack_t *lockstack,
                      jove_obj_t *rootdir,
                      size_t bytes_left,
                      void *payload_data)
{
    //Verify the message is big enough for the payload.
    size_t bytes_needed = sizeof(struct syscall_objdir_swap);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload.");

    //Verify the message is big enough for the other path.
    struct syscall_objdir_swap *payload = payload_data;
    bytes_needed += payload->other_path_length * sizeof(objpath_part_t);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for other path.");

    //Verify the object pointed to in the entry exists.
    jove_obj_t *target = lockstack_pop(lockstack);
    jove_owned_obj_t *obj_a = lockstack_push(lockstack, objdir_getlocal(target, payload->index));
    if(obj_a == NULL) {
        klogf("Getting local object %i failed : %s\n",
                payload->index, errstr(errno));
        return -errno;
    }

    //Verify the second object directory exists.
    jove_perm_obj_t objdir_b = link_traverse_objdir(rootdir, payload->other_path_length - 1, payload->other_path);
    if(objdir_b.obj == NULL) {
        obj_release(objdir_b.obj);
        klogf("Getting object %P failed : %s\n",
                payload->other_path, payload->other_path_length, errstr(errno));
        return -errno;
    }
    
    //Verify the second object directory has the correct permissions.
    CHECK_OBJPERM(objdir_b, SYSCALL_PERM_OBJDIR_SWAP_TGT, "Other object is missing permission");

    //Verify the second object exists.
    jove_owned_obj_t *obj_b = lockstack_push(lockstack, 
            objdir_getlocal_locked(objdir_b.obj, payload->other_path[payload->other_path_length-1]));
    if(obj_b == NULL) {
        klogf("Getting object %P failed : %s\n",
                payload->other_path, payload->other_path_length, errstr(errno));
        return -errno;
    }

    objdir_swapobj(obj_a, obj_b);
    return 0;
}

static int
s_syscall_objdir_link(jove_owned_obj_t *target_obj,
        lockstack_t *lockstack,
        jove_obj_t *rootdir_obj,
        size_t bytes_left,
        void *payload_data)
{
    //Verify the message is big enough for the payload.
    size_t bytes_needed = sizeof(struct syscall_objdir_link);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload");

    //Verify the message is big enough for the second path.
    struct syscall_objdir_link *payload = payload_data;
    bytes_needed += payload->other_path_length * sizeof(objpath_part_t);
    CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for other object");

    //Verify the objdir index is a valid object.
    jove_owned_obj_t *link_obj = lockstack_push(lockstack, objdir_getlocal_locked(target_obj, payload->index));
    if(link_obj == NULL) {
        klogf("Getting local object %i failed : %s\n", payload->index, errstr(errno));
        return -errno;
    }

    //Verify that the link object is infact a link object.
    CHECK_OBJTYPE(link_obj, JOVE_OBJ_LINK, "Local object is not a link object");
    
    jove_perm_obj_t dest_obj = link_traverse_objdir(rootdir_obj, payload->other_path_length, payload->other_path);
    lockstack_push(lockstack, dest_obj.obj);

    //Verify the destination path exists.
    if(dest_obj.obj == NULL) {
        klogf("Getting destination object %P failed : %s\n",
                payload->other_path, payload->other_path_length, errstr(errno));
        return -errno;
    }
    
    //Verify the destination path is empty.
    if(obj_gettype(dest_obj.obj) != JOVE_OBJ_NONE) {
        klogf("Destination object %P is not empty\n",
                payload->other_path, payload->other_path_length);
        return -EFULL;
    }
    //Verify the destination path has the correct permissions.
    CHECK_OBJPERM(dest_obj, SYSCALL_PERM_OBJDIR_LINK_TGT, "Destination object is missing permissions");
    return link_dup(link_obj, dest_obj.obj);
}

int
_syscall_handle_objdir(syscall_context_t *ctx)
{
    switch(ctx->header->callid) {
        case SYSCALL_OBJDIR_OBJTYPE:
            if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_OBJTYPE)
                return s_syscall_objdir_objtype(
                        ctx->objdir, lockstack_pop(&ctx->lockstack), ctx->bytes_left, ctx->payload);
            return -EPERM;

        case SYSCALL_OBJDIR_SWAP:
            if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_SWAP)
                return s_syscall_objdir_swap(
                        &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload);
            return -EPERM;
        
        case SYSCALL_OBJDIR_LINK:
            if(ctx->target.permissions & SYSCALL_PERM_OBJDIR_LINK)
                return s_syscall_objdir_link(ctx->target.obj,
                        &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload);
            return -EPERM;

        default:
            return -EBADCALL;
    }
}