Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
0fd73091
Unverified
Commit
0fd73091
authored
Mar 11, 2018
by
Christian Brauner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
conf: coding style changes
Signed-off-by:
Christian Brauner
<
christian.brauner@ubuntu.com
>
parent
12e6ab5d
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
706 additions
and
673 deletions
+706
-673
conf.c
src/lxc/conf.c
+706
-673
No files found.
src/lxc/conf.c
View file @
0fd73091
...
@@ -114,6 +114,15 @@
...
@@ -114,6 +114,15 @@
lxc_log_define
(
lxc_conf
,
lxc
);
lxc_log_define
(
lxc_conf
,
lxc
);
/* The lxc_conf of the container currently being worked on in an API call.
* This is used in the error calls.
*/
#ifdef HAVE_TLS
__thread
struct
lxc_conf
*
current_config
;
#else
struct
lxc_conf
*
current_config
;
#endif
/* Define pivot_root() if missing from the C library */
/* Define pivot_root() if missing from the C library */
#ifndef HAVE_PIVOT_ROOT
#ifndef HAVE_PIVOT_ROOT
static
int
pivot_root
(
const
char
*
new_root
,
const
char
*
put_old
)
static
int
pivot_root
(
const
char
*
new_root
,
const
char
*
put_old
)
...
@@ -129,10 +138,18 @@ static int pivot_root(const char *new_root, const char *put_old)
...
@@ -129,10 +138,18 @@ static int pivot_root(const char *new_root, const char *put_old)
extern
int
pivot_root
(
const
char
*
new_root
,
const
char
*
put_old
);
extern
int
pivot_root
(
const
char
*
new_root
,
const
char
*
put_old
);
#endif
#endif
char
*
lxchook_names
[
NUM_LXC_HOOKS
]
=
{
"pre-start"
,
"pre-mount"
,
"mount"
,
char
*
lxchook_names
[
NUM_LXC_HOOKS
]
=
{
"autodev"
,
"start"
,
"stop"
,
"pre-start"
,
"post-stop"
,
"clone"
,
"destroy"
,
"pre-mount"
,
"start-host"
};
"mount"
,
"autodev"
,
"start"
,
"stop"
,
"post-stop"
,
"clone"
,
"destroy"
,
"start-host"
};
struct
mount_opt
{
struct
mount_opt
{
char
*
name
;
char
*
name
;
...
@@ -150,17 +167,6 @@ struct limit_opt {
...
@@ -150,17 +167,6 @@ struct limit_opt {
int
value
;
int
value
;
};
};
/*
* The lxc_conf of the container currently being worked on in an
* API call
* This is used in the error calls
*/
#ifdef HAVE_TLS
__thread
struct
lxc_conf
*
current_config
;
#else
struct
lxc_conf
*
current_config
;
#endif
static
struct
mount_opt
mount_opt
[]
=
{
static
struct
mount_opt
mount_opt
[]
=
{
{
"async"
,
1
,
MS_SYNCHRONOUS
},
{
"async"
,
1
,
MS_SYNCHRONOUS
},
{
"atime"
,
1
,
MS_NOATIME
},
{
"atime"
,
1
,
MS_NOATIME
},
...
@@ -192,68 +198,68 @@ static struct mount_opt mount_opt[] = {
...
@@ -192,68 +198,68 @@ static struct mount_opt mount_opt[] = {
};
};
static
struct
mount_opt
propagation_opt
[]
=
{
static
struct
mount_opt
propagation_opt
[]
=
{
{
"private"
,
0
,
MS_PRIVATE
},
{
"private"
,
0
,
MS_PRIVATE
},
{
"shared"
,
0
,
MS_SHARED
},
{
"shared"
,
0
,
MS_SHARED
},
{
"slave"
,
0
,
MS_SLAVE
},
{
"slave"
,
0
,
MS_SLAVE
},
{
"unbindable"
,
0
,
MS_UNBINDABLE
},
{
"unbindable"
,
0
,
MS_UNBINDABLE
},
{
"rprivate"
,
0
,
MS_PRIVATE
|
MS_REC
},
{
"rprivate"
,
0
,
MS_PRIVATE
|
MS_REC
},
{
"rshared"
,
0
,
MS_SHARED
|
MS_REC
},
{
"rshared"
,
0
,
MS_SHARED
|
MS_REC
},
{
"rslave"
,
0
,
MS_SLAVE
|
MS_REC
},
{
"rslave"
,
0
,
MS_SLAVE
|
MS_REC
},
{
"runbindable"
,
0
,
MS_UNBINDABLE
|
MS_REC
},
{
"runbindable"
,
0
,
MS_UNBINDABLE
|
MS_REC
},
{
NULL
,
0
,
0
},
{
NULL
,
0
,
0
},
};
};
static
struct
caps_opt
caps_opt
[]
=
{
static
struct
caps_opt
caps_opt
[]
=
{
#if HAVE_LIBCAP
#if HAVE_LIBCAP
{
"chown"
,
CAP_CHOWN
},
{
"chown"
,
CAP_CHOWN
},
{
"dac_override"
,
CAP_DAC_OVERRIDE
},
{
"dac_override"
,
CAP_DAC_OVERRIDE
},
{
"dac_read_search"
,
CAP_DAC_READ_SEARCH
},
{
"dac_read_search"
,
CAP_DAC_READ_SEARCH
},
{
"fowner"
,
CAP_FOWNER
},
{
"fowner"
,
CAP_FOWNER
},
{
"fsetid"
,
CAP_FSETID
},
{
"fsetid"
,
CAP_FSETID
},
{
"kill"
,
CAP_KILL
},
{
"kill"
,
CAP_KILL
},
{
"setgid"
,
CAP_SETGID
},
{
"setgid"
,
CAP_SETGID
},
{
"setuid"
,
CAP_SETUID
},
{
"setuid"
,
CAP_SETUID
},
{
"setpcap"
,
CAP_SETPCAP
},
{
"setpcap"
,
CAP_SETPCAP
},
{
"linux_immutable"
,
CAP_LINUX_IMMUTABLE
},
{
"linux_immutable"
,
CAP_LINUX_IMMUTABLE
},
{
"net_bind_service"
,
CAP_NET_BIND_SERVICE
},
{
"net_bind_service"
,
CAP_NET_BIND_SERVICE
},
{
"net_broadcast"
,
CAP_NET_BROADCAST
},
{
"net_broadcast"
,
CAP_NET_BROADCAST
},
{
"net_admin"
,
CAP_NET_ADMIN
},
{
"net_admin"
,
CAP_NET_ADMIN
},
{
"net_raw"
,
CAP_NET_RAW
},
{
"net_raw"
,
CAP_NET_RAW
},
{
"ipc_lock"
,
CAP_IPC_LOCK
},
{
"ipc_lock"
,
CAP_IPC_LOCK
},
{
"ipc_owner"
,
CAP_IPC_OWNER
},
{
"ipc_owner"
,
CAP_IPC_OWNER
},
{
"sys_module"
,
CAP_SYS_MODULE
},
{
"sys_module"
,
CAP_SYS_MODULE
},
{
"sys_rawio"
,
CAP_SYS_RAWIO
},
{
"sys_rawio"
,
CAP_SYS_RAWIO
},
{
"sys_chroot"
,
CAP_SYS_CHROOT
},
{
"sys_chroot"
,
CAP_SYS_CHROOT
},
{
"sys_ptrace"
,
CAP_SYS_PTRACE
},
{
"sys_ptrace"
,
CAP_SYS_PTRACE
},
{
"sys_pacct"
,
CAP_SYS_PACCT
},
{
"sys_pacct"
,
CAP_SYS_PACCT
},
{
"sys_admin"
,
CAP_SYS_ADMIN
},
{
"sys_admin"
,
CAP_SYS_ADMIN
},
{
"sys_boot"
,
CAP_SYS_BOOT
},
{
"sys_boot"
,
CAP_SYS_BOOT
},
{
"sys_nice"
,
CAP_SYS_NICE
},
{
"sys_nice"
,
CAP_SYS_NICE
},
{
"sys_resource"
,
CAP_SYS_RESOURCE
},
{
"sys_resource"
,
CAP_SYS_RESOURCE
},
{
"sys_time"
,
CAP_SYS_TIME
},
{
"sys_time"
,
CAP_SYS_TIME
},
{
"sys_tty_config"
,
CAP_SYS_TTY_CONFIG
},
{
"sys_tty_config"
,
CAP_SYS_TTY_CONFIG
},
{
"mknod"
,
CAP_MKNOD
},
{
"mknod"
,
CAP_MKNOD
},
{
"lease"
,
CAP_LEASE
},
{
"lease"
,
CAP_LEASE
},
#ifdef CAP_AUDIT_READ
#ifdef CAP_AUDIT_READ
{
"audit_read"
,
CAP_AUDIT_READ
},
{
"audit_read"
,
CAP_AUDIT_READ
},
#endif
#endif
#ifdef CAP_AUDIT_WRITE
#ifdef CAP_AUDIT_WRITE
{
"audit_write"
,
CAP_AUDIT_WRITE
},
{
"audit_write"
,
CAP_AUDIT_WRITE
},
#endif
#endif
#ifdef CAP_AUDIT_CONTROL
#ifdef CAP_AUDIT_CONTROL
{
"audit_control"
,
CAP_AUDIT_CONTROL
},
{
"audit_control"
,
CAP_AUDIT_CONTROL
},
#endif
#endif
{
"setfcap"
,
CAP_SETFCAP
},
{
"setfcap"
,
CAP_SETFCAP
},
{
"mac_override"
,
CAP_MAC_OVERRIDE
},
{
"mac_override"
,
CAP_MAC_OVERRIDE
},
{
"mac_admin"
,
CAP_MAC_ADMIN
},
{
"mac_admin"
,
CAP_MAC_ADMIN
},
#ifdef CAP_SYSLOG
#ifdef CAP_SYSLOG
{
"syslog"
,
CAP_SYSLOG
},
{
"syslog"
,
CAP_SYSLOG
},
#endif
#endif
#ifdef CAP_WAKE_ALARM
#ifdef CAP_WAKE_ALARM
{
"wake_alarm"
,
CAP_WAKE_ALARM
},
{
"wake_alarm"
,
CAP_WAKE_ALARM
},
#endif
#endif
#ifdef CAP_BLOCK_SUSPEND
#ifdef CAP_BLOCK_SUSPEND
{
"block_suspend"
,
CAP_BLOCK_SUSPEND
},
{
"block_suspend"
,
CAP_BLOCK_SUSPEND
},
#endif
#endif
#endif
#endif
};
};
...
@@ -311,9 +317,9 @@ static struct limit_opt limit_opt[] = {
...
@@ -311,9 +317,9 @@ static struct limit_opt limit_opt[] = {
static
int
run_buffer
(
char
*
buffer
)
static
int
run_buffer
(
char
*
buffer
)
{
{
struct
lxc_popen_FILE
*
f
;
char
*
output
;
int
ret
;
int
ret
;
char
*
output
;
struct
lxc_popen_FILE
*
f
;
f
=
lxc_popen
(
buffer
);
f
=
lxc_popen
(
buffer
);
if
(
!
f
)
{
if
(
!
f
)
{
...
@@ -493,10 +499,10 @@ int run_script(const char *name, const char *section, const char *script, ...)
...
@@ -493,10 +499,10 @@ int run_script(const char *name, const char *section, const char *script, ...)
{
{
int
ret
;
int
ret
;
char
*
buffer
,
*
p
;
char
*
buffer
,
*
p
;
size_t
size
=
0
;
va_list
ap
;
va_list
ap
;
size_t
size
=
0
;
INFO
(
"Executing script
\"
%s
\"
for container
\"
%s
\"
, config section
\"
%s
\"
.
"
,
INFO
(
"Executing script
\"
%s
\"
for container
\"
%s
\"
, config section
\"
%s
\"
"
,
script
,
name
,
section
);
script
,
name
,
section
);
va_start
(
ap
,
script
);
va_start
(
ap
,
script
);
...
@@ -514,26 +520,17 @@ int run_script(const char *name, const char *section, const char *script, ...)
...
@@ -514,26 +520,17 @@ int run_script(const char *name, const char *section, const char *script, ...)
return
-
1
;
return
-
1
;
buffer
=
alloca
(
size
);
buffer
=
alloca
(
size
);
if
(
!
buffer
)
{
ERROR
(
"Failed to allocate memory."
);
return
-
1
;
}
ret
=
snprintf
(
buffer
,
size
,
"exec %s %s %s"
,
script
,
name
,
section
);
ret
=
snprintf
(
buffer
,
size
,
"exec %s %s %s"
,
script
,
name
,
section
);
if
(
ret
<
0
||
ret
>=
size
)
{
if
(
ret
<
0
||
ret
>=
size
)
ERROR
(
"Script name too long."
);
return
-
1
;
return
-
1
;
}
va_start
(
ap
,
script
);
va_start
(
ap
,
script
);
while
((
p
=
va_arg
(
ap
,
char
*
)))
{
while
((
p
=
va_arg
(
ap
,
char
*
)))
{
int
len
=
size
-
ret
;
int
len
=
size
-
ret
;
int
rc
;
int
rc
;
rc
=
snprintf
(
buffer
+
ret
,
len
,
" %s"
,
p
);
rc
=
snprintf
(
buffer
+
ret
,
len
,
" %s"
,
p
);
if
(
rc
<
0
||
rc
>=
len
)
{
if
(
rc
<
0
||
rc
>=
len
)
ERROR
(
"Script args too long."
);
return
-
1
;
return
-
1
;
}
ret
+=
rc
;
ret
+=
rc
;
}
}
va_end
(
ap
);
va_end
(
ap
);
...
@@ -541,8 +538,7 @@ int run_script(const char *name, const char *section, const char *script, ...)
...
@@ -541,8 +538,7 @@ int run_script(const char *name, const char *section, const char *script, ...)
return
run_buffer
(
buffer
);
return
run_buffer
(
buffer
);
}
}
/*
/* pin_rootfs
* pin_rootfs
* if rootfs is a directory, then open ${rootfs}/lxc.hold for writing for
* if rootfs is a directory, then open ${rootfs}/lxc.hold for writing for
* the duration of the container run, to prevent the container from marking
* the duration of the container run, to prevent the container from marking
* the underlying fs readonly on shutdown. unlink the file immediately so
* the underlying fs readonly on shutdown. unlink the file immediately so
...
@@ -553,10 +549,9 @@ int run_script(const char *name, const char *section, const char *script, ...)
...
@@ -553,10 +549,9 @@ int run_script(const char *name, const char *section, const char *script, ...)
*/
*/
int
pin_rootfs
(
const
char
*
rootfs
)
int
pin_rootfs
(
const
char
*
rootfs
)
{
{
char
absrootfs
[
MAXPATHLEN
]
;
int
fd
,
ret
;
char
absrootfspin
[
MAXPATHLEN
];
char
absrootfs
[
MAXPATHLEN
],
absrootfs
pin
[
MAXPATHLEN
];
struct
stat
s
;
struct
stat
s
;
int
ret
,
fd
;
if
(
rootfs
==
NULL
||
strlen
(
rootfs
)
==
0
)
if
(
rootfs
==
NULL
||
strlen
(
rootfs
)
==
0
)
return
-
2
;
return
-
2
;
...
@@ -564,10 +559,12 @@ int pin_rootfs(const char *rootfs)
...
@@ -564,10 +559,12 @@ int pin_rootfs(const char *rootfs)
if
(
!
realpath
(
rootfs
,
absrootfs
))
if
(
!
realpath
(
rootfs
,
absrootfs
))
return
-
2
;
return
-
2
;
if
(
access
(
absrootfs
,
F_OK
))
ret
=
access
(
absrootfs
,
F_OK
);
if
(
ret
!=
0
)
return
-
1
;
return
-
1
;
if
(
stat
(
absrootfs
,
&
s
))
ret
=
stat
(
absrootfs
,
&
s
);
if
(
ret
<
0
)
return
-
1
;
return
-
1
;
if
(
!
S_ISDIR
(
s
.
st_mode
))
if
(
!
S_ISDIR
(
s
.
st_mode
))
...
@@ -577,21 +574,23 @@ int pin_rootfs(const char *rootfs)
...
@@ -577,21 +574,23 @@ int pin_rootfs(const char *rootfs)
if
(
ret
>=
MAXPATHLEN
)
if
(
ret
>=
MAXPATHLEN
)
return
-
1
;
return
-
1
;
fd
=
open
(
absrootfspin
,
O_CREAT
|
O_RDWR
,
S_IWUSR
|
S_IRUSR
);
fd
=
open
(
absrootfspin
,
O_CREAT
|
O_RDWR
,
S_IWUSR
|
S_IRUSR
);
if
(
fd
<
0
)
if
(
fd
<
0
)
return
fd
;
return
fd
;
(
void
)
unlink
(
absrootfspin
);
(
void
)
unlink
(
absrootfspin
);
return
fd
;
return
fd
;
}
}
/*
/* If we are asking to remount something, make sure that any NOEXEC etc are
* If we are asking to remount something, make sure that any
* honored.
* NOEXEC etc are honored.
*/
*/
unsigned
long
add_required_remount_flags
(
const
char
*
s
,
const
char
*
d
,
unsigned
long
add_required_remount_flags
(
const
char
*
s
,
const
char
*
d
,
unsigned
long
flags
)
unsigned
long
flags
)
{
{
#ifdef HAVE_STATVFS
#ifdef HAVE_STATVFS
int
ret
;
struct
statvfs
sb
;
struct
statvfs
sb
;
unsigned
long
required_flags
=
0
;
unsigned
long
required_flags
=
0
;
...
@@ -603,7 +602,9 @@ unsigned long add_required_remount_flags(const char *s, const char *d,
...
@@ -603,7 +602,9 @@ unsigned long add_required_remount_flags(const char *s, const char *d,
if
(
!
s
)
if
(
!
s
)
return
flags
;
return
flags
;
if
(
statvfs
(
s
,
&
sb
)
<
0
)
ret
=
statvfs
(
s
,
&
sb
);
if
(
ret
<
0
)
return
flags
;
return
flags
;
if
(
sb
.
f_flag
&
MS_NOSUID
)
if
(
sb
.
f_flag
&
MS_NOSUID
)
...
@@ -623,8 +624,7 @@ unsigned long add_required_remount_flags(const char *s, const char *d,
...
@@ -623,8 +624,7 @@ unsigned long add_required_remount_flags(const char *s, const char *d,
static
int
lxc_mount_auto_mounts
(
struct
lxc_conf
*
conf
,
int
flags
,
struct
lxc_handler
*
handler
)
static
int
lxc_mount_auto_mounts
(
struct
lxc_conf
*
conf
,
int
flags
,
struct
lxc_handler
*
handler
)
{
{
int
r
;
int
i
,
r
;
int
i
;
static
struct
{
static
struct
{
int
match_mask
;
int
match_mask
;
int
match_flag
;
int
match_flag
;
...
@@ -634,83 +634,87 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
...
@@ -634,83 +634,87 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
unsigned
long
flags
;
unsigned
long
flags
;
const
char
*
options
;
const
char
*
options
;
}
default_mounts
[]
=
{
}
default_mounts
[]
=
{
/* Read-only bind-mounting... In older kernels, doing that required
/* Read-only bind-mounting... In older kernels, doing that
* to do one MS_BIND mount and then MS_REMOUNT|MS_RDONLY the same
* required to do one MS_BIND mount and then
* one. According to mount(2) manpage, MS_BIND honors MS_RDONLY from
* MS_REMOUNT|MS_RDONLY the same one. According to mount(2)
* kernel 2.6.26 onwards. However, this apparently does not work on
* manpage, MS_BIND honors MS_RDONLY from kernel 2.6.26
* kernel 3.8. Unfortunately, on that very same kernel, doing the
* onwards. However, this apparently does not work on kernel
* same trick as above doesn't seem to work either, there one needs
* 3.8. Unfortunately, on that very same kernel, doing the same
* to ALSO specify MS_BIND for the remount, otherwise the entire
* trick as above doesn't seem to work either, there one needs
* fs is remounted read-only or the mount fails because it's busy...
* to ALSO specify MS_BIND for the remount, otherwise the
* MS_REMOUNT|MS_BIND|MS_RDONLY seems to work for kernels as low as
* entire fs is remounted read-only or the mount fails because
* 2.6.32...
* it's busy... MS_REMOUNT|MS_BIND|MS_RDONLY seems to work for
* kernels as low as 2.6.32...
*/
*/
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"proc"
,
"%r/proc"
,
"proc"
,
MS_NODEV
|
MS_NOEXEC
|
MS_NOSUID
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"proc"
,
"%r/proc"
,
"proc"
,
MS_NODEV
|
MS_NOEXEC
|
MS_NOSUID
,
NULL
},
/* proc/tty is used as a temporary placeholder for proc/sys/net which we'll move back in a few steps */
/* proc/tty is used as a temporary placeholder for proc/sys/net which we'll move back in a few steps */
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/sys/net"
,
"%r/proc/tty"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/sys/net"
,
"%r/proc/tty"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/sys"
,
"%r/proc/sys"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/sys"
,
"%r/proc/sys"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
NULL
,
"%r/proc/sys"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_RDONLY
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
NULL
,
"%r/proc/sys"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_RDONLY
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/tty"
,
"%r/proc/sys/net"
,
NULL
,
MS_MOVE
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/tty"
,
"%r/proc/sys/net"
,
NULL
,
MS_MOVE
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/sysrq-trigger"
,
"%r/proc/sysrq-trigger"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
"%r/proc/sysrq-trigger"
,
"%r/proc/sysrq-trigger"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
NULL
,
"%r/proc/sysrq-trigger"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_RDONLY
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_MIXED
,
NULL
,
"%r/proc/sysrq-trigger"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_RDONLY
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_RW
,
"proc"
,
"%r/proc"
,
"proc"
,
MS_NODEV
|
MS_NOEXEC
|
MS_NOSUID
,
NULL
},
{
LXC_AUTO_PROC_MASK
,
LXC_AUTO_PROC_RW
,
"proc"
,
"%r/proc"
,
"proc"
,
MS_NODEV
|
MS_NOEXEC
|
MS_NOSUID
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_RW
,
"sysfs"
,
"%r/sys"
,
"sysfs"
,
0
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_RW
,
"sysfs"
,
"%r/sys"
,
"sysfs"
,
0
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_RO
,
"sysfs"
,
"%r/sys"
,
"sysfs"
,
MS_RDONLY
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_RO
,
"sysfs"
,
"%r/sys"
,
"sysfs"
,
MS_RDONLY
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"sysfs"
,
"%r/sys"
,
"sysfs"
,
MS_NODEV
|
MS_NOEXEC
|
MS_NOSUID
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"sysfs"
,
"%r/sys"
,
"sysfs"
,
MS_NODEV
|
MS_NOEXEC
|
MS_NOSUID
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"%r/sys"
,
"%r/sys"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"%r/sys"
,
"%r/sys"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
NULL
,
"%r/sys"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_RDONLY
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
NULL
,
"%r/sys"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_RDONLY
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"sysfs"
,
"%r/sys/devices/virtual/net"
,
"sysfs"
,
0
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"sysfs"
,
"%r/sys/devices/virtual/net"
,
"sysfs"
,
0
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"%r/sys/devices/virtual/net/devices/virtual/net"
,
"%r/sys/devices/virtual/net"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
"%r/sys/devices/virtual/net/devices/virtual/net"
,
"%r/sys/devices/virtual/net"
,
NULL
,
MS_BIND
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
NULL
,
"%r/sys/devices/virtual/net"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_NOSUID
|
MS_NODEV
|
MS_NOEXEC
,
NULL
},
{
LXC_AUTO_SYS_MASK
,
LXC_AUTO_SYS_MIXED
,
NULL
,
"%r/sys/devices/virtual/net"
,
NULL
,
MS_REMOUNT
|
MS_BIND
|
MS_NOSUID
|
MS_NODEV
|
MS_NOEXEC
,
NULL
},
{
0
,
0
,
NULL
,
NULL
,
NULL
,
0
,
NULL
}
{
0
,
0
,
NULL
,
NULL
,
NULL
,
0
,
NULL
}
};
};
for
(
i
=
0
;
default_mounts
[
i
].
match_mask
;
i
++
)
{
for
(
i
=
0
;
default_mounts
[
i
].
match_mask
;
i
++
)
{
if
((
flags
&
default_mounts
[
i
].
match_mask
)
==
default_mounts
[
i
].
match_flag
)
{
int
saved_errno
;
char
*
source
=
NULL
;
unsigned
long
mflags
;
char
*
destination
=
NULL
;
char
*
destination
=
NULL
;
int
saved_errno
;
char
*
source
=
NULL
;
unsigned
long
mflags
;
if
((
flags
&
default_mounts
[
i
].
match_mask
)
!=
default_mounts
[
i
].
match_flag
)
continue
;
if
(
default_mounts
[
i
].
source
)
{
/* will act like strdup if %r is not present */
if
(
default_mounts
[
i
].
source
)
{
source
=
lxc_string_replace
(
"%r"
,
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
default_mounts
[
i
].
source
);
if
(
!
source
)
{
SYSERROR
(
"memory allocation error"
);
return
-
1
;
}
}
if
(
!
default_mounts
[
i
].
destination
)
{
ERROR
(
"BUG: auto mounts destination %d was NULL"
,
i
);
free
(
source
);
return
-
1
;
}
/* will act like strdup if %r is not present */
/* will act like strdup if %r is not present */
destination
=
lxc_string_replace
(
"%r"
,
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
default_mounts
[
i
].
destination
);
source
=
lxc_string_replace
(
"%r"
,
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
default_mounts
[
i
].
source
);
if
(
!
destination
)
{
if
(
!
source
)
saved_errno
=
errno
;
SYSERROR
(
"memory allocation error"
);
free
(
source
);
errno
=
saved_errno
;
return
-
1
;
return
-
1
;
}
}
mflags
=
add_required_remount_flags
(
source
,
destination
,
default_mounts
[
i
].
flags
);
r
=
safe_mount
(
source
,
destination
,
default_mounts
[
i
].
fstype
,
mflags
,
default_mounts
[
i
].
options
,
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
NULL
);
saved_errno
=
errno
;
if
(
r
<
0
&&
errno
==
ENOENT
)
{
INFO
(
"Mount source or target for %s on %s doesn't exist. Skipping."
,
source
,
destination
);
r
=
0
;
}
else
if
(
r
<
0
)
SYSERROR
(
"error mounting %s on %s flags %lu"
,
source
,
destination
,
mflags
);
if
(
!
default_mounts
[
i
].
destination
)
{
ERROR
(
"BUG: auto mounts destination %d was NULL"
,
i
);
free
(
source
);
free
(
source
);
free
(
destination
);
return
-
1
;
if
(
r
<
0
)
{
}
errno
=
saved_errno
;
return
-
1
;
/* will act like strdup if %r is not present */
}
destination
=
lxc_string_replace
(
"%r"
,
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
default_mounts
[
i
].
destination
);
if
(
!
destination
)
{
saved_errno
=
errno
;
free
(
source
);
errno
=
saved_errno
;
return
-
1
;
}
mflags
=
add_required_remount_flags
(
source
,
destination
,
default_mounts
[
i
].
flags
);
r
=
safe_mount
(
source
,
destination
,
default_mounts
[
i
].
fstype
,
mflags
,
default_mounts
[
i
].
options
,
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
NULL
);
saved_errno
=
errno
;
if
(
r
<
0
&&
errno
==
ENOENT
)
{
INFO
(
"Mount source or target for
\"
%s
\"
on
\"
%s
\"
does "
"not exist. Skipping"
,
source
,
destination
);
r
=
0
;
}
else
if
(
r
<
0
)
{
SYSERROR
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
with flags %lu"
,
source
,
destination
,
mflags
);
}
free
(
source
);
free
(
destination
);
if
(
r
<
0
)
{
errno
=
saved_errno
;
return
-
1
;
}
}
}
}
...
@@ -718,14 +722,16 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
...
@@ -718,14 +722,16 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
int
cg_flags
;
int
cg_flags
;
cg_flags
=
flags
&
(
LXC_AUTO_CGROUP_MASK
&
~
LXC_AUTO_CGROUP_FORCE
);
cg_flags
=
flags
&
(
LXC_AUTO_CGROUP_MASK
&
~
LXC_AUTO_CGROUP_FORCE
);
/* If the type of cgroup mount was not specified, it depends on the
/* If the type of cgroup mount was not specified, it depends on
* container's capabilities as to what makes sense: if we have
* the container's capabilities as to what makes sense: if we
* CAP_SYS_ADMIN, the read-only part can be remounted read-write
* have CAP_SYS_ADMIN, the read-only part can be remounted
* anyway, so we may as well default to read-write; then the admin
* read-write anyway, so we may as well default to read-write;
* will not be given a false sense of security. (And if they really
* then the admin will not be given a false sense of security.
* want mixed r/o r/w, then they can explicitly specify :mixed.)
* (And if they really want mixed r/o r/w, then they can
* OTOH, if the container lacks CAP_SYS_ADMIN, do only default to
* explicitly specify :mixed.) OTOH, if the container lacks
* :mixed, because then the container can't remount it read-write. */
* CAP_SYS_ADMIN, do only default to :mixed, because then the
* container can't remount it read-write.
*/
if
(
cg_flags
==
LXC_AUTO_CGROUP_NOSPEC
||
cg_flags
==
LXC_AUTO_CGROUP_FULL_NOSPEC
)
{
if
(
cg_flags
==
LXC_AUTO_CGROUP_NOSPEC
||
cg_flags
==
LXC_AUTO_CGROUP_FULL_NOSPEC
)
{
int
has_sys_admin
=
0
;
int
has_sys_admin
=
0
;
...
@@ -739,10 +745,12 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
...
@@ -739,10 +745,12 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
else
else
cg_flags
=
has_sys_admin
?
LXC_AUTO_CGROUP_FULL_RW
:
LXC_AUTO_CGROUP_FULL_MIXED
;
cg_flags
=
has_sys_admin
?
LXC_AUTO_CGROUP_FULL_RW
:
LXC_AUTO_CGROUP_FULL_MIXED
;
}
}
if
(
flags
&
LXC_AUTO_CGROUP_FORCE
)
if
(
flags
&
LXC_AUTO_CGROUP_FORCE
)
cg_flags
|=
LXC_AUTO_CGROUP_FORCE
;
cg_flags
|=
LXC_AUTO_CGROUP_FORCE
;
if
(
!
cgroup_mount
(
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
handler
,
cg_flags
))
{
if
(
!
cgroup_mount
(
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
handler
,
cg_flags
))
{
SYSERROR
(
"
error mounting /sys/fs/cgroup
"
);
SYSERROR
(
"
Failed to mount
\"
/sys/fs/cgroup
\"
"
);
return
-
1
;
return
-
1
;
}
}
}
}
...
@@ -752,15 +760,18 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
...
@@ -752,15 +760,18 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
static
int
setup_utsname
(
struct
utsname
*
utsname
)
static
int
setup_utsname
(
struct
utsname
*
utsname
)
{
{
int
ret
;
if
(
!
utsname
)
if
(
!
utsname
)
return
0
;
return
0
;
if
(
sethostname
(
utsname
->
nodename
,
strlen
(
utsname
->
nodename
)))
{
ret
=
sethostname
(
utsname
->
nodename
,
strlen
(
utsname
->
nodename
));
SYSERROR
(
"failed to set the hostname to '%s'"
,
utsname
->
nodename
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set the hostname to
\"
%s
\"
"
,
utsname
->
nodename
);
return
-
1
;
return
-
1
;
}
}
INFO
(
"
'%s' hostname has been setup
"
,
utsname
->
nodename
);
INFO
(
"
Set hostname to
\"
%s
\"
"
,
utsname
->
nodename
);
return
0
;
return
0
;
}
}
...
@@ -771,44 +782,44 @@ struct dev_symlinks {
...
@@ -771,44 +782,44 @@ struct dev_symlinks {
};
};
static
const
struct
dev_symlinks
dev_symlinks
[]
=
{
static
const
struct
dev_symlinks
dev_symlinks
[]
=
{
{
"/proc/self/fd"
,
"fd"
},
{
"/proc/self/fd"
,
"fd"
},
{
"/proc/self/fd/0"
,
"stdin"
},
{
"/proc/self/fd/0"
,
"stdin"
},
{
"/proc/self/fd/1"
,
"stdout"
},
{
"/proc/self/fd/1"
,
"stdout"
},
{
"/proc/self/fd/2"
,
"stderr"
},
{
"/proc/self/fd/2"
,
"stderr"
},
};
};
static
int
lxc_setup_dev_symlinks
(
const
struct
lxc_rootfs
*
rootfs
)
static
int
lxc_setup_dev_symlinks
(
const
struct
lxc_rootfs
*
rootfs
)
{
{
int
i
,
ret
;
char
path
[
MAXPATHLEN
];
char
path
[
MAXPATHLEN
];
int
ret
,
i
;
struct
stat
s
;
struct
stat
s
;
for
(
i
=
0
;
i
<
sizeof
(
dev_symlinks
)
/
sizeof
(
dev_symlinks
[
0
]);
i
++
)
{
for
(
i
=
0
;
i
<
sizeof
(
dev_symlinks
)
/
sizeof
(
dev_symlinks
[
0
]);
i
++
)
{
const
struct
dev_symlinks
*
d
=
&
dev_symlinks
[
i
];
const
struct
dev_symlinks
*
d
=
&
dev_symlinks
[
i
];
ret
=
snprintf
(
path
,
sizeof
(
path
),
"%s/dev/%s"
,
rootfs
->
path
?
rootfs
->
mount
:
""
,
d
->
name
);
ret
=
snprintf
(
path
,
sizeof
(
path
),
"%s/dev/%s"
,
rootfs
->
path
?
rootfs
->
mount
:
""
,
d
->
name
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
return
-
1
;
return
-
1
;
/*
/* Stat the path first. If we don't get an error accept it as
* Stat the path first. If we don't get an error
* is and don't try to create it
* accept it as is and don't try to create it
*/
*/
if
(
!
stat
(
path
,
&
s
))
{
ret
=
stat
(
path
,
&
s
);
if
(
ret
==
0
)
continue
;
continue
;
}
ret
=
symlink
(
d
->
oldpath
,
path
);
ret
=
symlink
(
d
->
oldpath
,
path
);
if
(
ret
&&
errno
!=
EEXIST
)
{
if
(
ret
&&
errno
!=
EEXIST
)
{
if
(
errno
==
EROFS
)
{
if
(
errno
==
EROFS
)
{
WARN
(
"
Warning: Read Only file system while creating %s
"
,
path
);
WARN
(
"
Failed to create
\"
%s
\"
. Read-only filesystem
"
,
path
);
}
else
{
}
else
{
SYSERROR
(
"
Error creating %s
"
,
path
);
SYSERROR
(
"
Failed to create
\"
%s
\"
"
,
path
);
return
-
1
;
return
-
1
;
}
}
}
}
}
}
return
0
;
return
0
;
}
}
...
@@ -821,15 +832,19 @@ static bool append_ptyname(char **pp, char *name)
...
@@ -821,15 +832,19 @@ static bool append_ptyname(char **pp, char *name)
*
pp
=
malloc
(
strlen
(
name
)
+
strlen
(
"container_ttys="
)
+
1
);
*
pp
=
malloc
(
strlen
(
name
)
+
strlen
(
"container_ttys="
)
+
1
);
if
(
!*
pp
)
if
(
!*
pp
)
return
false
;
return
false
;
sprintf
(
*
pp
,
"container_ttys=%s"
,
name
);
sprintf
(
*
pp
,
"container_ttys=%s"
,
name
);
return
true
;
return
true
;
}
}
p
=
realloc
(
*
pp
,
strlen
(
*
pp
)
+
strlen
(
name
)
+
2
);
p
=
realloc
(
*
pp
,
strlen
(
*
pp
)
+
strlen
(
name
)
+
2
);
if
(
!
p
)
if
(
!
p
)
return
false
;
return
false
;
*
pp
=
p
;
*
pp
=
p
;
strcat
(
p
,
" "
);
strcat
(
p
,
" "
);
strcat
(
p
,
name
);
strcat
(
p
,
name
);
return
true
;
return
true
;
}
}
...
@@ -877,7 +892,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
...
@@ -877,7 +892,7 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
tty
->
name
,
path
);
tty
->
name
,
path
);
continue
;
continue
;
}
}
DEBUG
(
"
b
ind mounted
\"
%s
\"
onto
\"
%s
\"
"
,
tty
->
name
,
DEBUG
(
"
B
ind mounted
\"
%s
\"
onto
\"
%s
\"
"
,
tty
->
name
,
path
);
path
);
ret
=
snprintf
(
lxcpath
,
sizeof
(
lxcpath
),
"%s/tty%d"
,
ret
=
snprintf
(
lxcpath
,
sizeof
(
lxcpath
),
"%s/tty%d"
,
...
@@ -928,8 +943,8 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
...
@@ -928,8 +943,8 @@ static int lxc_setup_ttys(struct lxc_conf *conf)
int
lxc_allocate_ttys
(
const
char
*
name
,
struct
lxc_conf
*
conf
)
int
lxc_allocate_ttys
(
const
char
*
name
,
struct
lxc_conf
*
conf
)
{
{
struct
lxc_tty_info
*
ttys
=
&
conf
->
ttys
;
int
i
,
ret
;
int
i
,
ret
;
struct
lxc_tty_info
*
ttys
=
&
conf
->
ttys
;
/* no tty in the configuration */
/* no tty in the configuration */
if
(
!
conf
->
tty
)
if
(
!
conf
->
tty
)
...
@@ -945,26 +960,26 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
...
@@ -945,26 +960,26 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
ret
=
openpty
(
&
tty
->
master
,
&
tty
->
slave
,
ret
=
openpty
(
&
tty
->
master
,
&
tty
->
slave
,
tty
->
name
,
NULL
,
NULL
);
tty
->
name
,
NULL
,
NULL
);
if
(
ret
)
{
if
(
ret
)
{
SYSERROR
(
"
failed to create pty device number
%d"
,
i
);
SYSERROR
(
"
Failed to create tty
%d"
,
i
);
ttys
->
nbtty
=
i
;
ttys
->
nbtty
=
i
;
lxc_delete_tty
(
ttys
);
lxc_delete_tty
(
ttys
);
return
-
ENOTTY
;
return
-
ENOTTY
;
}
}
DEBUG
(
"
allocated p
ty
\"
%s
\"
with master fd %d and slave fd %d"
,
DEBUG
(
"
Created t
ty
\"
%s
\"
with master fd %d and slave fd %d"
,
tty
->
name
,
tty
->
master
,
tty
->
slave
);
tty
->
name
,
tty
->
master
,
tty
->
slave
);
/* Prevent leaking the file descriptors to the container */
/* Prevent leaking the file descriptors to the container */
ret
=
fcntl
(
tty
->
master
,
F_SETFD
,
FD_CLOEXEC
);
ret
=
fcntl
(
tty
->
master
,
F_SETFD
,
FD_CLOEXEC
);
if
(
ret
<
0
)
if
(
ret
<
0
)
WARN
(
"
f
ailed to set FD_CLOEXEC flag on master fd %d of "
WARN
(
"
F
ailed to set FD_CLOEXEC flag on master fd %d of "
"
p
ty device
\"
%s
\"
: %s"
,
"
t
ty device
\"
%s
\"
: %s"
,
tty
->
master
,
tty
->
name
,
strerror
(
errno
));
tty
->
master
,
tty
->
name
,
strerror
(
errno
));
ret
=
fcntl
(
tty
->
slave
,
F_SETFD
,
FD_CLOEXEC
);
ret
=
fcntl
(
tty
->
slave
,
F_SETFD
,
FD_CLOEXEC
);
if
(
ret
<
0
)
if
(
ret
<
0
)
WARN
(
"
f
ailed to set FD_CLOEXEC flag on slave fd %d of "
WARN
(
"
F
ailed to set FD_CLOEXEC flag on slave fd %d of "
"
p
ty device
\"
%s
\"
: %s"
,
"
t
ty device
\"
%s
\"
: %s"
,
tty
->
slave
,
tty
->
name
,
strerror
(
errno
));
tty
->
slave
,
tty
->
name
,
strerror
(
errno
));
tty
->
busy
=
0
;
tty
->
busy
=
0
;
...
@@ -972,7 +987,7 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
...
@@ -972,7 +987,7 @@ int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
ttys
->
nbtty
=
conf
->
tty
;
ttys
->
nbtty
=
conf
->
tty
;
INFO
(
"
finished allocating %d pts
devices"
,
conf
->
tty
);
INFO
(
"
Finished creating %d tty
devices"
,
conf
->
tty
);
return
0
;
return
0
;
}
}
...
@@ -995,12 +1010,12 @@ void lxc_delete_tty(struct lxc_tty_info *ttys)
...
@@ -995,12 +1010,12 @@ void lxc_delete_tty(struct lxc_tty_info *ttys)
static
int
lxc_send_ttys_to_parent
(
struct
lxc_handler
*
handler
)
static
int
lxc_send_ttys_to_parent
(
struct
lxc_handler
*
handler
)
{
{
int
i
;
int
i
;
int
ret
=
-
1
;
struct
lxc_conf
*
conf
=
handler
->
conf
;
struct
lxc_conf
*
conf
=
handler
->
conf
;
struct
lxc_tty_info
*
ttys
=
&
conf
->
ttys
;
struct
lxc_tty_info
*
ttys
=
&
conf
->
ttys
;
int
sock
=
handler
->
data_sock
[
0
];
int
sock
=
handler
->
data_sock
[
0
];
int
ret
=
-
1
;
if
(
!
conf
->
tty
)
if
(
conf
->
tty
==
0
)
return
0
;
return
0
;
for
(
i
=
0
;
i
<
conf
->
tty
;
i
++
)
{
for
(
i
=
0
;
i
<
conf
->
tty
;
i
++
)
{
...
@@ -1014,7 +1029,7 @@ static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
...
@@ -1014,7 +1029,7 @@ static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
if
(
ret
<
0
)
if
(
ret
<
0
)
break
;
break
;
TRACE
(
"Sen
d p
ty
\"
%s
\"
with master fd %d and slave fd %d to "
TRACE
(
"Sen
t
ty
\"
%s
\"
with master fd %d and slave fd %d to "
"parent"
,
tty
->
name
,
tty
->
master
,
tty
->
slave
);
"parent"
,
tty
->
name
,
tty
->
master
,
tty
->
slave
);
}
}
...
@@ -1068,62 +1083,70 @@ on_error:
...
@@ -1068,62 +1083,70 @@ on_error:
static
int
setup_rootfs_pivot_root
(
const
char
*
rootfs
)
static
int
setup_rootfs_pivot_root
(
const
char
*
rootfs
)
{
{
int
oldroot
=
-
1
,
newroot
=
-
1
;
int
ret
;
int
newroot
=
-
1
,
oldroot
=
-
1
;
oldroot
=
open
(
"/"
,
O_DIRECTORY
|
O_RDONLY
);
oldroot
=
open
(
"/"
,
O_DIRECTORY
|
O_RDONLY
);
if
(
oldroot
<
0
)
{
if
(
oldroot
<
0
)
{
SYSERROR
(
"
Error opening old-/ for fchdir
"
);
SYSERROR
(
"
Failed to open old root directory
"
);
return
-
1
;
return
-
1
;
}
}
newroot
=
open
(
rootfs
,
O_DIRECTORY
|
O_RDONLY
);
newroot
=
open
(
rootfs
,
O_DIRECTORY
|
O_RDONLY
);
if
(
newroot
<
0
)
{
if
(
newroot
<
0
)
{
SYSERROR
(
"
Error opening new-/ for fchdir
"
);
SYSERROR
(
"
Failed to open new root directory
"
);
goto
fail
;
goto
on_error
;
}
}
/* change into new root fs */
/* change into new root fs */
if
(
fchdir
(
newroot
))
{
ret
=
fchdir
(
newroot
);
SYSERROR
(
"can't chdir to new rootfs '%s'"
,
rootfs
);
if
(
ret
<
0
)
{
goto
fail
;
SYSERROR
(
"Failed to change to new rootfs
\"
%s
\"
"
,
rootfs
);
goto
on_error
;
}
}
/* pivot_root into our new root fs */
/* pivot_root into our new root fs */
if
(
pivot_root
(
"."
,
"."
))
{
ret
=
pivot_root
(
"."
,
"."
);
SYSERROR
(
"pivot_root syscall failed"
);
if
(
ret
<
0
)
{
goto
fail
;
SYSERROR
(
"Failed to pivot_root()"
);
goto
on_error
;
}
}
/*
/* At this point the old-root is mounted on top of our new-root To
* at this point the old-root is mounted on top of our new-root
* unmounted it we must not be chdir'd into it, so escape back to
* To unmounted it we must not be chdir'd into it, so escape back
* old-root.
* to old-root
*/
*/
if
(
fchdir
(
oldroot
)
<
0
)
{
ret
=
fchdir
(
oldroot
);
SYSERROR
(
"Error entering oldroot"
);
if
(
ret
<
0
)
{
goto
fail
;
SYSERROR
(
"Failed to enter old root directory"
);
goto
on_error
;
}
}
if
(
umount2
(
"."
,
MNT_DETACH
)
<
0
)
{
SYSERROR
(
"Error detaching old root"
);
ret
=
umount2
(
"."
,
MNT_DETACH
);
goto
fail
;
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to detach old root directory"
);
goto
on_error
;
}
}
if
(
fchdir
(
newroot
)
<
0
)
{
ret
=
fchdir
(
newroot
);
SYSERROR
(
"Error re-entering newroot"
);
if
(
ret
<
0
)
{
goto
fail
;
SYSERROR
(
"Failed to re-enter new root directory"
);
goto
on_error
;
}
}
close
(
oldroot
);
close
(
oldroot
);
close
(
newroot
);
close
(
newroot
);
DEBUG
(
"pivot_root
syscall to '%s'
successful"
,
rootfs
);
DEBUG
(
"pivot_root
(
\"
%s
\"
)
successful"
,
rootfs
);
return
0
;
return
0
;
fail
:
on_error
:
if
(
oldroot
!=
-
1
)
if
(
oldroot
!=
-
1
)
close
(
oldroot
);
close
(
oldroot
);
if
(
newroot
!=
-
1
)
if
(
newroot
!=
-
1
)
close
(
newroot
);
close
(
newroot
);
return
-
1
;
return
-
1
;
}
}
...
@@ -1275,22 +1298,25 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
...
@@ -1275,22 +1298,25 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
rootfs
=
&
conf
->
rootfs
;
rootfs
=
&
conf
->
rootfs
;
if
(
!
rootfs
->
path
)
{
if
(
!
rootfs
->
path
)
{
if
(
mount
(
""
,
"/"
,
NULL
,
MS_SLAVE
|
MS_REC
,
0
))
{
ret
=
mount
(
""
,
"/"
,
NULL
,
MS_SLAVE
|
MS_REC
,
0
);
SYSERROR
(
"Failed to make / rslave."
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to make / rslave"
);
return
-
1
;
return
-
1
;
}
}
return
0
;
return
0
;
}
}
if
(
access
(
rootfs
->
mount
,
F_OK
))
{
ret
=
access
(
rootfs
->
mount
,
F_OK
);
SYSERROR
(
"Failed to access to
\"
%s
\"
. Check it is present."
,
if
(
ret
!=
0
)
{
SYSERROR
(
"Failed to access to
\"
%s
\"
. Check it is present"
,
rootfs
->
mount
);
rootfs
->
mount
);
return
-
1
;
return
-
1
;
}
}
bdev
=
storage_init
(
conf
);
bdev
=
storage_init
(
conf
);
if
(
!
bdev
)
{
if
(
!
bdev
)
{
ERROR
(
"Failed to mount rootfs
\"
%s
\"
onto
\"
%s
\"
with options
\"
%s
\"
.
"
,
ERROR
(
"Failed to mount rootfs
\"
%s
\"
onto
\"
%s
\"
with options
\"
%s
\"
"
,
rootfs
->
path
,
rootfs
->
mount
,
rootfs
->
path
,
rootfs
->
mount
,
rootfs
->
options
?
rootfs
->
options
:
"(null)"
);
rootfs
->
options
?
rootfs
->
options
:
"(null)"
);
return
-
1
;
return
-
1
;
...
@@ -1299,13 +1325,13 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
...
@@ -1299,13 +1325,13 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
ret
=
bdev
->
ops
->
mount
(
bdev
);
ret
=
bdev
->
ops
->
mount
(
bdev
);
storage_put
(
bdev
);
storage_put
(
bdev
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to mount rootfs
\"
%s
\"
onto
\"
%s
\"
with options
\"
%s
\"
.
"
,
ERROR
(
"Failed to mount rootfs
\"
%s
\"
onto
\"
%s
\"
with options
\"
%s
\"
"
,
rootfs
->
path
,
rootfs
->
mount
,
rootfs
->
path
,
rootfs
->
mount
,
rootfs
->
options
?
rootfs
->
options
:
"(null)"
);
rootfs
->
options
?
rootfs
->
options
:
"(null)"
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"Mounted rootfs
\"
%s
\"
onto
\"
%s
\"
with options
\"
%s
\"
.
"
,
DEBUG
(
"Mounted rootfs
\"
%s
\"
onto
\"
%s
\"
with options
\"
%s
\"
"
,
rootfs
->
path
,
rootfs
->
mount
,
rootfs
->
path
,
rootfs
->
mount
,
rootfs
->
options
?
rootfs
->
options
:
"(null)"
);
rootfs
->
options
?
rootfs
->
options
:
"(null)"
);
...
@@ -1314,35 +1340,35 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
...
@@ -1314,35 +1340,35 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
int
prepare_ramfs_root
(
char
*
root
)
int
prepare_ramfs_root
(
char
*
root
)
{
{
char
buf
[
LXC_LINELEN
],
*
p
;
int
i
,
ret
;
char
nroot
[
PATH_MAX
];
char
*
p
,
*
p2
;
char
buf
[
LXC_LINELEN
],
nroot
[
PATH_MAX
];
FILE
*
f
;
FILE
*
f
;
int
i
;
char
*
p2
;
if
(
realpath
(
root
,
nroot
)
==
NULL
)
if
(
!
realpath
(
root
,
nroot
)
)
return
-
errno
;
return
-
1
;
if
(
chdir
(
"/"
)
==
-
1
)
ret
=
chdir
(
"/"
);
return
-
errno
;
if
(
ret
<
0
)
return
-
1
;
/*
/* We could use here MS_MOVE, but in userns this mount is locked and
* We could use here MS_MOVE, but in userns this mount is
* can't be moved.
* locked and can't be moved.
*/
*/
if
(
mount
(
root
,
"/"
,
NULL
,
MS_REC
|
MS_BIND
,
NULL
)
<
0
)
{
ret
=
mount
(
root
,
"/"
,
NULL
,
MS_REC
|
MS_BIND
,
NULL
);
SYSERROR
(
"Failed to move %s into /"
,
root
);
if
(
ret
<
0
)
{
return
-
errno
;
SYSERROR
(
"Failed to move
\"
%s
\"
into
\"
/
\"
"
,
root
);
return
-
1
;
}
}
if
(
mount
(
NULL
,
"/"
,
NULL
,
MS_REC
|
MS_PRIVATE
,
NULL
)
<
0
)
{
ret
=
mount
(
NULL
,
"/"
,
NULL
,
MS_REC
|
MS_PRIVATE
,
NULL
);
SYSERROR
(
"Failed to make . rprivate"
);
if
(
ret
<
0
)
{
return
-
errno
;
SYSERROR
(
"Failed to make
\"
/
\"
rprivate"
);
return
-
1
;
}
}
/*
/* The following code cleans up inhereted mounts which are not required
* The following code cleans up inhereted mounts which are not
* for CT.
* required for CT.
*
*
* The mountinfo file shows not all mounts, if a few points have been
* The mountinfo file shows not all mounts, if a few points have been
* unmounted between read operations from the mountinfo. So we need to
* unmounted between read operations from the mountinfo. So we need to
...
@@ -1351,7 +1377,7 @@ int prepare_ramfs_root(char *root)
...
@@ -1351,7 +1377,7 @@ int prepare_ramfs_root(char *root)
* This loop can be skipped if a container uses unserns, because all
* This loop can be skipped if a container uses unserns, because all
* inherited mounts are locked and we should live with all this trash.
* inherited mounts are locked and we should live with all this trash.
*/
*/
while
(
1
)
{
for
(;;
)
{
int
progress
=
0
;
int
progress
=
0
;
f
=
fopen
(
"./proc/self/mountinfo"
,
"r"
);
f
=
fopen
(
"./proc/self/mountinfo"
,
"r"
);
...
@@ -1359,11 +1385,14 @@ int prepare_ramfs_root(char *root)
...
@@ -1359,11 +1385,14 @@ int prepare_ramfs_root(char *root)
SYSERROR
(
"Unable to open /proc/self/mountinfo"
);
SYSERROR
(
"Unable to open /proc/self/mountinfo"
);
return
-
1
;
return
-
1
;
}
}
while
(
fgets
(
buf
,
LXC_LINELEN
,
f
))
{
while
(
fgets
(
buf
,
LXC_LINELEN
,
f
))
{
for
(
p
=
buf
,
i
=
0
;
p
&&
i
<
4
;
i
++
)
for
(
p
=
buf
,
i
=
0
;
p
&&
i
<
4
;
i
++
)
p
=
strchr
(
p
+
1
,
' '
);
p
=
strchr
(
p
+
1
,
' '
);
if
(
!
p
)
if
(
!
p
)
continue
;
continue
;
p2
=
strchr
(
p
+
1
,
' '
);
p2
=
strchr
(
p
+
1
,
' '
);
if
(
!
p2
)
if
(
!
p2
)
continue
;
continue
;
...
@@ -1373,27 +1402,33 @@ int prepare_ramfs_root(char *root)
...
@@ -1373,27 +1402,33 @@ int prepare_ramfs_root(char *root)
if
(
strcmp
(
p
+
1
,
"/"
)
==
0
)
if
(
strcmp
(
p
+
1
,
"/"
)
==
0
)
continue
;
continue
;
if
(
strcmp
(
p
+
1
,
"/proc"
)
==
0
)
if
(
strcmp
(
p
+
1
,
"/proc"
)
==
0
)
continue
;
continue
;
if
(
umount2
(
p
,
MNT_DETACH
)
==
0
)
ret
=
umount2
(
p
,
MNT_DETACH
);
if
(
ret
==
0
)
progress
++
;
progress
++
;
}
}
fclose
(
f
);
fclose
(
f
);
if
(
!
progress
)
if
(
!
progress
)
break
;
break
;
}
}
/* This also can be skipped if a container uses unserns */
/* This also can be skipped if a container uses unserns
.
*/
umount2
(
"./proc"
,
MNT_DETACH
);
(
void
)
umount2
(
"./proc"
,
MNT_DETACH
);
/* It is weird, but chdir("..") moves us in a new root */
/* It is weird, but chdir("..") moves us in a new root */
if
(
chdir
(
".."
)
==
-
1
)
{
ret
=
chdir
(
".."
);
if
(
ret
<
0
)
{
SYSERROR
(
"Unable to change working directory"
);
SYSERROR
(
"Unable to change working directory"
);
return
-
1
;
return
-
1
;
}
}
if
(
chroot
(
"."
)
==
-
1
)
{
ret
=
chroot
(
"."
);
if
(
ret
<
0
)
{
SYSERROR
(
"Unable to chroot"
);
SYSERROR
(
"Unable to chroot"
);
return
-
1
;
return
-
1
;
}
}
...
@@ -1403,28 +1438,33 @@ int prepare_ramfs_root(char *root)
...
@@ -1403,28 +1438,33 @@ int prepare_ramfs_root(char *root)
static
int
setup_pivot_root
(
const
struct
lxc_rootfs
*
rootfs
)
static
int
setup_pivot_root
(
const
struct
lxc_rootfs
*
rootfs
)
{
{
int
ret
;
if
(
!
rootfs
->
path
)
{
if
(
!
rootfs
->
path
)
{
DEBUG
(
"
container does not have a rootfs, so not doing pivot root
"
);
DEBUG
(
"
Container does not have a rootfs
"
);
return
0
;
return
0
;
}
}
if
(
detect_ramfs_rootfs
())
{
if
(
detect_ramfs_rootfs
())
{
DEBUG
(
"detected that container is on ramfs"
);
DEBUG
(
"Detected that container is on ramfs"
);
if
(
prepare_ramfs_root
(
rootfs
->
mount
))
{
ERROR
(
"failed to prepare minimal ramfs root"
);
ret
=
prepare_ramfs_root
(
rootfs
->
mount
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to prepare minimal ramfs root"
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"
p
repared ramfs root for container"
);
DEBUG
(
"
P
repared ramfs root for container"
);
return
0
;
return
0
;
}
}
if
(
setup_rootfs_pivot_root
(
rootfs
->
mount
)
<
0
)
{
ret
=
setup_rootfs_pivot_root
(
rootfs
->
mount
);
ERROR
(
"failed to pivot root"
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to pivot_root()"
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"
finished pivot root
"
);
DEBUG
(
"
Finished pivot_root()
"
);
return
0
;
return
0
;
}
}
...
@@ -1465,7 +1505,7 @@ static int lxc_setup_devpts(struct lxc_conf *conf)
...
@@ -1465,7 +1505,7 @@ static int lxc_setup_devpts(struct lxc_conf *conf)
char
devpts_mntopts
[
256
];
char
devpts_mntopts
[
256
];
if
(
conf
->
pts
<=
0
)
{
if
(
conf
->
pts
<=
0
)
{
DEBUG
(
"
n
o new devpts instance will be mounted since no pts "
DEBUG
(
"
N
o new devpts instance will be mounted since no pts "
"devices are requested"
);
"devices are requested"
);
return
0
;
return
0
;
}
}
...
@@ -1485,88 +1525,91 @@ static int lxc_setup_devpts(struct lxc_conf *conf)
...
@@ -1485,88 +1525,91 @@ static int lxc_setup_devpts(struct lxc_conf *conf)
if
(
!
ret
)
{
if
(
!
ret
)
{
ret
=
umount
(
"/dev/pts"
);
ret
=
umount
(
"/dev/pts"
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"
f
ailed to unmount old devpts instance"
);
SYSERROR
(
"
F
ailed to unmount old devpts instance"
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"
unmounted old /dev/
pts instance"
);
DEBUG
(
"
Unmounted old dev
pts instance"
);
}
}
/* Create mountpoint for devpts instance. */
/* Create mountpoint for devpts instance. */
ret
=
mkdir
(
"/dev/pts"
,
0755
);
ret
=
mkdir
(
"/dev/pts"
,
0755
);
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
SYSERROR
(
"
failed to create th
e
\"
/dev/pts
\"
directory"
);
SYSERROR
(
"
Failed to creat
e
\"
/dev/pts
\"
directory"
);
return
-
1
;
return
-
1
;
}
}
/* Mount new devpts instance. */
/* Mount new devpts instance. */
ret
=
mount
(
"devpts"
,
"/dev/pts"
,
"devpts"
,
MS_NOSUID
|
MS_NOEXEC
,
devpts_mntopts
);
ret
=
mount
(
"devpts"
,
"/dev/pts"
,
"devpts"
,
MS_NOSUID
|
MS_NOEXEC
,
devpts_mntopts
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"
f
ailed to mount new devpts instance"
);
SYSERROR
(
"
F
ailed to mount new devpts instance"
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"
m
ount new devpts instance with options
\"
%s
\"
"
,
devpts_mntopts
);
DEBUG
(
"
M
ount new devpts instance with options
\"
%s
\"
"
,
devpts_mntopts
);
/* Remove any pre-existing /dev/ptmx file. */
/* Remove any pre-existing /dev/ptmx file. */
ret
=
access
(
"/dev/ptmx"
,
F_OK
);
ret
=
access
(
"/dev/ptmx"
,
F_OK
);
if
(
!
ret
)
{
if
(
!
ret
)
{
ret
=
remove
(
"/dev/ptmx"
);
ret
=
remove
(
"/dev/ptmx"
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"
failed to remove existing
\"
/dev/ptmx
\"
"
);
SYSERROR
(
"
Failed to remove existing
\"
/dev/ptmx
\"
file
"
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"
removed existing
\"
/dev/ptmx
\"
"
);
DEBUG
(
"
Removed existing
\"
/dev/ptmx
\"
file
"
);
}
}
/* Create dummy /dev/ptmx file as bind mountpoint for /dev/pts/ptmx. */
/* Create dummy /dev/ptmx file as bind mountpoint for /dev/pts/ptmx. */
ret
=
open
(
"/dev/ptmx"
,
O_CREAT
,
0666
);
ret
=
open
(
"/dev/ptmx"
,
O_CREAT
,
0666
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"
f
ailed to create dummy
\"
/dev/ptmx
\"
file as bind mount target"
);
SYSERROR
(
"
F
ailed to create dummy
\"
/dev/ptmx
\"
file as bind mount target"
);
return
-
1
;
return
-
1
;
}
}
close
(
ret
);
close
(
ret
);
DEBUG
(
"
c
reated dummy
\"
/dev/ptmx
\"
file as bind mount target"
);
DEBUG
(
"
C
reated dummy
\"
/dev/ptmx
\"
file as bind mount target"
);
/* Fallback option: create symlink /dev/ptmx -> /dev/pts/ptmx */
/* Fallback option: create symlink /dev/ptmx -> /dev/pts/ptmx */
ret
=
mount
(
"/dev/pts/ptmx"
,
"/dev/ptmx"
,
NULL
,
MS_BIND
,
NULL
);
ret
=
mount
(
"/dev/pts/ptmx"
,
"/dev/ptmx"
,
NULL
,
MS_BIND
,
NULL
);
if
(
!
ret
)
{
if
(
!
ret
)
{
DEBUG
(
"
b
ind mounted
\"
/dev/pts/ptmx
\"
to
\"
/dev/ptmx
\"
"
);
DEBUG
(
"
B
ind mounted
\"
/dev/pts/ptmx
\"
to
\"
/dev/ptmx
\"
"
);
return
0
;
return
0
;
}
else
{
}
else
{
/* Fallthrough and try to create a symlink. */
/* Fallthrough and try to create a symlink. */
ERROR
(
"
f
ailed to bind mount
\"
/dev/pts/ptmx
\"
to
\"
/dev/ptmx
\"
"
);
ERROR
(
"
F
ailed to bind mount
\"
/dev/pts/ptmx
\"
to
\"
/dev/ptmx
\"
"
);
}
}
/* Remove the dummy /dev/ptmx file we created above. */
/* Remove the dummy /dev/ptmx file we created above. */
ret
=
remove
(
"/dev/ptmx"
);
ret
=
remove
(
"/dev/ptmx"
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"
f
ailed to remove existing
\"
/dev/ptmx
\"
"
);
SYSERROR
(
"
F
ailed to remove existing
\"
/dev/ptmx
\"
"
);
return
-
1
;
return
-
1
;
}
}
/* Fallback option: Create symlink /dev/ptmx -> /dev/pts/ptmx. */
/* Fallback option: Create symlink /dev/ptmx -> /dev/pts/ptmx. */
ret
=
symlink
(
"/dev/pts/ptmx"
,
"/dev/ptmx"
);
ret
=
symlink
(
"/dev/pts/ptmx"
,
"/dev/ptmx"
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"
failed to create symlink
\"
/dev/ptmx
\"
->
\"
/dev/pts/ptmx
\"
"
);
SYSERROR
(
"
Failed to create symlink from
\"
/dev/ptmx
\"
to
\"
/dev/pts/ptmx
\"
"
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"
created symlink
\"
/dev/ptmx
\"
->
\"
/dev/pts/ptmx
\"
"
);
DEBUG
(
"
Created symlink from
\"
/dev/ptmx
\"
to
\"
/dev/pts/ptmx
\"
"
);
return
0
;
return
0
;
}
}
static
int
setup_personality
(
int
persona
)
static
int
setup_personality
(
int
persona
)
{
{
#if HAVE_SYS_PERSONALITY_H
int
ret
;
#if HAVE_SYS_PERSONALITY_H
if
(
persona
==
-
1
)
if
(
persona
==
-
1
)
return
0
;
return
0
;
if
(
personality
(
persona
)
<
0
)
{
ret
=
personality
(
persona
);
SYSERROR
(
"failed to set personality to '0x%x'"
,
persona
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set personality to
\"
0x%x
\"
"
,
persona
);
return
-
1
;
return
-
1
;
}
}
INFO
(
"
set personality to '0x%x'
"
,
persona
);
INFO
(
"
Set personality to
\"
0x%x
\"
"
,
persona
);
#endif
#endif
return
0
;
return
0
;
}
}
...
@@ -1574,8 +1617,8 @@ static int setup_personality(int persona)
...
@@ -1574,8 +1617,8 @@ static int setup_personality(int persona)
static
int
lxc_setup_dev_console
(
const
struct
lxc_rootfs
*
rootfs
,
static
int
lxc_setup_dev_console
(
const
struct
lxc_rootfs
*
rootfs
,
const
struct
lxc_terminal
*
console
)
const
struct
lxc_terminal
*
console
)
{
{
int
fd
,
ret
;
char
path
[
MAXPATHLEN
];
char
path
[
MAXPATHLEN
];
int
ret
,
fd
;
char
*
rootfs_path
=
rootfs
->
path
?
rootfs
->
mount
:
""
;
char
*
rootfs_path
=
rootfs
->
path
?
rootfs
->
mount
:
""
;
if
(
console
->
path
&&
!
strcmp
(
console
->
path
,
"none"
))
if
(
console
->
path
&&
!
strcmp
(
console
->
path
,
"none"
))
...
@@ -1613,13 +1656,14 @@ static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs,
...
@@ -1613,13 +1656,14 @@ static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs,
ret
=
chmod
(
console
->
name
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
);
ret
=
chmod
(
console
->
name
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set mode '0%o' to '%s'"
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
,
console
->
name
);
SYSERROR
(
"Failed to set mode
\"
0%o
\"
to
\"
%s
\"
"
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
,
console
->
name
);
return
-
errno
;
return
-
errno
;
}
}
ret
=
safe_mount
(
console
->
name
,
path
,
"none"
,
MS_BIND
,
0
,
rootfs_path
);
ret
=
safe_mount
(
console
->
name
,
path
,
"none"
,
MS_BIND
,
0
,
rootfs_path
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to mount
'%s' on '%s'
"
,
console
->
name
,
path
);
ERROR
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
"
,
console
->
name
,
path
);
return
-
1
;
return
-
1
;
}
}
...
@@ -1645,7 +1689,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
...
@@ -1645,7 +1689,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
ret
=
mkdir
(
path
,
0755
);
ret
=
mkdir
(
path
,
0755
);
if
(
ret
&&
errno
!=
EEXIST
)
{
if
(
ret
&&
errno
!=
EEXIST
)
{
SYSERROR
(
"Failed
with errno %d to create %s"
,
errno
,
path
);
SYSERROR
(
"Failed
to create
\"
%s
\"
"
,
path
);
return
-
errno
;
return
-
errno
;
}
}
DEBUG
(
"Created directory for console and tty devices at
\"
%s
\"
"
,
path
);
DEBUG
(
"Created directory for console and tty devices at
\"
%s
\"
"
,
path
);
...
@@ -1656,7 +1700,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
...
@@ -1656,7 +1700,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
ret
=
creat
(
lxcpath
,
0660
);
ret
=
creat
(
lxcpath
,
0660
);
if
(
ret
==
-
1
&&
errno
!=
EEXIST
)
{
if
(
ret
==
-
1
&&
errno
!=
EEXIST
)
{
SYSERROR
(
"
Error %d creating %s"
,
errno
,
lxcpath
);
SYSERROR
(
"
Failed to create
\"
%s
\"
"
,
lxcpath
);
return
-
errno
;
return
-
errno
;
}
}
if
(
ret
>=
0
)
if
(
ret
>=
0
)
...
@@ -1669,7 +1713,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
...
@@ -1669,7 +1713,7 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
if
(
file_exists
(
path
))
{
if
(
file_exists
(
path
))
{
ret
=
lxc_unstack_mountpoint
(
path
,
false
);
ret
=
lxc_unstack_mountpoint
(
path
,
false
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"
Failed to unmount
\"
%s
\"
: %s"
,
path
,
strerror
(
errno
)
);
ERROR
(
"
%s - Failed to unmount
\"
%s
\"
"
,
strerror
(
errno
),
path
);
return
-
ret
;
return
-
ret
;
}
else
{
}
else
{
DEBUG
(
"Cleared all (%d) mounts from
\"
%s
\"
"
,
ret
,
path
);
DEBUG
(
"Cleared all (%d) mounts from
\"
%s
\"
"
,
ret
,
path
);
...
@@ -1688,14 +1732,15 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
...
@@ -1688,14 +1732,15 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
ret
=
chmod
(
console
->
name
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
);
ret
=
chmod
(
console
->
name
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set mode '0%o' to '%s'"
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
,
console
->
name
);
SYSERROR
(
"Failed to set mode
\"
0%o
\"
to
\"
%s
\"
"
,
S_IXUSR
|
S_IXGRP
|
S_IXOTH
,
console
->
name
);
return
-
errno
;
return
-
errno
;
}
}
/* bind mount console->name to '/dev/<ttydir>/console' */
/* bind mount console->name to '/dev/<ttydir>/console' */
ret
=
safe_mount
(
console
->
name
,
lxcpath
,
"none"
,
MS_BIND
,
0
,
rootfs_path
);
ret
=
safe_mount
(
console
->
name
,
lxcpath
,
"none"
,
MS_BIND
,
0
,
rootfs_path
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to mount
'%s' on '%s'
"
,
console
->
name
,
lxcpath
);
ERROR
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
"
,
console
->
name
,
lxcpath
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"Mounted
\"
%s
\"
onto
\"
%s
\"
"
,
console
->
name
,
lxcpath
);
DEBUG
(
"Mounted
\"
%s
\"
onto
\"
%s
\"
"
,
console
->
name
,
lxcpath
);
...
@@ -1703,13 +1748,12 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
...
@@ -1703,13 +1748,12 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
/* bind mount '/dev/<ttydir>/console' to '/dev/console' */
/* bind mount '/dev/<ttydir>/console' to '/dev/console' */
ret
=
safe_mount
(
lxcpath
,
path
,
"none"
,
MS_BIND
,
0
,
rootfs_path
);
ret
=
safe_mount
(
lxcpath
,
path
,
"none"
,
MS_BIND
,
0
,
rootfs_path
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to mount
'%s' on '%s'
"
,
console
->
name
,
lxcpath
);
ERROR
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
"
,
console
->
name
,
lxcpath
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"Mounted
\"
%s
\"
onto
\"
%s
\"
"
,
console
->
name
,
lxcpath
);
DEBUG
(
"Mounted
\"
%s
\"
onto
\"
%s
\"
"
,
console
->
name
,
lxcpath
);
DEBUG
(
"Console has been setup under
\"
%s
\"
and mounted to
\"
%s
\"
"
,
lxcpath
,
path
);
DEBUG
(
"Console has been setup under
\"
%s
\"
and mounted to
\"
%s
\"
"
,
lxcpath
,
path
);
return
0
;
return
0
;
}
}
...
@@ -1731,7 +1775,7 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data)
...
@@ -1731,7 +1775,7 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data)
* Otherwise append it to data. */
* Otherwise append it to data. */
for
(
mo
=
&
mount_opt
[
0
];
mo
->
name
!=
NULL
;
mo
++
)
{
for
(
mo
=
&
mount_opt
[
0
];
mo
->
name
!=
NULL
;
mo
++
)
{
if
(
!
strncmp
(
opt
,
mo
->
name
,
strlen
(
mo
->
name
))
)
{
if
(
strncmp
(
opt
,
mo
->
name
,
strlen
(
mo
->
name
))
==
0
)
{
if
(
mo
->
clear
)
if
(
mo
->
clear
)
*
flags
&=
~
mo
->
flag
;
*
flags
&=
~
mo
->
flag
;
else
else
...
@@ -1745,11 +1789,10 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data)
...
@@ -1745,11 +1789,10 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data)
strcat
(
*
data
,
opt
);
strcat
(
*
data
,
opt
);
}
}
int
parse_mntopts
(
const
char
*
mntopts
,
unsigned
long
*
mntflags
,
int
parse_mntopts
(
const
char
*
mntopts
,
unsigned
long
*
mntflags
,
char
**
mntdata
)
char
**
mntdata
)
{
{
char
*
s
,
*
data
;
char
*
data
,
*
p
,
*
s
;
char
*
p
,
*
saveptr
=
NULL
;
char
*
saveptr
=
NULL
;
*
mntdata
=
NULL
;
*
mntdata
=
NULL
;
*
mntflags
=
0L
;
*
mntflags
=
0L
;
...
@@ -1758,21 +1801,17 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags,
...
@@ -1758,21 +1801,17 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags,
return
0
;
return
0
;
s
=
strdup
(
mntopts
);
s
=
strdup
(
mntopts
);
if
(
!
s
)
{
if
(
!
s
)
SYSERROR
(
"failed to allocate memory"
);
return
-
1
;
return
-
1
;
}
data
=
malloc
(
strlen
(
s
)
+
1
);
data
=
malloc
(
strlen
(
s
)
+
1
);
if
(
!
data
)
{
if
(
!
data
)
{
SYSERROR
(
"failed to allocate memory"
);
free
(
s
);
free
(
s
);
return
-
1
;
return
-
1
;
}
}
*
data
=
0
;
*
data
=
0
;
for
(
p
=
strtok_r
(
s
,
","
,
&
saveptr
);
p
!=
NULL
;
for
(;
(
p
=
strtok_r
(
s
,
","
,
&
saveptr
));
s
=
NULL
)
p
=
strtok_r
(
NULL
,
","
,
&
saveptr
))
parse_mntopt
(
p
,
mntflags
,
&
data
);
parse_mntopt
(
p
,
mntflags
,
&
data
);
if
(
*
data
)
if
(
*
data
)
...
@@ -1789,23 +1828,23 @@ static void parse_propagationopt(char *opt, unsigned long *flags)
...
@@ -1789,23 +1828,23 @@ static void parse_propagationopt(char *opt, unsigned long *flags)
struct
mount_opt
*
mo
;
struct
mount_opt
*
mo
;
/* If opt is found in propagation_opt, set or clear flags. */
/* If opt is found in propagation_opt, set or clear flags. */
for
(
mo
=
&
propagation_opt
[
0
];
mo
->
name
!=
NULL
;
mo
++
)
{
for
(
mo
=
&
propagation_opt
[
0
];
mo
->
name
!=
NULL
;
mo
++
)
{
if
(
strncmp
(
opt
,
mo
->
name
,
strlen
(
mo
->
name
))
==
0
)
{
if
(
strncmp
(
opt
,
mo
->
name
,
strlen
(
mo
->
name
))
!=
0
)
if
(
mo
->
clear
)
continue
;
*
flags
&=
~
mo
->
flag
;
else
if
(
mo
->
clear
)
*
flags
|=
mo
->
flag
;
*
flags
&=
~
mo
->
flag
;
return
;
else
}
*
flags
|=
mo
->
flag
;
return
;
}
}
}
}
static
int
parse_propagationopts
(
const
char
*
mntopts
,
unsigned
long
*
pflags
)
static
int
parse_propagationopts
(
const
char
*
mntopts
,
unsigned
long
*
pflags
)
{
{
char
*
s
;
char
*
p
,
*
s
;
char
*
p
,
*
saveptr
=
NULL
;
char
*
saveptr
=
NULL
;
*
pflags
=
0L
;
if
(
!
mntopts
)
if
(
!
mntopts
)
return
0
;
return
0
;
...
@@ -1816,11 +1855,11 @@ static int parse_propagationopts(const char *mntopts, unsigned long *pflags)
...
@@ -1816,11 +1855,11 @@ static int parse_propagationopts(const char *mntopts, unsigned long *pflags)
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
for
(
p
=
strtok_r
(
s
,
","
,
&
saveptr
);
p
!=
NUL
L
;
*
pflags
=
0
L
;
p
=
strtok_r
(
NULL
,
","
,
&
saveptr
)
)
for
(;
(
p
=
strtok_r
(
s
,
","
,
&
saveptr
));
s
=
NULL
)
parse_propagationopt
(
p
,
pflags
);
parse_propagationopt
(
p
,
pflags
);
free
(
s
);
free
(
s
);
return
0
;
return
0
;
}
}
...
@@ -1831,21 +1870,22 @@ static void null_endofword(char *word)
...
@@ -1831,21 +1870,22 @@ static void null_endofword(char *word)
*
word
=
'\0'
;
*
word
=
'\0'
;
}
}
/*
/* skip @nfields spaces in @src */
* skip @nfields spaces in @src
*/
static
char
*
get_field
(
char
*
src
,
int
nfields
)
static
char
*
get_field
(
char
*
src
,
int
nfields
)
{
{
char
*
p
=
src
;
int
i
;
int
i
;
char
*
p
=
src
;
for
(
i
=
0
;
i
<
nfields
;
i
++
)
{
for
(
i
=
0
;
i
<
nfields
;
i
++
)
{
while
(
*
p
&&
*
p
!=
' '
&&
*
p
!=
'\t'
)
while
(
*
p
&&
*
p
!=
' '
&&
*
p
!=
'\t'
)
p
++
;
p
++
;
if
(
!*
p
)
if
(
!*
p
)
break
;
break
;
p
++
;
p
++
;
}
}
return
p
;
return
p
;
}
}
...
@@ -1874,8 +1914,9 @@ static int mount_entry(const char *fsname, const char *target,
...
@@ -1874,8 +1914,9 @@ static int mount_entry(const char *fsname, const char *target,
rootfs
);
rootfs
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
if
(
optional
)
{
if
(
optional
)
{
INFO
(
"Failed to mount
\"
%s
\"
on
\"
%s
\"
(optional): %s"
,
INFO
(
"%s - Failed to mount
\"
%s
\"
on
\"
%s
\"
"
srcpath
?
srcpath
:
"(null)"
,
target
,
strerror
(
errno
));
"(optional)"
,
strerror
(
errno
),
srcpath
?
srcpath
:
"(null)"
,
target
);
return
0
;
return
0
;
}
}
...
@@ -1974,7 +2015,13 @@ skipremount:
...
@@ -1974,7 +2015,13 @@ skipremount:
static
void
cull_mntent_opt
(
struct
mntent
*
mntent
)
static
void
cull_mntent_opt
(
struct
mntent
*
mntent
)
{
{
int
i
;
int
i
;
char
*
list
[]
=
{
"create=dir"
,
"create=file"
,
"optional"
,
"relative"
,
NULL
};
char
*
list
[]
=
{
"create=dir"
,
"create=file"
,
"optional"
,
"relative"
,
NULL
};
for
(
i
=
0
;
list
[
i
];
i
++
)
{
for
(
i
=
0
;
list
[
i
];
i
++
)
{
char
*
p
,
*
p2
;
char
*
p
,
*
p2
;
...
@@ -1997,8 +2044,7 @@ static void cull_mntent_opt(struct mntent *mntent)
...
@@ -1997,8 +2044,7 @@ static void cull_mntent_opt(struct mntent *mntent)
static
int
mount_entry_create_dir_file
(
const
struct
mntent
*
mntent
,
static
int
mount_entry_create_dir_file
(
const
struct
mntent
*
mntent
,
const
char
*
path
,
const
char
*
path
,
const
struct
lxc_rootfs
*
rootfs
,
const
struct
lxc_rootfs
*
rootfs
,
const
char
*
lxc_name
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
char
*
lxc_path
)
{
{
int
fd
,
ret
;
int
fd
,
ret
;
char
*
p1
,
*
p2
;
char
*
p1
,
*
p2
;
...
@@ -2017,29 +2063,31 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
...
@@ -2017,29 +2063,31 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
}
}
}
}
if
(
hasmntopt
(
mntent
,
"create=file"
)
&&
access
(
path
,
F_OK
))
{
if
(
!
hasmntopt
(
mntent
,
"create=file"
))
int
fd
;
return
0
;
char
*
p1
,
*
p2
;
p1
=
strdup
(
path
);
ret
=
access
(
path
,
F_OK
);
if
(
!
p1
)
if
(
ret
==
0
)
return
-
1
;
return
0
;
p2
=
dirname
(
p1
);
p1
=
strdup
(
path
);
if
(
!
p1
)
return
-
1
;
ret
=
mkdir_p
(
p2
,
0755
);
p2
=
dirname
(
p1
);
free
(
p1
);
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
SYSERROR
(
"Failed to create directory
\"
%s
\"
"
,
path
);
return
-
1
;
}
fd
=
open
(
path
,
O_CREAT
,
0644
);
ret
=
mkdir_p
(
p2
,
0755
);
if
(
fd
<
0
)
free
(
p1
);
return
-
1
;
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
close
(
fd
);
SYSERROR
(
"Failed to create directory
\"
%s
\"
"
,
path
);
return
-
1
;
}
}
fd
=
open
(
path
,
O_CREAT
,
0644
);
if
(
fd
<
0
)
return
-
1
;
close
(
fd
);
return
0
;
return
0
;
}
}
...
@@ -2156,98 +2204,26 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent,
...
@@ -2156,98 +2204,26 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent,
const
char
*
lxc_name
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
char
*
lxc_path
)
{
{
char
path
[
MAXPATHLEN
];
int
ret
;
int
ret
;
char
path
[
MAXPATHLEN
];
/* relative to root mount point */
/* relative to root mount point */
ret
=
snprintf
(
path
,
sizeof
(
path
),
"%s/%s"
,
rootfs
->
mount
,
mntent
->
mnt_dir
);
ret
=
snprintf
(
path
,
sizeof
(
path
),
"%s/%s"
,
rootfs
->
mount
,
mntent
->
mnt_dir
);
if
(
ret
<
0
||
ret
>=
sizeof
(
path
))
{
if
(
ret
<
0
||
(
size_t
)
ret
>=
sizeof
(
path
))
ERROR
(
"path name too long"
);
return
-
1
;
return
-
1
;
}
return
mount_entry_on_generic
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
return
mount_entry_on_generic
(
mntent
,
path
,
rootfs
,
lxc_name
,
lxc_path
);
}
}
/* This logs a NOTICE() when a user specifies mounts that would conflict with
* devices liblxc sets up automatically.
*/
static
void
log_notice_on_conflict
(
const
struct
lxc_conf
*
conf
,
const
char
*
src
,
const
char
*
dest
)
{
char
*
clean_mnt_fsname
,
*
clean_mnt_dir
,
*
tmp
;
bool
needs_warning
=
false
;
clean_mnt_fsname
=
lxc_deslashify
(
src
);
if
(
!
clean_mnt_fsname
)
return
;
clean_mnt_dir
=
lxc_deslashify
(
dest
);
if
(
!
clean_mnt_dir
)
{
free
(
clean_mnt_fsname
);
return
;
}
tmp
=
clean_mnt_dir
;
if
(
*
tmp
==
'/'
)
tmp
++
;
if
(
strncmp
(
src
,
"/dev"
,
4
)
||
strncmp
(
tmp
,
"dev"
,
3
))
{
free
(
clean_mnt_dir
);
free
(
clean_mnt_fsname
);
return
;
}
if
(
!
conf
->
autodev
&&
!
conf
->
pts
&&
!
conf
->
tty
&&
(
!
conf
->
console
.
path
||
!
strcmp
(
conf
->
console
.
path
,
"none"
)))
{
free
(
clean_mnt_dir
);
free
(
clean_mnt_fsname
);
return
;
}
if
(
!
strcmp
(
tmp
,
"dev"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/pts"
)
&&
(
conf
->
autodev
>
0
||
conf
->
pts
>
0
))
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/ptmx"
)
&&
(
conf
->
autodev
>
0
||
conf
->
pts
>
0
))
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/pts/ptmx"
)
&&
(
conf
->
autodev
>
0
||
conf
->
pts
>
0
))
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/null"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/zero"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/full"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/urandom"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/random"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strcmp
(
tmp
,
"dev/tty"
)
&&
conf
->
autodev
>
0
)
needs_warning
=
true
;
else
if
(
!
strncmp
(
tmp
,
"dev/tty"
,
7
)
&&
(
conf
->
autodev
>
0
||
conf
->
tty
>
0
))
needs_warning
=
true
;
if
(
needs_warning
)
NOTICE
(
"Requesting to mount
\"
%s
\"
on
\"
%s
\"
while requesting "
"automatic device setup under
\"
/dev
\"
"
,
clean_mnt_fsname
,
clean_mnt_dir
);
free
(
clean_mnt_dir
);
free
(
clean_mnt_fsname
);
}
static
int
mount_file_entries
(
const
struct
lxc_conf
*
conf
,
static
int
mount_file_entries
(
const
struct
lxc_conf
*
conf
,
const
struct
lxc_rootfs
*
rootfs
,
FILE
*
file
,
const
struct
lxc_rootfs
*
rootfs
,
FILE
*
file
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
char
*
lxc_name
,
const
char
*
lxc_path
)
{
{
struct
mntent
mntent
;
char
buf
[
4096
];
char
buf
[
4096
];
struct
mntent
mntent
;
int
ret
=
-
1
;
int
ret
=
-
1
;
while
(
getmntent_r
(
file
,
&
mntent
,
buf
,
sizeof
(
buf
)))
{
while
(
getmntent_r
(
file
,
&
mntent
,
buf
,
sizeof
(
buf
)))
{
log_notice_on_conflict
(
conf
,
mntent
.
mnt_fsname
,
mntent
.
mnt_dir
);
if
(
!
rootfs
->
path
)
if
(
!
rootfs
->
path
)
ret
=
mount_entry_on_systemfs
(
&
mntent
);
ret
=
mount_entry_on_systemfs
(
&
mntent
);
else
if
(
mntent
.
mnt_dir
[
0
]
!=
'/'
)
else
if
(
mntent
.
mnt_dir
[
0
]
!=
'/'
)
...
@@ -2261,7 +2237,7 @@ static int mount_file_entries(const struct lxc_conf *conf,
...
@@ -2261,7 +2237,7 @@ static int mount_file_entries(const struct lxc_conf *conf,
}
}
ret
=
0
;
ret
=
0
;
INFO
(
"
Set up mount entrie
s"
);
INFO
(
"
Finished setting up mount
s"
);
return
ret
;
return
ret
;
}
}
...
@@ -2294,42 +2270,50 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount)
...
@@ -2294,42 +2270,50 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount)
int
ret
;
int
ret
;
char
*
mount_entry
;
char
*
mount_entry
;
struct
lxc_list
*
iterator
;
struct
lxc_list
*
iterator
;
FILE
*
f
;
int
fd
=
-
1
;
int
fd
=
-
1
;
fd
=
memfd_create
(
"lxc_mount_file"
,
MFD_CLOEXEC
);
fd
=
memfd_create
(
"
.
lxc_mount_file"
,
MFD_CLOEXEC
);
if
(
fd
<
0
)
{
if
(
fd
<
0
)
{
if
(
errno
!=
ENOSYS
)
if
(
errno
!=
ENOSYS
)
return
NULL
;
return
NULL
;
f
=
tmpfile
();
fd
=
lxc_make_tmpfile
((
char
*
){
P_tmpdir
"/.lxc_mount_file"
},
true
);
if
(
fd
<
0
)
{
SYSERROR
(
"Could not create temporary mount file"
);
return
NULL
;
}
TRACE
(
"Created temporary mount file"
);
TRACE
(
"Created temporary mount file"
);
}
else
{
f
=
fdopen
(
fd
,
"r+"
);
TRACE
(
"Created anonymous mount file"
);
}
}
if
(
fd
<
0
)
{
if
(
!
f
)
{
SYSERROR
(
"Could not create temporary mount file"
);
SYSERROR
(
"Could not create mount file"
);
if
(
fd
!=
-
1
)
close
(
fd
);
return
NULL
;
return
NULL
;
}
}
lxc_list_for_each
(
iterator
,
mount
)
{
lxc_list_for_each
(
iterator
,
mount
)
{
size_t
len
;
mount_entry
=
iterator
->
elem
;
mount_entry
=
iterator
->
elem
;
ret
=
fprintf
(
f
,
"%s
\n
"
,
mount_entry
);
len
=
strlen
(
mount_entry
);
if
(
ret
<
strlen
(
mount_entry
))
WARN
(
"Could not write mount entry to mount file"
);
}
ret
=
fseek
(
f
,
0
,
SEEK_SET
);
ret
=
write
(
fd
,
mount_entry
,
len
);
if
(
ret
<
0
)
{
if
(
ret
!=
len
)
SYSERROR
(
"Failed to seek mount file"
);
goto
on_error
;
fclose
(
f
);
return
NULL
;
ret
=
write
(
fd
,
"
\n
"
,
1
);
if
(
ret
!=
1
)
goto
on_error
;
}
}
return
f
;
ret
=
lseek
(
fd
,
0
,
SEEK_SET
);
if
(
ret
<
0
)
goto
on_error
;
return
fdopen
(
fd
,
"r+"
);
on_error:
SYSERROR
(
"Failed to write mount entry to temporary mount file"
);
close
(
fd
);
return
NULL
;
}
}
static
int
setup_mount_entries
(
const
struct
lxc_conf
*
conf
,
static
int
setup_mount_entries
(
const
struct
lxc_conf
*
conf
,
...
@@ -2337,31 +2321,30 @@ static int setup_mount_entries(const struct lxc_conf *conf,
...
@@ -2337,31 +2321,30 @@ static int setup_mount_entries(const struct lxc_conf *conf,
struct
lxc_list
*
mount
,
const
char
*
lxc_name
,
struct
lxc_list
*
mount
,
const
char
*
lxc_name
,
const
char
*
lxc_path
)
const
char
*
lxc_path
)
{
{
FILE
*
f
;
int
ret
;
int
ret
;
FILE
*
f
;
f
=
make_anonymous_mount_file
(
mount
);
f
=
make_anonymous_mount_file
(
mount
);
if
(
!
f
)
if
(
!
f
)
return
-
1
;
return
-
1
;
ret
=
mount_file_entries
(
conf
,
rootfs
,
f
,
lxc_name
,
lxc_path
);
ret
=
mount_file_entries
(
conf
,
rootfs
,
f
,
lxc_name
,
lxc_path
);
fclose
(
f
);
fclose
(
f
);
return
ret
;
return
ret
;
}
}
static
int
parse_cap
(
const
char
*
cap
)
static
int
parse_cap
(
const
char
*
cap
)
{
{
char
*
ptr
=
NULL
;
size_t
i
;
size_t
i
;
int
capid
=
-
1
;
int
capid
=
-
1
;
size_t
end
=
sizeof
(
caps_opt
)
/
sizeof
(
caps_opt
[
0
]);
size_t
end
=
sizeof
(
caps_opt
)
/
sizeof
(
caps_opt
[
0
]);
char
*
ptr
=
NULL
;
if
(
!
strcmp
(
cap
,
"none"
)
)
if
(
strcmp
(
cap
,
"none"
)
==
0
)
return
-
2
;
return
-
2
;
for
(
i
=
0
;
i
<
end
;
i
++
)
{
for
(
i
=
0
;
i
<
end
;
i
++
)
{
if
(
strcmp
(
cap
,
caps_opt
[
i
].
name
))
if
(
strcmp
(
cap
,
caps_opt
[
i
].
name
))
continue
;
continue
;
...
@@ -2370,9 +2353,10 @@ static int parse_cap(const char *cap)
...
@@ -2370,9 +2353,10 @@ static int parse_cap(const char *cap)
}
}
if
(
capid
<
0
)
{
if
(
capid
<
0
)
{
/* try to see if it's numeric, so the user may specify
/* Try to see if it's numeric, so the user may specify
* capabilities that the running kernel knows about but
* capabilities that the running kernel knows about but we
* we don't */
* don't
*/
errno
=
0
;
errno
=
0
;
capid
=
strtol
(
cap
,
&
ptr
,
10
);
capid
=
strtol
(
cap
,
&
ptr
,
10
);
if
(
!
ptr
||
*
ptr
!=
'\0'
||
errno
!=
0
)
if
(
!
ptr
||
*
ptr
!=
'\0'
||
errno
!=
0
)
...
@@ -2389,10 +2373,10 @@ static int parse_cap(const char *cap)
...
@@ -2389,10 +2373,10 @@ static int parse_cap(const char *cap)
int
in_caplist
(
int
cap
,
struct
lxc_list
*
caps
)
int
in_caplist
(
int
cap
,
struct
lxc_list
*
caps
)
{
{
struct
lxc_list
*
iterator
;
int
capid
;
int
capid
;
struct
lxc_list
*
iterator
;
lxc_list_for_each
(
iterator
,
caps
)
{
lxc_list_for_each
(
iterator
,
caps
)
{
capid
=
parse_cap
(
iterator
->
elem
);
capid
=
parse_cap
(
iterator
->
elem
);
if
(
capid
==
cap
)
if
(
capid
==
cap
)
return
1
;
return
1
;
...
@@ -2403,116 +2387,121 @@ int in_caplist(int cap, struct lxc_list *caps)
...
@@ -2403,116 +2387,121 @@ int in_caplist(int cap, struct lxc_list *caps)
static
int
setup_caps
(
struct
lxc_list
*
caps
)
static
int
setup_caps
(
struct
lxc_list
*
caps
)
{
{
struct
lxc_list
*
iterator
;
char
*
drop_entry
;
int
capid
;
int
capid
;
char
*
drop_entry
;
struct
lxc_list
*
iterator
;
lxc_list_for_each
(
iterator
,
caps
)
{
lxc_list_for_each
(
iterator
,
caps
)
{
int
ret
;
drop_entry
=
iterator
->
elem
;
drop_entry
=
iterator
->
elem
;
capid
=
parse_cap
(
drop_entry
);
capid
=
parse_cap
(
drop_entry
);
if
(
capid
<
0
)
{
if
(
capid
<
0
)
{
ERROR
(
"unknown capability %s"
,
drop_entry
);
ERROR
(
"unknown capability %s"
,
drop_entry
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"drop capability '%s' (%d)"
,
drop_entry
,
capid
);
ret
=
prctl
(
PR_CAPBSET_DROP
,
capid
,
0
,
0
,
0
);
if
(
ret
<
0
)
{
if
(
prctl
(
PR_CAPBSET_DROP
,
capid
,
0
,
0
,
0
))
{
SYSERROR
(
"Failed to remove %s capability"
,
drop_entry
);
SYSERROR
(
"failed to remove %s capability"
,
drop_entry
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"Dropped %s (%d) capability"
,
drop_entry
,
capid
);
}
}
DEBUG
(
"capabilities have been setup"
);
DEBUG
(
"Capabilities have been setup"
);
return
0
;
return
0
;
}
}
static
int
dropcaps_except
(
struct
lxc_list
*
caps
)
static
int
dropcaps_except
(
struct
lxc_list
*
caps
)
{
{
struct
lxc_list
*
iterator
;
int
i
,
capid
,
numcaps
;
char
*
keep_entry
;
char
*
keep_entry
;
int
i
,
capid
;
struct
lxc_list
*
iterator
;
int
numcaps
=
lxc_caps_last_cap
()
+
1
;
INFO
(
"found %d capabilities"
,
numcaps
);
numcaps
=
lxc_caps_last_cap
()
+
1
;
if
(
numcaps
<=
0
||
numcaps
>
200
)
if
(
numcaps
<=
0
||
numcaps
>
200
)
return
-
1
;
return
-
1
;
TRACE
(
"Found %d capabilities"
,
numcaps
);
/* caplist[i] is 1 if we keep capability i */
/* caplist[i] is 1 if we keep capability i */
int
*
caplist
=
alloca
(
numcaps
*
sizeof
(
int
));
int
*
caplist
=
alloca
(
numcaps
*
sizeof
(
int
));
memset
(
caplist
,
0
,
numcaps
*
sizeof
(
int
));
memset
(
caplist
,
0
,
numcaps
*
sizeof
(
int
));
lxc_list_for_each
(
iterator
,
caps
)
{
lxc_list_for_each
(
iterator
,
caps
)
{
keep_entry
=
iterator
->
elem
;
keep_entry
=
iterator
->
elem
;
capid
=
parse_cap
(
keep_entry
);
capid
=
parse_cap
(
keep_entry
);
if
(
capid
==
-
2
)
if
(
capid
==
-
2
)
continue
;
continue
;
if
(
capid
<
0
)
{
if
(
capid
<
0
)
{
ERROR
(
"
u
nknown capability %s"
,
keep_entry
);
ERROR
(
"
U
nknown capability %s"
,
keep_entry
);
return
-
1
;
return
-
1
;
}
}
DEBUG
(
"keep capability '%s' (%d)"
,
keep_entry
,
capid
);
DEBUG
(
"Keep capability %s (%d)"
,
keep_entry
,
capid
);
caplist
[
capid
]
=
1
;
caplist
[
capid
]
=
1
;
}
}
for
(
i
=
0
;
i
<
numcaps
;
i
++
)
{
for
(
i
=
0
;
i
<
numcaps
;
i
++
)
{
int
ret
;
if
(
caplist
[
i
])
if
(
caplist
[
i
])
continue
;
continue
;
if
(
prctl
(
PR_CAPBSET_DROP
,
i
,
0
,
0
,
0
))
{
SYSERROR
(
"failed to remove capability %d"
,
i
);
ret
=
prctl
(
PR_CAPBSET_DROP
,
i
,
0
,
0
,
0
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to remove capability %d"
,
i
);
return
-
1
;
return
-
1
;
}
}
}
}
DEBUG
(
"capabilities have been setup"
);
DEBUG
(
"Capabilities have been setup"
);
return
0
;
return
0
;
}
}
static
int
parse_resource
(
const
char
*
res
)
{
static
int
parse_resource
(
const
char
*
res
)
{
int
ret
;
size_t
i
;
size_t
i
;
int
resid
=
-
1
;
int
resid
=
-
1
;
for
(
i
=
0
;
i
<
sizeof
(
limit_opt
)
/
sizeof
(
limit_opt
[
0
]);
++
i
)
{
for
(
i
=
0
;
i
<
sizeof
(
limit_opt
)
/
sizeof
(
limit_opt
[
0
]);
++
i
)
if
(
strcmp
(
res
,
limit_opt
[
i
].
name
)
==
0
)
if
(
strcmp
(
res
,
limit_opt
[
i
].
name
)
==
0
)
return
limit_opt
[
i
].
value
;
return
limit_opt
[
i
].
value
;
}
/*
t
ry to see if it's numeric, so the user may specify
/*
T
ry to see if it's numeric, so the user may specify
* resources that the running kernel knows about but
* resources that the running kernel knows about but
* we don't */
* we don't.
if
(
lxc_safe_int
(
res
,
&
resid
)
==
0
)
*/
return
resid
;
ret
=
lxc_safe_int
(
res
,
&
resid
);
return
-
1
;
if
(
ret
<
0
)
return
-
1
;
return
resid
;
}
}
int
setup_resource_limits
(
struct
lxc_list
*
limits
,
pid_t
pid
)
{
int
setup_resource_limits
(
struct
lxc_list
*
limits
,
pid_t
pid
)
{
int
resid
;
struct
lxc_list
*
it
;
struct
lxc_list
*
it
;
struct
lxc_limit
*
lim
;
struct
lxc_limit
*
lim
;
int
resid
;
lxc_list_for_each
(
it
,
limits
)
{
lxc_list_for_each
(
it
,
limits
)
{
lim
=
it
->
elem
;
lim
=
it
->
elem
;
resid
=
parse_resource
(
lim
->
resource
);
resid
=
parse_resource
(
lim
->
resource
);
if
(
resid
<
0
)
{
if
(
resid
<
0
)
{
ERROR
(
"
u
nknown resource %s"
,
lim
->
resource
);
ERROR
(
"
U
nknown resource %s"
,
lim
->
resource
);
return
-
1
;
return
-
1
;
}
}
#if HAVE_PRLIMIT || HAVE_PRLIMIT64
#if HAVE_PRLIMIT || HAVE_PRLIMIT64
if
(
prlimit
(
pid
,
resid
,
&
lim
->
limit
,
NULL
)
!=
0
)
{
if
(
prlimit
(
pid
,
resid
,
&
lim
->
limit
,
NULL
)
!=
0
)
{
ERROR
(
"failed to set limit %s: %s"
,
lim
->
resource
,
strerror
(
errno
));
ERROR
(
"Failed to set limit %s: %s"
,
lim
->
resource
,
strerror
(
errno
));
return
-
1
;
return
-
1
;
}
}
#else
#else
...
@@ -2520,6 +2509,7 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
...
@@ -2520,6 +2509,7 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
return
-
1
;
return
-
1
;
#endif
#endif
}
}
return
0
;
return
0
;
}
}
...
@@ -2527,11 +2517,11 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
...
@@ -2527,11 +2517,11 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
{
{
struct
lxc_list
*
it
;
struct
lxc_list
*
it
;
struct
lxc_sysctl
*
elem
;
struct
lxc_sysctl
*
elem
;
int
ret
=
0
;
char
*
tmp
=
NULL
;
char
*
tmp
=
NULL
;
char
filename
[
MAXPATHLEN
]
=
{
0
};
char
filename
[
MAXPATHLEN
]
=
{
0
};
int
ret
=
0
;
lxc_list_for_each
(
it
,
sysctls
)
{
lxc_list_for_each
(
it
,
sysctls
)
{
elem
=
it
->
elem
;
elem
=
it
->
elem
;
tmp
=
lxc_string_replace
(
"."
,
"/"
,
elem
->
key
);
tmp
=
lxc_string_replace
(
"."
,
"/"
,
elem
->
key
);
if
(
!
tmp
)
{
if
(
!
tmp
)
{
...
@@ -2546,12 +2536,15 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
...
@@ -2546,12 +2536,15 @@ int setup_sysctl_parameters(struct lxc_list *sysctls)
return
-
1
;
return
-
1
;
}
}
ret
=
lxc_write_to_file
(
filename
,
elem
->
value
,
strlen
(
elem
->
value
),
false
);
ret
=
lxc_write_to_file
(
filename
,
elem
->
value
,
strlen
(
elem
->
value
),
false
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to setup sysctl parameters %s to %s"
,
elem
->
key
,
elem
->
value
);
ERROR
(
"Failed to setup sysctl parameters %s to %s"
,
elem
->
key
,
elem
->
value
);
return
-
1
;
return
-
1
;
}
}
}
}
return
0
;
return
0
;
}
}
...
@@ -2559,11 +2552,11 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
...
@@ -2559,11 +2552,11 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
{
{
struct
lxc_list
*
it
;
struct
lxc_list
*
it
;
struct
lxc_proc
*
elem
;
struct
lxc_proc
*
elem
;
int
ret
=
0
;
char
*
tmp
=
NULL
;
char
*
tmp
=
NULL
;
char
filename
[
MAXPATHLEN
]
=
{
0
};
char
filename
[
MAXPATHLEN
]
=
{
0
};
int
ret
=
0
;
lxc_list_for_each
(
it
,
procs
)
{
lxc_list_for_each
(
it
,
procs
)
{
elem
=
it
->
elem
;
elem
=
it
->
elem
;
tmp
=
lxc_string_replace
(
"."
,
"/"
,
elem
->
filename
);
tmp
=
lxc_string_replace
(
"."
,
"/"
,
elem
->
filename
);
if
(
!
tmp
)
{
if
(
!
tmp
)
{
...
@@ -2578,12 +2571,15 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
...
@@ -2578,12 +2571,15 @@ int setup_proc_filesystem(struct lxc_list *procs, pid_t pid)
return
-
1
;
return
-
1
;
}
}
ret
=
lxc_write_to_file
(
filename
,
elem
->
value
,
strlen
(
elem
->
value
),
false
);
ret
=
lxc_write_to_file
(
filename
,
elem
->
value
,
strlen
(
elem
->
value
),
false
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Failed to setup proc filesystem %s to %s"
,
elem
->
filename
,
elem
->
value
);
ERROR
(
"Failed to setup proc filesystem %s to %s"
,
elem
->
filename
,
elem
->
value
);
return
-
1
;
return
-
1
;
}
}
}
}
return
0
;
return
0
;
}
}
...
@@ -2591,14 +2587,12 @@ static char *default_rootfs_mount = LXCROOTFSMOUNT;
...
@@ -2591,14 +2587,12 @@ static char *default_rootfs_mount = LXCROOTFSMOUNT;
struct
lxc_conf
*
lxc_conf_init
(
void
)
struct
lxc_conf
*
lxc_conf_init
(
void
)
{
{
struct
lxc_conf
*
new
;
int
i
;
int
i
;
struct
lxc_conf
*
new
;
new
=
malloc
(
sizeof
(
*
new
));
new
=
malloc
(
sizeof
(
*
new
));
if
(
!
new
)
{
if
(
!
new
)
ERROR
(
"lxc_conf_init : %s"
,
strerror
(
errno
));
return
NULL
;
return
NULL
;
}
memset
(
new
,
0
,
sizeof
(
*
new
));
memset
(
new
,
0
,
sizeof
(
*
new
));
new
->
loglevel
=
LXC_LOG_LEVEL_NOTSET
;
new
->
loglevel
=
LXC_LOG_LEVEL_NOTSET
;
...
@@ -2621,7 +2615,6 @@ struct lxc_conf *lxc_conf_init(void)
...
@@ -2621,7 +2615,6 @@ struct lxc_conf *lxc_conf_init(void)
new
->
nbd_idx
=
-
1
;
new
->
nbd_idx
=
-
1
;
new
->
rootfs
.
mount
=
strdup
(
default_rootfs_mount
);
new
->
rootfs
.
mount
=
strdup
(
default_rootfs_mount
);
if
(
!
new
->
rootfs
.
mount
)
{
if
(
!
new
->
rootfs
.
mount
)
{
ERROR
(
"lxc_conf_init : %s"
,
strerror
(
errno
));
free
(
new
);
free
(
new
);
return
NULL
;
return
NULL
;
}
}
...
@@ -2663,17 +2656,15 @@ struct lxc_conf *lxc_conf_init(void)
...
@@ -2663,17 +2656,15 @@ struct lxc_conf *lxc_conf_init(void)
int
write_id_mapping
(
enum
idtype
idtype
,
pid_t
pid
,
const
char
*
buf
,
int
write_id_mapping
(
enum
idtype
idtype
,
pid_t
pid
,
const
char
*
buf
,
size_t
buf_size
)
size_t
buf_size
)
{
{
char
path
[
MAXPATHLEN
];
int
fd
,
ret
;
int
fd
,
ret
;
char
path
[
MAXPATHLEN
];
if
(
geteuid
()
!=
0
&&
idtype
==
ID_TYPE_GID
)
{
if
(
geteuid
()
!=
0
&&
idtype
==
ID_TYPE_GID
)
{
size_t
buflen
;
size_t
buflen
;
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"/proc/%d/setgroups"
,
pid
);
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"/proc/%d/setgroups"
,
pid
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
{
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
ERROR
(
"Failed to create string"
);
return
-
E2BIG
;
return
-
E2BIG
;
}
fd
=
open
(
path
,
O_WRONLY
);
fd
=
open
(
path
,
O_WRONLY
);
if
(
fd
<
0
&&
errno
!=
ENOENT
)
{
if
(
fd
<
0
&&
errno
!=
ENOENT
)
{
...
@@ -2686,7 +2677,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
...
@@ -2686,7 +2677,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
errno
=
0
;
errno
=
0
;
ret
=
lxc_write_nointr
(
fd
,
"deny
\n
"
,
buflen
);
ret
=
lxc_write_nointr
(
fd
,
"deny
\n
"
,
buflen
);
if
(
ret
!=
buflen
)
{
if
(
ret
!=
buflen
)
{
SYSERROR
(
"Failed to write
\"
deny
\"
to
\"
/proc/%d/setgroups
\"
"
,
pid
);
SYSERROR
(
"Failed to write
\"
deny
\"
to "
"
\"
/proc/%d/setgroups
\"
"
,
pid
);
close
(
fd
);
close
(
fd
);
return
-
1
;
return
-
1
;
}
}
...
@@ -2696,10 +2688,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
...
@@ -2696,10 +2688,8 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"/proc/%d/%cid_map"
,
pid
,
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"/proc/%d/%cid_map"
,
pid
,
idtype
==
ID_TYPE_UID
?
'u'
:
'g'
);
idtype
==
ID_TYPE_UID
?
'u'
:
'g'
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
{
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
ERROR
(
"Failed to create string"
);
return
-
E2BIG
;
return
-
E2BIG
;
}
fd
=
open
(
path
,
O_WRONLY
);
fd
=
open
(
path
,
O_WRONLY
);
if
(
fd
<
0
)
{
if
(
fd
<
0
)
{
...
@@ -2726,7 +2716,6 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
...
@@ -2726,7 +2716,6 @@ int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
* @return 0 if binary exists but is lacking privilege
* @return 0 if binary exists but is lacking privilege
* @return -ENOENT if binary does not exist
* @return -ENOENT if binary does not exist
* @return -EINVAL if cap to check is neither CAP_SETUID nor CAP_SETGID
* @return -EINVAL if cap to check is neither CAP_SETUID nor CAP_SETGID
*
*/
*/
static
int
idmaptool_on_path_and_privileged
(
const
char
*
binary
,
cap_value_t
cap
)
static
int
idmaptool_on_path_and_privileged
(
const
char
*
binary
,
cap_value_t
cap
)
{
{
...
@@ -2750,18 +2739,18 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
...
@@ -2750,18 +2739,18 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
/* Check if the binary is setuid. */
/* Check if the binary is setuid. */
if
(
st
.
st_mode
&
S_ISUID
)
{
if
(
st
.
st_mode
&
S_ISUID
)
{
DEBUG
(
"The binary
\"
%s
\"
does have the setuid bit set
.
"
,
path
);
DEBUG
(
"The binary
\"
%s
\"
does have the setuid bit set"
,
path
);
fret
=
1
;
fret
=
1
;
goto
cleanup
;
goto
cleanup
;
}
}
#if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
#if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
/* Check if it has the CAP_SETUID capability. */
/* Check if it has the CAP_SETUID capability. */
if
((
cap
&
CAP_SETUID
)
&&
if
((
cap
&
CAP_SETUID
)
&&
lxc_file_cap_is_set
(
path
,
CAP_SETUID
,
CAP_EFFECTIVE
)
&&
lxc_file_cap_is_set
(
path
,
CAP_SETUID
,
CAP_EFFECTIVE
)
&&
lxc_file_cap_is_set
(
path
,
CAP_SETUID
,
CAP_PERMITTED
))
{
lxc_file_cap_is_set
(
path
,
CAP_SETUID
,
CAP_PERMITTED
))
{
DEBUG
(
"The binary
\"
%s
\"
has CAP_SETUID in its CAP_EFFECTIVE "
DEBUG
(
"The binary
\"
%s
\"
has CAP_SETUID in its CAP_EFFECTIVE "
"and CAP_PERMITTED sets
.
"
,
path
);
"and CAP_PERMITTED sets"
,
path
);
fret
=
1
;
fret
=
1
;
goto
cleanup
;
goto
cleanup
;
}
}
...
@@ -2771,19 +2760,19 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
...
@@ -2771,19 +2760,19 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
lxc_file_cap_is_set
(
path
,
CAP_SETGID
,
CAP_EFFECTIVE
)
&&
lxc_file_cap_is_set
(
path
,
CAP_SETGID
,
CAP_EFFECTIVE
)
&&
lxc_file_cap_is_set
(
path
,
CAP_SETGID
,
CAP_PERMITTED
))
{
lxc_file_cap_is_set
(
path
,
CAP_SETGID
,
CAP_PERMITTED
))
{
DEBUG
(
"The binary
\"
%s
\"
has CAP_SETGID in its CAP_EFFECTIVE "
DEBUG
(
"The binary
\"
%s
\"
has CAP_SETGID in its CAP_EFFECTIVE "
"and CAP_PERMITTED sets
.
"
,
path
);
"and CAP_PERMITTED sets"
,
path
);
fret
=
1
;
fret
=
1
;
goto
cleanup
;
goto
cleanup
;
}
}
#else
#else
/* If we cannot check for file capabilities we need to give the benefit
/* If we cannot check for file capabilities we need to give the benefit
* of the doubt. Otherwise we might fail even though all the necessary
* of the doubt. Otherwise we might fail even though all the necessary
* file capabilities are set.
* file capabilities are set.
*/
*/
DEBUG
(
"Cannot check for file capabilites as full capability support is "
DEBUG
(
"Cannot check for file capabilites as full capability support is "
"missing. Manual intervention needed
.
"
);
"missing. Manual intervention needed"
);
fret
=
1
;
fret
=
1
;
#endif
#endif
cleanup:
cleanup:
free
(
path
);
free
(
path
);
...
@@ -2798,13 +2787,13 @@ int lxc_map_ids_exec_wrapper(void *args)
...
@@ -2798,13 +2787,13 @@ int lxc_map_ids_exec_wrapper(void *args)
int
lxc_map_ids
(
struct
lxc_list
*
idmap
,
pid_t
pid
)
int
lxc_map_ids
(
struct
lxc_list
*
idmap
,
pid_t
pid
)
{
{
struct
id_map
*
map
;
int
fill
,
left
;
struct
lxc_list
*
iterator
;
enum
idtype
type
;
char
u_or_g
;
char
u_or_g
;
char
*
pos
;
char
*
pos
;
int
fill
,
left
;
char
cmd_output
[
MAXPATHLEN
];
char
cmd_output
[
MAXPATHLEN
];
struct
id_map
*
map
;
struct
lxc_list
*
iterator
;
enum
idtype
type
;
/* strlen("new@idmap") = 9
/* strlen("new@idmap") = 9
* +
* +
* strlen(" ") = 1
* strlen(" ") = 1
...
@@ -2816,9 +2805,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
...
@@ -2816,9 +2805,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
* We add some additional space to make sure that we really have
* We add some additional space to make sure that we really have
* LXC_IDMAPLEN bytes available for our the {g,u]id mapping.
* LXC_IDMAPLEN bytes available for our the {g,u]id mapping.
*/
*/
int
ret
=
0
,
gidmap
=
0
,
uidmap
=
0
;
char
mapbuf
[
9
+
1
+
LXC_NUMSTRLEN64
+
1
+
LXC_IDMAPLEN
]
=
{
0
};
char
mapbuf
[
9
+
1
+
LXC_NUMSTRLEN64
+
1
+
LXC_IDMAPLEN
]
=
{
0
};
int
ret
=
0
,
uidmap
=
0
,
gidmap
=
0
;
bool
had_entry
=
false
,
use_shadow
=
false
;
bool
use_shadow
=
false
,
had_entry
=
false
;
/* If new{g,u}idmap exists, that is, if shadow is handing out subuid
/* If new{g,u}idmap exists, that is, if shadow is handing out subuid
* ranges, then insist that root also reserve ranges in subuid. This
* ranges, then insist that root also reserve ranges in subuid. This
...
@@ -2838,7 +2827,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
...
@@ -2838,7 +2827,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
WARN
(
"newgidmap is lacking necessary privileges"
);
WARN
(
"newgidmap is lacking necessary privileges"
);
if
(
uidmap
>
0
&&
gidmap
>
0
)
{
if
(
uidmap
>
0
&&
gidmap
>
0
)
{
DEBUG
(
"Functional newuidmap and newgidmap binary found
.
"
);
DEBUG
(
"Functional newuidmap and newgidmap binary found"
);
use_shadow
=
true
;
use_shadow
=
true
;
}
else
{
}
else
{
/* In case unprivileged users run application containers via
/* In case unprivileged users run application containers via
...
@@ -2847,7 +2836,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
...
@@ -2847,7 +2836,7 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
* doing so by requiring geteuid() == 0.
* doing so by requiring geteuid() == 0.
*/
*/
DEBUG
(
"No newuidmap and newgidmap binary found. Trying to "
DEBUG
(
"No newuidmap and newgidmap binary found. Trying to "
"write directly with euid %d
.
"
,
geteuid
());
"write directly with euid %d"
,
geteuid
());
}
}
for
(
type
=
ID_TYPE_UID
,
u_or_g
=
'u'
;
type
<=
ID_TYPE_GID
;
for
(
type
=
ID_TYPE_UID
,
u_or_g
=
'u'
;
type
<=
ID_TYPE_GID
;
...
@@ -2910,24 +2899,22 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
...
@@ -2910,24 +2899,22 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
return
0
;
return
0
;
}
}
/*
/* Return the host uid/gid to which the container root is mapped in val.
* return the host uid/gid to which the container root is mapped in
* *val.
* Return true if id was found, false otherwise.
* Return true if id was found, false otherwise.
*/
*/
bool
get_mapped_rootid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
,
bool
get_mapped_rootid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
,
unsigned
long
*
val
)
unsigned
long
*
val
)
{
{
struct
lxc_list
*
it
;
struct
id_map
*
map
;
unsigned
nsid
;
unsigned
nsid
;
struct
id_map
*
map
;
struct
lxc_list
*
it
;
if
(
idtype
==
ID_TYPE_UID
)
if
(
idtype
==
ID_TYPE_UID
)
nsid
=
(
conf
->
root_nsuid_map
!=
NULL
)
?
0
:
conf
->
init_uid
;
nsid
=
(
conf
->
root_nsuid_map
!=
NULL
)
?
0
:
conf
->
init_uid
;
else
else
nsid
=
(
conf
->
root_nsgid_map
!=
NULL
)
?
0
:
conf
->
init_gid
;
nsid
=
(
conf
->
root_nsgid_map
!=
NULL
)
?
0
:
conf
->
init_gid
;
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
map
=
it
->
elem
;
map
=
it
->
elem
;
if
(
map
->
idtype
!=
idtype
)
if
(
map
->
idtype
!=
idtype
)
continue
;
continue
;
...
@@ -2942,33 +2929,39 @@ bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype,
...
@@ -2942,33 +2929,39 @@ bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype,
int
mapped_hostid
(
unsigned
id
,
struct
lxc_conf
*
conf
,
enum
idtype
idtype
)
int
mapped_hostid
(
unsigned
id
,
struct
lxc_conf
*
conf
,
enum
idtype
idtype
)
{
{
struct
lxc_list
*
it
;
struct
id_map
*
map
;
struct
id_map
*
map
;
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
struct
lxc_list
*
it
;
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
map
=
it
->
elem
;
map
=
it
->
elem
;
if
(
map
->
idtype
!=
idtype
)
if
(
map
->
idtype
!=
idtype
)
continue
;
continue
;
if
(
id
>=
map
->
hostid
&&
id
<
map
->
hostid
+
map
->
range
)
if
(
id
>=
map
->
hostid
&&
id
<
map
->
hostid
+
map
->
range
)
return
(
id
-
map
->
hostid
)
+
map
->
nsid
;
return
(
id
-
map
->
hostid
)
+
map
->
nsid
;
}
}
return
-
1
;
return
-
1
;
}
}
int
find_unmapped_nsid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
)
int
find_unmapped_nsid
(
struct
lxc_conf
*
conf
,
enum
idtype
idtype
)
{
{
struct
lxc_list
*
it
;
struct
id_map
*
map
;
struct
id_map
*
map
;
struct
lxc_list
*
it
;
unsigned
int
freeid
=
0
;
unsigned
int
freeid
=
0
;
again:
again:
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
map
=
it
->
elem
;
map
=
it
->
elem
;
if
(
map
->
idtype
!=
idtype
)
if
(
map
->
idtype
!=
idtype
)
continue
;
continue
;
if
(
freeid
>=
map
->
nsid
&&
freeid
<
map
->
nsid
+
map
->
range
)
{
if
(
freeid
>=
map
->
nsid
&&
freeid
<
map
->
nsid
+
map
->
range
)
{
freeid
=
map
->
nsid
+
map
->
range
;
freeid
=
map
->
nsid
+
map
->
range
;
goto
again
;
goto
again
;
}
}
}
}
return
freeid
;
return
freeid
;
}
}
...
@@ -2978,8 +2971,7 @@ int chown_mapped_root_exec_wrapper(void *args)
...
@@ -2978,8 +2971,7 @@ int chown_mapped_root_exec_wrapper(void *args)
return
-
1
;
return
-
1
;
}
}
/*
/* chown_mapped_root: for an unprivileged user with uid/gid X to
* chown_mapped_root: for an unprivileged user with uid/gid X to
* chown a dir to subuid/subgid Y, he needs to run chown as root
* chown a dir to subuid/subgid Y, he needs to run chown as root
* in a userns where nsid 0 is mapped to hostuid/hostgid Y, and
* in a userns where nsid 0 is mapped to hostuid/hostgid Y, and
* nsid Y is mapped to hostuid/hostgid X. That way, the container
* nsid Y is mapped to hostuid/hostgid X. That way, the container
...
@@ -3019,6 +3011,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf)
...
@@ -3019,6 +3011,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf)
return
-
1
;
return
-
1
;
}
}
rootuid
=
(
uid_t
)
val
;
rootuid
=
(
uid_t
)
val
;
if
(
!
get_mapped_rootid
(
conf
,
ID_TYPE_GID
,
&
val
))
{
if
(
!
get_mapped_rootid
(
conf
,
ID_TYPE_GID
,
&
val
))
{
ERROR
(
"No gid mapping for container root"
);
ERROR
(
"No gid mapping for container root"
);
return
-
1
;
return
-
1
;
...
@@ -3030,6 +3023,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf)
...
@@ -3030,6 +3023,7 @@ int chown_mapped_root(const char *path, struct lxc_conf *conf)
ERROR
(
"Error chowning %s"
,
path
);
ERROR
(
"Error chowning %s"
,
path
);
return
-
1
;
return
-
1
;
}
}
return
0
;
return
0
;
}
}
...
@@ -3125,7 +3119,7 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
...
@@ -3125,7 +3119,7 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
mounted
=
lxc_mount_proc_if_needed
(
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
);
mounted
=
lxc_mount_proc_if_needed
(
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
);
if
(
mounted
==
-
1
)
{
if
(
mounted
==
-
1
)
{
SYSERROR
(
"
failed to mount /
proc in the container"
);
SYSERROR
(
"
Failed to mount
proc in the container"
);
/* continue only if there is no rootfs */
/* continue only if there is no rootfs */
if
(
conf
->
rootfs
.
path
)
if
(
conf
->
rootfs
.
path
)
return
-
1
;
return
-
1
;
...
@@ -3138,39 +3132,47 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
...
@@ -3138,39 +3132,47 @@ int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
void
tmp_proc_unmount
(
struct
lxc_conf
*
lxc_conf
)
void
tmp_proc_unmount
(
struct
lxc_conf
*
lxc_conf
)
{
{
if
(
lxc_conf
->
tmp_umount_proc
==
1
)
{
if
(
lxc_conf
->
tmp_umount_proc
!=
1
)
umount
(
"/proc"
);
return
;
lxc_conf
->
tmp_umount_proc
=
0
;
}
umount
(
"/proc"
);
lxc_conf
->
tmp_umount_proc
=
0
;
}
}
/* Walk /proc/mounts and change any shared entries to slave. */
void
remount_all_slave
(
void
)
void
remount_all_slave
(
void
)
{
{
/* walk /proc/mounts and change any shared entries to slave */
FILE
*
f
;
FILE
*
f
=
fopen
(
"/proc/self/mountinfo"
,
"r"
);
char
*
line
=
NULL
;
size_t
len
=
0
;
size_t
len
=
0
;
char
*
line
=
NULL
;
f
=
fopen
(
"/proc/self/mountinfo"
,
"r"
);
if
(
!
f
)
{
if
(
!
f
)
{
SYSERROR
(
"Failed to open
/proc/self/mountinfo
to mark all shared"
);
SYSERROR
(
"Failed to open
\"
/proc/self/mountinfo
\"
to mark all shared"
);
ERROR
(
"Continuing container startup..."
);
ERROR
(
"Continuing container startup..."
);
return
;
return
;
}
}
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
char
*
target
,
*
opts
;
int
ret
;
char
*
opts
,
*
target
;
target
=
get_field
(
line
,
4
);
target
=
get_field
(
line
,
4
);
if
(
!
target
)
if
(
!
target
)
continue
;
continue
;
opts
=
get_field
(
target
,
2
);
opts
=
get_field
(
target
,
2
);
if
(
!
opts
)
if
(
!
opts
)
continue
;
continue
;
null_endofword
(
opts
);
null_endofword
(
opts
);
if
(
!
strstr
(
opts
,
"shared"
))
if
(
!
strstr
(
opts
,
"shared"
))
continue
;
continue
;
null_endofword
(
target
);
null_endofword
(
target
);
if
(
mount
(
NULL
,
target
,
NULL
,
MS_SLAVE
,
NULL
))
{
ret
=
mount
(
NULL
,
target
,
NULL
,
MS_SLAVE
,
NULL
);
SYSERROR
(
"Failed to make %s rslave"
,
target
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to make
\"
%s
\"
MS_SLAVE"
,
target
);
ERROR
(
"Continuing..."
);
ERROR
(
"Continuing..."
);
}
}
}
}
...
@@ -3191,24 +3193,22 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
...
@@ -3191,24 +3193,22 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
}
}
ret
=
snprintf
(
path
,
PATH_MAX
,
SBINDIR
"/init.lxc.static"
);
ret
=
snprintf
(
path
,
PATH_MAX
,
SBINDIR
"/init.lxc.static"
);
if
(
ret
<
0
||
ret
>=
PATH_MAX
)
{
if
(
ret
<
0
||
ret
>=
PATH_MAX
)
ERROR
(
"Path name too long searching for lxc.init.static"
);
return
-
1
;
return
-
1
;
}
if
(
!
file_exists
(
path
))
{
if
(
!
file_exists
(
path
))
{
ERROR
(
"
%s
does not exist on host"
,
path
);
ERROR
(
"
The file
\"
%s
\"
does not exist on host"
,
path
);
return
-
1
;
return
-
1
;
}
}
ret
=
snprintf
(
destpath
,
PATH_MAX
,
"%s%s"
,
conf
->
rootfs
.
mount
,
"/init.lxc.static"
);
ret
=
snprintf
(
destpath
,
PATH_MAX
,
"%s%s"
,
conf
->
rootfs
.
mount
,
"/init.lxc.static"
);
if
(
ret
<
0
||
ret
>=
PATH_MAX
)
{
if
(
ret
<
0
||
ret
>=
PATH_MAX
)
ERROR
(
"Path name too long for container's lxc.init.static"
);
return
-
1
;
return
-
1
;
}
if
(
!
file_exists
(
destpath
))
{
if
(
!
file_exists
(
destpath
))
{
FILE
*
pathfile
=
fopen
(
destpath
,
"wb"
);
FILE
*
pathfile
;
pathfile
=
fopen
(
destpath
,
"wb"
);
if
(
!
pathfile
)
{
if
(
!
pathfile
)
{
SYSERROR
(
"Failed to create mount target
\"
%s
\"
"
,
destpath
);
SYSERROR
(
"Failed to create mount target
\"
%s
\"
"
,
destpath
);
return
-
1
;
return
-
1
;
...
@@ -3219,7 +3219,7 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
...
@@ -3219,7 +3219,7 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
ret
=
safe_mount
(
path
,
destpath
,
"none"
,
MS_BIND
,
NULL
,
conf
->
rootfs
.
mount
);
ret
=
safe_mount
(
path
,
destpath
,
"none"
,
MS_BIND
,
NULL
,
conf
->
rootfs
.
mount
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to bind lxc.init.static into container"
);
SYSERROR
(
"Failed to bind
mount
lxc.init.static into container"
);
return
-
1
;
return
-
1
;
}
}
...
@@ -3227,34 +3227,40 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
...
@@ -3227,34 +3227,40 @@ static int lxc_execute_bind_init(struct lxc_conf *conf)
return
0
;
return
0
;
}
}
/*
/* This does the work of remounting / if it is shared, calling the container
* This does the work of remounting / if it is shared, calling the
* pre-mount hooks, and mounting the rootfs.
* container pre-mount hooks, and mounting the rootfs.
*/
*/
int
do_rootfs_setup
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
)
int
do_rootfs_setup
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
)
{
{
int
ret
;
if
(
conf
->
rootfs_setup
)
{
if
(
conf
->
rootfs_setup
)
{
/*
* rootfs was set up in another namespace. bind-mount it
* to give us a mount in our own ns so we can pivot_root to it
*/
const
char
*
path
=
conf
->
rootfs
.
mount
;
const
char
*
path
=
conf
->
rootfs
.
mount
;
if
(
mount
(
path
,
path
,
"rootfs"
,
MS_BIND
,
NULL
)
<
0
)
{
ERROR
(
"Failed to bind-mount container / onto itself"
);
/* The rootfs was set up in another namespace. bind-mount it to
* give us a mount in our own ns so we can pivot_root to it
*/
ret
=
mount
(
path
,
path
,
"rootfs"
,
MS_BIND
,
NULL
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to bind mount container / onto itself"
);
return
-
1
;
return
-
1
;
}
}
TRACE
(
"Bind mounted container / onto itself"
);
return
0
;
return
0
;
}
}
remount_all_slave
();
remount_all_slave
();
if
(
run_lxc_hooks
(
name
,
"pre-mount"
,
conf
,
NULL
))
{
ret
=
run_lxc_hooks
(
name
,
"pre-mount"
,
conf
,
NULL
);
ERROR
(
"failed to run pre-mount hooks for container '%s'."
,
name
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to run pre-mount hooks"
);
return
-
1
;
return
-
1
;
}
}
if
(
lxc_setup_rootfs
(
conf
))
{
ret
=
lxc_setup_rootfs
(
conf
);
ERROR
(
"failed to setup rootfs for '%s'"
,
name
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to setup rootfs for"
);
return
-
1
;
return
-
1
;
}
}
...
@@ -3264,23 +3270,27 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
...
@@ -3264,23 +3270,27 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
static
bool
verify_start_hooks
(
struct
lxc_conf
*
conf
)
static
bool
verify_start_hooks
(
struct
lxc_conf
*
conf
)
{
{
struct
lxc_list
*
it
;
char
path
[
MAXPATHLEN
];
char
path
[
MAXPATHLEN
];
lxc_list_for_each
(
it
,
&
conf
->
hooks
[
LXCHOOK_START
])
{
struct
lxc_list
*
it
;
char
*
hookname
=
it
->
elem
;
struct
stat
st
;
lxc_list_for_each
(
it
,
&
conf
->
hooks
[
LXCHOOK_START
])
{
int
ret
;
int
ret
;
struct
stat
st
;
char
*
hookname
=
it
->
elem
;
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s%s"
,
ret
=
snprintf
(
path
,
MAXPATHLEN
,
"%s%s"
,
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
hookname
);
conf
->
rootfs
.
path
?
conf
->
rootfs
.
mount
:
""
,
hookname
);
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
if
(
ret
<
0
||
ret
>=
MAXPATHLEN
)
return
false
;
return
false
;
ret
=
stat
(
path
,
&
st
);
ret
=
stat
(
path
,
&
st
);
if
(
ret
)
{
if
(
ret
<
0
)
{
SYSERROR
(
"Start hook %s not found in container"
,
SYSERROR
(
"Start hook %s not found in container"
,
hookname
);
hookname
);
return
false
;
return
false
;
}
}
return
true
;
return
true
;
}
}
...
@@ -3290,9 +3300,8 @@ static bool verify_start_hooks(struct lxc_conf *conf)
...
@@ -3290,9 +3300,8 @@ static bool verify_start_hooks(struct lxc_conf *conf)
int
lxc_setup
(
struct
lxc_handler
*
handler
)
int
lxc_setup
(
struct
lxc_handler
*
handler
)
{
{
int
ret
;
int
ret
;
const
char
*
name
=
handler
->
name
;
const
char
*
lxcpath
=
handler
->
lxcpath
,
*
name
=
handler
->
name
;
struct
lxc_conf
*
lxc_conf
=
handler
->
conf
;
struct
lxc_conf
*
lxc_conf
=
handler
->
conf
;
const
char
*
lxcpath
=
handler
->
lxcpath
;
ret
=
do_rootfs_setup
(
lxc_conf
,
name
,
lxcpath
);
ret
=
do_rootfs_setup
(
lxc_conf
,
name
,
lxcpath
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
...
@@ -3303,7 +3312,7 @@ int lxc_setup(struct lxc_handler *handler)
...
@@ -3303,7 +3312,7 @@ int lxc_setup(struct lxc_handler *handler)
if
(
handler
->
nsfd
[
LXC_NS_UTS
]
==
-
1
)
{
if
(
handler
->
nsfd
[
LXC_NS_UTS
]
==
-
1
)
{
ret
=
setup_utsname
(
lxc_conf
->
utsname
);
ret
=
setup_utsname
(
lxc_conf
->
utsname
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"
failed to setup the utsname for '%s'
"
,
name
);
ERROR
(
"
Failed to setup the utsname %s
"
,
name
);
return
-
1
;
return
-
1
;
}
}
}
}
...
@@ -3498,7 +3507,7 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
...
@@ -3498,7 +3507,7 @@ int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf,
else
else
return
-
1
;
return
-
1
;
lxc_list_for_each
(
it
,
&
conf
->
hooks
[
which
])
{
lxc_list_for_each
(
it
,
&
conf
->
hooks
[
which
])
{
int
ret
;
int
ret
;
char
*
hook
=
it
->
elem
;
char
*
hook
=
it
->
elem
;
...
@@ -3515,11 +3524,12 @@ int lxc_clear_config_caps(struct lxc_conf *c)
...
@@ -3515,11 +3524,12 @@ int lxc_clear_config_caps(struct lxc_conf *c)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
&
c
->
caps
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
caps
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
}
}
return
0
;
return
0
;
}
}
...
@@ -3527,7 +3537,7 @@ static int lxc_free_idmap(struct lxc_list *id_map)
...
@@ -3527,7 +3537,7 @@ static int lxc_free_idmap(struct lxc_list *id_map)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
id_map
,
next
)
{
lxc_list_for_each_safe
(
it
,
id_map
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
...
@@ -3543,13 +3553,14 @@ int lxc_clear_idmaps(struct lxc_conf *c)
...
@@ -3543,13 +3553,14 @@ int lxc_clear_idmaps(struct lxc_conf *c)
int
lxc_clear_config_keepcaps
(
struct
lxc_conf
*
c
)
int
lxc_clear_config_keepcaps
(
struct
lxc_conf
*
c
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
&
c
->
keepcaps
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
keepcaps
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
}
}
return
0
;
return
0
;
}
}
...
@@ -3564,12 +3575,12 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
...
@@ -3564,12 +3575,12 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
if
(
version
==
CGROUP2_SUPER_MAGIC
)
{
if
(
version
==
CGROUP2_SUPER_MAGIC
)
{
global_token
=
"lxc.cgroup2"
;
global_token
=
"lxc.cgroup2"
;
namespaced_token
=
"lxc.cgroup2."
;
namespaced_token
=
"lxc.cgroup2."
;
namespaced_token_len
=
sizeof
(
"lxc.cgroup2."
)
-
1
;
;
namespaced_token_len
=
sizeof
(
"lxc.cgroup2."
)
-
1
;
list
=
&
c
->
cgroup2
;
list
=
&
c
->
cgroup2
;
}
else
if
(
version
==
CGROUP_SUPER_MAGIC
)
{
}
else
if
(
version
==
CGROUP_SUPER_MAGIC
)
{
global_token
=
"lxc.cgroup"
;
global_token
=
"lxc.cgroup"
;
namespaced_token
=
"lxc.cgroup."
;
namespaced_token
=
"lxc.cgroup."
;
namespaced_token_len
=
sizeof
(
"lxc.cgroup."
)
-
1
;
;
namespaced_token_len
=
sizeof
(
"lxc.cgroup."
)
-
1
;
list
=
&
c
->
cgroup
;
list
=
&
c
->
cgroup
;
}
else
{
}
else
{
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -3582,7 +3593,7 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
...
@@ -3582,7 +3593,7 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
else
else
return
-
EINVAL
;
return
-
EINVAL
;
lxc_list_for_each_safe
(
it
,
list
,
next
)
{
lxc_list_for_each_safe
(
it
,
list
,
next
)
{
struct
lxc_cgroup
*
cg
=
it
->
elem
;
struct
lxc_cgroup
*
cg
=
it
->
elem
;
if
(
!
all
&&
strcmp
(
cg
->
subsystem
,
k
)
!=
0
)
if
(
!
all
&&
strcmp
(
cg
->
subsystem
,
k
)
!=
0
)
...
@@ -3601,8 +3612,8 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
...
@@ -3601,8 +3612,8 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version)
int
lxc_clear_limits
(
struct
lxc_conf
*
c
,
const
char
*
key
)
int
lxc_clear_limits
(
struct
lxc_conf
*
c
,
const
char
*
key
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
bool
all
=
false
;
const
char
*
k
=
NULL
;
const
char
*
k
=
NULL
;
bool
all
=
false
;
if
(
strcmp
(
key
,
"lxc.limit"
)
==
0
||
strcmp
(
key
,
"lxc.prlimit"
)
==
0
)
if
(
strcmp
(
key
,
"lxc.limit"
)
==
0
||
strcmp
(
key
,
"lxc.prlimit"
)
==
0
)
all
=
true
;
all
=
true
;
...
@@ -3613,10 +3624,12 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
...
@@ -3613,10 +3624,12 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
else
else
return
-
1
;
return
-
1
;
lxc_list_for_each_safe
(
it
,
&
c
->
limits
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
limits
,
next
)
{
struct
lxc_limit
*
lim
=
it
->
elem
;
struct
lxc_limit
*
lim
=
it
->
elem
;
if
(
!
all
&&
strcmp
(
lim
->
resource
,
k
)
!=
0
)
if
(
!
all
&&
strcmp
(
lim
->
resource
,
k
)
!=
0
)
continue
;
continue
;
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
lim
->
resource
);
free
(
lim
->
resource
);
free
(
lim
);
free
(
lim
);
...
@@ -3629,8 +3642,8 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
...
@@ -3629,8 +3642,8 @@ int lxc_clear_limits(struct lxc_conf *c, const char *key)
int
lxc_clear_sysctls
(
struct
lxc_conf
*
c
,
const
char
*
key
)
int
lxc_clear_sysctls
(
struct
lxc_conf
*
c
,
const
char
*
key
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
bool
all
=
false
;
const
char
*
k
=
NULL
;
const
char
*
k
=
NULL
;
bool
all
=
false
;
if
(
strcmp
(
key
,
"lxc.sysctl"
)
==
0
)
if
(
strcmp
(
key
,
"lxc.sysctl"
)
==
0
)
all
=
true
;
all
=
true
;
...
@@ -3639,24 +3652,27 @@ int lxc_clear_sysctls(struct lxc_conf *c, const char *key)
...
@@ -3639,24 +3652,27 @@ int lxc_clear_sysctls(struct lxc_conf *c, const char *key)
else
else
return
-
1
;
return
-
1
;
lxc_list_for_each_safe
(
it
,
&
c
->
sysctls
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
sysctls
,
next
)
{
struct
lxc_sysctl
*
elem
=
it
->
elem
;
struct
lxc_sysctl
*
elem
=
it
->
elem
;
if
(
!
all
&&
strcmp
(
elem
->
key
,
k
)
!=
0
)
if
(
!
all
&&
strcmp
(
elem
->
key
,
k
)
!=
0
)
continue
;
continue
;
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
elem
->
key
);
free
(
elem
->
key
);
free
(
elem
->
value
);
free
(
elem
->
value
);
free
(
elem
);
free
(
elem
);
free
(
it
);
free
(
it
);
}
}
return
0
;
return
0
;
}
}
int
lxc_clear_procs
(
struct
lxc_conf
*
c
,
const
char
*
key
)
int
lxc_clear_procs
(
struct
lxc_conf
*
c
,
const
char
*
key
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
bool
all
=
false
;
const
char
*
k
=
NULL
;
const
char
*
k
=
NULL
;
bool
all
=
false
;
if
(
strcmp
(
key
,
"lxc.proc"
)
==
0
)
if
(
strcmp
(
key
,
"lxc.proc"
)
==
0
)
all
=
true
;
all
=
true
;
...
@@ -3665,10 +3681,12 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key)
...
@@ -3665,10 +3681,12 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key)
else
else
return
-
1
;
return
-
1
;
lxc_list_for_each_safe
(
it
,
&
c
->
procs
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
procs
,
next
)
{
struct
lxc_proc
*
proc
=
it
->
elem
;
struct
lxc_proc
*
proc
=
it
->
elem
;
if
(
!
all
&&
strcmp
(
proc
->
filename
,
k
)
!=
0
)
if
(
!
all
&&
strcmp
(
proc
->
filename
,
k
)
!=
0
)
continue
;
continue
;
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
proc
->
filename
);
free
(
proc
->
filename
);
free
(
proc
->
value
);
free
(
proc
->
value
);
...
@@ -3681,37 +3699,40 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key)
...
@@ -3681,37 +3699,40 @@ int lxc_clear_procs(struct lxc_conf *c, const char *key)
int
lxc_clear_groups
(
struct
lxc_conf
*
c
)
int
lxc_clear_groups
(
struct
lxc_conf
*
c
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
&
c
->
groups
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
groups
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
}
}
return
0
;
return
0
;
}
}
int
lxc_clear_environment
(
struct
lxc_conf
*
c
)
int
lxc_clear_environment
(
struct
lxc_conf
*
c
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
&
c
->
environment
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
environment
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
}
}
return
0
;
return
0
;
}
}
int
lxc_clear_mount_entries
(
struct
lxc_conf
*
c
)
int
lxc_clear_mount_entries
(
struct
lxc_conf
*
c
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
&
c
->
mount_list
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
mount_list
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
}
}
return
0
;
return
0
;
}
}
...
@@ -3723,25 +3744,26 @@ int lxc_clear_automounts(struct lxc_conf *c)
...
@@ -3723,25 +3744,26 @@ int lxc_clear_automounts(struct lxc_conf *c)
int
lxc_clear_hooks
(
struct
lxc_conf
*
c
,
const
char
*
key
)
int
lxc_clear_hooks
(
struct
lxc_conf
*
c
,
const
char
*
key
)
{
{
struct
lxc_list
*
it
,
*
next
;
bool
all
=
false
,
done
=
false
;
const
char
*
k
=
NULL
;
int
i
;
int
i
;
struct
lxc_list
*
it
,
*
next
;
const
char
*
k
=
NULL
;
bool
all
=
false
,
done
=
false
;
if
(
strcmp
(
key
,
"lxc.hook"
)
==
0
)
if
(
strcmp
(
key
,
"lxc.hook"
)
==
0
)
all
=
true
;
all
=
true
;
else
if
(
strncmp
(
key
,
"lxc.hook."
,
sizeof
(
"lxc.hook."
)
-
1
)
==
0
)
else
if
(
strncmp
(
key
,
"lxc.hook."
,
sizeof
(
"lxc.hook."
)
-
1
)
==
0
)
k
=
key
+
sizeof
(
"lxc.hook."
)
-
1
;
k
=
key
+
sizeof
(
"lxc.hook."
)
-
1
;
else
else
return
-
1
;
return
-
1
;
for
(
i
=
0
;
i
<
NUM_LXC_HOOKS
;
i
++
)
{
for
(
i
=
0
;
i
<
NUM_LXC_HOOKS
;
i
++
)
{
if
(
all
||
strcmp
(
k
,
lxchook_names
[
i
])
==
0
)
{
if
(
all
||
strcmp
(
k
,
lxchook_names
[
i
])
==
0
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
hooks
[
i
],
next
)
{
lxc_list_for_each_safe
(
it
,
&
c
->
hooks
[
i
],
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
}
}
done
=
true
;
done
=
true
;
}
}
}
}
...
@@ -3750,14 +3772,15 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
...
@@ -3750,14 +3772,15 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
ERROR
(
"Invalid hook key: %s"
,
key
);
ERROR
(
"Invalid hook key: %s"
,
key
);
return
-
1
;
return
-
1
;
}
}
return
0
;
return
0
;
}
}
static
inline
void
lxc_clear_aliens
(
struct
lxc_conf
*
conf
)
static
inline
void
lxc_clear_aliens
(
struct
lxc_conf
*
conf
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
&
conf
->
aliens
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
conf
->
aliens
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
...
@@ -3766,9 +3789,9 @@ static inline void lxc_clear_aliens(struct lxc_conf *conf)
...
@@ -3766,9 +3789,9 @@ static inline void lxc_clear_aliens(struct lxc_conf *conf)
void
lxc_clear_includes
(
struct
lxc_conf
*
conf
)
void
lxc_clear_includes
(
struct
lxc_conf
*
conf
)
{
{
struct
lxc_list
*
it
,
*
next
;
struct
lxc_list
*
it
,
*
next
;
lxc_list_for_each_safe
(
it
,
&
conf
->
includes
,
next
)
{
lxc_list_for_each_safe
(
it
,
&
conf
->
includes
,
next
)
{
lxc_list_del
(
it
);
lxc_list_del
(
it
);
free
(
it
->
elem
);
free
(
it
->
elem
);
free
(
it
);
free
(
it
);
...
@@ -3779,6 +3802,7 @@ void lxc_conf_free(struct lxc_conf *conf)
...
@@ -3779,6 +3802,7 @@ void lxc_conf_free(struct lxc_conf *conf)
{
{
if
(
!
conf
)
if
(
!
conf
)
return
;
return
;
if
(
current_config
==
conf
)
if
(
current_config
==
conf
)
current_config
=
NULL
;
current_config
=
NULL
;
lxc_terminal_conf_free
(
&
conf
->
console
);
lxc_terminal_conf_free
(
&
conf
->
console
);
...
@@ -3831,8 +3855,8 @@ struct userns_fn_data {
...
@@ -3831,8 +3855,8 @@ struct userns_fn_data {
static
int
run_userns_fn
(
void
*
data
)
static
int
run_userns_fn
(
void
*
data
)
{
{
struct
userns_fn_data
*
d
=
data
;
char
c
;
char
c
;
struct
userns_fn_data
*
d
=
data
;
/* Close write end of the pipe. */
/* Close write end of the pipe. */
close
(
d
->
p
[
1
]);
close
(
d
->
p
[
1
]);
...
@@ -3848,6 +3872,7 @@ static int run_userns_fn(void *data)
...
@@ -3848,6 +3872,7 @@ static int run_userns_fn(void *data)
if
(
d
->
fn_name
)
if
(
d
->
fn_name
)
TRACE
(
"calling function
\"
%s
\"
"
,
d
->
fn_name
);
TRACE
(
"calling function
\"
%s
\"
"
,
d
->
fn_name
);
/* Call function to run. */
/* Call function to run. */
return
d
->
fn
(
d
->
arg
);
return
d
->
fn
(
d
->
arg
);
}
}
...
@@ -3872,11 +3897,11 @@ static struct id_map *mapped_nsid_add(struct lxc_conf *conf, unsigned id,
...
@@ -3872,11 +3897,11 @@ static struct id_map *mapped_nsid_add(struct lxc_conf *conf, unsigned id,
static
struct
id_map
*
find_mapped_hostid_entry
(
struct
lxc_conf
*
conf
,
static
struct
id_map
*
find_mapped_hostid_entry
(
struct
lxc_conf
*
conf
,
unsigned
id
,
enum
idtype
idtype
)
unsigned
id
,
enum
idtype
idtype
)
{
{
struct
lxc_list
*
it
;
struct
id_map
*
map
;
struct
id_map
*
map
;
struct
lxc_list
*
it
;
struct
id_map
*
retmap
=
NULL
;
struct
id_map
*
retmap
=
NULL
;
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
lxc_list_for_each
(
it
,
&
conf
->
id_map
)
{
map
=
it
->
elem
;
map
=
it
->
elem
;
if
(
map
->
idtype
!=
idtype
)
if
(
map
->
idtype
!=
idtype
)
continue
;
continue
;
...
@@ -3890,11 +3915,11 @@ static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf,
...
@@ -3890,11 +3915,11 @@ static struct id_map *find_mapped_hostid_entry(struct lxc_conf *conf,
return
retmap
;
return
retmap
;
}
}
/*
/* Allocate a new {g,u}id mapping for the given {g,u}id. Re-use an already
* Allocate a new {g,u}id mapping for the given {g,u}id. Re-use an already
* existing one or establish a new one.
* existing one or establish a new one.
*/
*/
static
struct
id_map
*
mapped_hostid_add
(
struct
lxc_conf
*
conf
,
uid_t
id
,
enum
idtype
type
)
static
struct
id_map
*
mapped_hostid_add
(
struct
lxc_conf
*
conf
,
uid_t
id
,
enum
idtype
type
)
{
{
int
hostid_mapped
;
int
hostid_mapped
;
struct
id_map
*
entry
=
NULL
,
*
tmp
=
NULL
;
struct
id_map
*
entry
=
NULL
,
*
tmp
=
NULL
;
...
@@ -4052,11 +4077,11 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4052,11 +4077,11 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
const
char
*
fn_name
)
const
char
*
fn_name
)
{
{
pid_t
pid
;
pid_t
pid
;
struct
userns_fn_data
d
;
int
p
[
2
];
int
p
[
2
];
char
c
=
'1'
;
struct
userns_fn_data
d
;
int
ret
=
-
1
,
status
=
-
1
;
struct
lxc_list
*
idmap
;
struct
lxc_list
*
idmap
;
int
ret
=
-
1
,
status
=
-
1
;
char
c
=
'1'
;
idmap
=
get_minimal_idmap
(
conf
);
idmap
=
get_minimal_idmap
(
conf
);
if
(
!
idmap
)
if
(
!
idmap
)
...
@@ -4076,7 +4101,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4076,7 +4101,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* Clone child in new user namespace. */
/* Clone child in new user namespace. */
pid
=
lxc_raw_clone_cb
(
run_userns_fn
,
&
d
,
CLONE_NEWUSER
);
pid
=
lxc_raw_clone_cb
(
run_userns_fn
,
&
d
,
CLONE_NEWUSER
);
if
(
pid
<
0
)
{
if
(
pid
<
0
)
{
ERROR
(
"
failed to clone child
process in new user namespace"
);
ERROR
(
"
Failed to clone
process in new user namespace"
);
goto
on_error
;
goto
on_error
;
}
}
...
@@ -4085,23 +4110,23 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4085,23 +4110,23 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
if
(
lxc_log_get_level
()
==
LXC_LOG_LEVEL_TRACE
||
if
(
lxc_log_get_level
()
==
LXC_LOG_LEVEL_TRACE
||
conf
->
loglevel
==
LXC_LOG_LEVEL_TRACE
)
{
conf
->
loglevel
==
LXC_LOG_LEVEL_TRACE
)
{
struct
lxc_list
*
it
;
struct
id_map
*
map
;
struct
id_map
*
map
;
struct
lxc_list
*
it
;
lxc_list_for_each
(
it
,
idmap
)
{
lxc_list_for_each
(
it
,
idmap
)
{
map
=
it
->
elem
;
map
=
it
->
elem
;
TRACE
(
"Establishing %cid mapping for
\"
%d
\"
in new "
TRACE
(
"Establishing %cid mapping for
\"
%d
\"
in new "
"user namespace: nsuid %lu - hostid %lu - range "
"user namespace: nsuid %lu - hostid %lu - range "
"%lu"
,
(
map
->
idtype
==
ID_TYPE_UID
)
?
'u'
:
'g'
,
"%lu"
,
pid
,
map
->
nsid
,
map
->
hostid
,
map
->
range
);
(
map
->
idtype
==
ID_TYPE_UID
)
?
'u'
:
'g'
,
pid
,
map
->
nsid
,
map
->
hostid
,
map
->
range
);
}
}
}
}
/* Set up {g,u}id mapping for user namespace of child process. */
/* Set up {g,u}id mapping for user namespace of child process. */
ret
=
lxc_map_ids
(
idmap
,
pid
);
ret
=
lxc_map_ids
(
idmap
,
pid
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"Error setting up {g,u}id mappings for child process "
ERROR
(
"Error setting up {g,u}id mappings for child process
\"
%d
\"
"
,
pid
);
"
\"
%d
\"
"
,
pid
);
goto
on_error
;
goto
on_error
;
}
}
...
@@ -4131,12 +4156,12 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4131,12 +4156,12 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
{
{
pid_t
pid
;
pid_t
pid
;
uid_t
euid
,
egid
;
uid_t
euid
,
egid
;
struct
userns_fn_data
d
;
int
p
[
2
];
int
p
[
2
];
struct
id_map
*
map
;
struct
id_map
*
map
;
struct
lxc_list
*
cur
;
struct
lxc_list
*
cur
;
char
c
=
'1'
;
struct
userns_fn_data
d
;
int
ret
=
-
1
;
int
ret
=
-
1
;
char
c
=
'1'
;
struct
lxc_list
*
idmap
=
NULL
,
*
tmplist
=
NULL
;
struct
lxc_list
*
idmap
=
NULL
,
*
tmplist
=
NULL
;
struct
id_map
*
container_root_uid
=
NULL
,
*
container_root_gid
=
NULL
,
struct
id_map
*
container_root_uid
=
NULL
,
*
container_root_gid
=
NULL
,
*
host_uid_map
=
NULL
,
*
host_gid_map
=
NULL
;
*
host_uid_map
=
NULL
,
*
host_gid_map
=
NULL
;
...
@@ -4155,7 +4180,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4155,7 +4180,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* Clone child in new user namespace. */
/* Clone child in new user namespace. */
pid
=
lxc_clone
(
run_userns_fn
,
&
d
,
CLONE_NEWUSER
);
pid
=
lxc_clone
(
run_userns_fn
,
&
d
,
CLONE_NEWUSER
);
if
(
pid
<
0
)
{
if
(
pid
<
0
)
{
ERROR
(
"
failed to clone child
process in new user namespace"
);
ERROR
(
"
Failed to clone
process in new user namespace"
);
goto
on_error
;
goto
on_error
;
}
}
...
@@ -4172,7 +4197,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4172,7 +4197,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
lxc_list_init
(
idmap
);
lxc_list_init
(
idmap
);
/* Find container root. */
/* Find container root. */
lxc_list_for_each
(
cur
,
&
conf
->
id_map
)
{
lxc_list_for_each
(
cur
,
&
conf
->
id_map
)
{
struct
id_map
*
tmpmap
;
struct
id_map
*
tmpmap
;
tmplist
=
malloc
(
sizeof
(
*
tmplist
));
tmplist
=
malloc
(
sizeof
(
*
tmplist
));
...
@@ -4262,7 +4287,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4262,7 +4287,7 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
if
(
lxc_log_get_level
()
==
LXC_LOG_LEVEL_TRACE
||
if
(
lxc_log_get_level
()
==
LXC_LOG_LEVEL_TRACE
||
conf
->
loglevel
==
LXC_LOG_LEVEL_TRACE
)
{
conf
->
loglevel
==
LXC_LOG_LEVEL_TRACE
)
{
lxc_list_for_each
(
cur
,
idmap
)
{
lxc_list_for_each
(
cur
,
idmap
)
{
map
=
cur
->
elem
;
map
=
cur
->
elem
;
TRACE
(
"establishing %cid mapping for
\"
%d
\"
in new "
TRACE
(
"establishing %cid mapping for
\"
%d
\"
in new "
"user namespace: nsuid %lu - hostid %lu - range "
"user namespace: nsuid %lu - hostid %lu - range "
...
@@ -4275,14 +4300,13 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
...
@@ -4275,14 +4300,13 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* Set up {g,u}id mapping for user namespace of child process. */
/* Set up {g,u}id mapping for user namespace of child process. */
ret
=
lxc_map_ids
(
idmap
,
pid
);
ret
=
lxc_map_ids
(
idmap
,
pid
);
if
(
ret
<
0
)
{
if
(
ret
<
0
)
{
ERROR
(
"error setting up {g,u}id mappings for child process "
ERROR
(
"error setting up {g,u}id mappings for child process
\"
%d
\"
"
,
pid
);
"
\"
%d
\"
"
,
pid
);
goto
on_error
;
goto
on_error
;
}
}
/* Tell child to proceed. */
/* Tell child to proceed. */
if
(
write
(
p
[
1
],
&
c
,
1
)
!=
1
)
{
if
(
write
(
p
[
1
],
&
c
,
1
)
!=
1
)
{
SYSERROR
(
"
f
ailed telling child process
\"
%d
\"
to proceed"
,
pid
);
SYSERROR
(
"
F
ailed telling child process
\"
%d
\"
to proceed"
,
pid
);
goto
on_error
;
goto
on_error
;
}
}
...
@@ -4306,7 +4330,7 @@ on_error:
...
@@ -4306,7 +4330,7 @@ on_error:
}
}
/* not thread-safe, do not use from api without first forking */
/* not thread-safe, do not use from api without first forking */
static
char
*
getuname
(
void
)
static
char
*
getuname
(
void
)
{
{
struct
passwd
*
result
;
struct
passwd
*
result
;
...
@@ -4332,16 +4356,18 @@ static char *getgname(void)
...
@@ -4332,16 +4356,18 @@ static char *getgname(void)
/* not thread-safe, do not use from api without first forking */
/* not thread-safe, do not use from api without first forking */
void
suggest_default_idmap
(
void
)
void
suggest_default_idmap
(
void
)
{
{
char
*
uname
,
*
gname
;
FILE
*
f
;
FILE
*
f
;
unsigned
int
uid
=
0
,
urange
=
0
,
gid
=
0
,
grange
=
0
;
unsigned
int
uid
=
0
,
urange
=
0
,
gid
=
0
,
grange
=
0
;
char
*
line
=
NULL
;
char
*
uname
,
*
gname
;
size_t
len
=
0
;
size_t
len
=
0
;
char
*
line
=
NULL
;
if
(
!
(
uname
=
getuname
()))
uname
=
getuname
();
if
(
!
uname
)
return
;
return
;
if
(
!
(
gname
=
getgname
()))
{
gname
=
getgname
();
if
(
!
gname
)
{
free
(
uname
);
free
(
uname
);
return
;
return
;
}
}
...
@@ -4353,17 +4379,22 @@ void suggest_default_idmap(void)
...
@@ -4353,17 +4379,22 @@ void suggest_default_idmap(void)
free
(
uname
);
free
(
uname
);
return
;
return
;
}
}
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
char
*
p
,
*
p2
;
size_t
no_newline
=
0
;
size_t
no_newline
=
0
;
char
*
p
=
strchr
(
line
,
':'
),
*
p2
;
p
=
strchr
(
line
,
':'
);
if
(
*
line
==
'#'
)
if
(
*
line
==
'#'
)
continue
;
continue
;
if
(
!
p
)
if
(
!
p
)
continue
;
continue
;
*
p
=
'\0'
;
*
p
=
'\0'
;
p
++
;
p
++
;
if
(
strcmp
(
line
,
uname
))
if
(
strcmp
(
line
,
uname
))
continue
;
continue
;
p2
=
strchr
(
p
,
':'
);
p2
=
strchr
(
p
,
':'
);
if
(
!
p2
)
if
(
!
p2
)
continue
;
continue
;
...
@@ -4375,9 +4406,9 @@ void suggest_default_idmap(void)
...
@@ -4375,9 +4406,9 @@ void suggest_default_idmap(void)
p2
[
no_newline
]
=
'\0'
;
p2
[
no_newline
]
=
'\0'
;
if
(
lxc_safe_uint
(
p
,
&
uid
)
<
0
)
if
(
lxc_safe_uint
(
p
,
&
uid
)
<
0
)
WARN
(
"Could not parse UID
.
"
);
WARN
(
"Could not parse UID"
);
if
(
lxc_safe_uint
(
p2
,
&
urange
)
<
0
)
if
(
lxc_safe_uint
(
p2
,
&
urange
)
<
0
)
WARN
(
"Could not parse UID range
.
"
);
WARN
(
"Could not parse UID range"
);
}
}
fclose
(
f
);
fclose
(
f
);
...
@@ -4388,17 +4419,22 @@ void suggest_default_idmap(void)
...
@@ -4388,17 +4419,22 @@ void suggest_default_idmap(void)
free
(
uname
);
free
(
uname
);
return
;
return
;
}
}
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
char
*
p
,
*
p2
;
size_t
no_newline
=
0
;
size_t
no_newline
=
0
;
char
*
p
=
strchr
(
line
,
':'
),
*
p2
;
p
=
strchr
(
line
,
':'
);
if
(
*
line
==
'#'
)
if
(
*
line
==
'#'
)
continue
;
continue
;
if
(
!
p
)
if
(
!
p
)
continue
;
continue
;
*
p
=
'\0'
;
*
p
=
'\0'
;
p
++
;
p
++
;
if
(
strcmp
(
line
,
uname
))
if
(
strcmp
(
line
,
uname
))
continue
;
continue
;
p2
=
strchr
(
p
,
':'
);
p2
=
strchr
(
p
,
':'
);
if
(
!
p2
)
if
(
!
p2
)
continue
;
continue
;
...
@@ -4410,9 +4446,9 @@ void suggest_default_idmap(void)
...
@@ -4410,9 +4446,9 @@ void suggest_default_idmap(void)
p2
[
no_newline
]
=
'\0'
;
p2
[
no_newline
]
=
'\0'
;
if
(
lxc_safe_uint
(
p
,
&
gid
)
<
0
)
if
(
lxc_safe_uint
(
p
,
&
gid
)
<
0
)
WARN
(
"Could not parse GID
.
"
);
WARN
(
"Could not parse GID"
);
if
(
lxc_safe_uint
(
p2
,
&
grange
)
<
0
)
if
(
lxc_safe_uint
(
p2
,
&
grange
)
<
0
)
WARN
(
"Could not parse GID range
.
"
);
WARN
(
"Could not parse GID range"
);
}
}
fclose
(
f
);
fclose
(
f
);
...
@@ -4439,48 +4475,45 @@ static void free_cgroup_settings(struct lxc_list *result)
...
@@ -4439,48 +4475,45 @@ static void free_cgroup_settings(struct lxc_list *result)
{
{
struct
lxc_list
*
iterator
,
*
next
;
struct
lxc_list
*
iterator
,
*
next
;
lxc_list_for_each_safe
(
iterator
,
result
,
next
)
{
lxc_list_for_each_safe
(
iterator
,
result
,
next
)
{
lxc_list_del
(
iterator
);
lxc_list_del
(
iterator
);
free
(
iterator
);
free
(
iterator
);
}
}
free
(
result
);
free
(
result
);
}
}
/*
/* Return the list of cgroup_settings sorted according to the following rules
* Return the list of cgroup_settings sorted according to the following rules
* 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes
* 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes
*/
*/
struct
lxc_list
*
sort_cgroup_settings
(
struct
lxc_list
*
cgroup_settings
)
struct
lxc_list
*
sort_cgroup_settings
(
struct
lxc_list
*
cgroup_settings
)
{
{
struct
lxc_list
*
result
;
struct
lxc_list
*
result
;
struct
lxc_list
*
memsw_limit
=
NULL
;
struct
lxc_list
*
it
=
NULL
;
struct
lxc_cgroup
*
cg
=
NULL
;
struct
lxc_cgroup
*
cg
=
NULL
;
struct
lxc_list
*
it
em
=
NULL
;
struct
lxc_list
*
it
=
NULL
,
*
item
=
NULL
,
*
memsw_limit
=
NULL
;
result
=
malloc
(
sizeof
(
*
result
));
result
=
malloc
(
sizeof
(
*
result
));
if
(
!
result
)
{
if
(
!
result
)
ERROR
(
"failed to allocate memory to sort cgroup settings"
);
return
NULL
;
return
NULL
;
}
lxc_list_init
(
result
);
lxc_list_init
(
result
);
/*
Iterate over the cgroup settings and copy them to the output list
*/
/*
Iterate over the cgroup settings and copy them to the output list.
*/
lxc_list_for_each
(
it
,
cgroup_settings
)
{
lxc_list_for_each
(
it
,
cgroup_settings
)
{
item
=
malloc
(
sizeof
(
*
item
));
item
=
malloc
(
sizeof
(
*
item
));
if
(
!
item
)
{
if
(
!
item
)
{
ERROR
(
"failed to allocate memory to sort cgroup settings"
);
free_cgroup_settings
(
result
);
free_cgroup_settings
(
result
);
return
NULL
;
return
NULL
;
}
}
item
->
elem
=
it
->
elem
;
item
->
elem
=
it
->
elem
;
cg
=
it
->
elem
;
cg
=
it
->
elem
;
if
(
strcmp
(
cg
->
subsystem
,
"memory.memsw.limit_in_bytes"
)
==
0
)
{
if
(
strcmp
(
cg
->
subsystem
,
"memory.memsw.limit_in_bytes"
)
==
0
)
{
/* Store the memsw_limit location */
/* Store the memsw_limit location */
memsw_limit
=
item
;
memsw_limit
=
item
;
}
else
if
(
strcmp
(
cg
->
subsystem
,
"memory.limit_in_bytes"
)
==
0
&&
memsw_limit
!=
NULL
)
{
}
else
if
(
strcmp
(
cg
->
subsystem
,
"memory.limit_in_bytes"
)
==
0
&&
/* lxc.cgroup.memory.memsw.limit_in_bytes is found before
memsw_limit
!=
NULL
)
{
* lxc.cgroup.memory.limit_in_bytes, swap these two items */
/* lxc.cgroup.memory.memsw.limit_in_bytes is found
* before lxc.cgroup.memory.limit_in_bytes, swap these
* two items */
item
->
elem
=
memsw_limit
->
elem
;
item
->
elem
=
memsw_limit
->
elem
;
memsw_limit
->
elem
=
it
->
elem
;
memsw_limit
->
elem
=
it
->
elem
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment