aboutgitcodelistschat:MatrixIRC
diff options
context:
space:
mode:
-rw-r--r--common/gluten.h29
-rw-r--r--common/util.c7
-rw-r--r--cooker/call.c19
-rw-r--r--demo/mknod.hjson2
-rw-r--r--operations.c55
-rw-r--r--operations.h2
6 files changed, 93 insertions, 21 deletions
diff --git a/common/gluten.h b/common/gluten.h
index 185927a..f3ef47d 100644
--- a/common/gluten.h
+++ b/common/gluten.h
@@ -12,6 +12,7 @@
#include <stdbool.h>
#include <sys/types.h>
#include <linux/limits.h>
+#include <limits.h>
#include <linux/seccomp.h>
#include <stdio.h>
@@ -75,23 +76,25 @@ enum op_type {
};
/**
- * enum context_spec_type - Type of reference to target namespace and directory
+ * enum context_spec_type - Type of reference to namespace, directory, UID/GID
*/
enum context_spec_type {
CONTEXT_SPEC_NONE = 0,
- /* PID from seccomp_data */
+ /* PID from seccomp_data, UID/GID resolved via procfs in seitan */
CONTEXT_SPEC_CALLER = 1,
- /* PID/path from gluten, resolved in seitan */
- CONTEXT_SPEC_PID = 2,
- CONTEXT_SPEC_PATH = 3,
+ /* UID/GID, or PID resolved in seitan */
+ CONTEXT_SPEC_NUM = 2,
- CONTEXT_SPEC_TYPE_MAX = CONTEXT_SPEC_PATH,
+ /* User/group names or namespace path, resolved in seitan */
+ CONTEXT_SPEC_NAME = 3,
+
+ CONTEXT_SPEC_TYPE_MAX = CONTEXT_SPEC_NAME,
};
/**
- * enum context_type - Working directory, and namespaces (see <linux/sched.h>)
+ * enum context_type - Directory, namespaces (see <linux/sched.h>), UID/GID
*/
enum context_type {
NS_MOUNT = 0,
@@ -104,17 +107,22 @@ enum context_type {
NS_TIME = 7,
NS_TYPE_MAX = NS_TIME,
CWD = 8,
- CONTEXT_TYPE_MAX = CWD,
+ UID = 9,
+ GID = 10,
+ CONTEXT_TYPE_MAX = GID,
};
extern const char *context_type_name[CONTEXT_TYPE_MAX + 1];
extern const char *context_spec_type_name[CONTEXT_SPEC_TYPE_MAX + 1];
/**
* struct context_desc - Identification of one type of context information
- * @context: Type of context (namespace types, or working directory)
+ * @context: Type of context (namespace, working directory, UID/GID)
* @spec: Reference type
* @target.pid: PID in procfs reference
+ * @target.uid: UID to switch to
+ * @target.gid: GID to switch to
* @target.path: Filesystem-bound (nsfs) reference
+ * @target.name: Username or group name
*/
struct context_desc {
#ifdef __GNUC__
@@ -126,7 +134,10 @@ struct context_desc {
#endif
union {
pid_t pid;
+ uid_t uid;
+ gid_t gid;
char path[PATH_MAX];
+ char name[LOGIN_NAME_MAX];
} target;
};
diff --git a/common/util.c b/common/util.c
index 21676b0..d74e199 100644
--- a/common/util.c
+++ b/common/util.c
@@ -8,6 +8,9 @@
* Author: Stefano Brivio <sbrivio@redhat.com>
*/
+#include <bits/local_lim.h> /* TODO: Why isn't __USE_POSIX with limits.h
+ * enough for LOGIN_NAME_MAX here?
+ */
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
@@ -35,7 +38,9 @@ const char *gluten_offset_name[OFFSET_TYPE_MAX + 1] = {
};
const char *context_type_name[CONTEXT_TYPE_MAX + 1] = {
- "mnt", "cgroup", "uts", "ipc", "user", "pid", "net", "time", "cwd",
+ "mnt", "cgroup", "uts", "ipc", "user", "pid", "net", "time",
+ "cwd",
+ "uid", "gid",
};
const char *context_spec_type_name[CONTEXT_SPEC_TYPE_MAX + 1] = {
diff --git a/cooker/call.c b/cooker/call.c
index c3f290c..6dbfd29 100644
--- a/cooker/call.c
+++ b/cooker/call.c
@@ -458,14 +458,25 @@ static void parse_context(struct context_desc *cdesc, JSON_Object *obj)
if (!strcmp(str, "caller")) {
cdesc[n].spec = CONTEXT_SPEC_CALLER;
} else {
- cdesc[n].spec = CONTEXT_SPEC_PATH;
- strncpy(cdesc[n].target.path, str, PATH_MAX);
+ cdesc[n].spec = CONTEXT_SPEC_NAME;
+ if (type == UID || type == GID) {
+ strncpy(cdesc[n].target.name, str,
+ LOGIN_NAME_MAX);
+ } else {
+ strncpy(cdesc[n].target.path, str,
+ PATH_MAX);
+ }
}
} else if ((num = json_object_get_number(obj, name))) {
debug(" '%s' context: %lli", name, num);
- cdesc[n].spec = CONTEXT_SPEC_PID;
- cdesc[n].target.pid = num;
+ cdesc[n].spec = CONTEXT_SPEC_NUM;
+ if (type == UID)
+ cdesc[n].target.uid = num;
+ else if (type == GID)
+ cdesc[n].target.gid = num;
+ else
+ cdesc[n].target.pid = num;
} else {
die("invalid context specification");
}
diff --git a/demo/mknod.hjson b/demo/mknod.hjson
index 9124a8a..1936eb8 100644
--- a/demo/mknod.hjson
+++ b/demo/mknod.hjson
@@ -26,7 +26,7 @@
"major": 1,
"minor": { "tag": { "get": "minor" } }
},
- "context": { "mnt": "caller" }
+ "context": { "mnt": "caller", "uid": "caller", "gid": "caller" }
},
"return": { "value": 0, "error": 0 }
}
diff --git a/operations.c b/operations.c
index 97c4730..5a882d9 100644
--- a/operations.c
+++ b/operations.c
@@ -14,11 +14,13 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
-#include <limits.h>
#include <sched.h>
#include <unistd.h>
#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
+#include <pwd.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>
@@ -79,6 +81,7 @@ static int write_syscall_ret(struct gluten *g, struct syscall_desc *s,
return 0;
}
+/* TODO: Move all "context" stuff to separate file */
static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
struct syscall_desc *s, struct context_desc *cdesc,
struct arg_clone *c)
@@ -130,26 +133,57 @@ static int prepare_arg_clone(const struct seccomp_notif *req, struct gluten *g,
if (type == CWD) {
snprintf(c->cwd, PATH_MAX, "/proc/%d/root",
req->pid);
+ } else if (type == UID || type == GID) {
+ /* TODO: Move into its own function */
+ struct stat st = { 0 };
+ char path[PATH_MAX];
+
+ snprintf(path, PATH_MAX, "/proc/%d", req->pid);
+ if (stat(path, &st))
+ return errno;
+
+ if (type == UID)
+ c->uid = st.st_uid;
+ else if (type == GID)
+ c->gid = st.st_gid;
} else {
snprintf(*dst, PATH_MAX, "/proc/%d/ns/%s",
- req->pid, context_type_name[type]);
+ req->pid, context_type_name[type]);
}
+
break;
- case CONTEXT_SPEC_PID:
+ case CONTEXT_SPEC_NUM:
if (type == CWD) {
snprintf(c->cwd, PATH_MAX, "/proc/%d/root",
cdesc->target.pid);
+ } else if (type == UID) {
+ c->uid = cdesc->target.uid;
+ } else if (type == GID) {
+ c->gid = cdesc->target.gid;
} else {
snprintf(*dst, PATH_MAX, "/proc/%d/ns/%s",
cdesc->target.pid,
context_type_name[type]);
}
+
break;
- case CONTEXT_SPEC_PATH:
- if (type == CWD)
+ case CONTEXT_SPEC_NAME:
+ if (type == CWD) {
strncpy(c->cwd, cdesc->target.path, PATH_MAX);
- else
+ } else if (type == UID || type == GID) {
+ struct passwd *pw;
+
+ if (!(pw = getpwnam(cdesc->target.name)))
+ return errno;
+
+ if (type == UID)
+ c->uid = pw->pw_uid;
+ else if (type == GID)
+ c->gid = pw->pw_gid;
+ } else {
strncpy(*dst, cdesc->target.path, PATH_MAX);
+ }
+
break;
default:
break;
@@ -183,6 +217,15 @@ static int execute_syscall(void *args)
{
struct arg_clone *c = (struct arg_clone *)args;
+ /* We can use 0 as "unspecified" value because we can't switch from a
+ * non-zero UID/GID to zero.
+ */
+ if (c->uid && setuid(c->uid))
+ exit(EXIT_FAILURE);
+
+ if (c->gid && setgid(c->gid))
+ exit(EXIT_FAILURE);
+
if (*c->cwd && chdir(c->cwd) < 0)
exit(EXIT_FAILURE);
diff --git a/operations.h b/operations.h
index 9f2e2d6..6cff7a8 100644
--- a/operations.h
+++ b/operations.h
@@ -37,6 +37,8 @@ struct arg_clone {
const void *args[6];
char ns_path[NS_TYPE_MAX + 1][PATH_MAX];
char cwd[PATH_MAX];
+ uid_t uid;
+ gid_t gid;
long ret;
int err;
};