Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #20 from Bumblebee-Project/upstream-merge

Security improvements and package result type support
  • Loading branch information...
commit a58d68935d97be943a26a7db87da3d79d11d884c 2 parents 07a2e89 + 2b2f69f
@mkottman authored
Showing with 94 additions and 30 deletions.
  1. +4 −3 Makefile
  2. +11 −2 README
  3. +79 −25 acpi_call.c
View
7 Makefile
@@ -1,6 +1,7 @@
obj-m := acpi_call.o
-KDIR := /lib/modules/$(shell uname -r)/build
+KVERSION := $(shell uname -r)
+KDIR := /lib/modules/$(KVERSION)/build
PWD := $(shell pwd)
default:
@@ -10,5 +11,5 @@ clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
load:
- -sudo /sbin/rmmod acpi_call
- sudo /sbin/insmod acpi_call.ko
+ -/sbin/rmmod acpi_call
+ /sbin/insmod acpi_call.ko
View
13 README
@@ -1,9 +1,16 @@
A kernel module that enables you to call ACPI methods by writing the method
-name followed by arguments to /proc/acpi/call, for example to turn off discrete
-graphics card in a dual graphics environment (like NVIDIA Optimus).
+name followed by arguments to /proc/acpi/call.
Usage:
+ echo '<call>' | sudo tee /proc/acpi/call
+You can then retrieve the result of the call by checking your dmesg or:
+
+ sudo cat /proc/acpi/call
+
+An example to turn off discrete graphics card in a dual graphics environment
+(like NVIDIA Optimus):
+
# turn off discrete graphics card
echo '\_SB.PCI0.PEG1.GFX0.DOFF' > /proc/acpi/call
# turn it back on
@@ -31,6 +38,8 @@ The status after a call can be read back from /proc/acpi/call:
* '0xNN' - the call succeeded, and returned an integer
* '"..."' - the call succeeded, and returned a string
* '{0xNN, ...}' - the call succeeded, and returned a buffer
+* '[...]' - the call succeeded, and returned a package which may contain the
+ above types (integer, string and buffer) and other package types
Copyright (c) 2010: Michal Kottman
View
104 acpi_call.c
@@ -9,11 +9,71 @@
MODULE_LICENSE("GPL");
+#define BUFFER_SIZE 256
+
extern struct proc_dir_entry *acpi_root_dir;
-static char result_buffer[256];
+static char result_buffer[BUFFER_SIZE];
-static u8 temporary_buffer[256];
+static u8 temporary_buffer[BUFFER_SIZE];
+
+static size_t get_avail_bytes(void) {
+ return BUFFER_SIZE - strlen(result_buffer);
+}
+static char *get_buffer_end(void) {
+ return result_buffer + strlen(result_buffer);
+}
+/** Appends the contents of an acpi_object to the result buffer
+@param result An acpi object holding result data
+@returns 0 if the result could fully be saved, a higher value otherwise
+*/
+static int acpi_result_to_string(union acpi_object *result) {
+ if (result->type == ACPI_TYPE_INTEGER) {
+ snprintf(get_buffer_end(), get_avail_bytes(),
+ "0x%x", (int)result->integer.value);
+ } else if (result->type == ACPI_TYPE_STRING) {
+ snprintf(get_buffer_end(), get_avail_bytes(),
+ "\"%*s\"", result->string.length, result->string.pointer);
+ } else if (result->type == ACPI_TYPE_BUFFER) {
+ int i;
+ // do not store more than data if it does not fit. The first element is
+ // just 4 chars, but there is also two bytes from the curly brackets
+ int show_values = min(result->buffer.length, get_avail_bytes() / 6);
+
+ sprintf(get_buffer_end(), "{");
+ for (i = 0; i < show_values; i++)
+ sprintf(get_buffer_end(),
+ i == 0 ? "0x%02x" : ", 0x%02x", result->buffer.pointer[i]);
+
+ if (result->buffer.length > show_values) {
+ // if data was truncated, show a trailing comma if there is space
+ snprintf(get_buffer_end(), get_avail_bytes(), ",");
+ return 1;
+ } else {
+ // in case show_values == 0, but the buffer is too small to hold
+ // more values (i.e. the buffer cannot have anything more than "{")
+ snprintf(get_buffer_end(), get_avail_bytes(), "}");
+ }
+ } else if (result->type == ACPI_TYPE_PACKAGE) {
+ int i;
+ sprintf(get_buffer_end(), "[");
+ for (i=0; i<result->package.count; i++) {
+ if (i > 0)
+ snprintf(get_buffer_end(), get_avail_bytes(), ", ");
+
+ // abort if there is no more space available
+ if (!get_avail_bytes() || acpi_result_to_string(&result->package.elements[i]))
+ return 1;
+ }
+ snprintf(get_buffer_end(), get_avail_bytes(), "]");
+ } else {
+ snprintf(get_buffer_end(), get_avail_bytes(),
+ "Object type 0x%x\n", result->type);
+ }
+
+ // return 0 if there are still bytes available, 1 otherwise
+ return !get_avail_bytes();
+}
/**
@param method The full name of ACPI method to call
@@ -26,7 +86,6 @@ static void do_acpi_call(const char * method, int argc, union acpi_object *argv)
acpi_handle handle;
struct acpi_object_list arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *result;
printk(KERN_INFO "acpi_call: Calling %s\n", method);
@@ -35,7 +94,7 @@ static void do_acpi_call(const char * method, int argc, union acpi_object *argv)
if (ACPI_FAILURE(status))
{
- sprintf(result_buffer, "Error: %s", acpi_format_exception(status));
+ snprintf(result_buffer, BUFFER_SIZE, "Error: %s", acpi_format_exception(status));
printk(KERN_ERR "acpi_call: Cannot get handle: %s\n", result_buffer);
return;
}
@@ -48,25 +107,14 @@ static void do_acpi_call(const char * method, int argc, union acpi_object *argv)
status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
if (ACPI_FAILURE(status))
{
- sprintf(result_buffer, "Error: %s", acpi_format_exception(status));
+ snprintf(result_buffer, BUFFER_SIZE, "Error: %s", acpi_format_exception(status));
printk(KERN_ERR "acpi_call: Method call failed: %s\n", result_buffer);
return;
}
- result = buffer.pointer;
- if (result->type == ACPI_TYPE_INTEGER) {
- sprintf(result_buffer, "0x%x", (int)result->integer.value);
- } else if (result->type == ACPI_TYPE_STRING) {
- sprintf(result_buffer, "\"%*s\"", result->string.length, result->string.pointer);
- } else if (result->type == ACPI_TYPE_BUFFER) {
- int i;
- sprintf(result_buffer, "{");
- for (i = 0; i < result->buffer.length; i++)
- sprintf(result_buffer + strlen(result_buffer),
- i == 0 ? "0x%02x" : ", 0x%02x", result->buffer.pointer[i]);
- strcpy(result_buffer + strlen(result_buffer), "}");
- } else {
- sprintf(result_buffer, "Object type 0x%x\n", result->type);
- }
+
+ // reset the result buffer
+ *result_buffer = '\0';
+ acpi_result_to_string(buffer.pointer);
kfree(buffer.pointer);
printk(KERN_INFO "acpi_call: Call successful: %s\n", result_buffer);
@@ -149,8 +197,13 @@ static char *parse_acpi_args(char *input, int *nargs, union acpi_object **args)
arg->buffer.pointer = buf;
arg->buffer.length = 0;
while (*s && *s++ != '}') {
- if (buf >= temporary_buffer + sizeof(temporary_buffer))
- printk(KERN_ERR "buffer full\n");
+ if (buf >= temporary_buffer + sizeof(temporary_buffer)) {
+ printk(KERN_ERR "acpi_call: buffer arg%d is truncated because the buffer is full\n", *nargs);
+ // clear remaining arguments
+ while (*s && *s != '}')
+ ++s;
+ break;
+ }
else if (*s >= '0' && *s <= '9') {
// decode integer into buffer
arg->buffer.length ++;
@@ -190,7 +243,7 @@ static char *parse_acpi_args(char *input, int *nargs, union acpi_object **args)
static int acpi_proc_write( struct file *filp, const char __user *buff,
unsigned long len, void *data )
{
- char input[512] = { '\0' };
+ char input[2 * BUFFER_SIZE] = { '\0' };
union acpi_object *args;
int nargs, i;
char *method;
@@ -247,7 +300,7 @@ static int acpi_proc_read(char *page, char **start, off_t off,
/** module initialization function */
static int __init init_acpi_call(void)
{
- struct proc_dir_entry *acpi_entry = create_proc_entry("call", 0666, acpi_root_dir);
+ struct proc_dir_entry *acpi_entry = create_proc_entry("call", 0660, acpi_root_dir);
strcpy(result_buffer, "not called");
@@ -263,9 +316,10 @@ static int __init init_acpi_call(void)
return 0;
}
-static void unload_acpi_call(void)
+static void __exit unload_acpi_call(void)
{
remove_proc_entry("call", acpi_root_dir);
+ printk(KERN_INFO "acpi_call: Module unloaded successfully\n");
}
module_init(init_acpi_call);
Please sign in to comment.
Something went wrong with that request. Please try again.