Skip to content

Commit 8055a25

Browse files
authored
[fix]: UI upgrade now runs as the same user as the js-controller (#2950)
* the UI upgrade now runs as the same user as the js-controller * jsdoc * jsdoc * make method private
1 parent 0320a1a commit 8055a25

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
## __WORK IN PROGRESS__
55
-->
66

7-
## __WORK IN PROGRESS__
7+
## __WORK IN PROGRESS__ - Lucy
8+
* (@foxriver76) the UI upgrade now runs as the same user as the js-controller
89
* (@foxriver76) fixed `iob validate` command and `setup custom` migration
910

1011
## 7.0.1 (2024-10-21) - Lucy

packages/controller/src/lib/upgradeManager.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ import fs from 'fs-extra';
1111
import type { Socket } from 'node:net';
1212
import type { Duplex } from 'node:stream';
1313
import url from 'node:url';
14+
import process from 'node:process';
1415

16+
/** The upgrade arguments provided to the constructor of the UpgradeManager */
1517
export interface UpgradeArguments {
1618
/** Version of controller to upgrade too */
1719
version: string;
1820
/** Admin instance which triggered the upgrade */
1921
adminInstance: number;
22+
/** User id the process should run as */
23+
uid: number;
24+
/** Group id the process should run as */
25+
gid: number;
2026
}
2127

2228
interface Certificates {
@@ -63,6 +69,10 @@ class UpgradeManager {
6369
private readonly adminInstance: number;
6470
/** Desired controller version */
6571
private readonly version: string;
72+
/** Group id the process should run as */
73+
private readonly gid: number;
74+
/** User id the process should run as */
75+
private readonly uid: number;
6676
/** Response send by webserver */
6777
private readonly response: ServerResponse = {
6878
running: true,
@@ -85,6 +95,30 @@ class UpgradeManager {
8595
this.adminInstance = args.adminInstance;
8696
this.version = args.version;
8797
this.logger = this.setupLogger();
98+
this.gid = args.gid;
99+
this.uid = args.uid;
100+
101+
this.applyUser();
102+
}
103+
104+
/**
105+
* To prevent commands (including npm) running as root, we apply the passed in gid and uid
106+
*/
107+
private applyUser(): void {
108+
if (!process.setuid || !process.setgid) {
109+
const errMessage = 'Cannot ensure user and group ids on this system, because no POSIX platform';
110+
this.log(errMessage, true);
111+
throw new Error(errMessage);
112+
}
113+
114+
try {
115+
process.setgid(this.gid);
116+
process.setuid(this.uid);
117+
} catch (e) {
118+
const errMessage = `Could not ensure user and group ids on this system: ${e.message}`;
119+
this.log(errMessage, true);
120+
throw new Error(errMessage);
121+
}
88122
}
89123

90124
/**
@@ -103,6 +137,8 @@ class UpgradeManager {
103137

104138
const version = additionalArgs[0];
105139
const adminInstance = parseInt(additionalArgs[1]);
140+
const uid = parseInt(additionalArgs[2]);
141+
const gid = parseInt(additionalArgs[3]);
106142

107143
const isValid = !!valid(version);
108144

@@ -116,7 +152,17 @@ class UpgradeManager {
116152
throw new Error('Please provide a valid admin instance');
117153
}
118154

119-
return { version, adminInstance };
155+
if (isNaN(uid)) {
156+
UpgradeManager.printUsage();
157+
throw new Error('Please provide a valid uid');
158+
}
159+
160+
if (isNaN(gid)) {
161+
UpgradeManager.printUsage();
162+
throw new Error('Please provide a valid gid');
163+
}
164+
165+
return { version, adminInstance, uid, gid };
120166
}
121167

122168
/**
@@ -163,7 +209,7 @@ class UpgradeManager {
163209
* Print how the module should be used
164210
*/
165211
static printUsage(): void {
166-
console.info('Example usage: "node upgradeManager.js <version> <adminInstance>"');
212+
console.info('Example usage: "node upgradeManager.js <version> <adminInstance> <uid> <gid>"');
167213
}
168214

169215
/**

packages/controller/src/main.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2760,7 +2760,12 @@ async function processMessage(msg: ioBroker.SendableMessage): Promise<null | voi
27602760
const { version, adminInstance } = msg.message;
27612761

27622762
logger.info(`${hostLogPrefix} Controller will upgrade itself to version ${version}`);
2763-
await startUpgradeManager({ version, adminInstance });
2763+
await startUpgradeManager({
2764+
version,
2765+
adminInstance,
2766+
uid: process.getuid ? process.getuid() : 0,
2767+
gid: process.getgid ? process.getgid() : 0,
2768+
});
27642769

27652770
if (msg.callback) {
27662771
sendTo(msg.from, msg.command, { result: true }, msg.callback);
@@ -5848,7 +5853,7 @@ async function upgradeOsPackages(packages: UpgradePacket[]): Promise<void> {
58485853
* @param options Arguments passed to the UpgradeManager process
58495854
*/
58505855
async function startUpgradeManager(options: UpgradeArguments): Promise<void> {
5851-
const { version, adminInstance } = options;
5856+
const { version, adminInstance, uid, gid } = options;
58525857
const upgradeProcessPath = require.resolve('./lib/upgradeManager');
58535858
let upgradeProcess: cp.ChildProcess;
58545859

@@ -5864,6 +5869,8 @@ async function startUpgradeManager(options: UpgradeArguments): Promise<void> {
58645869
upgradeProcessPath,
58655870
version,
58665871
adminInstance.toString(),
5872+
uid.toString(),
5873+
gid.toString(),
58675874
],
58685875
{
58695876
detached: true,

0 commit comments

Comments
 (0)